aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian <julian@sparx.micasa>2012-02-23 17:59:07 +0100
committerJulian <julian@sparx.micasa>2012-02-23 17:59:07 +0100
commita9461cd8861fd449806ccb6cf0827762bd1089c1 (patch)
tree263243bfcd4a4055e47db595cfef3c87043c1a8e
downloadblassic-a9461cd8861fd449806ccb6cf0827762bd1089c1.tar.gz
initializing repo from version 0.10.2 minus the example files
-rw-r--r--AUTHORS3
-rw-r--r--COPYING674
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL237
-rw-r--r--Makefile.am208
-rw-r--r--Makefile.in1413
-rw-r--r--NEWS570
-rw-r--r--README83
-rw-r--r--acinclude.m4198
-rw-r--r--aclocal.m4869
-rwxr-xr-xautogen.sh3
-rw-r--r--blassic.cpp963
-rw-r--r--blassic.h254
-rw-r--r--blassic.spec.in63
-rwxr-xr-xbootstrap5
-rw-r--r--charset.h25
-rw-r--r--codeline.cpp990
-rw-r--r--codeline.h60
-rw-r--r--configure.ac295
-rw-r--r--cpc.def2817
-rw-r--r--cursor.cpp1477
-rw-r--r--cursor.h56
-rw-r--r--default.def2827
-rw-r--r--dim.cpp64
-rw-r--r--dim.h29
-rw-r--r--directory.cpp252
-rw-r--r--directory.h38
-rw-r--r--dynamic.cpp222
-rw-r--r--dynamic.h108
-rw-r--r--edit.cpp515
-rw-r--r--edit.h23
-rw-r--r--element.cpp87
-rw-r--r--element.h155
-rw-r--r--error.cpp194
-rw-r--r--error.h105
-rw-r--r--file.cpp903
-rw-r--r--file.h178
-rw-r--r--fileconsole.cpp532
-rw-r--r--filepopen.cpp1191
-rw-r--r--fileprinter.cpp684
-rw-r--r--filesocket.cpp152
-rw-r--r--filewindow.cpp332
-rw-r--r--function.cpp249
-rw-r--r--function.h50
-rw-r--r--gencharset.cpp221
-rw-r--r--graphics.cpp8110
-rw-r--r--graphics.h164
-rw-r--r--key.cpp155
-rw-r--r--key.h43
-rw-r--r--keyword.cpp378
-rw-r--r--keyword.h305
-rw-r--r--mbf.cpp158
-rw-r--r--mbf.h25
-rw-r--r--memory.cpp166
-rw-r--r--memory.h23
-rw-r--r--msx.def2816
-rw-r--r--program.cpp1611
-rw-r--r--program.h47
-rw-r--r--regexp.cpp302
-rw-r--r--regexp.h38
-rw-r--r--result.h558
-rw-r--r--runner.cpp2190
-rw-r--r--runner.h658
-rw-r--r--runnerline.cpp26
-rw-r--r--runnerline.h34
-rw-r--r--runnerline_impl.cpp4347
-rw-r--r--runnerline_impl.h531
-rw-r--r--runnerline_instructions.cpp4277
-rw-r--r--runnerline_print.cpp367
-rw-r--r--showerror.cpp89
-rw-r--r--showerror.h7
-rw-r--r--socket.cpp272
-rw-r--r--socket.h54
-rw-r--r--spectrum.def1556
-rw-r--r--sysvar.cpp153
-rw-r--r--sysvar.h198
-rw-r--r--testdl.cpp49
-rw-r--r--token.cpp315
-rw-r--r--token.h53
-rw-r--r--trace.cpp176
-rw-r--r--trace.h39
-rw-r--r--using.cpp582
-rw-r--r--using.h96
-rw-r--r--util.h202
-rw-r--r--var.cpp715
-rw-r--r--var.h71
-rw-r--r--version.cpp13
87 files changed, 52343 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b1e648c
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+Author: Julián Albo, "NotFound".
+julian.notfound@gmail.com
+See also the 'THANKS' file.
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ 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
+state 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) <year> <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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU 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 Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d3c5b40
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,237 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007 Free Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 6. Often, you can also type `make uninstall' to remove the installed
+ files again.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..1bffb80
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,208 @@
+# Makefile.am
+# Originally written by Pierre Sarrazin
+# Changes and additions by Julián Albo
+# Last revision 23-feb-2012
+
+noinst_PROGRAMS = gencharset
+bin_PROGRAMS = blassic
+
+
+# This tells Automake that charset.cpp must be generated before
+# anything else is compiled.
+
+# Changed, now use several charsets.
+#BUILT_SOURCES = charset.cpp
+# Testing other way.
+#BUILT_SOURCES = charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp
+BUILT_SOURCES = gencharset$(EXEEXT)
+
+# Needed to generate charset cpp files:
+
+gencharset_SOURCES = gencharset.cpp
+
+gencharset_CXXFLAGS = $(CXXFLAGS_FOR_BUILD)
+
+gencharset_LDFLAGS =
+
+# This way the .exe extension is appended when compiling for windows
+# under linux, but it works anyway.
+gencharset$(EXEEXT): gencharset.cpp
+ $(CXX_FOR_BUILD) $(gencharset_CXXFLAGS) $(gencharset_LDFLAGS) \
+ -o gencharset$(EXEEXT) \
+ gencharset.cpp
+
+# Character sets for graphics modes.
+
+#charset.cpp: $(srcdir)/charset.def gencharset
+# ./gencharset $(srcdir)/charset.def charset.cpp
+# test -f charset.cpp
+
+charset_default.cpp: $(srcdir)/default.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/default.def \
+ charset_default.cpp default
+ test -f charset_default.cpp
+
+charset_cpc.cpp: $(srcdir)/cpc.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/cpc.def \
+ charset_cpc.cpp cpc
+ test -f charset_cpc.cpp
+
+charset_spectrum.cpp: $(srcdir)/spectrum.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/spectrum.def \
+ charset_spectrum.cpp spectrum
+ test -f charset_spectrum.cpp
+
+charset_msx.cpp: $(srcdir)/msx.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/msx.def \
+ charset_msx.cpp msx
+ test -f charset_msx.cpp
+
+
+blassic_SOURCES = \
+ charset_default.cpp \
+ charset_cpc.cpp \
+ charset_spectrum.cpp \
+ charset_msx.cpp \
+ charset.h \
+ blassic.cpp \
+ blassic.h \
+ codeline.cpp \
+ codeline.h \
+ cursor.cpp \
+ cursor.h \
+ dim.cpp \
+ dim.h \
+ directory.cpp \
+ directory.h \
+ dynamic.cpp \
+ dynamic.h \
+ edit.cpp \
+ edit.h \
+ element.h \
+ element.cpp \
+ error.cpp \
+ error.h \
+ file.cpp \
+ file.h \
+ fileconsole.cpp \
+ filepopen.cpp \
+ fileprinter.cpp \
+ filesocket.cpp \
+ filewindow.cpp \
+ function.cpp \
+ function.h \
+ graphics.cpp \
+ graphics.h \
+ key.cpp \
+ key.h \
+ keyword.cpp \
+ keyword.h \
+ mbf.cpp \
+ mbf.h \
+ memory.cpp \
+ memory.h \
+ program.cpp \
+ program.h \
+ regexp.cpp \
+ regexp.h \
+ result.h \
+ runner.cpp \
+ runner.h \
+ runnerline.cpp \
+ runnerline.h \
+ runnerline_impl.cpp \
+ runnerline_impl.h \
+ runnerline_instructions.cpp \
+ runnerline_print.cpp \
+ showerror.cpp \
+ showerror.h \
+ socket.cpp \
+ socket.h \
+ sysvar.cpp \
+ sysvar.h \
+ token.cpp \
+ token.h \
+ trace.cpp \
+ trace.h \
+ using.cpp \
+ using.h \
+ util.h \
+ var.cpp \
+ var.h \
+ version.cpp
+
+blassic_CXXFLAGS = @SVGALIB_CFLAGS@ @BL_X_CFLAGS@
+blassic_LDFLAGS = @BL_X_LIBS@
+blassic_LDADD = @SVGALIB_LIBS@ @CYGWIN_FLAGS@ @BL_X_ADD@
+
+
+# testdl: a tiny library to test blassic dynamic link.
+
+
+# Julian: modified this to allow cross-compiling.
+#testdl.so: testdl.o
+# gcc -shared -Wl,-soname,testdl.so -o testdl.so testdl.o
+#testdl.o: testdl.cpp
+# gcc -Wall -fPIC -c testdl.cpp
+
+#testdl_CXXFLAGS = \
+# -W -Wall -Wwrite-strings -Wstrict-prototypes \
+# -Wunused
+
+testdl.so: testdl.o
+ $(CXX) -shared -Wl,-soname,testdl.so $(LDFLAGS) -o testdl.so testdl.o
+
+testdl.o: testdl.cpp
+ $(CXX) -fPIC $(testdl_CXXFLAGS) -c testdl.cpp
+
+
+rpm: dist
+ rpm -ta $(distdir).tar.gz
+
+EXTRA_DIST = \
+ bootstrap autogen.sh \
+ do_conf \
+ do_confnodeb \
+ do_confcross_arm \
+ do_confcross_mingw \
+ do_confhpux \
+ blassic.spec \
+ alphabet.blc automod.blc \
+ blassic.bpr \
+ testdl.bpr \
+ random.dat \
+ gencharset.cpp \
+ charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp \
+ default.def cpc.def spectrum.def msx.def \
+ counter.sh \
+ testdl.cpp
+
+#CLEANFILES = testdl.so $(BUILT_SOURCES)
+CLEANFILES = testdl.so
+
+# When Automake needs to regenerate configure, the following options
+# will be passed to aclocal, as in the bootstrap script.
+ACLOCAL_AMFLAGS = -I .
+
+
+# Boilerplate:
+
+auxdir = @ac_aux_dir@
+AUX_DIST = $(auxdir)/install-sh $(auxdir)/missing $(auxdir)/mkinstalldirs
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ aclocal.m4 \
+ configure \
+ sic/config-h.in \
+ sic/stamp-h.in \
+ $(AUX_DIST) \
+ depcomp \
+ config.guess \
+ config.log \
+ config.status \
+ config.sub \
+ install-sh \
+ missing \
+ mkinstalldirs
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..67c99d8
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,1413 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile.am
+# Originally written by Pierre Sarrazin
+# Changes and additions by Julián Albo
+# Last revision 23-feb-2012
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+noinst_PROGRAMS = gencharset$(EXEEXT)
+bin_PROGRAMS = blassic$(EXEEXT)
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/blassic.spec.in \
+ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
+ config.guess config.sub depcomp install-sh missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_CLEAN_FILES = blassic.spec
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
+am_blassic_OBJECTS = blassic-charset_default.$(OBJEXT) \
+ blassic-charset_cpc.$(OBJEXT) \
+ blassic-charset_spectrum.$(OBJEXT) \
+ blassic-charset_msx.$(OBJEXT) blassic-blassic.$(OBJEXT) \
+ blassic-codeline.$(OBJEXT) blassic-cursor.$(OBJEXT) \
+ blassic-dim.$(OBJEXT) blassic-directory.$(OBJEXT) \
+ blassic-dynamic.$(OBJEXT) blassic-edit.$(OBJEXT) \
+ blassic-element.$(OBJEXT) blassic-error.$(OBJEXT) \
+ blassic-file.$(OBJEXT) blassic-fileconsole.$(OBJEXT) \
+ blassic-filepopen.$(OBJEXT) blassic-fileprinter.$(OBJEXT) \
+ blassic-filesocket.$(OBJEXT) blassic-filewindow.$(OBJEXT) \
+ blassic-function.$(OBJEXT) blassic-graphics.$(OBJEXT) \
+ blassic-key.$(OBJEXT) blassic-keyword.$(OBJEXT) \
+ blassic-mbf.$(OBJEXT) blassic-memory.$(OBJEXT) \
+ blassic-program.$(OBJEXT) blassic-regexp.$(OBJEXT) \
+ blassic-runner.$(OBJEXT) blassic-runnerline.$(OBJEXT) \
+ blassic-runnerline_impl.$(OBJEXT) \
+ blassic-runnerline_instructions.$(OBJEXT) \
+ blassic-runnerline_print.$(OBJEXT) blassic-showerror.$(OBJEXT) \
+ blassic-socket.$(OBJEXT) blassic-sysvar.$(OBJEXT) \
+ blassic-token.$(OBJEXT) blassic-trace.$(OBJEXT) \
+ blassic-using.$(OBJEXT) blassic-var.$(OBJEXT) \
+ blassic-version.$(OBJEXT)
+blassic_OBJECTS = $(am_blassic_OBJECTS)
+blassic_DEPENDENCIES =
+blassic_LINK = $(CXXLD) $(blassic_CXXFLAGS) $(CXXFLAGS) \
+ $(blassic_LDFLAGS) $(LDFLAGS) -o $@
+am_gencharset_OBJECTS = gencharset-gencharset.$(OBJEXT)
+gencharset_OBJECTS = $(am_gencharset_OBJECTS)
+gencharset_LDADD = $(LDADD)
+gencharset_LINK = $(CXXLD) $(gencharset_CXXFLAGS) $(CXXFLAGS) \
+ $(gencharset_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(blassic_SOURCES) $(gencharset_SOURCES)
+DIST_SOURCES = $(blassic_SOURCES) $(gencharset_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d $(distdir) \
+ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr $(distdir); }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BL_X_ADD = @BL_X_ADD@
+BL_X_CFLAGS = @BL_X_CFLAGS@
+BL_X_LIBS = @BL_X_LIBS@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@
+CXX_FOR_BUILD = @CXX_FOR_BUILD@
+CYGPATH_W = @CYGPATH_W@
+CYGWIN_FLAGS = @CYGWIN_FLAGS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+SVGALIB_CFLAGS = @SVGALIB_CFLAGS@
+SVGALIB_LIBS = @SVGALIB_LIBS@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# This tells Automake that charset.cpp must be generated before
+# anything else is compiled.
+
+# Changed, now use several charsets.
+#BUILT_SOURCES = charset.cpp
+# Testing other way.
+#BUILT_SOURCES = charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp
+BUILT_SOURCES = gencharset$(EXEEXT)
+
+# Needed to generate charset cpp files:
+gencharset_SOURCES = gencharset.cpp
+gencharset_CXXFLAGS = $(CXXFLAGS_FOR_BUILD)
+gencharset_LDFLAGS =
+blassic_SOURCES = \
+ charset_default.cpp \
+ charset_cpc.cpp \
+ charset_spectrum.cpp \
+ charset_msx.cpp \
+ charset.h \
+ blassic.cpp \
+ blassic.h \
+ codeline.cpp \
+ codeline.h \
+ cursor.cpp \
+ cursor.h \
+ dim.cpp \
+ dim.h \
+ directory.cpp \
+ directory.h \
+ dynamic.cpp \
+ dynamic.h \
+ edit.cpp \
+ edit.h \
+ element.h \
+ element.cpp \
+ error.cpp \
+ error.h \
+ file.cpp \
+ file.h \
+ fileconsole.cpp \
+ filepopen.cpp \
+ fileprinter.cpp \
+ filesocket.cpp \
+ filewindow.cpp \
+ function.cpp \
+ function.h \
+ graphics.cpp \
+ graphics.h \
+ key.cpp \
+ key.h \
+ keyword.cpp \
+ keyword.h \
+ mbf.cpp \
+ mbf.h \
+ memory.cpp \
+ memory.h \
+ program.cpp \
+ program.h \
+ regexp.cpp \
+ regexp.h \
+ result.h \
+ runner.cpp \
+ runner.h \
+ runnerline.cpp \
+ runnerline.h \
+ runnerline_impl.cpp \
+ runnerline_impl.h \
+ runnerline_instructions.cpp \
+ runnerline_print.cpp \
+ showerror.cpp \
+ showerror.h \
+ socket.cpp \
+ socket.h \
+ sysvar.cpp \
+ sysvar.h \
+ token.cpp \
+ token.h \
+ trace.cpp \
+ trace.h \
+ using.cpp \
+ using.h \
+ util.h \
+ var.cpp \
+ var.h \
+ version.cpp
+
+blassic_CXXFLAGS = @SVGALIB_CFLAGS@ @BL_X_CFLAGS@
+blassic_LDFLAGS = @BL_X_LIBS@
+blassic_LDADD = @SVGALIB_LIBS@ @CYGWIN_FLAGS@ @BL_X_ADD@
+EXTRA_DIST = \
+ bootstrap autogen.sh \
+ do_conf \
+ do_confnodeb \
+ do_confcross_arm \
+ do_confcross_mingw \
+ do_confhpux \
+ blassic.spec \
+ alphabet.blc automod.blc \
+ blassic.bpr \
+ testdl.bpr \
+ random.dat \
+ gencharset.cpp \
+ charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp \
+ default.def cpc.def spectrum.def msx.def \
+ counter.sh \
+ testdl.cpp
+
+
+#CLEANFILES = testdl.so $(BUILT_SOURCES)
+CLEANFILES = testdl.so
+
+# When Automake needs to regenerate configure, the following options
+# will be passed to aclocal, as in the bootstrap script.
+ACLOCAL_AMFLAGS = -I .
+
+# Boilerplate:
+auxdir = @ac_aux_dir@
+AUX_DIST = $(auxdir)/install-sh $(auxdir)/missing $(auxdir)/mkinstalldirs
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ aclocal.m4 \
+ configure \
+ sic/config-h.in \
+ sic/stamp-h.in \
+ $(AUX_DIST) \
+ depcomp \
+ config.guess \
+ config.log \
+ config.status \
+ config.sub \
+ install-sh \
+ missing \
+ mkinstalldirs
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .o .obj
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
+ cd $(srcdir) && $(AUTOMAKE) --gnu \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+blassic.spec: $(top_builddir)/config.status $(srcdir)/blassic.spec.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+ if test -f $$p \
+ ; then \
+ f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+ $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; for p in $$list; do \
+ f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+ echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+ rm -f "$(DESTDIR)$(bindir)/$$f"; \
+ done
+
+clean-binPROGRAMS:
+ -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+blassic$(EXEEXT): $(blassic_OBJECTS) $(blassic_DEPENDENCIES)
+ @rm -f blassic$(EXEEXT)
+ $(blassic_LINK) $(blassic_OBJECTS) $(blassic_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-blassic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_cpc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_default.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_msx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_spectrum.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-codeline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-cursor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-dim.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-directory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-dynamic.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-edit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-element.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-error.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-file.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-fileconsole.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-filepopen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-fileprinter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-filesocket.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-filewindow.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-function.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-graphics.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-key.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-keyword.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-mbf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-program.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-regexp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runner.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline_impl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline_instructions.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline_print.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-showerror.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-socket.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-sysvar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-token.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-trace.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-using.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-var.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gencharset-gencharset.Po@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+blassic-charset_default.o: charset_default.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_default.o -MD -MP -MF $(DEPDIR)/blassic-charset_default.Tpo -c -o blassic-charset_default.o `test -f 'charset_default.cpp' || echo '$(srcdir)/'`charset_default.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_default.Tpo $(DEPDIR)/blassic-charset_default.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_default.cpp' object='blassic-charset_default.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_default.o `test -f 'charset_default.cpp' || echo '$(srcdir)/'`charset_default.cpp
+
+blassic-charset_default.obj: charset_default.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_default.obj -MD -MP -MF $(DEPDIR)/blassic-charset_default.Tpo -c -o blassic-charset_default.obj `if test -f 'charset_default.cpp'; then $(CYGPATH_W) 'charset_default.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_default.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_default.Tpo $(DEPDIR)/blassic-charset_default.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_default.cpp' object='blassic-charset_default.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_default.obj `if test -f 'charset_default.cpp'; then $(CYGPATH_W) 'charset_default.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_default.cpp'; fi`
+
+blassic-charset_cpc.o: charset_cpc.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_cpc.o -MD -MP -MF $(DEPDIR)/blassic-charset_cpc.Tpo -c -o blassic-charset_cpc.o `test -f 'charset_cpc.cpp' || echo '$(srcdir)/'`charset_cpc.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_cpc.Tpo $(DEPDIR)/blassic-charset_cpc.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_cpc.cpp' object='blassic-charset_cpc.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_cpc.o `test -f 'charset_cpc.cpp' || echo '$(srcdir)/'`charset_cpc.cpp
+
+blassic-charset_cpc.obj: charset_cpc.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_cpc.obj -MD -MP -MF $(DEPDIR)/blassic-charset_cpc.Tpo -c -o blassic-charset_cpc.obj `if test -f 'charset_cpc.cpp'; then $(CYGPATH_W) 'charset_cpc.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_cpc.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_cpc.Tpo $(DEPDIR)/blassic-charset_cpc.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_cpc.cpp' object='blassic-charset_cpc.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_cpc.obj `if test -f 'charset_cpc.cpp'; then $(CYGPATH_W) 'charset_cpc.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_cpc.cpp'; fi`
+
+blassic-charset_spectrum.o: charset_spectrum.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_spectrum.o -MD -MP -MF $(DEPDIR)/blassic-charset_spectrum.Tpo -c -o blassic-charset_spectrum.o `test -f 'charset_spectrum.cpp' || echo '$(srcdir)/'`charset_spectrum.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_spectrum.Tpo $(DEPDIR)/blassic-charset_spectrum.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_spectrum.cpp' object='blassic-charset_spectrum.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_spectrum.o `test -f 'charset_spectrum.cpp' || echo '$(srcdir)/'`charset_spectrum.cpp
+
+blassic-charset_spectrum.obj: charset_spectrum.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_spectrum.obj -MD -MP -MF $(DEPDIR)/blassic-charset_spectrum.Tpo -c -o blassic-charset_spectrum.obj `if test -f 'charset_spectrum.cpp'; then $(CYGPATH_W) 'charset_spectrum.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_spectrum.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_spectrum.Tpo $(DEPDIR)/blassic-charset_spectrum.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_spectrum.cpp' object='blassic-charset_spectrum.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_spectrum.obj `if test -f 'charset_spectrum.cpp'; then $(CYGPATH_W) 'charset_spectrum.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_spectrum.cpp'; fi`
+
+blassic-charset_msx.o: charset_msx.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_msx.o -MD -MP -MF $(DEPDIR)/blassic-charset_msx.Tpo -c -o blassic-charset_msx.o `test -f 'charset_msx.cpp' || echo '$(srcdir)/'`charset_msx.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_msx.Tpo $(DEPDIR)/blassic-charset_msx.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_msx.cpp' object='blassic-charset_msx.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_msx.o `test -f 'charset_msx.cpp' || echo '$(srcdir)/'`charset_msx.cpp
+
+blassic-charset_msx.obj: charset_msx.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_msx.obj -MD -MP -MF $(DEPDIR)/blassic-charset_msx.Tpo -c -o blassic-charset_msx.obj `if test -f 'charset_msx.cpp'; then $(CYGPATH_W) 'charset_msx.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_msx.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_msx.Tpo $(DEPDIR)/blassic-charset_msx.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_msx.cpp' object='blassic-charset_msx.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_msx.obj `if test -f 'charset_msx.cpp'; then $(CYGPATH_W) 'charset_msx.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_msx.cpp'; fi`
+
+blassic-blassic.o: blassic.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-blassic.o -MD -MP -MF $(DEPDIR)/blassic-blassic.Tpo -c -o blassic-blassic.o `test -f 'blassic.cpp' || echo '$(srcdir)/'`blassic.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-blassic.Tpo $(DEPDIR)/blassic-blassic.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='blassic.cpp' object='blassic-blassic.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-blassic.o `test -f 'blassic.cpp' || echo '$(srcdir)/'`blassic.cpp
+
+blassic-blassic.obj: blassic.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-blassic.obj -MD -MP -MF $(DEPDIR)/blassic-blassic.Tpo -c -o blassic-blassic.obj `if test -f 'blassic.cpp'; then $(CYGPATH_W) 'blassic.cpp'; else $(CYGPATH_W) '$(srcdir)/blassic.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-blassic.Tpo $(DEPDIR)/blassic-blassic.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='blassic.cpp' object='blassic-blassic.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-blassic.obj `if test -f 'blassic.cpp'; then $(CYGPATH_W) 'blassic.cpp'; else $(CYGPATH_W) '$(srcdir)/blassic.cpp'; fi`
+
+blassic-codeline.o: codeline.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-codeline.o -MD -MP -MF $(DEPDIR)/blassic-codeline.Tpo -c -o blassic-codeline.o `test -f 'codeline.cpp' || echo '$(srcdir)/'`codeline.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-codeline.Tpo $(DEPDIR)/blassic-codeline.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='codeline.cpp' object='blassic-codeline.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-codeline.o `test -f 'codeline.cpp' || echo '$(srcdir)/'`codeline.cpp
+
+blassic-codeline.obj: codeline.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-codeline.obj -MD -MP -MF $(DEPDIR)/blassic-codeline.Tpo -c -o blassic-codeline.obj `if test -f 'codeline.cpp'; then $(CYGPATH_W) 'codeline.cpp'; else $(CYGPATH_W) '$(srcdir)/codeline.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-codeline.Tpo $(DEPDIR)/blassic-codeline.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='codeline.cpp' object='blassic-codeline.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-codeline.obj `if test -f 'codeline.cpp'; then $(CYGPATH_W) 'codeline.cpp'; else $(CYGPATH_W) '$(srcdir)/codeline.cpp'; fi`
+
+blassic-cursor.o: cursor.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-cursor.o -MD -MP -MF $(DEPDIR)/blassic-cursor.Tpo -c -o blassic-cursor.o `test -f 'cursor.cpp' || echo '$(srcdir)/'`cursor.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-cursor.Tpo $(DEPDIR)/blassic-cursor.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cursor.cpp' object='blassic-cursor.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-cursor.o `test -f 'cursor.cpp' || echo '$(srcdir)/'`cursor.cpp
+
+blassic-cursor.obj: cursor.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-cursor.obj -MD -MP -MF $(DEPDIR)/blassic-cursor.Tpo -c -o blassic-cursor.obj `if test -f 'cursor.cpp'; then $(CYGPATH_W) 'cursor.cpp'; else $(CYGPATH_W) '$(srcdir)/cursor.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-cursor.Tpo $(DEPDIR)/blassic-cursor.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cursor.cpp' object='blassic-cursor.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-cursor.obj `if test -f 'cursor.cpp'; then $(CYGPATH_W) 'cursor.cpp'; else $(CYGPATH_W) '$(srcdir)/cursor.cpp'; fi`
+
+blassic-dim.o: dim.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dim.o -MD -MP -MF $(DEPDIR)/blassic-dim.Tpo -c -o blassic-dim.o `test -f 'dim.cpp' || echo '$(srcdir)/'`dim.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dim.Tpo $(DEPDIR)/blassic-dim.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dim.cpp' object='blassic-dim.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dim.o `test -f 'dim.cpp' || echo '$(srcdir)/'`dim.cpp
+
+blassic-dim.obj: dim.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dim.obj -MD -MP -MF $(DEPDIR)/blassic-dim.Tpo -c -o blassic-dim.obj `if test -f 'dim.cpp'; then $(CYGPATH_W) 'dim.cpp'; else $(CYGPATH_W) '$(srcdir)/dim.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dim.Tpo $(DEPDIR)/blassic-dim.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dim.cpp' object='blassic-dim.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dim.obj `if test -f 'dim.cpp'; then $(CYGPATH_W) 'dim.cpp'; else $(CYGPATH_W) '$(srcdir)/dim.cpp'; fi`
+
+blassic-directory.o: directory.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-directory.o -MD -MP -MF $(DEPDIR)/blassic-directory.Tpo -c -o blassic-directory.o `test -f 'directory.cpp' || echo '$(srcdir)/'`directory.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-directory.Tpo $(DEPDIR)/blassic-directory.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='directory.cpp' object='blassic-directory.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-directory.o `test -f 'directory.cpp' || echo '$(srcdir)/'`directory.cpp
+
+blassic-directory.obj: directory.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-directory.obj -MD -MP -MF $(DEPDIR)/blassic-directory.Tpo -c -o blassic-directory.obj `if test -f 'directory.cpp'; then $(CYGPATH_W) 'directory.cpp'; else $(CYGPATH_W) '$(srcdir)/directory.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-directory.Tpo $(DEPDIR)/blassic-directory.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='directory.cpp' object='blassic-directory.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-directory.obj `if test -f 'directory.cpp'; then $(CYGPATH_W) 'directory.cpp'; else $(CYGPATH_W) '$(srcdir)/directory.cpp'; fi`
+
+blassic-dynamic.o: dynamic.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dynamic.o -MD -MP -MF $(DEPDIR)/blassic-dynamic.Tpo -c -o blassic-dynamic.o `test -f 'dynamic.cpp' || echo '$(srcdir)/'`dynamic.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dynamic.Tpo $(DEPDIR)/blassic-dynamic.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dynamic.cpp' object='blassic-dynamic.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dynamic.o `test -f 'dynamic.cpp' || echo '$(srcdir)/'`dynamic.cpp
+
+blassic-dynamic.obj: dynamic.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dynamic.obj -MD -MP -MF $(DEPDIR)/blassic-dynamic.Tpo -c -o blassic-dynamic.obj `if test -f 'dynamic.cpp'; then $(CYGPATH_W) 'dynamic.cpp'; else $(CYGPATH_W) '$(srcdir)/dynamic.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dynamic.Tpo $(DEPDIR)/blassic-dynamic.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dynamic.cpp' object='blassic-dynamic.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dynamic.obj `if test -f 'dynamic.cpp'; then $(CYGPATH_W) 'dynamic.cpp'; else $(CYGPATH_W) '$(srcdir)/dynamic.cpp'; fi`
+
+blassic-edit.o: edit.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-edit.o -MD -MP -MF $(DEPDIR)/blassic-edit.Tpo -c -o blassic-edit.o `test -f 'edit.cpp' || echo '$(srcdir)/'`edit.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-edit.Tpo $(DEPDIR)/blassic-edit.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='edit.cpp' object='blassic-edit.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-edit.o `test -f 'edit.cpp' || echo '$(srcdir)/'`edit.cpp
+
+blassic-edit.obj: edit.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-edit.obj -MD -MP -MF $(DEPDIR)/blassic-edit.Tpo -c -o blassic-edit.obj `if test -f 'edit.cpp'; then $(CYGPATH_W) 'edit.cpp'; else $(CYGPATH_W) '$(srcdir)/edit.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-edit.Tpo $(DEPDIR)/blassic-edit.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='edit.cpp' object='blassic-edit.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-edit.obj `if test -f 'edit.cpp'; then $(CYGPATH_W) 'edit.cpp'; else $(CYGPATH_W) '$(srcdir)/edit.cpp'; fi`
+
+blassic-element.o: element.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-element.o -MD -MP -MF $(DEPDIR)/blassic-element.Tpo -c -o blassic-element.o `test -f 'element.cpp' || echo '$(srcdir)/'`element.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-element.Tpo $(DEPDIR)/blassic-element.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='element.cpp' object='blassic-element.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-element.o `test -f 'element.cpp' || echo '$(srcdir)/'`element.cpp
+
+blassic-element.obj: element.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-element.obj -MD -MP -MF $(DEPDIR)/blassic-element.Tpo -c -o blassic-element.obj `if test -f 'element.cpp'; then $(CYGPATH_W) 'element.cpp'; else $(CYGPATH_W) '$(srcdir)/element.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-element.Tpo $(DEPDIR)/blassic-element.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='element.cpp' object='blassic-element.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-element.obj `if test -f 'element.cpp'; then $(CYGPATH_W) 'element.cpp'; else $(CYGPATH_W) '$(srcdir)/element.cpp'; fi`
+
+blassic-error.o: error.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-error.o -MD -MP -MF $(DEPDIR)/blassic-error.Tpo -c -o blassic-error.o `test -f 'error.cpp' || echo '$(srcdir)/'`error.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-error.Tpo $(DEPDIR)/blassic-error.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='error.cpp' object='blassic-error.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-error.o `test -f 'error.cpp' || echo '$(srcdir)/'`error.cpp
+
+blassic-error.obj: error.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-error.obj -MD -MP -MF $(DEPDIR)/blassic-error.Tpo -c -o blassic-error.obj `if test -f 'error.cpp'; then $(CYGPATH_W) 'error.cpp'; else $(CYGPATH_W) '$(srcdir)/error.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-error.Tpo $(DEPDIR)/blassic-error.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='error.cpp' object='blassic-error.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-error.obj `if test -f 'error.cpp'; then $(CYGPATH_W) 'error.cpp'; else $(CYGPATH_W) '$(srcdir)/error.cpp'; fi`
+
+blassic-file.o: file.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-file.o -MD -MP -MF $(DEPDIR)/blassic-file.Tpo -c -o blassic-file.o `test -f 'file.cpp' || echo '$(srcdir)/'`file.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-file.Tpo $(DEPDIR)/blassic-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='file.cpp' object='blassic-file.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-file.o `test -f 'file.cpp' || echo '$(srcdir)/'`file.cpp
+
+blassic-file.obj: file.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-file.obj -MD -MP -MF $(DEPDIR)/blassic-file.Tpo -c -o blassic-file.obj `if test -f 'file.cpp'; then $(CYGPATH_W) 'file.cpp'; else $(CYGPATH_W) '$(srcdir)/file.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-file.Tpo $(DEPDIR)/blassic-file.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='file.cpp' object='blassic-file.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-file.obj `if test -f 'file.cpp'; then $(CYGPATH_W) 'file.cpp'; else $(CYGPATH_W) '$(srcdir)/file.cpp'; fi`
+
+blassic-fileconsole.o: fileconsole.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileconsole.o -MD -MP -MF $(DEPDIR)/blassic-fileconsole.Tpo -c -o blassic-fileconsole.o `test -f 'fileconsole.cpp' || echo '$(srcdir)/'`fileconsole.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileconsole.Tpo $(DEPDIR)/blassic-fileconsole.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileconsole.cpp' object='blassic-fileconsole.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileconsole.o `test -f 'fileconsole.cpp' || echo '$(srcdir)/'`fileconsole.cpp
+
+blassic-fileconsole.obj: fileconsole.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileconsole.obj -MD -MP -MF $(DEPDIR)/blassic-fileconsole.Tpo -c -o blassic-fileconsole.obj `if test -f 'fileconsole.cpp'; then $(CYGPATH_W) 'fileconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/fileconsole.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileconsole.Tpo $(DEPDIR)/blassic-fileconsole.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileconsole.cpp' object='blassic-fileconsole.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileconsole.obj `if test -f 'fileconsole.cpp'; then $(CYGPATH_W) 'fileconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/fileconsole.cpp'; fi`
+
+blassic-filepopen.o: filepopen.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filepopen.o -MD -MP -MF $(DEPDIR)/blassic-filepopen.Tpo -c -o blassic-filepopen.o `test -f 'filepopen.cpp' || echo '$(srcdir)/'`filepopen.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filepopen.Tpo $(DEPDIR)/blassic-filepopen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filepopen.cpp' object='blassic-filepopen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filepopen.o `test -f 'filepopen.cpp' || echo '$(srcdir)/'`filepopen.cpp
+
+blassic-filepopen.obj: filepopen.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filepopen.obj -MD -MP -MF $(DEPDIR)/blassic-filepopen.Tpo -c -o blassic-filepopen.obj `if test -f 'filepopen.cpp'; then $(CYGPATH_W) 'filepopen.cpp'; else $(CYGPATH_W) '$(srcdir)/filepopen.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filepopen.Tpo $(DEPDIR)/blassic-filepopen.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filepopen.cpp' object='blassic-filepopen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filepopen.obj `if test -f 'filepopen.cpp'; then $(CYGPATH_W) 'filepopen.cpp'; else $(CYGPATH_W) '$(srcdir)/filepopen.cpp'; fi`
+
+blassic-fileprinter.o: fileprinter.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileprinter.o -MD -MP -MF $(DEPDIR)/blassic-fileprinter.Tpo -c -o blassic-fileprinter.o `test -f 'fileprinter.cpp' || echo '$(srcdir)/'`fileprinter.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileprinter.Tpo $(DEPDIR)/blassic-fileprinter.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileprinter.cpp' object='blassic-fileprinter.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileprinter.o `test -f 'fileprinter.cpp' || echo '$(srcdir)/'`fileprinter.cpp
+
+blassic-fileprinter.obj: fileprinter.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileprinter.obj -MD -MP -MF $(DEPDIR)/blassic-fileprinter.Tpo -c -o blassic-fileprinter.obj `if test -f 'fileprinter.cpp'; then $(CYGPATH_W) 'fileprinter.cpp'; else $(CYGPATH_W) '$(srcdir)/fileprinter.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileprinter.Tpo $(DEPDIR)/blassic-fileprinter.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileprinter.cpp' object='blassic-fileprinter.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileprinter.obj `if test -f 'fileprinter.cpp'; then $(CYGPATH_W) 'fileprinter.cpp'; else $(CYGPATH_W) '$(srcdir)/fileprinter.cpp'; fi`
+
+blassic-filesocket.o: filesocket.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filesocket.o -MD -MP -MF $(DEPDIR)/blassic-filesocket.Tpo -c -o blassic-filesocket.o `test -f 'filesocket.cpp' || echo '$(srcdir)/'`filesocket.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filesocket.Tpo $(DEPDIR)/blassic-filesocket.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filesocket.cpp' object='blassic-filesocket.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filesocket.o `test -f 'filesocket.cpp' || echo '$(srcdir)/'`filesocket.cpp
+
+blassic-filesocket.obj: filesocket.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filesocket.obj -MD -MP -MF $(DEPDIR)/blassic-filesocket.Tpo -c -o blassic-filesocket.obj `if test -f 'filesocket.cpp'; then $(CYGPATH_W) 'filesocket.cpp'; else $(CYGPATH_W) '$(srcdir)/filesocket.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filesocket.Tpo $(DEPDIR)/blassic-filesocket.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filesocket.cpp' object='blassic-filesocket.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filesocket.obj `if test -f 'filesocket.cpp'; then $(CYGPATH_W) 'filesocket.cpp'; else $(CYGPATH_W) '$(srcdir)/filesocket.cpp'; fi`
+
+blassic-filewindow.o: filewindow.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filewindow.o -MD -MP -MF $(DEPDIR)/blassic-filewindow.Tpo -c -o blassic-filewindow.o `test -f 'filewindow.cpp' || echo '$(srcdir)/'`filewindow.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filewindow.Tpo $(DEPDIR)/blassic-filewindow.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filewindow.cpp' object='blassic-filewindow.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filewindow.o `test -f 'filewindow.cpp' || echo '$(srcdir)/'`filewindow.cpp
+
+blassic-filewindow.obj: filewindow.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filewindow.obj -MD -MP -MF $(DEPDIR)/blassic-filewindow.Tpo -c -o blassic-filewindow.obj `if test -f 'filewindow.cpp'; then $(CYGPATH_W) 'filewindow.cpp'; else $(CYGPATH_W) '$(srcdir)/filewindow.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filewindow.Tpo $(DEPDIR)/blassic-filewindow.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filewindow.cpp' object='blassic-filewindow.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filewindow.obj `if test -f 'filewindow.cpp'; then $(CYGPATH_W) 'filewindow.cpp'; else $(CYGPATH_W) '$(srcdir)/filewindow.cpp'; fi`
+
+blassic-function.o: function.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-function.o -MD -MP -MF $(DEPDIR)/blassic-function.Tpo -c -o blassic-function.o `test -f 'function.cpp' || echo '$(srcdir)/'`function.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-function.Tpo $(DEPDIR)/blassic-function.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='function.cpp' object='blassic-function.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-function.o `test -f 'function.cpp' || echo '$(srcdir)/'`function.cpp
+
+blassic-function.obj: function.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-function.obj -MD -MP -MF $(DEPDIR)/blassic-function.Tpo -c -o blassic-function.obj `if test -f 'function.cpp'; then $(CYGPATH_W) 'function.cpp'; else $(CYGPATH_W) '$(srcdir)/function.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-function.Tpo $(DEPDIR)/blassic-function.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='function.cpp' object='blassic-function.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-function.obj `if test -f 'function.cpp'; then $(CYGPATH_W) 'function.cpp'; else $(CYGPATH_W) '$(srcdir)/function.cpp'; fi`
+
+blassic-graphics.o: graphics.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-graphics.o -MD -MP -MF $(DEPDIR)/blassic-graphics.Tpo -c -o blassic-graphics.o `test -f 'graphics.cpp' || echo '$(srcdir)/'`graphics.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-graphics.Tpo $(DEPDIR)/blassic-graphics.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='graphics.cpp' object='blassic-graphics.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-graphics.o `test -f 'graphics.cpp' || echo '$(srcdir)/'`graphics.cpp
+
+blassic-graphics.obj: graphics.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-graphics.obj -MD -MP -MF $(DEPDIR)/blassic-graphics.Tpo -c -o blassic-graphics.obj `if test -f 'graphics.cpp'; then $(CYGPATH_W) 'graphics.cpp'; else $(CYGPATH_W) '$(srcdir)/graphics.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-graphics.Tpo $(DEPDIR)/blassic-graphics.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='graphics.cpp' object='blassic-graphics.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-graphics.obj `if test -f 'graphics.cpp'; then $(CYGPATH_W) 'graphics.cpp'; else $(CYGPATH_W) '$(srcdir)/graphics.cpp'; fi`
+
+blassic-key.o: key.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-key.o -MD -MP -MF $(DEPDIR)/blassic-key.Tpo -c -o blassic-key.o `test -f 'key.cpp' || echo '$(srcdir)/'`key.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-key.Tpo $(DEPDIR)/blassic-key.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='key.cpp' object='blassic-key.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-key.o `test -f 'key.cpp' || echo '$(srcdir)/'`key.cpp
+
+blassic-key.obj: key.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-key.obj -MD -MP -MF $(DEPDIR)/blassic-key.Tpo -c -o blassic-key.obj `if test -f 'key.cpp'; then $(CYGPATH_W) 'key.cpp'; else $(CYGPATH_W) '$(srcdir)/key.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-key.Tpo $(DEPDIR)/blassic-key.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='key.cpp' object='blassic-key.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-key.obj `if test -f 'key.cpp'; then $(CYGPATH_W) 'key.cpp'; else $(CYGPATH_W) '$(srcdir)/key.cpp'; fi`
+
+blassic-keyword.o: keyword.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-keyword.o -MD -MP -MF $(DEPDIR)/blassic-keyword.Tpo -c -o blassic-keyword.o `test -f 'keyword.cpp' || echo '$(srcdir)/'`keyword.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-keyword.Tpo $(DEPDIR)/blassic-keyword.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='keyword.cpp' object='blassic-keyword.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-keyword.o `test -f 'keyword.cpp' || echo '$(srcdir)/'`keyword.cpp
+
+blassic-keyword.obj: keyword.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-keyword.obj -MD -MP -MF $(DEPDIR)/blassic-keyword.Tpo -c -o blassic-keyword.obj `if test -f 'keyword.cpp'; then $(CYGPATH_W) 'keyword.cpp'; else $(CYGPATH_W) '$(srcdir)/keyword.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-keyword.Tpo $(DEPDIR)/blassic-keyword.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='keyword.cpp' object='blassic-keyword.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-keyword.obj `if test -f 'keyword.cpp'; then $(CYGPATH_W) 'keyword.cpp'; else $(CYGPATH_W) '$(srcdir)/keyword.cpp'; fi`
+
+blassic-mbf.o: mbf.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-mbf.o -MD -MP -MF $(DEPDIR)/blassic-mbf.Tpo -c -o blassic-mbf.o `test -f 'mbf.cpp' || echo '$(srcdir)/'`mbf.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-mbf.Tpo $(DEPDIR)/blassic-mbf.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mbf.cpp' object='blassic-mbf.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-mbf.o `test -f 'mbf.cpp' || echo '$(srcdir)/'`mbf.cpp
+
+blassic-mbf.obj: mbf.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-mbf.obj -MD -MP -MF $(DEPDIR)/blassic-mbf.Tpo -c -o blassic-mbf.obj `if test -f 'mbf.cpp'; then $(CYGPATH_W) 'mbf.cpp'; else $(CYGPATH_W) '$(srcdir)/mbf.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-mbf.Tpo $(DEPDIR)/blassic-mbf.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mbf.cpp' object='blassic-mbf.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-mbf.obj `if test -f 'mbf.cpp'; then $(CYGPATH_W) 'mbf.cpp'; else $(CYGPATH_W) '$(srcdir)/mbf.cpp'; fi`
+
+blassic-memory.o: memory.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-memory.o -MD -MP -MF $(DEPDIR)/blassic-memory.Tpo -c -o blassic-memory.o `test -f 'memory.cpp' || echo '$(srcdir)/'`memory.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-memory.Tpo $(DEPDIR)/blassic-memory.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='memory.cpp' object='blassic-memory.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-memory.o `test -f 'memory.cpp' || echo '$(srcdir)/'`memory.cpp
+
+blassic-memory.obj: memory.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-memory.obj -MD -MP -MF $(DEPDIR)/blassic-memory.Tpo -c -o blassic-memory.obj `if test -f 'memory.cpp'; then $(CYGPATH_W) 'memory.cpp'; else $(CYGPATH_W) '$(srcdir)/memory.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-memory.Tpo $(DEPDIR)/blassic-memory.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='memory.cpp' object='blassic-memory.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-memory.obj `if test -f 'memory.cpp'; then $(CYGPATH_W) 'memory.cpp'; else $(CYGPATH_W) '$(srcdir)/memory.cpp'; fi`
+
+blassic-program.o: program.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-program.o -MD -MP -MF $(DEPDIR)/blassic-program.Tpo -c -o blassic-program.o `test -f 'program.cpp' || echo '$(srcdir)/'`program.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-program.Tpo $(DEPDIR)/blassic-program.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='program.cpp' object='blassic-program.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-program.o `test -f 'program.cpp' || echo '$(srcdir)/'`program.cpp
+
+blassic-program.obj: program.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-program.obj -MD -MP -MF $(DEPDIR)/blassic-program.Tpo -c -o blassic-program.obj `if test -f 'program.cpp'; then $(CYGPATH_W) 'program.cpp'; else $(CYGPATH_W) '$(srcdir)/program.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-program.Tpo $(DEPDIR)/blassic-program.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='program.cpp' object='blassic-program.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-program.obj `if test -f 'program.cpp'; then $(CYGPATH_W) 'program.cpp'; else $(CYGPATH_W) '$(srcdir)/program.cpp'; fi`
+
+blassic-regexp.o: regexp.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-regexp.o -MD -MP -MF $(DEPDIR)/blassic-regexp.Tpo -c -o blassic-regexp.o `test -f 'regexp.cpp' || echo '$(srcdir)/'`regexp.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-regexp.Tpo $(DEPDIR)/blassic-regexp.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='regexp.cpp' object='blassic-regexp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-regexp.o `test -f 'regexp.cpp' || echo '$(srcdir)/'`regexp.cpp
+
+blassic-regexp.obj: regexp.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-regexp.obj -MD -MP -MF $(DEPDIR)/blassic-regexp.Tpo -c -o blassic-regexp.obj `if test -f 'regexp.cpp'; then $(CYGPATH_W) 'regexp.cpp'; else $(CYGPATH_W) '$(srcdir)/regexp.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-regexp.Tpo $(DEPDIR)/blassic-regexp.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='regexp.cpp' object='blassic-regexp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-regexp.obj `if test -f 'regexp.cpp'; then $(CYGPATH_W) 'regexp.cpp'; else $(CYGPATH_W) '$(srcdir)/regexp.cpp'; fi`
+
+blassic-runner.o: runner.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runner.o -MD -MP -MF $(DEPDIR)/blassic-runner.Tpo -c -o blassic-runner.o `test -f 'runner.cpp' || echo '$(srcdir)/'`runner.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runner.Tpo $(DEPDIR)/blassic-runner.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runner.cpp' object='blassic-runner.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runner.o `test -f 'runner.cpp' || echo '$(srcdir)/'`runner.cpp
+
+blassic-runner.obj: runner.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runner.obj -MD -MP -MF $(DEPDIR)/blassic-runner.Tpo -c -o blassic-runner.obj `if test -f 'runner.cpp'; then $(CYGPATH_W) 'runner.cpp'; else $(CYGPATH_W) '$(srcdir)/runner.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runner.Tpo $(DEPDIR)/blassic-runner.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runner.cpp' object='blassic-runner.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runner.obj `if test -f 'runner.cpp'; then $(CYGPATH_W) 'runner.cpp'; else $(CYGPATH_W) '$(srcdir)/runner.cpp'; fi`
+
+blassic-runnerline.o: runnerline.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline.o -MD -MP -MF $(DEPDIR)/blassic-runnerline.Tpo -c -o blassic-runnerline.o `test -f 'runnerline.cpp' || echo '$(srcdir)/'`runnerline.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline.Tpo $(DEPDIR)/blassic-runnerline.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline.cpp' object='blassic-runnerline.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline.o `test -f 'runnerline.cpp' || echo '$(srcdir)/'`runnerline.cpp
+
+blassic-runnerline.obj: runnerline.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline.Tpo -c -o blassic-runnerline.obj `if test -f 'runnerline.cpp'; then $(CYGPATH_W) 'runnerline.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline.Tpo $(DEPDIR)/blassic-runnerline.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline.cpp' object='blassic-runnerline.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline.obj `if test -f 'runnerline.cpp'; then $(CYGPATH_W) 'runnerline.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline.cpp'; fi`
+
+blassic-runnerline_impl.o: runnerline_impl.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_impl.o -MD -MP -MF $(DEPDIR)/blassic-runnerline_impl.Tpo -c -o blassic-runnerline_impl.o `test -f 'runnerline_impl.cpp' || echo '$(srcdir)/'`runnerline_impl.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_impl.Tpo $(DEPDIR)/blassic-runnerline_impl.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_impl.cpp' object='blassic-runnerline_impl.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_impl.o `test -f 'runnerline_impl.cpp' || echo '$(srcdir)/'`runnerline_impl.cpp
+
+blassic-runnerline_impl.obj: runnerline_impl.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_impl.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline_impl.Tpo -c -o blassic-runnerline_impl.obj `if test -f 'runnerline_impl.cpp'; then $(CYGPATH_W) 'runnerline_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_impl.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_impl.Tpo $(DEPDIR)/blassic-runnerline_impl.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_impl.cpp' object='blassic-runnerline_impl.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_impl.obj `if test -f 'runnerline_impl.cpp'; then $(CYGPATH_W) 'runnerline_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_impl.cpp'; fi`
+
+blassic-runnerline_instructions.o: runnerline_instructions.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_instructions.o -MD -MP -MF $(DEPDIR)/blassic-runnerline_instructions.Tpo -c -o blassic-runnerline_instructions.o `test -f 'runnerline_instructions.cpp' || echo '$(srcdir)/'`runnerline_instructions.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_instructions.Tpo $(DEPDIR)/blassic-runnerline_instructions.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_instructions.cpp' object='blassic-runnerline_instructions.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_instructions.o `test -f 'runnerline_instructions.cpp' || echo '$(srcdir)/'`runnerline_instructions.cpp
+
+blassic-runnerline_instructions.obj: runnerline_instructions.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_instructions.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline_instructions.Tpo -c -o blassic-runnerline_instructions.obj `if test -f 'runnerline_instructions.cpp'; then $(CYGPATH_W) 'runnerline_instructions.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_instructions.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_instructions.Tpo $(DEPDIR)/blassic-runnerline_instructions.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_instructions.cpp' object='blassic-runnerline_instructions.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_instructions.obj `if test -f 'runnerline_instructions.cpp'; then $(CYGPATH_W) 'runnerline_instructions.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_instructions.cpp'; fi`
+
+blassic-runnerline_print.o: runnerline_print.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_print.o -MD -MP -MF $(DEPDIR)/blassic-runnerline_print.Tpo -c -o blassic-runnerline_print.o `test -f 'runnerline_print.cpp' || echo '$(srcdir)/'`runnerline_print.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_print.Tpo $(DEPDIR)/blassic-runnerline_print.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_print.cpp' object='blassic-runnerline_print.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_print.o `test -f 'runnerline_print.cpp' || echo '$(srcdir)/'`runnerline_print.cpp
+
+blassic-runnerline_print.obj: runnerline_print.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_print.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline_print.Tpo -c -o blassic-runnerline_print.obj `if test -f 'runnerline_print.cpp'; then $(CYGPATH_W) 'runnerline_print.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_print.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_print.Tpo $(DEPDIR)/blassic-runnerline_print.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_print.cpp' object='blassic-runnerline_print.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_print.obj `if test -f 'runnerline_print.cpp'; then $(CYGPATH_W) 'runnerline_print.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_print.cpp'; fi`
+
+blassic-showerror.o: showerror.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-showerror.o -MD -MP -MF $(DEPDIR)/blassic-showerror.Tpo -c -o blassic-showerror.o `test -f 'showerror.cpp' || echo '$(srcdir)/'`showerror.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-showerror.Tpo $(DEPDIR)/blassic-showerror.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='showerror.cpp' object='blassic-showerror.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-showerror.o `test -f 'showerror.cpp' || echo '$(srcdir)/'`showerror.cpp
+
+blassic-showerror.obj: showerror.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-showerror.obj -MD -MP -MF $(DEPDIR)/blassic-showerror.Tpo -c -o blassic-showerror.obj `if test -f 'showerror.cpp'; then $(CYGPATH_W) 'showerror.cpp'; else $(CYGPATH_W) '$(srcdir)/showerror.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-showerror.Tpo $(DEPDIR)/blassic-showerror.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='showerror.cpp' object='blassic-showerror.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-showerror.obj `if test -f 'showerror.cpp'; then $(CYGPATH_W) 'showerror.cpp'; else $(CYGPATH_W) '$(srcdir)/showerror.cpp'; fi`
+
+blassic-socket.o: socket.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-socket.o -MD -MP -MF $(DEPDIR)/blassic-socket.Tpo -c -o blassic-socket.o `test -f 'socket.cpp' || echo '$(srcdir)/'`socket.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-socket.Tpo $(DEPDIR)/blassic-socket.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='socket.cpp' object='blassic-socket.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-socket.o `test -f 'socket.cpp' || echo '$(srcdir)/'`socket.cpp
+
+blassic-socket.obj: socket.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-socket.obj -MD -MP -MF $(DEPDIR)/blassic-socket.Tpo -c -o blassic-socket.obj `if test -f 'socket.cpp'; then $(CYGPATH_W) 'socket.cpp'; else $(CYGPATH_W) '$(srcdir)/socket.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-socket.Tpo $(DEPDIR)/blassic-socket.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='socket.cpp' object='blassic-socket.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-socket.obj `if test -f 'socket.cpp'; then $(CYGPATH_W) 'socket.cpp'; else $(CYGPATH_W) '$(srcdir)/socket.cpp'; fi`
+
+blassic-sysvar.o: sysvar.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-sysvar.o -MD -MP -MF $(DEPDIR)/blassic-sysvar.Tpo -c -o blassic-sysvar.o `test -f 'sysvar.cpp' || echo '$(srcdir)/'`sysvar.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-sysvar.Tpo $(DEPDIR)/blassic-sysvar.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sysvar.cpp' object='blassic-sysvar.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-sysvar.o `test -f 'sysvar.cpp' || echo '$(srcdir)/'`sysvar.cpp
+
+blassic-sysvar.obj: sysvar.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-sysvar.obj -MD -MP -MF $(DEPDIR)/blassic-sysvar.Tpo -c -o blassic-sysvar.obj `if test -f 'sysvar.cpp'; then $(CYGPATH_W) 'sysvar.cpp'; else $(CYGPATH_W) '$(srcdir)/sysvar.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-sysvar.Tpo $(DEPDIR)/blassic-sysvar.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sysvar.cpp' object='blassic-sysvar.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-sysvar.obj `if test -f 'sysvar.cpp'; then $(CYGPATH_W) 'sysvar.cpp'; else $(CYGPATH_W) '$(srcdir)/sysvar.cpp'; fi`
+
+blassic-token.o: token.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-token.o -MD -MP -MF $(DEPDIR)/blassic-token.Tpo -c -o blassic-token.o `test -f 'token.cpp' || echo '$(srcdir)/'`token.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-token.Tpo $(DEPDIR)/blassic-token.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='token.cpp' object='blassic-token.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-token.o `test -f 'token.cpp' || echo '$(srcdir)/'`token.cpp
+
+blassic-token.obj: token.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-token.obj -MD -MP -MF $(DEPDIR)/blassic-token.Tpo -c -o blassic-token.obj `if test -f 'token.cpp'; then $(CYGPATH_W) 'token.cpp'; else $(CYGPATH_W) '$(srcdir)/token.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-token.Tpo $(DEPDIR)/blassic-token.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='token.cpp' object='blassic-token.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-token.obj `if test -f 'token.cpp'; then $(CYGPATH_W) 'token.cpp'; else $(CYGPATH_W) '$(srcdir)/token.cpp'; fi`
+
+blassic-trace.o: trace.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-trace.o -MD -MP -MF $(DEPDIR)/blassic-trace.Tpo -c -o blassic-trace.o `test -f 'trace.cpp' || echo '$(srcdir)/'`trace.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-trace.Tpo $(DEPDIR)/blassic-trace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='trace.cpp' object='blassic-trace.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-trace.o `test -f 'trace.cpp' || echo '$(srcdir)/'`trace.cpp
+
+blassic-trace.obj: trace.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-trace.obj -MD -MP -MF $(DEPDIR)/blassic-trace.Tpo -c -o blassic-trace.obj `if test -f 'trace.cpp'; then $(CYGPATH_W) 'trace.cpp'; else $(CYGPATH_W) '$(srcdir)/trace.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-trace.Tpo $(DEPDIR)/blassic-trace.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='trace.cpp' object='blassic-trace.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-trace.obj `if test -f 'trace.cpp'; then $(CYGPATH_W) 'trace.cpp'; else $(CYGPATH_W) '$(srcdir)/trace.cpp'; fi`
+
+blassic-using.o: using.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-using.o -MD -MP -MF $(DEPDIR)/blassic-using.Tpo -c -o blassic-using.o `test -f 'using.cpp' || echo '$(srcdir)/'`using.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-using.Tpo $(DEPDIR)/blassic-using.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='using.cpp' object='blassic-using.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-using.o `test -f 'using.cpp' || echo '$(srcdir)/'`using.cpp
+
+blassic-using.obj: using.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-using.obj -MD -MP -MF $(DEPDIR)/blassic-using.Tpo -c -o blassic-using.obj `if test -f 'using.cpp'; then $(CYGPATH_W) 'using.cpp'; else $(CYGPATH_W) '$(srcdir)/using.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-using.Tpo $(DEPDIR)/blassic-using.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='using.cpp' object='blassic-using.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-using.obj `if test -f 'using.cpp'; then $(CYGPATH_W) 'using.cpp'; else $(CYGPATH_W) '$(srcdir)/using.cpp'; fi`
+
+blassic-var.o: var.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-var.o -MD -MP -MF $(DEPDIR)/blassic-var.Tpo -c -o blassic-var.o `test -f 'var.cpp' || echo '$(srcdir)/'`var.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-var.Tpo $(DEPDIR)/blassic-var.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='var.cpp' object='blassic-var.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-var.o `test -f 'var.cpp' || echo '$(srcdir)/'`var.cpp
+
+blassic-var.obj: var.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-var.obj -MD -MP -MF $(DEPDIR)/blassic-var.Tpo -c -o blassic-var.obj `if test -f 'var.cpp'; then $(CYGPATH_W) 'var.cpp'; else $(CYGPATH_W) '$(srcdir)/var.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-var.Tpo $(DEPDIR)/blassic-var.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='var.cpp' object='blassic-var.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-var.obj `if test -f 'var.cpp'; then $(CYGPATH_W) 'var.cpp'; else $(CYGPATH_W) '$(srcdir)/var.cpp'; fi`
+
+blassic-version.o: version.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-version.o -MD -MP -MF $(DEPDIR)/blassic-version.Tpo -c -o blassic-version.o `test -f 'version.cpp' || echo '$(srcdir)/'`version.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-version.Tpo $(DEPDIR)/blassic-version.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='version.cpp' object='blassic-version.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-version.o `test -f 'version.cpp' || echo '$(srcdir)/'`version.cpp
+
+blassic-version.obj: version.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-version.obj -MD -MP -MF $(DEPDIR)/blassic-version.Tpo -c -o blassic-version.obj `if test -f 'version.cpp'; then $(CYGPATH_W) 'version.cpp'; else $(CYGPATH_W) '$(srcdir)/version.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-version.Tpo $(DEPDIR)/blassic-version.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='version.cpp' object='blassic-version.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-version.obj `if test -f 'version.cpp'; then $(CYGPATH_W) 'version.cpp'; else $(CYGPATH_W) '$(srcdir)/version.cpp'; fi`
+
+gencharset-gencharset.o: gencharset.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -MT gencharset-gencharset.o -MD -MP -MF $(DEPDIR)/gencharset-gencharset.Tpo -c -o gencharset-gencharset.o `test -f 'gencharset.cpp' || echo '$(srcdir)/'`gencharset.cpp
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/gencharset-gencharset.Tpo $(DEPDIR)/gencharset-gencharset.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gencharset.cpp' object='gencharset-gencharset.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -c -o gencharset-gencharset.o `test -f 'gencharset.cpp' || echo '$(srcdir)/'`gencharset.cpp
+
+gencharset-gencharset.obj: gencharset.cpp
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -MT gencharset-gencharset.obj -MD -MP -MF $(DEPDIR)/gencharset-gencharset.Tpo -c -o gencharset-gencharset.obj `if test -f 'gencharset.cpp'; then $(CYGPATH_W) 'gencharset.cpp'; else $(CYGPATH_W) '$(srcdir)/gencharset.cpp'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/gencharset-gencharset.Tpo $(DEPDIR)/gencharset-gencharset.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gencharset.cpp' object='gencharset-gencharset.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -c -o gencharset-gencharset.obj `if test -f 'gencharset.cpp'; then $(CYGPATH_W) 'gencharset.cpp'; else $(CYGPATH_W) '$(srcdir)/gencharset.cpp'; fi`
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d $(distdir) || mkdir $(distdir)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r $(distdir)
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-lzma: distdir
+ tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lzma*) \
+ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && cd $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @cd $(distuninstallcheck_dir) \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
+ clean-binPROGRAMS clean-generic clean-noinstPROGRAMS ctags \
+ dist dist-all dist-bzip2 dist-gzip dist-lzma dist-shar \
+ dist-tarZ dist-zip distcheck distclean distclean-compile \
+ distclean-generic distclean-tags distcleancheck distdir \
+ distuninstallcheck dvi dvi-am html html-am info info-am \
+ install install-am install-binPROGRAMS install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS
+
+
+# This way the .exe extension is appended when compiling for windows
+# under linux, but it works anyway.
+gencharset$(EXEEXT): gencharset.cpp
+ $(CXX_FOR_BUILD) $(gencharset_CXXFLAGS) $(gencharset_LDFLAGS) \
+ -o gencharset$(EXEEXT) \
+ gencharset.cpp
+
+# Character sets for graphics modes.
+
+#charset.cpp: $(srcdir)/charset.def gencharset
+# ./gencharset $(srcdir)/charset.def charset.cpp
+# test -f charset.cpp
+
+charset_default.cpp: $(srcdir)/default.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/default.def \
+ charset_default.cpp default
+ test -f charset_default.cpp
+
+charset_cpc.cpp: $(srcdir)/cpc.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/cpc.def \
+ charset_cpc.cpp cpc
+ test -f charset_cpc.cpp
+
+charset_spectrum.cpp: $(srcdir)/spectrum.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/spectrum.def \
+ charset_spectrum.cpp spectrum
+ test -f charset_spectrum.cpp
+
+charset_msx.cpp: $(srcdir)/msx.def gencharset.cpp charset.h
+ ./gencharset$(EXEEXT) $(srcdir)/msx.def \
+ charset_msx.cpp msx
+ test -f charset_msx.cpp
+
+# testdl: a tiny library to test blassic dynamic link.
+
+# Julian: modified this to allow cross-compiling.
+#testdl.so: testdl.o
+# gcc -shared -Wl,-soname,testdl.so -o testdl.so testdl.o
+#testdl.o: testdl.cpp
+# gcc -Wall -fPIC -c testdl.cpp
+
+#testdl_CXXFLAGS = \
+# -W -Wall -Wwrite-strings -Wstrict-prototypes \
+# -Wunused
+
+testdl.so: testdl.o
+ $(CXX) -shared -Wl,-soname,testdl.so $(LDFLAGS) -o testdl.so testdl.o
+
+testdl.o: testdl.cpp
+ $(CXX) -fPIC $(testdl_CXXFLAGS) -c testdl.cpp
+
+rpm: dist
+ rpm -ta $(distdir).tar.gz
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..5bfc64c
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,570 @@
+Version 0.10.1
+
+ Added msx option and charset.
+
+Version 0.10.0
+
+ Improved configure, easier and with more options.
+
+ New system var to control if blank lines are converted
+ to comments when loading a program in text mode, and
+ command line option --comblank to set it.
+
+ Now the graphics system is not initialized until a
+ graphics mode is established. Under X the X server
+ can be established or changed on the fly by channging
+ the value of the DISPLAY environment variable.
+
+ String slicing operations ZX Basic style using [ ].
+
+ Added SCROLL, ZX_PLOT and ZX_UNPLOT instructions.
+
+ Additional optional parameters for COPYCHR$.
+
+ Characters redefinition Spectrum style now extends
+ to Z.
+
+ LABEL can be used as function, giving the line number
+ where the label is defined. Useful with 'IF ERL = ...',
+ for example.
+
+ RENUM takes another optional argument, to stop
+ renumbering at certain line.
+
+ Changed default charset, added charsets spectrum and
+ cpc, selected when used the corresponding command
+ line option and with a new syntax for SYMBOL AFTER.
+
+ RETURN now admits an optional line number argument.
+
+ FN RETURN instruction added.
+
+ POPEN now can be bidirectional and capture the error
+ output. This feature may or not works well in windows,
+ depending on the windows versions, more work in this
+ is needed.
+
+ CHAIN MERGE now does not affect the current program
+ if the loading of the chained fails.
+
+ Line number 0 is now valid (and you can even ON ERROR GOTO
+ to it, but only with a LABEL).
+
+ New machine type command line option --appleII
+
+ New operator \ for integer division.
+
+ New system flags to control if true value is -1 or 1
+ and if the logical operators are binary or boolean.
+
+ GO TO and GO SUB are now accepted. They can be listed
+ as two words using a new system flag. <= and others
+ also are accepted with embedded spaces.
+
+ New system flag to allow GOTO and other jump instructions
+ refer to a line number inexistent, using the next line in
+ that case.
+
+ New command line options --errout, --norun, --tron and
+ --tronline.
+
+ Processing of command line options reworked. Now a option
+ inexistent is not taken as a filename, generates an error
+ instead.
+
+ Better LABEL caching and error detection.
+
+ Now can be compiled without graphics in platforms where
+ they are supported just by commenting the line
+ #define BLASSIC_HAS_GRAPHICS
+ in graphics.cpp
+
+ Added flag in system vars to control if debug info is showed
+ on certain errors, and --info command line option to turn
+ it on. More debug info added to be used with this.
+
+ Added UCASE$ and LCASE$ aliases for UPPER$ and LOWER$.
+
+ Added GET and PUT graphic variants.
+
+ Corrected bug of LINE ... B in windows.
+
+ Added function ALLOC_MEMORY and instruction FREE_MEMORY,
+ this allows use of machine code in operating systems with
+ protection against execution in data areas.
+
+ Regular expression functions (currently not working under
+ windows).
+
+ INSTR with initial value less than 1 now gives error.
+
+ Corrected READ: now a comma at the end of a DATA sentence
+ is valid.
+
+ EOF now works with random files. Also added the LOC function
+ for him.
+
+
+Version 0.8.1
+
+ -p command line option to print expressions.
+
+ - in command line means read program from standard input.
+
+ Suffix # for floating point variables is now accepted.
+
+Version 0.8.0
+
+ THEN omitted and flag that controls if it's accepetd.
+
+ Flags to insert space before non negative numbers in PRINT
+ and in STR$, and to convert LF to CR in GET a$ and INKEY$.
+
+ LOF, FREEFILE, INKEY and ROUND functions added.
+
+ LSET and RSET corrected, and now works with standalone vars.
+
+ FIELD now assign the field variables, and accepts matrix
+ elements.
+
+ END now closes files.
+
+ => , =< and >< added.
+
+ PULL instruction and his variants added.
+
+ MID$ instruction now accepts subindexed variables and works
+ with fields.
+
+ Command line options --gwbasic, --allflags and --lfcr added.
+
+ CLOSE without parameters, CLEAR and others now does not close
+ window channels.
+
+ WIDTH LPRINT now accepts a second parameter for setting left
+ margin.
+
+ Graphics modes can be rotated, with system var and command
+ line option --rotate.
+
+ ZONE now works in text mode.
+
+ The end of command line options is marked with --.
+
+ FIELD CLEAR and FIELD APPEND instructions.
+
+ Text input in graphics mode now uses accent dead keys.
+
+ **BREAK** when launched program from command line now goes
+ to standard error.
+
+ Automatic conversions from floating point to integer now
+ are rounded and can result in overflow error.
+
+ PAINT instruction.
+
+ Now compiles again when no graphics library found.
+
+ Functions to convert to and from MBF format (floating point
+ format used in several Basic): MKSMBF$, MKDMBF$, CVSMBF and
+ CVDMBF.
+
+Version 0.7.2
+
+ ASC now does not require parenthesis.
+
+ SCREEN$ function.
+
+ --cpc and --spectrum command line options.
+
+ Command line option -m now accepts mode by name.
+
+ BRIGHT instruction and PRINT modifier.
+
+ Added BINARY to open modes for files.
+
+ Spectrum syntax for CIRCLE is now accepted.
+
+ DRAWARC instruction.
+
+Version 0.7.1
+
+ POPEN in unix versions now redirects the standard streams
+ to /dev/null.
+
+ FILES to printer channel now uses correct line width.
+
+ "Sin soporte de graficos" and some other messages still in
+ spanish are translated.
+
+ Moving in the history buffer now places the cursor at the end
+ of line.
+
+ New flag in Flags1 system variable controls TAB style.
+
+ INKEY$ now accepts a channel parameter and can be used with files.
+
+ Avoided high use of CPU on unix when waiting a key in graphics mode.
+
+ PAUSE 0 now does a usleep (0) on unix.
+
+ Implemented the effect of the ; initial in INPUT and LINE INPUT
+ (previously was accepted but does nothing).
+
+ Functions found on Sinclair Basics (and some other funtions) now
+ does not require parenthesis (USR only when used whith UDG).
+
+ VAL$ function.
+
+Version 0.7.0
+
+ USR "Spectrum graphic characters style".
+
+ Corrected bug with APPEND mode.
+
+ Printer support with LPRINT and LLIST.
+
+ WIDTH LPRINT instruction.
+
+ ZONE implemented at least!
+
+ Solved problems with popen under Windows (I hope).
+
+Version 0.6.1
+
+ MODE 0 when graphics not available now is not an error.
+
+ Added underline mode to console emulation in graphics mode.
+
+ Bug RESTORE always set line 0 corrected.
+
+ Bug ' after DATA corrected.
+
+ Bug vars whith suffix ! corrected.
+
+ IF_DEBUG instruction, DebugLevel system var, --debug command
+ line option.
+
+Version 0.6.0
+
+ Corrected an obscure bug in windows.
+
+ FILES now gives error when file not found and has an optional
+ channel parameter.
+
+ Problem with popen as direct command in windows solved in
+ windows 98, but now does not work on XP. Compiling with
+ MinGW the problem dissapears. Borland's fault?
+
+ FN recursion level limited, controled by a new system var.
+
+ Instructions TAG, TAGOFF, ORIGIN, DEG, RAD and INVERSE.
+
+ Crash when copychr out of screen corrected.
+
+ Delete key in graphics mode in linux/unix now acts as Delete.
+
+ Now compiles under Cygwin and under MinGW. Can be compiled on
+ unix with curses instead of ncurses or without any curses.
+
+ USING corrected, now does not require the ecvt function,
+ that is not provided in all platforms.
+
+ New system var Flags1, bit 0 control LOCATE style
+ Microsoft (row, col) or Amstrad CPC (col, row).
+
+ Graphic window on Windows can be minimized.
+
+ New graphics modes pcw, pcw2, cpc0 and cpc1, mode cpc2 corrected.
+
+ MODE has new optional arguments zoomx and zoomy.
+
+ Control characters in graphics mode now acts like both Amstrad
+ CPC in Basic and Amstrad CPC and PCW in CP/M.
+
+ Line feed now has no automatic CR in graphics mode.
+
+ CLEAR and similars now does a RESTORE.
+
+ Separators between PRINT items are no longer required.
+
+ INK Spectrum syntax is now accepeted.
+
+ INK, PAPER and INVERSE as PRINT specifiers Spectrum style.
+
+ Bug local integer variables incorrectly restored, solved
+
+ Workaround for a possible compiler error on arm.
+
+Version 0.5.7
+
+ cursor.cpp not compiled under gcc 2.95, corrected.
+
+ Bug MODE segfaulting in console, corrected.
+
+ Some READ improvement.
+
+ STRERR$ function.
+
+ CLEAR INK instruction.
+
+ DEC$ function.
+
+ PRINT USING improved, now with scientific notation and
+ currency sign for dollar, pound and euro.
+
+ Bug editing chars with code > 127 ignored, corrected.
+
+ POS and VPOS functions.
+
+ Line editing in INPUT and LINE INPUT now also works in
+ text mode in unix.
+
+ TAB now works correctly in text mode.
+
+ Speed improvement in text output in graphics mode.
+
+ INPUT corrected, LINE INPUT improved.
+
+ CLEAR INPUT instruction.
+
+ Better handling of multiline FN functions.
+
+ GOTO (and others) to a line number that not exist now
+ is an error.
+
+ SET_TITLE instruction.
+
+Version 0.5.6
+
+ Instructions BEEP, DEFINT, DEFSTR, DEFREAL, DEFSNG and DEFDBL.
+
+ RESUME without error is an error even with line number.
+
+ Function COPYCHR$.
+
+ Instruction WINDOW SWAP.
+
+ Functions TEST and TESTR.
+
+ Instruction INK.
+
+ Solved problem when running from telnet in hp-ux.
+
+Version 0.5.5
+
+ SINH, COSH, TANH, ASINH, ACOSH and ATANH functions.
+
+ Better handling of math errors.
+
+ ATAN2 function.
+
+ Command history.
+
+ Behaviour of RUN, CLEAR and NEW corrected.
+
+ Bug MODE not destroyed the window channels, corrected.
+
+ FINDFIRST$ and FINDNEXT$ functions.
+
+Version 0.5.4
+
+ Command line option -x to exclude keywords.
+
+ #include directive in text programs.
+
+ Functions RINSTR, FIND_FIRST_OF, FIND_LAST_OF,
+ FIND_FIRST_NOT_OF and FIND_LAST_NOT_OF.
+
+ LET as operator.
+
+ SYMBOL AFTER instruction.
+
+Version 0.5.3
+
+ Bugs in ellipses and arcs of ellipses with high
+ eccentricity, corrected.
+
+ INPUT & LINE INPUT now works in graphics mode.
+
+ Corrected bug synchronized mode not reset when changing mode.
+
+Version 0.5.2
+
+ CIRCLE extended to ellipses.
+
+Version 0.5.1
+
+ Bug in CLS in graphics mode corrected.
+
+ Cleaner circles.
+
+ The syntax of the CIRCLE instruction has been changed and
+ completed for compatibility with Gwbasic.
+
+ Bug DRAW string debug output not cleaned, corrected.
+
+Version 0.5.0
+
+ Speed improvement.
+
+ "PRINT , , 1" now is valid syntax. Same in WRITE.
+
+ Better implementation of FILES.
+
+ XPOS, YPOS, PEEK16 and PEEK32 functions.
+
+ DRAWR, PLOTR, MOVER, POKE16, POKE32, RENUM, CIRCLE, MASK,
+ WINDOW and GRAPHICS instructions.
+
+ Completed the syntax of PLOT, PLOTR, DRAW, DRAWR, MOVE
+ and MOVER with ink and ink mode parameters.
+
+ Adapated some instructions to work with text windows.
+
+ MODE string, when string can be "spectrum" or "cpc2"
+
+ Bug PRINT AT invert arguments, corrected.
+
+ Bug PRINT AT does not always work, corrected.
+
+ Added variant: VAL evaluates expressions (can run more Sinclair
+ ZX family programs). Activable with "POKE SYSVARPTR + 25, 1".
+
+ New command line options -m mode and -d.
+
+ Added variant "Next check relaxed", needed for many ZX-81
+ and Spectrum programas. Activable with "POKE SYSVARPTR + 26, 1".
+
+ Added variant can DIM an array already dimensioned, needed
+ for ZX programs. Activable with "POKE SYVARPTR + 27, 1".
+
+ New sample programs.
+
+ Memory leak in ERASE corrected.
+
+ Bug on negative integer DATA corrected.
+
+Version 0.4.5
+
+ EDIT command. Line editing in AUTO and in prompt.
+
+ Prompt "Ok" instead of "]" (sorry, Apple ]['s nostalgics).
+
+Version 0.4.4
+
+ Bug DATA terminated with comma, corrected.
+
+ Mouse secondary button and button release.
+
+ Special keys support improved.
+
+Version 0.4.3
+
+ Mouse support in graphics mode (keywords XMOUSE and YMOUSE).
+
+ Special keys are recongnized in linux in text mode.
+
+ The return value of the SHELL instruction is saved
+ in a system var.
+
+Version 0.4.2
+
+ Now compiles with Kylix.
+
+ Workarounds for bugs that cause crash on some platforms
+ when a syntax error is generated.
+
+ Bug ON BREAK CONT causes internal error on INPUT.
+
+ Bug AUTO n causes syntax error.
+
+Version 0.4.1
+
+ TRON LINE.
+
+ Channel specification in TRON.
+
+ Doesn't use hash_map in gcc 3.
+
+ Corrected problem in gcc 2.95.2
+
+ Big numbers whitout decimal nor exponent are now handled
+ correctly on all platforms.
+
+Version 0.4.0
+
+ Integer type variables. Integer and real suffixes.
+
+ DEF STR, DEF INT, DEF REAL
+
+ Comments with '
+
+ No keywords in comments.
+
+ MERGE and CHAIN MERGE now try .blc and .bas extensions
+ and work with binary files.
+
+ OSNAME$
+
+ Tabs in graphics mode.
+
+Version 0.3.5
+
+ CHAIN, CHAIN MERGE
+
+ Bug some instructions don't continue processing current line.
+
+Version 0.3.4
+
+ ON BREAK STOP / CONT / GOSUB
+
+ SYNCHRONIZE, PAUSE.
+
+ Bug LOCATE in graphics mode started in 0 instead of 1, corrected.
+
+ Bug PRINT AT doesn't work in graphics mode, corrected.
+
+Version 0.3.3
+
+ Bug scroll & cls in invert mode corrected.
+
+ Bug scroll fills white instead of current paper corrected.
+
+ Bug blank or empty USING corrected.
+
+ Bug INPUT only positive integer coorrected.
+
+ FIX and CINT functions.
+
+ Preliminary support for colors on text mode.
+
+Version 0.3.2
+
+ PAPER, PEN, SHELL, CHDIR, MKDIR and RMDIR instructions.
+
+ Syntax of LINE has changed, now is like Gwbasic.
+
+ Simple implementation of FILES.
+
+ Text output in graphics mode now in colors and with
+ transparent option.
+
+ Error corrections to compile on C++ Builder 6.
+
+ Graphics modes now works on Win 2000 and XP.
+
+Version 0.3.1
+
+ POP, NAME, KILL and FILES instructions (FILES not implemented).
+
+ MIN and MAX functions.
+
+ Corrected bug in Makefile.
+
+ Some changes to avoid errors and warnings on some versions
+ of gcc and C++ Builder.
+
+ Some code cleanup.
+
+ File not found on OPEN for input.
diff --git a/README b/README
new file mode 100644
index 0000000..ac5abef
--- /dev/null
+++ b/README
@@ -0,0 +1,83 @@
+ NOTES ABOUT CURRENT VERSION
+
+There are problems using some versions of gcc on some platforms.
+In case Blassic core dumps on exiting or when a program has an
+error, compile it using -O0
+
+The regular expression functions are not supported under windows.
+
+The bidirectional POPEN may or may not work on windows depending
+on the windows version used.
+
+Now configure admits several options: --disable-graphics to compile
+without graphics support and --disable-curses to compile without
+curses nor ncurses. In the last case, CLS, LOCATE and other
+instructions when used in text mode are silently ignored. In the
+former, trying to enter in graphics mode generates an error.
+If curses is enabled, first ncurses is tested, if not available
+curses is used instead. The --disable-ncurses option skips the
+ncurses test and uses always curses.
+
+When configuring for unix/linux, using --without-x has the same
+effect as --disable-graphics. For windows is ignored.
+
+Several scripts to call configure are provided, see the do_conf*
+files.
+
+
+ NOTES ABOUT CROSS-COMPILING BLASSIC
+
+The cross-compiling has been simplified in Blasic 0.10.0, it must now
+automatically use the native compiler to create gencharset. If this
+fails you can manually compile it, or create a dummy, it does not
+need to be executed unless the charset data files are modified.
+
+
+ * * *
+
+
+To run the test of dynamic linking of functions do:
+
+ make testdl.so
+
+ ./blassic testdl
+
+On windows with Borland C++ Builder build the project testdl and do:
+
+ blassic testdl
+
+There is no other documentation than the testdl.cpp source, sorry.
+
+
+ * * *
+
+
+ BASIC /bay'-sic/ n.
+
+A programming language, originally designed for Dartmouth's experimental
+timesharing system in the early 1960s, which for many years was the leading
+cause of brain damage in proto-hackers. Edsger W. Dijkstra observed in
+"Selected Writings on Computing: A Personal Perspective" that "It is
+practically impossible to teach good programming style to students that have
+had prior exposure to BASIC: as potential programmers they are mentally
+mutilated beyond hope of regeneration." This is another case (like Pascal)
+of the cascading lossage that happens when a language deliberately designed
+as an educational toy gets taken too seriously. A novice can write short
+BASIC programs (on the order of 10-20 lines) very easily; writing anything
+longer (a) is very painful, and (b) encourages bad habits that will make it
+harder to use more powerful languages well. This wouldn't be so bad if
+historical accidents hadn't made BASIC so common on low-end micros in the
+1980s. As it is, it probably ruined tens of thousands of potential wizards.
+
+ "The new hacker's dictionary"
+
+I disagree with this point of view, but...
+
+ *****************************
+ ** You have been warned! **
+ *****************************
+
+
+(C) 2001-2005 Julián Albo
+
+julian.notfound@gmail.com
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..767d71a
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,198 @@
+# Configure paths for SVGAlib
+# Created by Pierre Sarrazin <http://sarrazip.com/>
+# Tiny changes by Julian Albo.
+# This file is in the public domain.
+# Created from sdl.m4.
+
+# This test must be executed in C mode (AC_LANG_C), not C++ mode.
+
+# Defines SVGALIB_CFLAGS and SVGALIB_LIBS and submits them to AC_SUBST()
+
+dnl AM_PATH_SVGALIB([MINIMUM-VERSION [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]])
+dnl Test for SVGAlib, and define SVGALIB_CFLAGS and SVGALIB_LIBS
+dnl
+AC_DEFUN(AM_PATH_SVGALIB,
+[
+ AC_ARG_WITH(svgalib-prefix,
+ AC_HELP_STRING([--with-svgalib-prefix=PFX],
+ [Prefix where SVGAlib is installed [[/usr]]] ),
+ svgalib_prefix="$withval",
+ svgalib_prefix="/usr"
+ )
+ AC_MSG_RESULT([using $svgalib_prefix as SVGAlib prefix])
+ AC_ARG_ENABLE(svgalibtest,
+ AC_HELP_STRING([--disable-svgalibtest],
+ [Do not try to compile and run a test program] ),
+ ,
+ enable_svgalibtest=yes
+ )
+
+dnl Changed this check.
+dnl AC_REQUIRE([AC_CANONICAL_TARGET])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ min_svgalib_version=ifelse([$1], ,1.4.0, $1)
+ AC_MSG_CHECKING([for SVGAlib - version >= $min_svgalib_version])
+ no_svgalib=""
+
+
+ if test "$svgalib_prefix" = /usr; then
+ # Avoid the switch -I/usr/include - it might break gcc 3.x
+ SVGALIB_CFLAGS=
+ else
+ SVGALIB_CFLAGS="-I$svgalib_prefix/include"
+ fi
+
+ SVGALIB_LIBS="-L$svgalib_prefix/lib -lvgagl -lvga"
+
+ # Get the version number, which appears to be in the lib*.so.* filename:
+ #
+ if test -f $svgalib_prefix/lib/libvga.so.*.*.*; then
+
+ _f=`echo $svgalib_prefix/lib/libvga.so.*.*.* | \
+ sed 's/^.*\.so\.//'`
+ svgalib_major_version=`echo $_f | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+ svgalib_minor_version=`echo $_f | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+ svgalib_micro_version=`echo $_f | \
+ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+
+ unset _f
+
+ else
+ AC_MSG_ERROR([could not find $svgalib_prefix/lib/libvga.so.*.*.*])
+ fi
+
+ if test "_$enable_svgalibtest" = "_yes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $SVGALIB_CFLAGS"
+ LIBS="$LIBS $SVGALIB_LIBS"
+dnl
+dnl Check if the installed SVGAlib is sufficiently new.
+dnl
+ rm -f conf.svgalibtest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "vga.h"
+
+char*
+my_strdup (char *str)
+{
+ char *new_str;
+
+ if (str)
+ {
+ new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
+ strcpy (new_str, str);
+ }
+ else
+ new_str = NULL;
+
+ return new_str;
+}
+
+int main (int argc, char *argv[])
+{
+ int major, minor, micro;
+ char *tmp_version;
+
+ /* This hangs on some systems (?)
+ system ("touch conf.svgalibtest");
+ */
+ { FILE *fp = fopen("conf.svgalibtest", "a"); if ( fp ) fclose(fp); }
+
+ /* HP/UX 9 (%@#!) writes to sscanf strings */
+ tmp_version = my_strdup("$min_svgalib_version");
+ if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+ printf("%s, bad version string\n", "$min_svgalib_version");
+ exit(1);
+ }
+
+ if (($svgalib_major_version > major) ||
+ (($svgalib_major_version == major) && ($svgalib_minor_version > minor)) ||
+ (($svgalib_major_version == major) && ($svgalib_minor_version == minor) && ($svgalib_micro_version >= micro)))
+ {
+ return 0;
+ }
+ else
+ {
+ printf("\n*** Installed SVGAlib version is %d.%d.%d, but the minimum version\n", $svgalib_major_version, $svgalib_minor_version, $svgalib_micro_version);
+ printf("*** of SVGAlib required is %d.%d.%d.\n", major, minor, micro);
+ printf("*** It is best to upgrade to the required version.\n");
+ printf("*** The web site is http://www.svgalib.org/\n");
+ printf("*** See also --with-svgalib-prefix\n");
+ return 1;
+ }
+}
+
+],
+ ,
+ no_svgalib=yes,
+ [echo $ac_n "cross compiling; assumed OK... $ac_c"]
+ )
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+ fi
+
+
+ if test "_$no_svgalib" = _ ; then
+ AC_MSG_RESULT([found $svgalib_major_version.$svgalib_minor_version.$svgalib_micro_version])
+ ifelse([$2], , :, [$2])
+ else
+ AC_MSG_ERROR([SVGAlib >= min_svgalib_version not found])
+
+ if test -f conf.svgalibtest ; then
+ :
+ else
+ echo "*** Could not run SVGAlib test program, checking why..."
+
+ CFLAGS="$CFLAGS $SVGALIB_CFLAGS"
+ LIBS="$LIBS $SVGALIB_LIBS"
+
+ AC_TRY_LINK([
+#include <stdio.h>
+#include "vga.h"
+
+int main(int argc, char *argv[])
+{ return 0; }
+#undef main
+#define main K_and_R_C_main
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding SVGAlib or finding the wrong"
+ echo "*** version of SVGAlib. If it is not finding SVGAlib, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+ ],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means SVGAlib was incorrectly installed"
+ echo "*** or that you have moved SVGAlib since it was installed."
+ echo "***"
+ echo "*** SVGAlib web site: http://www.svgalib.org/"
+ ]
+ )
+
+ CFLAGS="$ac_save_CFLAGS"
+ LIBS="$ac_save_LIBS"
+
+ AC_MSG_ERROR([SVGAlib >= min_svgalib_version not found])
+
+ fi
+
+ SVGALIB_CFLAGS=""
+ SVGALIB_LIBS=""
+ ifelse([$3], , :, [$3])
+ fi
+
+ AC_SUBST(SVGALIB_CFLAGS)
+ AC_SUBST(SVGALIB_LIBS)
+ rm -f conf.svgalibtest
+])
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..2c8aa27
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,869 @@
+# generated automatically by aclocal 1.10.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(AC_AUTOCONF_VERSION, [2.61],,
+[m4_warning([this file was generated for autoconf 2.61.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.10'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.10.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.10.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 8
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ case $depmode in
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ none) break ;;
+ esac
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this.
+ if depmode=$depmode \
+ source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 3
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[for mf in $CONFIG_FILES; do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+done
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 13
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.60])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AM_PROG_INSTALL_SH
+AM_PROG_INSTALL_STRIP
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo done
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# We grep out `Entering directory' and `Leaving directory'
+# messages which can occur if `w' ends up in MAKEFLAGS.
+# In particular we don't look at `^make:' because GNU make might
+# be invoked under some other name (usually "gmake"), in which
+# case it prints its new name instead of `make'.
+if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
+ am__include=include
+ am__quote=
+ _am_result=GNU
+fi
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ fi
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t $srcdir/configure conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([acinclude.m4])
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..1bf205d
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+./bootstrap && ./configure $*
diff --git a/blassic.cpp b/blassic.cpp
new file mode 100644
index 0000000..e78c4ab
--- /dev/null
+++ b/blassic.cpp
@@ -0,0 +1,963 @@
+// blassic.cpp
+// Revision 24-apr-2009
+
+#include "blassic.h"
+
+#include "keyword.h"
+
+#include "program.h"
+#include "runner.h"
+#include "cursor.h"
+
+#include "graphics.h"
+#include "charset.h"
+#include "sysvar.h"
+#include "trace.h"
+#include "util.h"
+#include "error.h"
+
+#include <string>
+
+#include <iostream>
+#include <cctype>
+#include <fstream>
+//#include <iomanip>
+#include <sstream>
+#include <memory>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+
+#ifdef BLASSIC_USE_WINDOWS
+
+#include <windows.h>
+
+#else
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#endif
+
+#if defined __BORLANDC__ && defined _Windows
+
+#include <condefs.h>
+
+#else
+
+#define USEUNIT(a)
+
+#endif
+
+USEUNIT("codeline.cpp");
+USEUNIT("error.cpp");
+USEUNIT("keyword.cpp");
+USEUNIT("program.cpp");
+USEUNIT("runner.cpp");
+USEUNIT("token.cpp");
+USEUNIT("var.cpp");
+USEUNIT("dim.cpp");
+USEUNIT("file.cpp");
+USEUNIT("cursor.cpp");
+USEUNIT("graphics.cpp");
+USEUNIT("sysvar.cpp");
+USEUNIT("version.cpp");
+USEUNIT("trace.cpp");
+USEUNIT("socket.cpp");
+USEUNIT("runnerline.cpp");
+USEUNIT("function.cpp");
+USEUNIT("key.cpp");
+USEUNIT("edit.cpp");
+USEUNIT("directory.cpp");
+USEUNIT("using.cpp");
+USEUNIT("regexp.cpp");
+USEUNIT("dynamic.cpp");
+USEUNIT("mbf.cpp");
+USEUNIT("memory.cpp");
+USEUNIT("fileconsole.cpp");
+USEUNIT("filepopen.cpp");
+USEUNIT("fileprinter.cpp");
+USEUNIT("filewindow.cpp");
+USEUNIT("runnerline_instructions.cpp");
+USEUNIT("showerror.cpp");
+USEUNIT("runnerline_impl.cpp");
+USEUNIT("runnerline_print.cpp");
+USEUNIT("filesocket.cpp");
+USEUNIT("charset_spectrum.cpp");
+USEUNIT("charset_default.cpp");
+USEUNIT("charset_cpc.cpp");
+USEUNIT("element.cpp");
+//---------------------------------------------------------------------------
+bool fInterrupted= false;
+
+const std::string strPrompt ("Ok");
+
+namespace sysvar= blassic::sysvar;
+
+//************************************************
+// Local functions and classes
+//************************************************
+
+namespace {
+
+void set_title (const std::string & str, Runner & runner)
+{
+ // C++ Builder don't like this.
+ //std::string title ( str.empty () ? std::string ("Blassic") :
+ // (str == "-") ? std::string ("Blassic (stdin)") : str);
+ std::string title;
+ if (str.empty () )
+ title= "Blassic";
+ else if (str == "-")
+ title= "Blassic (stdin)";
+ else
+ title= str;
+
+ graphics::set_default_title (title);
+ runner.set_title (title);
+}
+
+// Workaround to problem in cygwin:
+#ifndef SIGBREAK
+const int SIGBREAK= 21;
+#endif
+
+void handle_sigint (int)
+{
+ fInterrupted= true;
+ #ifdef BLASSIC_USE_WINDOWS
+ signal (SIGINT, handle_sigint);
+ signal (SIGBREAK, handle_sigint);
+ #endif
+}
+
+#ifndef BLASSIC_USE_WINDOWS
+
+void handle_SIGSEGV (int, siginfo_t * info, void *)
+{
+ fprintf (stderr, "Segmentation fault with si_addr %p"
+ #ifdef HAVE_SIGINFO_T_SI_PTR
+ " si_ptr %p"
+ #endif
+ " and si_code %i\n",
+ info->si_addr,
+ #ifdef HAVE_SIGINFO_T_SI_PTR
+ info->si_ptr,
+ #endif
+ info->si_code);
+ abort ();
+}
+
+#endif
+
+void init_signal_handlers ()
+{
+ TRACEFUNC (tr, "init_signal_handlers");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ signal (SIGINT, handle_sigint);
+ signal (SIGBREAK, handle_sigint);
+
+ #else
+
+ struct sigaction act;
+ act.sa_handler= handle_sigint;
+ act.sa_flags= 0;
+ sigaction (SIGINT, & act, 0);
+
+ signal (SIGPIPE, SIG_IGN);
+
+ #ifndef NDEBUG
+ signal (SIGUSR1, TraceFunc::show);
+ #endif
+
+ // This helps debugging machine code.
+ #ifndef NDEBUG
+ act.sa_handler= NULL;
+ act.sa_sigaction= & handle_SIGSEGV;
+ act.sa_flags= SA_SIGINFO;
+ sigaction (SIGSEGV, & act, 0);
+ #endif
+
+ #endif
+}
+
+class Initializer {
+public:
+ Initializer (const char * progname, bool detached) :
+ detached_text (detached),
+ detached_graphics (false)
+ {
+ TRACEFUNC (tr, "Initializer::Initializer");
+
+ if (! detached_text)
+ cursor::initconsole ();
+ graphics::initialize (progname);
+ }
+ ~Initializer ()
+ {
+ TRACEFUNC (tr, "Initializer::~Initializer");
+
+ if (! detached_graphics)
+ graphics::uninitialize ();
+ if (! detached_text)
+ cursor::quitconsole ();
+ }
+ void detachgraphics () { detached_graphics= true; }
+ void detachtext () { detached_text= true; }
+private:
+ bool detached_text;
+ bool detached_graphics;
+};
+
+std::vector <std::string> args;
+
+void setprogramargs (char * * argv, size_t n)
+{
+ TRACEFUNC (tr, "setprogramargs");
+
+ sysvar::set16 (sysvar::NumArgs, short (n) );
+ args.clear ();
+ std::copy (argv, argv + n, std::back_inserter (args) );
+}
+
+void blassic_runprogram (const std::string & name,
+ Runner & runner)
+{
+ set_title (name, runner);
+ runner.run ();
+}
+
+} // namespace
+
+// These are globals.
+
+void setprogramargs (const std::vector <std::string> & nargs)
+{
+ TRACEFUNC (tr, "setprogramargs");
+
+ sysvar::set16 (sysvar::NumArgs, short (nargs.size () ) );
+ args= nargs;
+}
+
+std::string getprogramarg (size_t n)
+{
+ //if (n >= num_args)
+ if (n >= args.size () )
+ return std::string ();
+ //return std::string (args [n]);
+ return args [n];
+}
+
+namespace {
+
+class ProtectCerrBuf {
+public:
+ ProtectCerrBuf () :
+ buf (std::cerr.rdbuf () )
+ {
+ }
+ ~ProtectCerrBuf ()
+ {
+ std::cerr.rdbuf (buf);
+ }
+private:
+ std::streambuf * buf;
+};
+
+//************************************************
+// Options processing.
+//************************************************
+
+class Options {
+public:
+ Options (int argc, char * * argv);
+ bool must_run () const;
+
+ // Public, to read it directly instead of provide accesor.
+ bool detach;
+ bool tron;
+ bool tronline;
+ bool errout;
+ std::string exec_command;
+ std::string print_args;
+ std::string progname;
+ std::string mode;
+
+private:
+ bool norun;
+ const int argc;
+ char * * const argv;
+
+ typedef bool (Options::*handle_option_t) (int & n);
+ typedef std::map <std::string, handle_option_t> mapoption_t;
+ static mapoption_t mapoption;
+ static bool initmapoption ();
+ static bool mapoption_inited;
+ static const mapoption_t::const_iterator no_option;
+
+ static const char IncompatibleExecPrint [];
+
+ handle_option_t gethandle (const char * str);
+
+ bool handle_option_exec (int & n);
+ bool handle_option_print (int & n);
+ bool handle_option_mode (int & n);
+ bool handle_option_detach (int & n);
+ bool handle_option_auto (int & n);
+ bool handle_option_exclude (int & n);
+ bool handle_option_debug (int & n);
+ bool handle_option_info (int & n);
+ bool handle_option_cpc (int & n);
+ bool handle_option_spectrum (int & n);
+ bool handle_option_msx (int & n);
+ bool handle_option_gwbasic (int & n);
+ bool handle_option_appleII (int & n);
+ bool handle_option_allflags (int & n);
+ bool handle_option_rotate (int & n);
+ bool handle_option_lfcr (int & n);
+ bool handle_option_norun (int & n);
+ bool handle_option_tron (int & n);
+ bool handle_option_tronline (int & n);
+ bool handle_option_errout (int & n);
+ bool handle_option_comblank (int & n);
+ bool handle_option_double_dash (int & n);
+ bool handle_option_dash (int & n);
+ bool handle_option_default (int & n);
+};
+
+Options::Options (int argc, char * * argv) :
+ detach (false),
+ tron (false),
+ tronline (false),
+ errout (false),
+ norun (false),
+ argc (argc),
+ argv (argv)
+{
+ TRACEFUNC (tr, "Options::Options");
+
+ int n= 1;
+ for ( ; n < argc; ++n)
+ {
+ if ( (this->*gethandle (argv [n]) ) (n) )
+ break;
+ }
+
+ if (n >= argc)
+ return;
+
+ progname= argv [n];
+ ++n;
+
+ if (n < argc)
+ {
+ int narg= argc - n;
+ setprogramargs (argv + n, narg);
+ }
+}
+
+bool Options::must_run () const
+{
+ return ! norun && ! progname.empty ();
+}
+
+Options::mapoption_t Options::mapoption;
+
+bool Options::initmapoption ()
+{
+ mapoption ["-e"]= & Options::handle_option_exec;
+ mapoption ["-p"]= & Options::handle_option_print;
+ mapoption ["-m"]= & Options::handle_option_mode;
+ mapoption ["-d"]= & Options::handle_option_detach;
+ mapoption ["-a"]= & Options::handle_option_auto;
+ mapoption ["-x"]= & Options::handle_option_exclude;
+ mapoption ["--debug"]= & Options::handle_option_debug;
+ mapoption ["--info"]= & Options::handle_option_info;
+ mapoption ["--cpc"]= & Options::handle_option_cpc;
+ mapoption ["--spectrum"]= & Options::handle_option_spectrum;
+ mapoption ["--msx"]= & Options::handle_option_msx;
+ mapoption ["--gwbasic"]= & Options::handle_option_gwbasic;
+ mapoption ["--appleII"]= & Options::handle_option_appleII;
+ mapoption ["--allflags"]= & Options::handle_option_allflags;
+ mapoption ["--rotate"]= & Options::handle_option_rotate;
+ mapoption ["--lfcr"]= & Options::handle_option_lfcr;
+ mapoption ["--norun"]= & Options::handle_option_norun;
+ mapoption ["--tron"]= & Options::handle_option_tron;
+ mapoption ["--tronline"]= & Options::handle_option_tronline;
+ mapoption ["--errout"]= & Options::handle_option_errout;
+ mapoption ["--comblank"]= & Options::handle_option_comblank;
+ mapoption ["--"]= & Options::handle_option_double_dash;
+ mapoption ["-"]= & Options::handle_option_dash;
+
+ return true;
+}
+
+bool Options::mapoption_inited= Options::initmapoption ();
+
+const Options::mapoption_t::const_iterator
+ Options::no_option= mapoption.end ();
+
+const char Options::IncompatibleExecPrint []=
+ "Options -e and -p are incompatibles";
+
+Options::handle_option_t Options::gethandle (const char * str)
+{
+ mapoption_t::const_iterator it (mapoption.find (str) );
+ if (it != no_option)
+ return it->second;
+ else
+ {
+ if (str [0] == '-')
+ throw "Invalid option";
+ else
+ return & Options::handle_option_default;
+ }
+}
+
+bool Options::handle_option_exec (int & n)
+{
+ if (++n == argc)
+ throw "Option -e needs argument";
+ if (! exec_command.empty () )
+ throw "Option -e can only be used once";
+ if (! print_args.empty () )
+ throw IncompatibleExecPrint;
+ exec_command= argv [n];
+ return false;
+}
+
+bool Options::handle_option_print (int & n)
+{
+ static const char PrintNeedsArgument []=
+ "Option -p needs at least one argument";
+
+ if (++n == argc)
+ throw PrintNeedsArgument;
+ if (! exec_command.empty () )
+ throw IncompatibleExecPrint;
+
+ bool empty= true;
+ while (n < argc)
+ {
+ if (strcmp (argv [n], "--") == 0)
+ break;
+
+ if (! print_args.empty () )
+ print_args+= ": ";
+ print_args+= "PRINT ";
+ print_args+= argv [n];
+
+ ++n;
+ empty= false;
+ }
+ if (empty)
+ throw PrintNeedsArgument;
+ return false;
+}
+
+bool Options::handle_option_mode (int & n)
+{
+ if (++n == argc)
+ throw "Option -m needs argument";
+ if (!mode.empty () )
+ throw "Option -m can only be used once";
+ mode= argv [n];
+ if (mode.empty () )
+ throw "Invalid empty string mode";
+ return false;
+}
+
+bool Options::handle_option_detach (int & /*n*/)
+{
+ detach= true;
+ return false;
+}
+
+bool Options::handle_option_auto (int & n)
+{
+ if (++n == argc)
+ throw "Option -a needs argument";
+ std::istringstream iss (argv [n]);
+ BlLineNumber ini;
+ iss >> ini;
+ char c= char (iss.get () );
+ if (! iss.eof () )
+ {
+ if (c != ',')
+ throw "Bad parameter";
+ BlLineNumber inc;
+ iss >> inc;
+ if (! iss)
+ throw "Bad parameter";
+ iss >> c;
+ if (! iss.eof () )
+ throw "Bad parameter";
+ sysvar::set32 (sysvar::AutoInc, inc);
+ }
+ sysvar::set32 (sysvar::AutoInit, ini);
+ return false;
+}
+
+bool Options::handle_option_exclude (int & n)
+{
+ if (++n == argc)
+ throw "Option -x needs argument";
+ excludekeyword (argv [n] );
+ return false;
+}
+
+bool Options::handle_option_debug (int & n)
+{
+ if (++n == argc)
+ throw "Option --debug needs argument";
+ sysvar::set32 (sysvar::DebugLevel, atoi (argv [n] ) );
+ return false;
+}
+
+bool Options::handle_option_info (int & /* n */)
+{
+ sysvar::setFlags1 (sysvar::ShowDebugInfo);
+ return false;
+}
+
+bool Options::handle_option_cpc (int & /* n */)
+{
+ TRACEFUNC (tr, "handle_option_cpc");
+
+ sysvar::setFlags1 (sysvar::LocateStyle | sysvar::ThenOmitted |
+ sysvar::SpaceBefore | sysvar::SpaceStr_s);
+ sysvar::set16 (sysvar::Zone, 13);
+
+ charset::default_charset= & charset::cpc_data;
+
+ return false;
+}
+
+bool Options::handle_option_spectrum (int & /* n */)
+{
+ TRACEFUNC (tr, "handle_option_spectrum");
+
+ sysvar::set (sysvar::TypeOfVal, 1);
+ sysvar::set (sysvar::TypeOfNextCheck, 1);
+ sysvar::set (sysvar::TypeOfDimCheck, 1);
+ sysvar::setFlags1 (sysvar::TabStyle | sysvar::RelaxedGoto);
+ sysvar::setFlags2 (sysvar::SeparatedGoto |
+ sysvar::TruePositive | sysvar::BoolMode);
+ sysvar::set16 (sysvar::Zone, 16);
+
+ charset::default_charset= & charset::spectrum_data;
+
+ return false;
+}
+
+bool Options::handle_option_msx (int & /* n */)
+{
+ TRACEFUNC (tr, "handle_option_msx");
+
+ sysvar::setFlags1 (sysvar::ThenOmitted |
+ sysvar::SpaceBefore | sysvar::SpaceStr_s);
+ sysvar::set16 (sysvar::Zone, 14);
+
+ charset::default_charset= & charset::msx_data;
+
+ return false;
+}
+
+bool Options::handle_option_gwbasic (int & /* n */)
+{
+ TRACEFUNC (tr, "handle_option_gwbasic");
+
+ sysvar::setFlags1 (sysvar::ThenOmitted |
+ sysvar::SpaceBefore | sysvar::SpaceStr_s);
+ sysvar::set16 (sysvar::Zone, 14);
+ return false;
+}
+
+bool Options::handle_option_appleII (int & /* n */)
+{
+ TRACEFUNC (tr, "handle_option_appleII");
+
+ // Pending of determine Flags 1 values.
+ //sysvar::setFlags1 (sysvar::LocateStyle | sysvar::ThenOmitted |
+ // sysvar::SpaceBefore | sysvar::SpaceStr_s);
+ sysvar::setFlags2 (sysvar::TruePositive | sysvar::BoolMode);
+ // Pending of stablish Zone value.
+ sysvar::set16 (sysvar::Zone, 13);
+ return false;
+}
+
+bool Options::handle_option_allflags (int & /* n */)
+{
+ sysvar::setFlags1 (sysvar::Flags1Full);
+ sysvar::setFlags2 (sysvar::Flags2Full);
+ return false;
+}
+
+bool Options::handle_option_rotate (int & /* n */)
+{
+ sysvar::set (sysvar::GraphRotate, 1);
+ return false;
+}
+
+bool Options::handle_option_lfcr (int & /* n */)
+{
+ sysvar::setFlags1 (sysvar::ConvertLFCR);
+ return false;
+}
+
+bool Options::handle_option_norun (int & /* n */)
+{
+ norun= true;
+ return false;
+}
+
+bool Options::handle_option_tron (int & /* n */)
+{
+ tron= true;
+ return false;
+}
+
+bool Options::handle_option_tronline (int & /* n */)
+{
+ tron= true;
+ tronline= true;
+ return false;
+}
+
+bool Options::handle_option_errout (int & /* n */)
+{
+ errout= true;
+ std::cerr.rdbuf (std::cout.rdbuf () );
+ return false;
+}
+
+bool Options::handle_option_comblank (int & /* n */)
+{
+ sysvar::setFlags2 (sysvar::BlankComment);
+ return false;
+}
+
+bool Options::handle_option_double_dash (int & n)
+{
+ ++n;
+ return true;
+}
+
+bool Options::handle_option_dash (int & /* n */)
+{
+ return true;
+}
+
+bool Options::handle_option_default (int & /*n*/)
+{
+ return true;
+}
+
+class BlBuf : public std::streambuf
+{
+public:
+ BlBuf (GlobalRunner & globalrunner) :
+ globalrunner (globalrunner)
+ {
+ }
+private:
+ void sendchar (blassic::file::BlFile & f, char c)
+ {
+ if (c == '\n')
+ f.endline ();
+ else
+ f << c;
+ }
+ int overflow (int ch)
+ {
+ sync ();
+ blassic::file::BlFile & f=
+ globalrunner.getfile (DefaultChannel);
+ sendchar (f, static_cast <char>
+ (static_cast <unsigned char> (ch) ) );
+ return 0;
+ }
+ int sync ()
+ {
+ blassic::file::BlFile & f=
+ globalrunner.getfile (DefaultChannel);
+ std::streamsize n= pptr () - pbase ();
+ for (std::streamsize i= 0; i < n; ++i)
+ sendchar (f, * (pbase () + i) );
+ pbump (-n);
+ gbump (egptr () - gptr () );
+ return 0;
+ }
+ GlobalRunner & globalrunner;
+};
+
+int blassic_main (int argc, char * * argv)
+{
+ using std::cerr;
+ using std::endl;
+
+ TRACEFUNC (tr, "blassic_main");
+
+ init_signal_handlers ();
+ sysvar::init ();
+
+ Options options (argc, argv);
+
+ //Program program;
+ std::auto_ptr <Program> pprogram (newProgram () );
+ Program & program= * pprogram.get ();
+
+ // Load program before detaching, or error messages are lost.
+ // Can be to run it or for use with options print or execute.
+ // Seems not very useful with print, but does not hurt and
+ // somebody can find an application.
+
+ if (! options.progname.empty () )
+ {
+ if (options.progname == "-")
+ program.load (std::cin);
+ else
+ program.load (options.progname);
+ }
+
+ // Detach is done before initializing console and graphics.
+
+ if (options.detach)
+ {
+ #ifdef BLASSIC_USE_WINDOWS
+
+ FreeConsole ();
+
+ #else
+
+ switch (fork () )
+ {
+ case pid_t (-1):
+ throw "fork failed";
+ case pid_t (0):
+ // Child. Detach and continue.
+ {
+ bool showdebug= showdebuginfo ();
+ int newstd= open ("/dev/null", O_RDWR);
+ if (newstd == -1)
+ {
+ close (STDIN_FILENO);
+ close (STDOUT_FILENO);
+ if (! showdebug)
+ close (STDERR_FILENO);
+ }
+ else
+ {
+ dup2 (newstd, STDIN_FILENO);
+ dup2 (newstd, STDOUT_FILENO);
+ if (! showdebug)
+ dup2 (newstd, STDERR_FILENO);
+ close (newstd);
+ }
+ }
+ break;
+ default:
+ // Parent: exit inmediately.
+ return 0;
+ }
+
+ #endif
+ }
+
+ // Iniittialize console if not detached and graphics.
+
+ Initializer initializer (argv [0], options.detach);
+
+ // Execute mode options.
+
+ bool spectrummode= false;
+
+ if (! options.mode.empty () )
+ {
+ if (options.mode.size () > 0 && isdigit (options.mode [0] ) )
+ {
+ int mode= atoi (options.mode.c_str () );
+ std::string::size_type x=
+ options.mode.find ('x');
+ if (x != std::string::npos)
+ {
+ int mode2= atoi
+ (options.mode.c_str () + x + 1);
+ graphics::setmode
+ (mode, mode2, false);
+ }
+ else
+ if (mode != 0)
+ graphics::setmode (mode);
+ }
+ else
+ {
+ graphics::setmode (options.mode);
+ if (options.mode == "spectrum")
+ spectrummode= true;
+ }
+ }
+
+ // Initialize runners.
+
+ GlobalRunner globalrunner (program);
+ Runner runner (globalrunner);
+
+ if (spectrummode)
+ runner.spectrumwindows ();
+
+ // Save state of cerr now, after possible redirection to cout
+ // but before redirection to program output, to keep it
+ // usable in main.
+ ProtectCerrBuf protectcerrbuf;
+
+ if (options.errout)
+ {
+ static BlBuf buf (globalrunner);
+ std::cerr.rdbuf (& buf);
+ }
+
+ // Tron options.
+
+ if (options.tron)
+ globalrunner.tron (options.tronline, 0);
+
+ // Execution options.
+
+ static const char EXECUTING []= "Executing line: ";
+
+ if (! options.exec_command.empty () )
+ {
+ if (showdebuginfo () )
+ cerr << EXECUTING << options.exec_command <<
+ endl;
+ CodeLine codeline;
+ codeline.scan (options.exec_command);
+ if (codeline.number () != LineDirectCommand)
+ {
+ program.insert (codeline);
+ runner.run ();
+ }
+ else
+ runner.runline (codeline);
+ return 0;
+ }
+
+ if (! options.print_args.empty () )
+ {
+ if (showdebuginfo () )
+ cerr << EXECUTING << options.print_args <<
+ endl;
+ CodeLine codeline;
+ codeline.scan (options.print_args);
+ runner.runline (codeline);
+ return 0;
+ }
+
+ //if (! options.progname.empty () )
+ if (options.must_run () )
+ {
+ blassic_runprogram (options.progname, runner);
+ return 0;
+ }
+
+ // And if nothing of these...
+
+ set_title (options.progname, runner);
+ runner.interactive ();
+
+ return 0;
+}
+
+} // namespace
+
+//************************************************
+// class Exit
+//************************************************
+
+Exit::Exit (int ncode) :
+ exitcode (ncode)
+{ }
+
+int Exit::code () const
+{
+ return exitcode;
+}
+
+//************************************************
+// main
+//************************************************
+
+int main (int argc, char * * argv)
+{
+ using std::cerr;
+ using std::endl;
+
+ // This can make some speed gain.
+ //std::ios::sync_with_stdio (false);
+ std::cout.sync_with_stdio (false);
+
+ TRACEFUNC (tr, "main");
+ int r;
+
+ try
+ {
+ r= blassic_main (argc, argv);
+ #ifndef NDEBUG
+ std::ostringstream oss;
+ oss << "Returning " << r << " without exception.";
+ TRMESSAGE (tr, oss.str () );
+ #endif
+ }
+ catch (BlErrNo ben)
+ {
+ cerr << ErrStr (ben) << endl;
+ TRMESSAGE (tr, ErrStr (ben) );
+ r= 127;
+ }
+ catch (BlError & be)
+ {
+ cerr << be << endl;
+ TRMESSAGE (tr, util::to_string (be) );
+ r= 127;
+ }
+ catch (BlBreakInPos & bbip)
+ {
+ cerr << bbip << endl;
+ TRMESSAGE (tr, util::to_string (bbip) );
+ r= 127;
+ }
+ catch (std::exception & e)
+ {
+ cerr << e.what () << endl;
+ TRMESSAGE (tr, e.what () );
+ r= 127;
+ }
+ catch (Exit & e)
+ {
+ r= e.code ();
+ TRMESSAGE (tr, "Exit " + util::to_string (r) );
+ }
+ catch (const char * str)
+ {
+ cerr << str << endl;
+ TRMESSAGE (tr, str);
+ r= 127;
+ }
+ catch (...)
+ {
+ cerr << "Unexpected error." << endl;
+ TRMESSAGE (tr, "Unexpected error.");
+ r= 127;
+ }
+
+ return r;
+}
+
+// End of blassic.cpp
diff --git a/blassic.h b/blassic.h
new file mode 100644
index 0000000..219d439
--- /dev/null
+++ b/blassic.h
@@ -0,0 +1,254 @@
+#ifndef INCLUDE_BLASSIC_H
+#define INCLUDE_BLASSIC_H
+
+// blassic.h
+// Revision 6-feb-2005
+
+// Now do not use hash_map at all.
+//#if ! defined __BORLANDC__ && __GNUC__ < 3
+//#if defined __GNUC__
+//#define USE_HASH_MAP
+//#endif
+
+
+#if defined _Windows || defined __CYGWIN__ || defined __MINGW32__
+
+
+#define BLASSIC_USE_WINDOWS
+
+#ifndef __MT__
+#define __MT__
+#endif
+
+
+#else
+
+
+// This is controlled with the configure option --disable-graphics
+#ifndef BLASSIC_CONFIG_NO_GRAPHICS
+
+#define BLASSIC_USE_X
+
+#endif
+
+
+#ifdef __linux__
+
+// Uncomment next #define if you want to use the svgalib option
+// or tell it to configure.
+// Support for svgalib is currently outdated.
+//#define BLASSIC_USE_SVGALIB
+
+#endif
+
+#endif
+
+// Borland define _M_IX86, gcc define __i386__
+#if defined (_M_IX86) || defined (__i386__)
+
+#define BLASSIC_INTEL
+
+// In other processor used the endianess is different and / or
+// there are restrictions of alignment.
+
+#endif
+
+
+#ifdef __BORLANDC__
+#pragma warn -8027
+#endif
+
+
+#ifdef HAVE_CSTDLIB
+#include <cstdlib>
+#else
+#include <stdlib.h>
+#endif
+
+#include <string>
+#include <vector>
+#include <climits>
+
+// Now defined here instead of in var.h to reduce dependencies.
+
+enum VarType { VarUndef, VarNumber, VarInteger,
+ VarString, VarStringSlice };
+
+inline bool is_numeric_type (VarType v)
+{ return v == VarNumber || v == VarInteger; }
+
+inline bool is_string_type (VarType v)
+{ return v == VarString || v == VarStringSlice; }
+
+
+typedef unsigned char BlChar;
+typedef unsigned short BlCode;
+typedef double BlNumber;
+
+#if ULONG_MAX == 4294967295UL
+
+typedef long BlInt32;
+const BlInt32 BlInt32Max= LONG_MAX;
+const BlInt32 BlInt32Min= LONG_MIN;
+
+typedef unsigned long BlUint32;
+const BlUint32 BlUint32Max= ULONG_MAX;
+
+#elif UINT_MAX == 4294967295UL
+
+typedef int BlInt32;
+const BlInt32 BlInt32Max= INT_MAX;
+const BlInt32 BlInt32Min= INT_MIN;
+
+typedef unsigned int BlUint32;
+const BlUint32 BlUint32Max= UINT_MAX;
+
+#elif USHRT_MAX == 4294967295UL
+
+typedef short BlInt32;
+const BlInt32 BlInt32Max= SHRT_MAX;
+const BlInt32 BlInt32Min= SHRT_MIN;
+
+typedef unsigned short BlUint32;
+const BlUint32 BlUint32Max= USHRT_MAX;
+
+#else
+
+#error Unsupported platform
+
+#endif
+
+typedef BlInt32 BlInteger;
+typedef BlUint32 BlLineNumber;
+typedef BlUint32 BlLineLength;
+
+const BlInteger BlIntegerMax= BlInt32Max;
+const BlInteger BlIntegerMin= BlInt32Min;
+
+// We limit the max line number as if it were signed.
+const BlLineNumber BlMaxLineNumber= BlIntegerMax;
+
+// Special line number values.
+
+const BlLineNumber LineEndProgram= BlUint32Max;
+const BlLineNumber LineBeginProgram= BlUint32Max - 1;
+const BlLineNumber LineDirectCommand= BlUint32Max - 2;
+const BlLineNumber LineNoDelete= BlUint32Max - 3;
+
+typedef unsigned short BlChunk;
+typedef unsigned short BlErrNo;
+typedef unsigned short BlChannel;
+
+const BlChannel DefaultChannel= 0;
+const BlChannel PrinterChannel= 65535;
+
+class ProgramPos {
+public:
+ ProgramPos () :
+ num (LineEndProgram), chunk (0)
+ { }
+ ProgramPos (BlLineNumber num) :
+ num (num), chunk (0)
+ { }
+ ProgramPos (BlLineNumber num, BlChunk chunk) :
+ num (num), chunk (chunk)
+ { }
+ void operator= (BlLineNumber num)
+ {
+ this->num= num;
+ chunk= 0;
+ }
+ void nextchunk () { ++chunk; }
+ void nextline () { ++num; chunk= 0; }
+ operator bool () { return num != 0 || chunk != 0; }
+ BlLineNumber getnum () const { return num; }
+ BlChunk getchunk () const { return chunk; }
+ void setchunk (BlChunk n) { chunk= n; }
+private:
+ BlLineNumber num;
+ BlChunk chunk;
+};
+
+// Global variables:
+
+//extern BlLineNumber blnAuto, blnAutoInc;
+
+extern bool fInterrupted;
+
+extern const std::string strPrompt;
+
+// version.cpp
+namespace version {
+
+extern const unsigned short Major, Minor, Release;
+
+} // namespace version
+
+class Exit {
+public:
+ Exit (int ncode= 0);
+ int code () const;
+private:
+ int exitcode;
+};
+
+std::string getprogramarg (size_t n);
+void setprogramargs (const std::vector <std::string> & nargs);
+
+inline BlInteger peek16 (const BlChar * p)
+{
+ #ifdef BLASSIC_INTEL
+ return * reinterpret_cast <const unsigned short *> (p);
+ #else
+ return p [0] | (static_cast <unsigned short> (p [1]) << 8);
+ #endif
+}
+
+inline void poke16 (BlChar * p, short n)
+{
+ #ifdef BLASSIC_INTEL
+ * reinterpret_cast <short *> (p)= n;
+ #else
+ p [0]= BlChar (n & 0xFF);
+ p [1]= BlChar ( (n >> 8) & 0xFF);
+ #endif
+}
+
+inline BlInteger peek32 (const BlChar * p)
+{
+ #ifdef BLASSIC_INTEL
+ return * reinterpret_cast <const BlInteger *> (p);
+ #else
+ return p [0] |
+ (BlInteger (p [1]) << 8) |
+ (BlInteger (p [2]) << 16) |
+ (BlInteger (p [3]) << 24);
+ #endif
+}
+
+inline void poke32 (BlChar * p, BlUint32 n)
+{
+ #ifdef BLASSIC_INTEL
+ * reinterpret_cast <BlInteger *> (p)= n;
+ #else
+ p [0]= BlChar (n & 0xFF);
+ p [1]= BlChar ( (n >> 8) & 0xFF);
+ p [2]= BlChar ( (n >> 16) & 0xFF);
+ p [3]= BlChar (n >> 24);
+ #endif
+}
+
+inline void poke32 (BlChar * p, BlInteger n)
+{
+ poke32 (p, static_cast <BlUint32> (n) );
+}
+
+namespace blassic {
+
+void idle (); // Implemented in graphics.cpp
+
+} // namespace blassic
+
+#endif
+
+// Fin de blassic.h
diff --git a/blassic.spec.in b/blassic.spec.in
new file mode 100644
index 0000000..1a42668
--- /dev/null
+++ b/blassic.spec.in
@@ -0,0 +1,63 @@
+# RPM .spec file for blassic
+
+# Release number can be specified with rpm --define 'rel SOMETHING' ...
+# If no such --define is used, the release number is 1.
+#
+# Source archive's extension can be specified with rpm --define 'srcext .foo'
+# where .foo is the source archive's actual extension.
+# To compile an RPM from a .bz2 source archive, give the command
+# rpm -tb --define 'srcext .bz2' @PACKAGE@-@VERSION@.tar.bz2
+#
+%if %{?rel:0}%{!?rel:1}
+%define rel 1
+%endif
+%if %{?srcext:0}%{!?srcext:1}
+%define srcext .gz
+%endif
+
+Summary: Classic Basic interpreter
+Name: @PACKAGE@
+Version: @VERSION@
+Release: %{rel}
+Copyright: GPL
+Group: Development/Languages
+Source: %{name}-%{version}.tar%{srcext}
+Prefix: /usr
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+#Requires: svgalib >= 1.4.0
+
+%description
+Blassic is a classic Basic interpreter. The line numbers are
+mandatory, and it has PEEK & POKE. The main goal is to execute
+programs written in old interpreters, but it can be used as a
+scripting language.
+
+%package examples
+Summary: Example programs for the Blassic Basic interpreter
+Group: Development/Languages
+
+%description examples
+Example Basic programs for Blassic, the classic Basic interpreter.
+
+
+%prep
+%setup
+
+%build
+./configure --prefix=%{prefix} --enable-installed-examples --disable-svgalib
+make CXXFLAGS="-DNDEBUG -O3"
+
+%install
+rm -fR $RPM_BUILD_ROOT
+make DESTDIR=$RPM_BUILD_ROOT install
+
+%clean
+rm -fR $RPM_BUILD_ROOT
+
+%files
+%defattr(-, root, root)
+%{prefix}/bin/@PACKAGE@
+
+%files examples
+%defattr(-, root, root)
+%{prefix}/share/@PACKAGE@
diff --git a/bootstrap b/bootstrap
new file mode 100755
index 0000000..f9c6b88
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,5 @@
+#!/bin/sh -e
+
+aclocal -I .
+automake --add-missing --copy
+autoconf
diff --git a/charset.h b/charset.h
new file mode 100644
index 0000000..bfbd1f4
--- /dev/null
+++ b/charset.h
@@ -0,0 +1,25 @@
+#ifndef INCLUDE_BLASSIC_CHARSET_H
+#define INCLUDE_BLASSIC_CHARSET_H
+
+// charset.h
+// Revision 13-jun-2006
+
+namespace charset {
+
+typedef unsigned char chardata [8];
+typedef chardata chardataset [256];
+
+extern const chardataset default_data;
+extern const chardataset cpc_data;
+extern const chardataset spectrum_data;
+extern const chardataset msx_data;
+
+extern chardataset data;
+
+extern const chardataset * default_charset;
+
+}
+
+#endif
+
+// End of charset.h
diff --git a/codeline.cpp b/codeline.cpp
new file mode 100644
index 0000000..f2d35c4
--- /dev/null
+++ b/codeline.cpp
@@ -0,0 +1,990 @@
+// codeline.cpp
+// Revision 10-feb-2005
+
+#include "codeline.h"
+
+#include "keyword.h"
+#include "token.h"
+#include "error.h"
+#include "util.h"
+
+#include "trace.h"
+
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include <cctype>
+#include <iostream>
+
+#include <math.h>
+
+using std::cerr;
+using std::endl;
+using std::flush;
+using std::istringstream;
+using std::fill_n;
+using std::transform;
+using std::isxdigit;
+
+
+namespace {
+
+inline bool is_space (char c)
+{
+ return isspace (static_cast <unsigned char> (c) );
+}
+
+inline bool is_bindigit (char c)
+{
+ return c == '0' || c == '1';
+}
+
+inline bool is_octdigit (char c)
+{
+ return c >= '0' && c <= '7';
+}
+
+inline bool is_decdigit (char c)
+{
+ return isdigit (static_cast <unsigned char> (c) );
+}
+
+
+inline bool is_hexdigit (char c)
+{
+ return isxdigit (static_cast <unsigned char> (c) );
+}
+
+inline bool is_base (char c, int base)
+{
+ switch (base)
+ {
+ case 2:
+ return is_bindigit (c);
+ case 8:
+ return is_octdigit (c);
+ case 16:
+ return is_hexdigit (c);
+ default:
+ return false;
+ }
+}
+
+inline int valdigit (unsigned char c)
+{
+ if (islower (c) )
+ c= static_cast <unsigned char> (c + '9' - 'a' + 1);
+ else if (isupper (c) )
+ c= static_cast <unsigned char> (c + '9' - 'A' + 1);
+ return c - '0';
+}
+
+inline bool is_beginidentifier (char c)
+{
+ return isalpha (static_cast <unsigned char> (c) ) /* || c == '_' */;
+}
+
+inline bool is_identifier (char c)
+{
+ return isalnum (static_cast <unsigned char> (c) ) || c == '_';
+}
+
+} // namespace
+
+BlNumber CodeLine::Token::number (const std::string & str)
+{
+ const size_t l= str.size ();
+ if (l == 0)
+ return 0;
+ size_t i= 0;
+ BlNumber n= 0;
+ unsigned char c;
+ if (str [0] == '&')
+ {
+ if (l > 1)
+ {
+ long num= 0;
+ c= str [1];
+ if (c == 'X' || c == 'x')
+ {
+ // Binary
+ i= 1;
+ while (++i < l && is_bindigit (c= str [i]) )
+ {
+ num*= 2;
+ num+= c- '0';
+ }
+ }
+ else if (c == 'O' || c == 'o')
+ {
+ // Octal
+ i= 1;
+ while (++i < l && is_octdigit (c= str [i]) )
+ {
+ num*= 8;
+ num+= c- '0';
+ }
+ }
+ else
+ {
+ // Hexadecimal
+ if (c == 'H' || c == 'h')
+ i= 1;
+ while (++i < l && is_hexdigit (c= str [i] ) )
+ {
+ num*= 16;
+ if (c >= 'a' && c <= 'f')
+ c= (unsigned char)
+ (c + '9' - 'a' + 1);
+ else if (c >= 'A' && c <= 'F')
+ c= (unsigned char)
+ (c + '9' - 'A' + 1);
+ num+= c - '0';
+ }
+ }
+ n= num;
+ }
+ }
+ else {
+ // Decimal
+ #if 0
+ while (i < l && is_digit (c= str [i]) )
+ {
+ n*= 10;
+ n+= c - '0';
+ ++i;
+ }
+ if (i < l && str [i] == '.')
+ {
+ ++i;
+ BlNumber mult= 0.1;
+ while (i < l && is_digit (c= str [i] ) )
+ {
+ n+= (c - '0') * mult;
+ mult/= 10;
+ ++i;
+ }
+ }
+ if (i < l && (str [i] == 'E' || str [i] == 'e') )
+ {
+ ++i;
+ BlNumber e= 0;
+ bool neg= false;
+ if (str [i] == '-')
+ {
+ neg= true;
+ ++i;
+ }
+ while (i < l && (is_digit (c= str [i] ) ) )
+ {
+ e*= 10;
+ e+= c - '0';
+ ++i;
+ }
+ if (neg) e= -e;
+ n*= pow (10, e);
+ }
+ #else
+ istringstream iss (str);
+ iss >> n;
+ #endif
+ }
+ return n;
+}
+
+BlNumber CodeLine::Token::number () const
+{
+ switch (code)
+ {
+ case keyNUMBER:
+ case keySTRING:
+ return number (str);
+ case keyINTEGER:
+ return valueint;
+ case keyENDLINE:
+ return 0.0;
+ default:
+ if (showdebuginfo () )
+ cerr << "Codeline::Token::number called but code= " <<
+ code << " is not valid." << endl;
+ throw ErrBlassicInternal;
+ }
+}
+
+CodeLine::CodeLine () :
+ strcontent (0),
+ linenumber (LineEndProgram),
+ len (0),
+ owner (false),
+ pos (0),
+ chk (0),
+ lastcode (0)
+{
+}
+
+CodeLine::CodeLine (const BlChar * str, BlLineNumber number,
+ BlLineLength length) :
+ strcontent (str),
+ linenumber (number),
+ len (length),
+ owner (false),
+ pos (0),
+ chk (0),
+ lastcode (0)
+{
+}
+
+CodeLine::CodeLine (const CodeLine & old) :
+ strcontent (old.strcontent),
+ linenumber (old.linenumber),
+ len (old.len),
+ owner (false),
+ pos (0),
+ chk (0),
+ lastcode (0)
+{
+}
+
+CodeLine::~CodeLine ()
+{
+ TRACEFUNC (tr, "CodeLine::~CodeLine");
+
+ if (owner && strcontent)
+ delete [] strcontent;
+}
+
+void CodeLine::assign (const BlChar * str, BlLineNumber number,
+ BlLineLength length)
+{
+ if (owner)
+ delete strcontent;
+ strcontent= str;
+ linenumber= number;
+ len= length;
+ owner= false;
+ pos= 0;
+ chk= 0;
+ lastcode= 0;
+}
+
+CodeLine & CodeLine::operator= (const CodeLine & old)
+{
+ if (& old != this)
+ {
+ if (owner && strcontent)
+ delete [] strcontent;
+ strcontent= old.strcontent;
+ linenumber= old.linenumber;
+ len= old.len;
+ owner= false;
+ pos= 0;
+ chk= 0;
+ lastcode= 0;
+ }
+ return * this;
+}
+
+CodeLine::Token CodeLine::getdata ()
+{
+ using std::string;
+
+ while (pos < len && is_space (strcontent [pos] ) )
+ ++pos;
+ Token r;
+ if (pos >= len)
+ {
+ r.code= lastcode= keyENDLINE;
+ return r;
+ }
+ char c= strcontent [pos];
+ if (c == '"')
+ {
+ ++pos;
+ while ( (c= strcontent [pos++]) != '\0')
+ r.str+= c;
+ }
+ else if (c == INTEGER_PREFIX)
+ {
+ //BlInteger n;
+ //n= * (BlInteger *) (strcontent + pos + 1);
+ //r.valueint= n;
+ r.valueint= peek32 (strcontent + pos + 1);
+ r.code= keyINTEGER;
+ pos+= 5;
+ return r;
+ }
+ else
+ {
+ while (pos < len &&
+ (c= strcontent [pos]) != ',' && c != ':' && c != '\'')
+ {
+ if (c == INTEGER_PREFIX)
+ {
+ r.str+= util::to_string
+ (peek32 (strcontent + pos + 1) );
+ pos+= 5;
+ }
+ else
+ {
+ if (iskey (c) )
+ {
+ BlCode s= c;
+ s<<= 8;
+ s|= strcontent [pos + 1];
+ r.str+= decodekeyword (s);
+ pos+= 2;
+ }
+ else
+ {
+ r.str+= c;
+ ++pos;
+ }
+ }
+ }
+ string::size_type last= r.str.find_last_not_of (" ");
+ if (last != string::npos)
+ r.str.erase (last + 1);
+ }
+ r.code= keySTRING;
+ return r;
+}
+
+namespace {
+
+BlChar validinitident [256];
+BlChar validident [256];
+
+bool inittables ()
+{
+ fill_n (& validident [0], 256, 0);
+ fill_n (& validinitident [0], 256, 0);
+
+ // cast to avoid a warning.
+ validident [static_cast <unsigned char> ('_')]= '_';
+
+ for (BlChar i= '0'; i <= '9'; ++i)
+ {
+ validident [i]= i;
+ }
+
+ for (BlChar i= 'A'; i <= 'Z'; ++i)
+ {
+ validident [i]= i;
+ validinitident [i]= i;
+ }
+ for (BlChar i= 'a'; i <= 'z'; ++i)
+ {
+ validident [i]= BlChar (i - 'a' + 'A');
+ validinitident [i]= BlChar (i - 'a' + 'A');
+ }
+ return true;
+}
+
+bool initiated= inittables ();
+
+} // namespace
+
+void CodeLine::gettoken (Token & r)
+{
+ using std::string;
+
+ while (pos < len && is_space (strcontent [pos] ) )
+ ++pos;
+ if (pos >= len)
+ {
+ r.code= lastcode= keyENDLINE;
+ ++chk;
+ return;
+ }
+ BlChar c= strcontent [pos];
+ BlChar c2;
+ if (c == '\0')
+ {
+ r.code= lastcode= keyENDLINE;
+ ++chk;
+ return;
+ }
+ else if (iskey (c) )
+ {
+ BlCode code= c;
+ ++pos;
+ code<<= 8;
+ code|= strcontent [pos++];
+ switch (code)
+ {
+ case keyTHEN:
+ case keyELSE:
+ ++chk;
+ break;
+ case keyEQUALMINOR:
+ code= keyMINOREQUAL;
+ break;
+ case keyEQUALGREATER:
+ code= keyGREATEREQUAL;
+ break;
+ case keyGREATERMINOR:
+ code= keyDISTINCT;
+ break;
+ default:
+ ; // Nothing in particular.
+ }
+ r.code= lastcode= code;
+ return;
+ }
+ else if ( (c2= validinitident [c]) != 0)
+ {
+ r.code= lastcode= keyIDENTIFIER;
+ r.str= c2;
+ while ( ++pos < len &&
+ (c2= validident [ (c= strcontent [pos] ) ] ) != 0)
+ {
+ r.str+= c2;
+ }
+ if (pos < len &&
+ (c == '$' || c == '%' || c == '!' || c == '#') )
+ {
+ ++pos;
+ r.str+= c;
+ }
+ return;
+ }
+ else if (is_decdigit (c) || c == '.')
+ {
+ r.code= lastcode= keyNUMBER;
+ {
+ string strnum;
+ while (pos < len &&
+ (is_decdigit (c= strcontent [pos]) ) )
+ {
+ strnum+= c;
+ ++pos;
+ }
+ if (pos < len && (c= strcontent [pos] ) == '.')
+ {
+ strnum+= '.';
+ ++pos;
+ while (pos < len &&
+ (is_decdigit (c= strcontent [pos]) ) )
+ {
+ strnum+= c;
+ ++pos;
+ }
+ }
+ if (pos < len && (c == 'E' || c == 'e') )
+ {
+ strnum+= c;
+ ++pos;
+ if ( (c= strcontent [pos]) == '-' || c == '+')
+ {
+ strnum+= c;
+ ++pos;
+ }
+ while (pos < len &&
+ (is_decdigit (c= strcontent [pos] ) ) )
+ {
+ strnum+= c;
+ ++pos;
+ }
+ }
+ r.str= strnum;
+ }
+ return;
+ }
+ else if (c == '&')
+ {
+ #if 0
+ // Hexadecimal, octal or binary number.
+ r.code= keyNUMBER;
+ r.str= '&';
+ ++pos;
+ if (pos < len)
+ {
+ c= strcontent [pos];
+ if (c == 'X' || c == 'x')
+ {
+ // Binary
+ ++pos;
+ r.str+= c;
+ while (pos < len &&
+ is_bindigit (strcontent [pos] ) )
+ {
+ r.str+= strcontent [pos];
+ ++pos;
+ }
+ }
+ else if (c == 'O' || c == 'o')
+ {
+ // Octal
+ ++pos;
+ r.str+= c;
+ while (pos < len &&
+ is_octdigit (strcontent [pos] ) )
+ {
+ r.str+= strcontent [pos];
+ ++pos;
+ }
+ }
+ else
+ {
+ // Hexadecimal
+ if (c == 'H' || c == 'h')
+ {
+ ++pos;
+ r.str+= c;
+ }
+ while (pos < len &&
+ is_xdigit (strcontent [pos] ) )
+ {
+ r.str+= strcontent [pos];
+ ++pos;
+ }
+ }
+ }
+ #else
+
+ // Doing it another way, to return the values
+ // as integers.
+ ++pos;
+ if (pos >= len)
+ r.code= '&';
+ else
+ {
+ int base= 0;
+ BlLineLength oldpos= pos;
+ c= strcontent [pos];
+ switch (c)
+ {
+ case 'X': case 'x':
+ // Binary
+ base= 2; ++pos; break;
+ case 'O': case 'o':
+ // Octal
+ base= 8; ++pos; break;
+ case 'H': case 'h':
+ // Hexadecimal
+ base= 16; ++pos; break;
+ default:
+ if (is_hexdigit (c) )
+ base= 16;
+ }
+ switch (base)
+ {
+ case 2:
+ case 8:
+ case 16:
+ if (pos >= len || ! is_base
+ ( (c= strcontent [pos] ), base) )
+ {
+ pos= oldpos;
+ r.code= '&';
+ }
+ else
+ {
+ r.code= lastcode= keyINTEGER;
+ r.valueint= 0;
+ do
+ {
+ r.valueint*= base;
+ r.valueint+= valdigit (c);
+ ++pos;
+ } while (pos < len && is_base
+ ( (c= strcontent [pos] ),
+ base) );
+ }
+ return;
+ //break;
+ default:
+ pos= oldpos;
+ r.code= lastcode= '&';
+ return;
+ }
+ }
+
+ #endif
+ }
+ else
+ {
+ ++pos;
+ switch (c)
+ {
+ case INTEGER_PREFIX:
+ r.code= lastcode= keyINTEGER;
+ {
+ r.valueint= peek32 (strcontent + pos);
+ pos+= 4;
+ }
+ return;
+ //break;
+ case '"':
+ r.code= lastcode= keySTRING;
+ r.str.erase ();
+ while ( (c= strcontent [pos++]) != '\0')
+ r.str+= c;
+ return;
+ //break;
+ case '<':
+ if (pos < len)
+ {
+ switch (strcontent [pos] )
+ {
+ case '>':
+ r.code= keyDISTINCT;
+ ++pos;
+ break;
+ case '=':
+ r.code= keyMINOREQUAL;
+ ++pos;
+ break;
+ default:
+ r.code= '<';
+ }
+ }
+ else r.code= '<';
+ lastcode= r.code;
+ return;
+ //break;
+ case '>':
+ if (pos < len)
+ {
+ switch (strcontent [pos] )
+ {
+ case '<':
+ r.code= keyDISTINCT;
+ ++pos;
+ break;
+ case '=':
+ r.code= keyGREATEREQUAL;
+ ++pos;
+ break;
+ default:
+ r.code= '>';
+ }
+ }
+ else r.code= '>';
+ lastcode= r.code;
+ return;
+ //break;
+ case '=':
+ if (pos < len)
+ {
+ switch (strcontent [pos] )
+ {
+ case '<':
+ r.code= keyMINOREQUAL;
+ ++pos;
+ break;
+ case '>':
+ r.code= keyGREATEREQUAL;
+ ++pos;
+ break;
+ default:
+ r.code= '=';
+ }
+ }
+ else r.code= '=';
+ lastcode= r.code;
+ return;
+ //break;
+ case '\'':
+ r.code= lastcode= keyENDLINE;
+ ++chk;
+ pos= len;
+ return;
+ //break;
+ case ':':
+ r.code= lastcode= ':';
+ ++chk;
+ return;
+ //break;
+ default:
+ r.code= lastcode= c;
+ return;
+ }
+ }
+}
+
+void CodeLine::gotochunk (BlChunk chknew)
+{
+ pos= 0; chk= 0;
+ if (chknew == 0)
+ {
+ lastcode= 0;
+ return;
+ }
+ while (chk < chknew)
+ {
+ if (pos >= len)
+ {
+ lastcode= keyENDLINE;
+ return;
+ }
+ char c= strcontent [pos];
+ if (c == INTEGER_PREFIX)
+ {
+ pos+= 5;
+ }
+ else if (iskey (c) )
+ {
+ BlCode code;
+ code= strcontent [pos++];
+ code<<= 8;
+ code|= strcontent [pos++];
+ if (code == keyTHEN || code == keyELSE)
+ {
+ lastcode= code;
+ ++chk;
+ }
+ else if (code == keyREM)
+ {
+ lastcode= code;
+ pos= len;
+ }
+ }
+ else
+ {
+ if (c == '\'')
+ {
+ lastcode= '\'';
+ pos= len;
+ }
+ if (c == '"')
+ {
+ ++pos;
+ while (strcontent [pos] != '\0')
+ ++pos;
+ ++pos;
+ }
+ else
+ {
+ if (c == ':')
+ {
+ lastcode= ':';
+ ++chk;
+ }
+ ++pos;
+ }
+ }
+ }
+}
+
+namespace {
+
+using std::string;
+
+inline string stringupper (const string & str)
+{
+ string u (str.size (), 0);
+ transform (str.begin (), str.end (), u.begin (), toupper);
+ return u;
+}
+
+inline bool is_word (const Tokenizer::Token & token, const char * str)
+{
+ if (token.type != Tokenizer::Plain)
+ return false;
+ return stringupper (token.str) == str;
+}
+
+inline bool isGO (const Tokenizer::Token & token)
+{
+ return is_word (token, "GO");
+}
+
+inline bool isSUB (const Tokenizer::Token & token)
+{
+ return is_word (token, "SUB");
+}
+
+const string strprefinteger (1, INTEGER_PREFIX);
+
+inline string codeinteger (BlInteger n)
+{
+ #ifdef BLASSIC_INTEL
+
+ return strprefinteger +
+ string (reinterpret_cast <const char *> (& n), 4);
+
+ #else
+
+ return strprefinteger +
+ char (n & 0xFF) +
+ char ( (n >> 8) & 0xFF) +
+ char ( (n >> 16) & 0xFF) +
+ char (n >> 24);
+
+ #endif
+}
+
+} // namespace
+
+void CodeLine::scan (const std::string & line)
+{
+ using std::string;
+
+ //linenumber= 0;
+ //len= 0;
+ //pos= 0;
+ //BlLineNumber newlinenumber= 0;
+ BlLineNumber newlinenumber= LineDirectCommand;
+ string newcontent;
+ static const char INVALID []= "Line number invalid";
+
+ if (! line.empty () )
+ {
+ int i= 0, l= line.size ();
+ while (i < l && is_space (line [i] ) )
+ ++i;
+ if (i < l && is_decdigit (line [i] ) )
+ {
+ newlinenumber= 0;
+ while (i < l && is_decdigit (line [i] ) )
+ {
+ if (newlinenumber > BlMaxLineNumber / 10)
+ {
+ if (showdebuginfo () )
+ cerr << INVALID << endl;
+ throw ErrSyntax;
+ }
+ newlinenumber*= 10;
+ BlLineNumber n= static_cast <BlLineNumber>
+ (line [i] - '0');
+ if (newlinenumber > BlMaxLineNumber - n)
+ {
+ if (showdebuginfo () )
+ cerr << INVALID << endl;
+ throw ErrSyntax;
+ }
+ newlinenumber+= n;
+ ++i;
+ }
+ if (i < l && line [i] == ' ') ++i;
+ }
+ else i= 0;
+
+ Tokenizer t (line.substr (i) );
+ //string str;
+ Tokenizer::Token token;
+ Tokenizer::Token prevtoken;
+ BlCode code;
+ bool incomment= false;
+ bool addspace;
+ string::size_type prevsize= string::npos;
+ string::size_type lastsize= 0;
+
+ while (! incomment &&
+ (token= t.get () ).type != Tokenizer::EndLine)
+ {
+ //cerr << '(' << str << ')' << flush;
+ switch (token.type)
+ {
+ case Tokenizer::Blank:
+ newcontent+= token.str;
+ break;
+ case Tokenizer::Literal:
+ newcontent+= '"';
+ newcontent+= token.str;
+ newcontent+= '\0';
+ break;
+ case Tokenizer::Integer:
+ newcontent+= codeinteger (token.n);
+ break;
+ case Tokenizer::Plain:
+ //code= 0;
+ addspace= false;
+ if (token.str == "?")
+ {
+ code= keyPRINT;
+ char c= t.peek ();
+ if (c != '\0' && !
+ is_space (c) )
+ addspace= true;
+ }
+ else
+ code= keyword (token.str);
+
+ // GO TO
+ if (code == keyTO)
+ {
+ if (isGO (prevtoken) )
+ {
+ code= keyGOTO;
+ newcontent.erase
+ (prevsize);
+ }
+ }
+ // GO SUB
+ if (code == 0 && isSUB (token) )
+ {
+ if (isGO (prevtoken) )
+ {
+ code= keyGOSUB;
+ newcontent.erase
+ (prevsize);
+ }
+ }
+ if (code == 0)
+ {
+ newcontent+= token.str;
+ if (token.str == "'")
+ incomment= true;
+ }
+ else
+ {
+ newcontent+= char (code >> 8);
+ newcontent+= char (code & 0xFF);
+ if (code == keyREM)
+ incomment= true;
+ }
+ if (addspace)
+ newcontent+= ' ';
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ if (token.type != Tokenizer::Blank)
+ {
+ prevtoken= token;
+ prevsize= lastsize;
+ }
+ lastsize= newcontent.size ();
+ }
+ if (incomment)
+ {
+ newcontent+= t.getrest ();
+ }
+
+ //if (owner && strcontent)
+ // delete [] strcontent;
+
+ }
+
+ BlLineLength newlen= newcontent.size ();
+ if (newlen > 0)
+ {
+ //strcontent= new unsigned char [newlen];
+ //newcontent.copy ( (char *) strcontent, newlen);
+ unsigned char * auxcontent= new unsigned char [newlen];
+ // No need to protect auxcontent, copy and delete
+ // must not throw.
+ newcontent.copy ( (char *) auxcontent, newlen);
+ if (owner && strcontent)
+ delete [] strcontent;
+ strcontent= auxcontent;
+ owner= true;
+ }
+ else
+ {
+ if (owner && strcontent)
+ delete [] strcontent;
+ owner= false;
+ strcontent= NULL;
+ }
+
+ len= newlen;
+ linenumber= newlinenumber;
+ pos= 0;
+ chk= 0;
+ lastcode= 0;
+}
+
+// Fin de codeline.cpp
diff --git a/codeline.h b/codeline.h
new file mode 100644
index 0000000..b4c5ccb
--- /dev/null
+++ b/codeline.h
@@ -0,0 +1,60 @@
+#ifndef INCLUDE_BLASSIC_CODELINE_H
+#define INCLUDE_BLASSIC_CODELINE_H
+
+// codeline.h
+// Revision 11-jul-2004
+
+#include "blassic.h"
+#include "keyword.h"
+
+class CodeLine {
+ const BlChar * strcontent;
+ BlLineNumber linenumber;
+ BlLineLength len;
+ bool owner;
+ BlLineLength pos;
+ BlChunk chk;
+ BlCode lastcode;
+public:
+ class Token {
+ public:
+ BlCode code;
+ std::string str;
+ BlInteger valueint;
+ static BlNumber number (const std::string & str);
+ BlNumber number () const;
+ BlInteger integer () const { return valueint; }
+ inline bool isendsentence () const
+ {
+ return code == ':' ||
+ code == keyENDLINE ||
+ code == keyELSE;
+ }
+ };
+
+ CodeLine ();
+ CodeLine (const BlChar * str, BlLineNumber number,
+ BlLineLength length);
+ CodeLine (const CodeLine & old);
+ ~CodeLine ();
+ void assign (const BlChar * str, BlLineNumber number,
+ BlLineLength length);
+ CodeLine & operator= (const CodeLine & old);
+ bool empty () const { return len == 0; }
+ BlLineNumber number () const { return linenumber; }
+ void setnumber (BlLineNumber n) { linenumber= n; }
+ BlLineLength length () const { return len; }
+ BlChunk chunk () const { return chk; }
+ //BlChar * content () { return strcontent; }
+ const BlChar * content () const { return strcontent; }
+ BlCode actualcode () const { return lastcode; }
+ Token getdata ();
+ //Token gettoken ();
+ void gettoken (Token & r);
+ void gotochunk (BlChunk chknew);
+ void scan (const std::string & line);
+};
+
+#endif
+
+// Fin de codeline.h
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..aa815fe
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,295 @@
+# configure.ac for blassic
+
+AC_INIT(version.cpp)
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+
+# Require autoconf >= 2.50
+AC_PREREQ(2.50)
+
+# Parse version.cpp to get the version number.
+# The number is defined in version.cpp to avoid affecting the Windows
+# compilation process.
+#
+# Julian: changed the "grep -w Major" for "grep 'version::Major'"
+# because the -w option in not always present.
+
+AC_MSG_CHECKING(for version number in $srcdir/version.cpp)
+
+VERSION_MAJOR=`grep 'version::Major' $srcdir/version.cpp | \
+ sed 's/.*version::.*= *//;s/[[,;]]//'`
+VERSION_MINOR=`grep 'version::Minor' $srcdir/version.cpp | \
+ sed 's/.*version::.*= *//;s/[[,;]]//'`
+VERSION_RELEASE=`grep 'version::Release' $srcdir/version.cpp | \
+ sed 's/.*version::.*= *//;s/[[,;]]//'`
+
+AC_MSG_RESULT([got $VERSION_MAJOR.$VERSION_MINOR.$VERSION_RELEASE])
+
+if test "_$VERSION_MAJOR" = "_"; then
+ AC_MSG_ERROR([version::Major not found])
+elif test "_$VERSION_MINOR" = "_"; then
+ AC_MSG_ERROR([version::Minor not found])
+elif test "_$VERSION_RELEASE" = "_"; then
+ AC_MSG_ERROR([version::Release not found])
+fi
+
+AM_INIT_AUTOMAKE(blassic, $VERSION_MAJOR.$VERSION_MINOR.$VERSION_RELEASE)
+
+# This is to check in the sources that configure has been used.
+AC_DEFINE([BLASSIC_CONFIG])
+
+# Checks for programs.
+AC_PROG_CXX
+AC_LANG_CPLUSPLUS
+
+# Check if compiling for windows.
+case "$host" in
+*-*-cygwin*|*mingw*)
+ HOST_WIN=1
+ ;;
+*)
+ ;;
+esac
+
+###############################################################################
+
+# Option to disable graphics.
+
+AC_ARG_ENABLE(graphics, AC_HELP_STRING(
+ [--enable-graphics], [Use graphics [[yes]]] ) )
+if test "$enable_graphics" = "no"; then
+ AC_MSG_RESULT([not using graphics])
+ AC_DEFINE(BLASSIC_CONFIG_NO_GRAPHICS)
+else
+ AC_MSG_RESULT([using graphics])
+fi
+
+###############################################################################
+
+# Option to disable curses / ncurses.
+
+if test "_$HOST_WIN" != _1
+then
+ AC_ARG_ENABLE(curses, AC_HELP_STRING(
+ [--enable-curses], [Use curses [[yes]]] ) )
+ if test "$enable_curses" = "no"; then
+ AC_MSG_RESULT([not using curses])
+ AC_DEFINE(BLASSIC_CONFIG_NO_CURSES)
+ else
+ AC_MSG_RESULT([using curses])
+
+ # Option to disable ncurses, checking only curses
+
+ AC_ARG_ENABLE(curses, AC_HELP_STRING(
+ [--enable-ncurses],
+ [Check ncurses before curses [[yes]]] ) )
+ if test "$enable_ncurses" = "no"; then
+ AC_MSG_RESULT([not checking ncurses])
+ AC_DEFINE(BLASSIC_CONFIG_NO_NCURSES)
+ else
+ AC_MSG_RESULT([checking ncurses])
+ fi
+
+ fi
+fi
+
+###############################################################################
+
+# Option to enable svgalib (actually unsupported).
+
+if test "_$HOST_WIN" != _1
+then
+ AC_ARG_ENABLE(svgalib, AC_HELP_STRING(
+ [--enable-svgalib], [Use svgalib [[yes]]] ),
+ [
+ if test "_$enableval" = "_no"; then
+ :
+ AC_SUBST(SVGALIB_CFLAGS)
+ AC_SUBST(SVGALIB_LIBS)
+ else
+ AM_PATH_SVGALIB(1.4.0)
+ fi
+ ],
+ [
+ :
+ AC_SUBST(SVGALIB_CFLAGS)
+ AC_SUBST(SVGALIB_LIBS)
+ ]
+ )
+ if test "_$SVGALIB_LIBS" = "_"; then
+ AC_MSG_RESULT([not using svgalib])
+ fi
+fi
+
+###############################################################################
+
+# Check for cross-compiling:
+
+if test "$cross_compiling" = "yes"
+then
+ if test "$CXX_FOR_BUILD" = ""
+ then
+ CXX_FOR_BUILD="g++"
+ fi
+ AC_SUBST(CXX_FOR_BUILD,[$CXX_FOR_BUILD])
+ if test "$CXXFLAGS_FOR_BUILD" = ""
+ then
+ CXXFLAGS_FOR_BUILD=$CXXFLGAS
+ fi
+ AC_SUBST(CXXFLAGS_FOR_BUILD,[$CXXFLAGS_FOR_BUILD])
+else
+ AC_SUBST(CXX_FOR_BUILD,[$CXX])
+ AC_SUBST(CXXFLAGS_FOR_BUILD,[$CXXFLAGS])
+fi
+
+###############################################################################
+
+# Check headers and libs.
+
+
+# Compatibility with old versions of C++
+
+AC_CHECK_HEADERS([cstdlib])
+
+
+# Cursor, graphics and printer.
+
+case "$host" in
+*-*-cygwin*|*mingw*)
+ AC_SUBST(CYGWIN_FLAGS, ["-lgdi32 -lwsock32 -lwinspool"])
+
+ # isatty can be defined here or in unistd.h
+ AC_CHECK_HEADERS([io.h])
+ ;;
+*)
+ AC_SUBST(CYGWIN_FLAGS)
+
+ # Check for sys/mman.h, needed for mmap.
+ # This test seems to not work correctly when cross-compiling.
+ #AC_FUNC_MMAP
+ AC_CHECK_HEADERS([sys/mman.h], AC_DEFINE([HAVE_MMAP], 1) )
+
+
+ # If the systems has libdl, use it.
+ AC_CHECK_LIB(dl, dlopen)
+
+ # Check for ncurses, if not found for curses.
+ # Done in a complicated way to work in all possible cases
+ # and avoid to link both libs.
+ if test "$enable_curses" != "no"
+ then
+ if test "$enable_ncurses" != "no"
+ then
+ AC_MSG_NOTICE([checking if ncurses or curses can be used])
+ else
+ AC_MSG_NOTICE([checking if curses can be used])
+ fi
+ if test "$enable_ncurses" != "no"
+ then
+ ncurses_found=yes
+ AC_CHECK_HEADERS([ncurses.h],,[ncurses_found=no])
+ if test "$ncurses_found" = yes
+ then
+ AC_CHECK_LIB([ncurses],[tputs],,[ncurses_found=no])
+ if test "$ncurses_found" = yes
+ then
+ AC_DEFINE(BLASSIC_CONFIG_USE_NCURSES)
+ AC_MSG_NOTICE([using ncurses])
+ else
+ AC_MSG_WARN([ncurses header found but no lib])
+ fi
+ fi
+ fi
+ if test "$ncurses_found" != yes
+ then
+ if test "$enable_ncurses" != "no"
+ then
+ AC_MSG_NOTICE([ncurses not available, checking curses])
+ fi
+ curses_found=yes
+ AC_CHECK_HEADERS([curses.h],,[curses_found=no])
+ if test "$curses_found" = yes
+ then
+ AC_CHECK_LIB(curses,tputs,,[curses_found=no])
+ if test "$curses_found" = yes
+ then
+ AC_DEFINE(BLASSIC_CONFIG_USE_CURSES)
+ if test "$enable_ncurses" != "no"
+ then
+ AC_MSG_NOTICE([using curses])
+ fi
+ else
+ AC_MSG_WARN([curses header found but no lib])
+ fi
+ fi
+ fi
+ if test "$ncurses_found" != yes && test "$curses_found" != yes
+ then
+ AC_MSG_NOTICE([not using curses])
+ fi
+ AC_CHECK_HEADERS([term.h])
+ fi
+
+
+ # Check X11.
+ if test "$enable_graphics" != "no"
+ then
+ AC_PATH_XTRA
+ if test "x$no_x" = xyes
+ then
+ AC_MSG_NOTICE([X not available or disabled, disabling graphics])
+ AC_DEFINE(BLASSIC_CONFIG_NO_GRAPHICS)
+ else
+ xflags="$X_CFLAGS"
+ xlibs="$X_LIBS"
+ xadd="$X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
+ fi
+ fi
+ AC_SUBST([BL_X_CFLAGS], [$xflags] )
+ AC_SUBST([BL_X_LIBS], [$xlibs] )
+ AC_SUBST([BL_X_ADD], [$xadd] )
+
+ AC_HEADER_SYS_WAIT
+
+ # Check some variants used in debugging when available.
+ AC_CHECK_MEMBERS([siginfo_t.si_ptr],,,[#include <signal.h>])
+
+ ;;
+esac
+
+# Check availability of hyperbolic trigonometric functions.
+
+AC_CHECK_DECLS([asinh, acosh, atanh], , , [#include <math.h>] )
+
+
+###############################################################################
+
+
+AC_ARG_ENABLE(installed-examples, AC_HELP_STRING(
+ [--enable-installed-examples],
+ [Install the example programs [[yes]]] ),
+ [
+ if test "_$enableval" = "_no"; then
+ INSTALL_EXAMPLE_PROGS=no
+ else
+ INSTALL_EXAMPLE_PROGS=yes
+ fi
+ ],
+ [
+ INSTALL_EXAMPLE_PROGS=yes
+ ]
+)
+
+AM_CONDITIONAL(INSTALL_EXAMPLE_PROGS, [test "_$INSTALL_EXAMPLE_PROGS" = _yes])
+
+
+
+
+###############################################################################
+
+# Generate files.
+AC_OUTPUT([
+ Makefile
+ blassic.spec
+])
diff --git a/cpc.def b/cpc.def
new file mode 100644
index 0000000..2f2dafd
--- /dev/null
+++ b/cpc.def
@@ -0,0 +1,2817 @@
+
+ 0
+
+11111111
+11000011
+11000011
+11000011
+11000011
+11000011
+11000011
+11111111
+
+ 1
+
+11111111
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+
+ 2
+
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+11111111
+
+ 3
+
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+11111111
+
+ 4
+
+00001100
+00011000
+00110000
+01111110
+00001100
+00011000
+00110000
+00000000
+
+ 5
+
+11111111
+11000011
+11100111
+11011011
+11011011
+11100111
+11000011
+11111111
+
+ 6
+
+00000000
+00000001
+00000011
+00000110
+11001100
+01111000
+00110000
+00000000
+
+ 7
+
+00111100
+01100110
+11000011
+11000011
+11111111
+00100100
+11100111
+00000000
+
+ 8
+
+00000000
+00000000
+00110000
+01100000
+11111111
+01100000
+00110000
+00000000
+
+ 9
+
+00000000
+00000000
+00001100
+00000110
+11111111
+00000110
+00001100
+00000000
+
+ 10
+
+00011000
+00011000
+00011000
+00011000
+11011011
+01111110
+00111100
+00011000
+
+ 11
+
+00011000
+00111100
+01111110
+11011011
+00011000
+00011000
+00011000
+00011000
+
+ 12
+
+00011000
+01011010
+00111100
+10011001
+11011011
+01111110
+00111100
+00011000
+
+ 13
+
+00000000
+00000011
+00110011
+01100011
+11111110
+01100000
+00110000
+00000000
+
+ 14
+
+00111100
+01100110
+11111111
+11011011
+11011011
+11111111
+01100110
+00111100
+
+ 15
+
+00111100
+01100110
+11000011
+11011011
+11011011
+11000011
+01100110
+00111100
+
+ 16
+
+11111111
+11000011
+11000011
+11111111
+11000011
+11000011
+11000011
+11111111
+
+ 17
+
+00111100
+01111110
+11011011
+11011011
+11011111
+11000011
+01100110
+00111100
+
+ 18
+
+00111100
+01100110
+11000011
+11011111
+11011011
+11011011
+01111110
+00111100
+
+ 19
+
+00111100
+01100110
+11000011
+11111011
+11011011
+11011011
+01111110
+00111100
+
+ 20
+
+00111100
+01111110
+11011011
+11011011
+11111011
+11000011
+01100110
+00111100
+
+ 21
+
+00000000
+00000001
+00110011
+00011110
+11001110
+01111011
+00110001
+00000000
+
+ 22
+
+01111110
+01100110
+01100110
+01100110
+01100110
+01100110
+01100110
+11100111
+
+ 23
+
+00000011
+00000011
+00000011
+11111111
+00000011
+00000011
+00000011
+00000000
+
+ 24
+
+11111111
+01100110
+00111100
+00011000
+00011000
+00111100
+01100110
+11111111
+
+ 25
+
+00011000
+00011000
+00111100
+00111100
+00111100
+00111100
+00011000
+00011000
+
+ 26
+
+00111100
+01100110
+01100110
+00110000
+00011000
+00000000
+00011000
+00000000
+
+ 27
+
+00111100
+01100110
+11000011
+11111111
+11000011
+11000011
+01100110
+00111100
+
+ 28
+
+11111111
+11011011
+11011011
+11011011
+11111011
+11000011
+11000011
+11111111
+
+ 29
+
+11111111
+11000011
+11000011
+11111011
+11011011
+11011011
+11011011
+11111111
+
+ 30
+
+11111111
+11000011
+11000011
+11011111
+11011011
+11011011
+11011011
+11111111
+
+ 31
+
+11111111
+11011011
+11011011
+11011011
+11011111
+11000011
+11000011
+11111111
+
+ 32
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 33
+
+00011000
+00011000
+00011000
+00011000
+00011000
+00000000
+00011000
+00000000
+
+ 34
+
+01101100
+01101100
+01101100
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 35
+
+01101100
+01101100
+11111110
+01101100
+11111110
+01101100
+01101100
+00000000
+
+ 36
+
+00011000
+00111110
+01011000
+00111100
+00011010
+01111100
+00011000
+00000000
+
+ 37
+
+00000000
+11000110
+11001100
+00011000
+00110000
+01100110
+11000110
+00000000
+
+ 38
+
+00111000
+01101100
+00111000
+01110110
+11011100
+11001100
+01110110
+00000000
+
+ 39
+
+00011000
+00011000
+00110000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 40
+
+00001100
+00011000
+00110000
+00110000
+00110000
+00011000
+00001100
+00000000
+
+ 41
+
+00110000
+00011000
+00001100
+00001100
+00001100
+00011000
+00110000
+00000000
+
+ 42
+
+00000000
+01100110
+00111100
+11111111
+00111100
+01100110
+00000000
+00000000
+
+ 43
+
+00000000
+00011000
+00011000
+01111110
+00011000
+00011000
+00000000
+00000000
+
+ 44
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00011000
+00011000
+00110000
+
+ 45
+
+00000000
+00000000
+00000000
+01111110
+00000000
+00000000
+00000000
+00000000
+
+ 46
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00011000
+00011000
+00000000
+
+ 47
+
+00000110
+00001100
+00011000
+00110000
+01100000
+11000000
+10000000
+00000000
+
+ 48
+
+01111100
+11000110
+11001110
+11010110
+11100110
+11000110
+01111100
+00000000
+
+ 49
+
+00011000
+00111000
+00011000
+00011000
+00011000
+00011000
+01111110
+00000000
+
+ 50
+
+00111100
+01100110
+00000110
+00111100
+01100000
+01100110
+01111110
+00000000
+
+ 51
+
+00111100
+01100110
+00000110
+00011100
+00000110
+01100110
+00111100
+00000000
+
+ 52
+
+00011100
+00111100
+01101100
+11001100
+11111110
+00001100
+00011110
+00000000
+
+ 53
+
+01111110
+01100010
+01100000
+01111100
+00000110
+01100110
+00111100
+00000000
+
+ 54
+
+00111100
+01100110
+01100000
+01111100
+01100110
+01100110
+00111100
+00000000
+
+ 55
+
+01111110
+01100110
+00000110
+00001100
+00011000
+00011000
+00011000
+00000000
+
+ 56
+
+00111100
+01100110
+01100110
+00111100
+01100110
+01100110
+00111100
+00000000
+
+ 57
+
+00111100
+01100110
+01100110
+00111110
+00000110
+01100110
+00111100
+00000000
+
+ 58
+
+00000000
+00000000
+00011000
+00011000
+00000000
+00011000
+00011000
+00000000
+
+ 59
+
+00000000
+00000000
+00011000
+00011000
+00000000
+00011000
+00011000
+00110000
+
+ 60
+
+00001100
+00011000
+00110000
+01100000
+00110000
+00011000
+00001100
+00000000
+
+ 61
+
+00000000
+00000000
+01111110
+00000000
+00000000
+01111110
+00000000
+00000000
+
+ 62
+
+01100000
+00110000
+00011000
+00001100
+00011000
+00110000
+01100000
+00000000
+
+ 63
+
+00111100
+01100110
+01100110
+00001100
+00011000
+00000000
+00011000
+00000000
+
+ 64
+
+01111100
+11000110
+11011110
+11011110
+11011110
+11000000
+01111100
+00000000
+
+ 65
+
+00011000
+00111100
+01100110
+01100110
+01111110
+01100110
+01100110
+00000000
+
+ 66
+
+11111100
+01100110
+01100110
+01111100
+01100110
+01100110
+11111100
+00000000
+
+ 67
+
+00111100
+01100110
+11000000
+11000000
+11000000
+01100110
+00111100
+00000000
+
+ 68
+
+11111000
+01101100
+01100110
+01100110
+01100110
+01101100
+11111000
+00000000
+
+ 69
+
+11111110
+01100010
+01101000
+01111000
+01101000
+01100010
+11111110
+00000000
+
+ 70
+
+11111110
+01100010
+01101000
+01111000
+01101000
+01100000
+11110000
+00000000
+
+ 71
+
+00111100
+01100110
+11000000
+11000000
+11001110
+01100110
+00111110
+00000000
+
+ 72
+
+01100110
+01100110
+01100110
+01111110
+01100110
+01100110
+01100110
+00000000
+
+ 73
+
+01111110
+00011000
+00011000
+00011000
+00011000
+00011000
+01111110
+00000000
+
+ 74
+
+00011110
+00001100
+00001100
+00001100
+11001100
+11001100
+01111000
+00000000
+
+ 75
+
+11100110
+01100110
+01101100
+01111000
+01101100
+01100110
+11100110
+00000000
+
+ 76
+
+11110000
+01100000
+01100000
+01100000
+01100010
+01100110
+11111110
+00000000
+
+ 77
+
+11000110
+11101110
+11111110
+11111110
+11010110
+11000110
+11000110
+00000000
+
+ 78
+
+11000110
+11100110
+11110110
+11011110
+11001110
+11000110
+11000110
+00000000
+
+ 79
+
+00111000
+01101100
+11000110
+11000110
+11000110
+01101100
+00111000
+00000000
+
+ 80
+
+11111100
+01100110
+01100110
+01111100
+01100000
+01100000
+11110000
+00000000
+
+ 81
+
+00111000
+01101100
+11000110
+11000110
+11011010
+11001100
+01110110
+00000000
+
+ 82
+
+11111100
+01100110
+01100110
+01111100
+01101100
+01100110
+11100110
+00000000
+
+ 83
+
+00111100
+01100110
+01100000
+00111100
+00000110
+01100110
+00111100
+00000000
+
+ 84
+
+01111110
+01011010
+00011000
+00011000
+00011000
+00011000
+00111100
+00000000
+
+ 85
+
+01100110
+01100110
+01100110
+01100110
+01100110
+01100110
+00111100
+00000000
+
+ 86
+
+01100110
+01100110
+01100110
+01100110
+01100110
+00111100
+00011000
+00000000
+
+ 87
+
+11000110
+11000110
+11000110
+11010110
+11111110
+11101110
+11000110
+00000000
+
+ 88
+
+11000110
+01101100
+00111000
+00111000
+01101100
+11000110
+11000110
+00000000
+
+ 89
+
+01100110
+01100110
+01100110
+00111100
+00011000
+00011000
+00111100
+00000000
+
+ 90
+
+11111110
+11000110
+10001100
+00011000
+00110010
+01100110
+11111110
+00000000
+
+ 91
+
+00111100
+00110000
+00110000
+00110000
+00110000
+00110000
+00111100
+00000000
+
+ 92
+
+11000000
+01100000
+00110000
+00011000
+00001100
+00000110
+00000010
+00000000
+
+ 93
+
+00111100
+00001100
+00001100
+00001100
+00001100
+00001100
+00111100
+00000000
+
+ 94
+
+00011000
+00111100
+01111110
+00011000
+00011000
+00011000
+00011000
+00000000
+
+ 95
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11111111
+
+ 96
+
+00110000
+00011000
+00001100
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 97
+
+00000000
+00000000
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 98
+
+11100000
+01100000
+01111100
+01100110
+01100110
+01100110
+11011100
+00000000
+
+ 99
+
+00000000
+00000000
+00111100
+01100110
+01100000
+01100110
+00111100
+00000000
+
+ 100
+
+00011100
+00001100
+01111100
+11001100
+11001100
+11001100
+01110110
+00000000
+
+ 101
+
+00000000
+00000000
+00111100
+01100110
+01111110
+01100000
+00111100
+00000000
+
+ 102
+
+00011100
+00110110
+00110000
+01111000
+00110000
+00110000
+01111000
+00000000
+
+ 103
+
+00000000
+00000000
+00111110
+01100110
+01100110
+00111110
+00000110
+01111100
+
+ 104
+
+11100000
+01100000
+01101100
+01110110
+01100110
+01100110
+11100110
+00000000
+
+ 105
+
+00011000
+00000000
+00111000
+00011000
+00011000
+00011000
+00111100
+00000000
+
+ 106
+
+00000110
+00000000
+00001110
+00000110
+00000110
+01100110
+01100110
+00111100
+
+ 107
+
+11100000
+01100000
+01100110
+01101100
+01111000
+01101100
+11100110
+00000000
+
+ 108
+
+00111000
+00011000
+00011000
+00011000
+00011000
+00011000
+00111100
+00000000
+
+ 109
+
+00000000
+00000000
+01101100
+11111110
+11010110
+11010110
+11000110
+00000000
+
+ 110
+
+00000000
+00000000
+11011100
+01100110
+01100110
+01100110
+01100110
+00000000
+
+ 111
+
+00000000
+00000000
+00111100
+01100110
+01100110
+01100110
+00111100
+00000000
+
+ 112
+
+00000000
+00000000
+11011100
+01100110
+01100110
+01111100
+01100000
+11110000
+
+ 113
+
+00000000
+00000000
+01110110
+11001100
+11001100
+01111100
+00001100
+00011110
+
+ 114
+
+00000000
+00000000
+11011100
+01110110
+01100000
+01100000
+11110000
+00000000
+
+ 115
+
+00000000
+00000000
+00111100
+01100000
+00111100
+00000110
+01111100
+00000000
+
+ 116
+
+00110000
+00110000
+01111100
+00110000
+00110000
+00110110
+00011100
+00000000
+
+ 117
+
+00000000
+00000000
+01100110
+01100110
+01100110
+01100110
+00111110
+00000000
+
+ 118
+
+00000000
+00000000
+01100110
+01100110
+01100110
+00111100
+00011000
+00000000
+
+ 119
+
+00000000
+00000000
+11000110
+11010110
+11010110
+11111110
+01101100
+00000000
+
+ 120
+
+00000000
+00000000
+11000110
+01101100
+00111000
+01101100
+11000110
+00000000
+
+ 121
+
+00000000
+00000000
+01100110
+01100110
+01100110
+00111110
+00000110
+01111100
+
+ 122
+
+00000000
+00000000
+01111110
+01001100
+00011000
+00110010
+01111110
+00000000
+
+ 123
+
+00001110
+00011000
+00011000
+01110000
+00011000
+00011000
+00001110
+00000000
+
+ 124
+
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00000000
+
+ 125
+
+01110000
+00011000
+00011000
+00001110
+00011000
+00011000
+01110000
+00000000
+
+ 126
+
+01110110
+11011100
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 127
+
+11001100
+00110011
+11001100
+00110011
+11001100
+00110011
+11001100
+00110011
+
+ 128
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 129
+
+11110000
+11110000
+11110000
+11110000
+00000000
+00000000
+00000000
+00000000
+
+ 130
+
+00001111
+00001111
+00001111
+00001111
+00000000
+00000000
+00000000
+00000000
+
+ 131
+
+11111111
+11111111
+11111111
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 132
+
+00000000
+00000000
+00000000
+00000000
+11110000
+11110000
+11110000
+11110000
+
+ 133
+
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+
+ 134
+
+00001111
+00001111
+00001111
+00001111
+11110000
+11110000
+11110000
+11110000
+
+ 135
+
+11111111
+11111111
+11111111
+11111111
+11110000
+11110000
+11110000
+11110000
+
+ 136
+
+00000000
+00000000
+00000000
+00000000
+00001111
+00001111
+00001111
+00001111
+
+ 137
+
+11110000
+11110000
+11110000
+11110000
+00001111
+00001111
+00001111
+00001111
+
+ 138
+
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+
+ 139
+
+11111111
+11111111
+11111111
+11111111
+00001111
+00001111
+00001111
+00001111
+
+ 140
+
+00000000
+00000000
+00000000
+00000000
+11111111
+11111111
+11111111
+11111111
+
+ 141
+
+11110000
+11110000
+11110000
+11110000
+11111111
+11111111
+11111111
+11111111
+
+ 142
+
+00001111
+00001111
+00001111
+00001111
+11111111
+11111111
+11111111
+11111111
+
+ 143
+
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+
+ 144
+
+00000000
+00000000
+00000000
+00011000
+00011000
+00000000
+00000000
+00000000
+
+ 145
+
+00011000
+00011000
+00011000
+00011000
+00011000
+00000000
+00000000
+00000000
+
+ 146
+
+00000000
+00000000
+00000000
+00011111
+00011111
+00000000
+00000000
+00000000
+
+ 147
+
+00011000
+00011000
+00011000
+00011111
+00001111
+00000000
+00000000
+00000000
+
+ 148
+
+00000000
+00000000
+00000000
+00011000
+00011000
+00011000
+00011000
+00011000
+
+ 149
+
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+
+ 150
+
+00000000
+00000000
+00000000
+00001111
+00011111
+00011000
+00011000
+00011000
+
+ 151
+
+00011000
+00011000
+00011000
+00011111
+00011111
+00011000
+00011000
+00011000
+
+ 152
+
+00000000
+00000000
+00000000
+11111000
+11111000
+00000000
+00000000
+00000000
+
+ 153
+
+00011000
+00011000
+00011000
+11111000
+11110000
+00000000
+00000000
+00000000
+
+ 154
+
+00000000
+00000000
+00000000
+11111111
+11111111
+00000000
+00000000
+00000000
+
+ 155
+
+00011000
+00011000
+00011000
+11111111
+11111111
+00000000
+00000000
+00000000
+
+ 156
+
+00000000
+00000000
+00000000
+11110000
+11111000
+00011000
+00011000
+00011000
+
+ 157
+
+00011000
+00011000
+00011000
+11111000
+11111000
+00011000
+00011000
+00011000
+
+ 158
+
+00000000
+00000000
+00000000
+11111111
+11111111
+00011000
+00011000
+00011000
+
+ 159
+
+00011000
+00011000
+00011000
+11111111
+11111111
+00011000
+00011000
+00011000
+
+ 160
+
+00010000
+00111000
+01101100
+11000110
+00000000
+00000000
+00000000
+00000000
+
+ 161
+
+00001100
+00011000
+00110000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 162
+
+01100110
+01100110
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 163
+
+00111100
+01100110
+01100000
+11111000
+01100000
+01100110
+11111110
+00000000
+
+ 164
+
+00111000
+01000100
+10111010
+10100010
+10111010
+01000100
+00111000
+00000000
+
+ 165
+
+01111110
+11110100
+11110100
+01110100
+00110100
+00110100
+00110100
+00000000
+
+ 166
+
+00011110
+00110000
+00111000
+01101100
+00111000
+00011000
+11110000
+00000000
+
+ 167
+
+00011000
+00011000
+00001100
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 168
+
+01000000
+11000000
+01000100
+01001100
+01010100
+00011110
+00000100
+00000000
+
+ 169
+
+01000000
+11000000
+01001100
+01010010
+01000100
+00001000
+00011110
+00000000
+
+ 170
+
+11100000
+00010000
+01100010
+00010110
+11101010
+00001111
+00000010
+00000000
+
+ 171
+
+00000000
+00011000
+00011000
+01111110
+00011000
+00011000
+01111110
+00000000
+
+ 172
+
+00011000
+00011000
+00000000
+01111110
+00000000
+00011000
+00011000
+00000000
+
+ 173
+
+00000000
+00000000
+00000000
+01111110
+00000110
+00000110
+00000000
+00000000
+
+ 174
+
+00011000
+00000000
+00011000
+00110000
+01100110
+01100110
+00111100
+00000000
+
+ 175
+
+00011000
+00000000
+00011000
+00011000
+00011000
+00011000
+00011000
+00000000
+
+ 176
+
+00000000
+00000000
+01110011
+11011110
+11001100
+11011110
+01110011
+00000000
+
+ 177
+
+01111100
+11000110
+11000110
+11111100
+11000110
+11000110
+11111000
+11000000
+
+ 178
+
+00000000
+01100110
+01100110
+00111100
+01100110
+01100110
+00111100
+00000000
+
+ 179
+
+00111100
+01100000
+01100000
+00111100
+01100110
+01100110
+00111100
+00000000
+
+ 180
+
+00000000
+00000000
+00011110
+00110000
+01111100
+00110000
+00011110
+00000000
+
+ 181
+
+00111000
+01101100
+11000110
+11111110
+11000110
+01101100
+00111000
+00000000
+
+ 182
+
+00000000
+11000000
+01100000
+00110000
+00111000
+01101100
+11000110
+00000000
+
+ 183
+
+00000000
+00000000
+01100110
+01100110
+01100110
+01111100
+01100000
+01100000
+
+ 184
+
+00000000
+00000000
+00000000
+11111110
+01101100
+01101100
+01101100
+00000000
+
+ 185
+
+00000000
+00000000
+00000000
+01111110
+11011000
+11011000
+01110000
+00000000
+
+ 186
+
+00000011
+00000110
+00001100
+00111100
+01100110
+00111100
+01100000
+11000000
+
+ 187
+
+00000011
+00000110
+00001100
+01100110
+01100110
+00111100
+01100000
+11000000
+
+ 188
+
+00000000
+11100110
+00111100
+00011000
+00111000
+01101100
+11000111
+00000000
+
+ 189
+
+00000000
+00000000
+01100110
+11000011
+11011011
+11011011
+01111110
+00000000
+
+ 190
+
+11111110
+11000110
+01100000
+00110000
+01100000
+11000110
+11111110
+00000000
+
+ 191
+
+00000000
+01111100
+11000110
+11000110
+11000110
+01101100
+11101110
+00000000
+
+ 192
+
+00011000
+00110000
+01100000
+11000000
+10000000
+00000000
+00000000
+00000000
+
+ 193
+
+00011000
+00001100
+00000110
+00000011
+00000001
+00000000
+00000000
+00000000
+
+ 194
+
+00000000
+00000000
+00000000
+00000001
+00000011
+00000110
+00001100
+00011000
+
+ 195
+
+00000000
+00000000
+00000000
+10000000
+11000000
+01100000
+00110000
+00011000
+
+ 196
+
+00011000
+00111100
+01100110
+11000011
+10000001
+00000000
+00000000
+00000000
+
+ 197
+
+00011000
+00001100
+00000110
+00000011
+00000011
+00000110
+00001100
+00011000
+
+ 198
+
+00000000
+00000000
+00000000
+10000001
+11000011
+01100110
+00111100
+00011000
+
+ 199
+
+00011000
+00110000
+01100000
+11000000
+11000000
+01100000
+00110000
+00011000
+
+ 200
+
+00011000
+00110000
+01100000
+11000001
+10000011
+00000110
+00001100
+00011000
+
+ 201
+
+00011000
+00001100
+00000110
+10000011
+11000001
+01100000
+00110000
+00011000
+
+ 202
+
+00011000
+00111100
+01100110
+11000011
+11000011
+01100110
+00111100
+00011000
+
+ 203
+
+11000011
+11100111
+01111110
+00111100
+00111100
+01111110
+11100111
+11000011
+
+ 204
+
+00000011
+00000111
+00001110
+00011100
+00111000
+01110000
+11100000
+11000000
+
+ 205
+
+11000000
+11100000
+01110000
+00111000
+00011100
+00001110
+00000111
+00000011
+
+ 206
+
+11001100
+11001100
+00110011
+00110011
+11001100
+11001100
+00110011
+00110011
+
+ 207
+
+10101010
+01010101
+10101010
+01010101
+10101010
+01010101
+10101010
+01010101
+
+ 208
+
+11111111
+11111111
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 209
+
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+
+ 210
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11111111
+11111111
+
+ 211
+
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+
+ 212
+
+11111111
+11111110
+11111100
+11111000
+11110000
+11100000
+11000000
+10000000
+
+ 213
+
+11111111
+01111111
+00111111
+00011111
+00001111
+00000111
+00000011
+00000001
+
+ 214
+
+00000001
+00000011
+00000111
+00001111
+00011111
+00111111
+01111111
+11111111
+
+ 215
+
+10000000
+11000000
+11100000
+11110000
+11111000
+11111100
+11111110
+11111111
+
+ 216
+
+10101010
+01010101
+10101010
+01010101
+00000000
+00000000
+00000000
+00000000
+
+ 217
+
+00001010
+00000101
+00001010
+00000101
+00001010
+00000101
+00001010
+00000101
+
+ 218
+
+00000000
+00000000
+00000000
+00000000
+10101010
+01010101
+10101010
+01010101
+
+ 219
+
+10100000
+01010000
+10100000
+01010000
+10100000
+01010000
+10100000
+01010000
+
+ 220
+
+10101010
+01010100
+10101000
+01010000
+10100000
+01000000
+10000000
+00000000
+
+ 221
+
+10101010
+01010101
+00101010
+00010101
+00001010
+00000101
+00000010
+00000001
+
+ 222
+
+00000001
+00000010
+00000101
+00001010
+00010101
+00101010
+01010101
+10101010
+
+ 223
+
+00000000
+10000000
+01000000
+10100000
+01010000
+10101000
+01010100
+10101010
+
+ 224
+
+01111110
+11111111
+10011001
+11111111
+10111101
+11000011
+11111111
+01111110
+
+ 225
+
+01111110
+11111111
+10011001
+11111111
+11000011
+10111101
+11111111
+01111110
+
+ 226
+
+00111000
+00111000
+11111110
+11111110
+11111110
+00010000
+00111000
+00000000
+
+ 227
+
+00010000
+00111000
+01111100
+11111110
+01111100
+00111000
+00010000
+00000000
+
+ 228
+
+01101100
+11111110
+11111110
+11111110
+01111100
+00111000
+00010000
+00000000
+
+ 229
+
+00010000
+00111000
+01111100
+11111110
+11111110
+00010000
+00111000
+00000000
+
+ 230
+
+00000000
+00111100
+01100110
+11000011
+11000011
+01100110
+00111100
+00000000
+
+ 231
+
+00000000
+00111100
+01111110
+11111111
+11111111
+01111110
+00111100
+00000000
+
+ 232
+
+00000000
+01111110
+01100110
+01100110
+01100110
+01100110
+01111110
+00000000
+
+ 233
+
+00000000
+01111110
+01111110
+01111110
+01111110
+01111110
+01111110
+00000000
+
+ 234
+
+00001111
+00000111
+00001101
+01111000
+11001100
+11001100
+11001100
+01111000
+
+ 235
+
+00111100
+01100110
+01100110
+01100110
+00111100
+00011000
+01111110
+00011000
+
+ 236
+
+00001100
+00001100
+00001100
+00001100
+00001100
+00111100
+01111100
+00111000
+
+ 237
+
+00011000
+00011100
+00011110
+00011011
+00011000
+01111000
+11111000
+01110000
+
+ 238
+
+10011001
+01011010
+00100100
+11000011
+11000011
+00100100
+01011010
+10011001
+
+ 239
+
+00010000
+00111000
+00111000
+00111000
+00111000
+00111000
+01111100
+11010110
+
+ 240
+
+00011000
+00111100
+01111110
+11111111
+00011000
+00011000
+00011000
+00011000
+
+ 241
+
+00011000
+00011000
+00011000
+00011000
+11111111
+01111110
+00111100
+00011000
+
+ 242
+
+00010000
+00110000
+01110000
+11111111
+11111111
+01110000
+00110000
+00010000
+
+ 243
+
+00001000
+00001100
+00001110
+11111111
+11111111
+00001110
+00001100
+00001000
+
+ 244
+
+00000000
+00000000
+00011000
+00111100
+01111110
+11111111
+11111111
+00000000
+
+ 245
+
+00000000
+00000000
+11111111
+11111111
+01111110
+00111100
+00011000
+00000000
+
+ 246
+
+10000000
+11100000
+11111000
+11111110
+11111000
+11100000
+10000000
+00000000
+
+ 247
+
+00000010
+00001110
+00111110
+11111110
+00111110
+00001110
+00000010
+00000000
+
+ 248
+
+00111000
+00111000
+10010010
+01111100
+00010000
+00101000
+00101000
+00101000
+
+ 249
+
+00111000
+00111000
+00010000
+11111110
+00010000
+00101000
+01000100
+10000010
+
+ 250
+
+00111000
+00111000
+00010010
+01111100
+10010000
+00101000
+00100100
+00100010
+
+ 251
+
+00111000
+00111000
+10010000
+01111100
+00010010
+00101000
+01001000
+10001000
+
+ 252
+
+00000000
+00111100
+00011000
+00111100
+00111100
+00111100
+00011000
+00000000
+
+ 253
+
+00111100
+11111111
+11111111
+00011000
+00001100
+00011000
+00110000
+00011000
+
+ 254
+
+00011000
+00111100
+01111110
+00011000
+00011000
+01111110
+00111100
+00011000
+
+ 255
+
+00000000
+00100100
+01100110
+11111111
+01100110
+00100100
+00000000
+00000000
+
diff --git a/cursor.cpp b/cursor.cpp
new file mode 100644
index 0000000..1dde81a
--- /dev/null
+++ b/cursor.cpp
@@ -0,0 +1,1477 @@
+// cursor.cpp
+// Revision 24-apr-2009
+
+#include "cursor.h"
+
+#include "blassic.h"
+
+#include "key.h"
+#include "util.h"
+#include "error.h"
+#include "showerror.h"
+
+#include "trace.h"
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#include <map>
+#include <queue>
+#include <sstream>
+
+#include <string.h>
+
+#ifdef BLASSIC_USE_WINDOWS
+
+
+#include <windows.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if defined HAVE_IO_H || ! defined BLASSIC_CONFIG
+#include <io.h>
+#endif
+
+
+#else
+
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <cassert>
+#define ASSERT assert
+
+#include <termios.h>
+
+// We check for terminfo only if not in windows,
+// use windows console functions even in Cygwin.
+
+// Now curses can be disabled from configure.
+#ifndef BLASSIC_CONFIG_NO_CURSES
+
+#ifdef BLASSIC_CONFIG_USE_NCURSES
+
+#include <ncurses.h>
+
+#elif defined BLASSIC_CONFIG_USE_CURSES
+
+#include <curses.h>
+
+#else
+
+#error Bad configuration of curses options.
+
+#endif
+
+#ifdef HAVE_TERM_H
+// I suppose that if this is not availabe, then is not required.
+#include <term.h>
+#endif
+
+#define BLASSIC_USE_TERMINFO
+
+// curses can define erase as macro, invalidating string::erase.
+#ifdef erase
+#undef erase
+#endif
+// curses can define bool as macro.
+#ifdef bool
+#undef bool
+#endif
+
+#endif
+
+
+// Stuff needed by getwidth
+
+#include <sys/ioctl.h>
+#include <termios.h>
+
+// This is from ncurses.
+#ifdef TIOCGSIZE
+# define IOCTL_WINSIZE TIOCGSIZE
+# define STRUCT_WINSIZE struct ttysize
+# define WINSIZE_ROWS(n) (int)n.ts_lines
+# define WINSIZE_COLS(n) (int)n.ts_cols
+#else
+# ifdef TIOCGWINSZ
+# define IOCTL_WINSIZE TIOCGWINSZ
+# define STRUCT_WINSIZE struct winsize
+# define WINSIZE_ROWS(n) (int)n.ws_row
+# define WINSIZE_COLS(n) (int)n.ws_col
+# endif
+#endif
+
+#endif
+
+#include <iostream>
+#include <map>
+
+using util::touch;
+
+
+namespace {
+
+using namespace cursor;
+
+
+#ifndef BLASSIC_USE_WINDOWS
+
+#ifdef BLASSIC_USE_TERMINFO
+
+bool fInit= true;
+
+int background= 8;
+
+const char
+ * strKeypadXmit= NULL, * strKeypadLocal= NULL,
+ * strCls= NULL, * strCup= NULL,
+ * strCursorNormal= NULL, * strCursorInvisible= NULL,
+ * strForeground= NULL, * strBackground= NULL,
+ * strEnterBold= NULL, * strExitBold= NULL,
+ * strMoveForward= NULL, * strMoveBack= NULL,
+ * strMoveForwardN= NULL, * strMoveBackN= NULL,
+ * strMoveUp= NULL, * strMoveDown= NULL,
+ * strMoveUpN= NULL, * strMoveDownN= NULL,
+ * strSaveCursorPos= NULL, * strRestoreCursorPos= NULL,
+ * strBell= NULL;
+
+const char * newstr (const char * str)
+{
+ if (str == NULL)
+ return NULL;
+ size_t l= strlen (str);
+ char *n= new char [l + 1];
+ strcpy (n, str);
+ return n;
+}
+
+inline const char * calltigetstr (const char * id)
+{
+ #ifdef BLASSIC_CONFIG_USE_NCURSES
+ const char * str= tigetstr ( (char *) id);
+ #else
+ char buffer [128];
+ char * area= buffer;
+ const char * str= tgetstr (const_cast <char *> (id), & area);
+ #endif
+ if (str == (char *) -1)
+ return NULL;
+ return str;
+}
+
+inline const char * mytigetstr (const char * id)
+{
+ return newstr (calltigetstr (id) );
+}
+
+int putfunc (int ic)
+{
+ char c= ic;
+ write (STDOUT_FILENO, & c, 1);
+ return c;
+}
+
+inline void calltputs (const char * str)
+{
+ if (str != NULL)
+ tputs (str, 1, putfunc);
+}
+
+inline void calltparm (const char * str, int n)
+{
+ if (str != NULL)
+ {
+ #ifdef BLASSIC_CONFIG_USE_NCURSES
+ calltputs (tparm ( (char *) str, n) );
+ #else
+ calltputs (tgoto ( (char *) str, n, 0) );
+ #endif
+ }
+}
+
+void initkeytable ();
+
+struct str_terminfo {
+ const char * & str;
+ const char * tinfoname;
+ str_terminfo (const char * & str, const char * tinfoname) :
+ str (str), tinfoname (tinfoname)
+ { }
+};
+
+#ifdef BLASSIC_CONFIG_USE_NCURSES
+
+const str_terminfo strinfo []= {
+ str_terminfo (strKeypadXmit, "smkx"),
+ str_terminfo (strKeypadLocal, "rmkx"),
+
+ str_terminfo (strCls, "clear" ),
+ str_terminfo (strCup, "cup" ),
+
+ str_terminfo (strCursorNormal, "cnorm" ),
+ str_terminfo (strCursorInvisible, "civis" ),
+
+ str_terminfo (strForeground, "setaf" ),
+ str_terminfo (strBackground, "setab" ),
+
+ str_terminfo (strEnterBold, "bold" ),
+ str_terminfo (strExitBold, "sgr0" ),
+
+ str_terminfo (strMoveForward, "cuf1" ),
+ str_terminfo (strMoveBack, "cub1" ),
+ str_terminfo (strMoveForwardN, "cuf" ),
+ str_terminfo (strMoveBackN, "cub" ),
+ str_terminfo (strMoveUp, "cuu1" ),
+ str_terminfo (strMoveDown, "cud1" ),
+ str_terminfo (strMoveUpN, "cuu" ),
+ str_terminfo (strMoveDownN, "cud" ),
+
+ str_terminfo (strSaveCursorPos, "sc" ),
+ str_terminfo (strRestoreCursorPos, "rc" ),
+
+ str_terminfo (strBell, "bel"),
+};
+
+#else
+
+const str_terminfo strinfo []= {
+ str_terminfo (strKeypadXmit, "ks"),
+ str_terminfo (strKeypadLocal, "ke"),
+
+ str_terminfo (strCls, "cl" ),
+ str_terminfo (strCup, "cm" ),
+
+ str_terminfo (strCursorNormal, "ve" ),
+ str_terminfo (strCursorInvisible, "vi" ),
+
+ str_terminfo (strForeground, "AF" ),
+ str_terminfo (strBackground, "AB" ),
+
+ str_terminfo (strEnterBold, "md" ),
+ str_terminfo (strExitBold, "me" ),
+
+ str_terminfo (strMoveForward, "nd" ),
+ str_terminfo (strMoveBack, "le" ),
+ str_terminfo (strMoveForwardN, "RI" ),
+ str_terminfo (strMoveBackN, "LE" ),
+ str_terminfo (strMoveUp, "up" ),
+ str_terminfo (strMoveDown, "do" ),
+ str_terminfo (strMoveUpN, "UP" ),
+ str_terminfo (strMoveDownN, "DO" ),
+
+ str_terminfo (strSaveCursorPos, "sc" ),
+ str_terminfo (strRestoreCursorPos, "rc" ),
+
+ str_terminfo (strBell, "bl"),
+};
+
+#endif
+
+#ifndef BLASSIC_CONFIG_USE_NCURSES
+
+char tgetent_buffer [1024];
+
+#endif
+
+void init ()
+{
+ TRACEFUNC (tr, "init");
+
+ fInit= false;
+ #ifdef BLASSIC_CONFIG_USE_NCURSES
+ {
+ int errret;
+ setupterm (0, 1, & errret);
+ }
+ #else
+ {
+ char * strterm= getenv ("TERM");
+ if (strterm != NULL && strterm [0] != '\0')
+ tgetent (tgetent_buffer, strterm);
+ }
+ #endif
+
+ for (size_t i= 0; i < util::dim_array (strinfo); ++i)
+ strinfo [i].str= mytigetstr (strinfo [i].tinfoname);
+
+ initkeytable ();
+
+ if (isatty (STDOUT_FILENO) )
+ {
+ #if 0
+ const char * str_keypad_xmit= calltigetstr ("smkx");
+ calltputs (str_keypad_xmit);
+ #else
+ calltputs (strKeypadXmit);
+ #endif
+ }
+
+}
+
+inline void checkinit ()
+{
+ if (fInit)
+ init ();
+}
+
+#else
+
+inline void checkinit () { }
+
+#endif
+
+#endif
+
+} // namespace
+
+void cursor::initconsole ()
+{
+ TRACEFUNC (tr, "initconsole");
+
+ cursorinvisible ();
+}
+
+void cursor::quitconsole ()
+{
+ TRACEFUNC (tr, "quitconsole");
+
+ cursorvisible ();
+
+ #ifdef BLASSIC_USE_TERMINFO
+
+ if (! fInit)
+ {
+ if (isatty (STDOUT_FILENO) )
+ {
+ #if 0
+ const char * str_keypad_local= calltigetstr ("rmkx");
+ calltputs (str_keypad_local);
+ #else
+ calltputs (strKeypadLocal);
+ #endif
+ }
+
+ }
+
+ #endif
+}
+
+size_t cursor::getwidth ()
+{
+ const size_t default_value= 80;
+ size_t width;
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ width= info.dwSize.X;
+ else
+ width= default_value;
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ STRUCT_WINSIZE win;
+ if (ioctl (0, IOCTL_WINSIZE, & win) == 0)
+ width= WINSIZE_COLS (win);
+ else
+ {
+ const char * aux= getenv ("COLUMNS");
+ if (aux)
+ width= atoi (aux);
+ else
+ width= default_value;
+ }
+
+ #else
+
+ width= default_value;
+
+ #endif
+
+ return width;
+}
+
+void cursor::cursorvisible ()
+{
+ TRACEFUNC (tr, "cursorvisible");
+
+ // checkinit not needed, is done by showcursor
+ showcursor ();
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ struct termios ter;
+ tcgetattr (STDIN_FILENO, & ter);
+ //ter.c_lflag|= (ECHO | ICANON | PENDIN);
+ ter.c_lflag|= (ECHO | ICANON);
+ tcsetattr (STDIN_FILENO, TCSANOW, & ter);
+
+ #endif
+}
+
+void cursor::cursorinvisible ()
+{
+ TRACEFUNC (tr, "cursorinvisible");
+
+ // checkinit not needed, is done by hidecursor
+ hidecursor ();
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ struct termios ter;
+ tcgetattr (STDIN_FILENO, & ter);
+ ter.c_lflag&= ~ (ECHO | ICANON);
+ ter.c_cc [VMIN]= 1;
+ tcsetattr (STDIN_FILENO, TCSANOW, & ter);
+
+ #endif
+}
+
+void cursor::showcursor ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_CURSOR_INFO info;
+ GetConsoleCursorInfo (h, & info);
+ info.bVisible= TRUE;
+ SetConsoleCursorInfo (h, & info);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ if (isatty (STDOUT_FILENO) )
+ calltputs (strCursorNormal );
+
+ #endif
+}
+
+void cursor::hidecursor ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_CURSOR_INFO info;
+ GetConsoleCursorInfo (h, & info);
+ info.bVisible= FALSE;
+ SetConsoleCursorInfo (h, & info);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ if (isatty (STDOUT_FILENO) )
+ calltputs (strCursorInvisible);
+
+ #endif
+}
+
+#ifdef BLASSIC_USE_WINDOWS
+
+const WORD init_attributes=
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+WORD attributes= init_attributes;
+
+#endif
+
+void cursor::cls ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ DWORD l= info.dwSize.X * info.dwSize.Y;
+ COORD coord= {0, 0};
+ DWORD notused;
+ FillConsoleOutputAttribute (h,
+ attributes,
+ l, coord, & notused);
+ FillConsoleOutputCharacter (h,
+ ' ', l, coord, & notused);
+ SetConsoleCursorPosition (h, coord);
+ }
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ calltputs (strCls);
+
+ #endif
+}
+
+void cursor::gotoxy (int x, int y)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ COORD coord= { SHORT (x), SHORT (y) };
+ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coord);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ if (strCup)
+ calltputs (tgoto (const_cast <char *> (strCup), x, y) );
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+int cursor::getcursorx ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) == 0)
+ return 0;
+ return info.dwCursorPosition.X;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+void cursor::movecharforward ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movecharforward (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveForward);
+
+ #endif
+}
+
+void cursor::movecharback ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movecharback (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveBack);
+
+ #endif
+}
+
+void cursor::movecharup ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movecharup (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveUp);
+
+ #endif
+}
+
+void cursor::movechardown ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movechardown (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveDown);
+
+ #endif
+}
+
+namespace {
+
+#ifdef BLASSIC_USE_TERMINFO
+
+inline void auxmovechar (const char * strN, const char * str, size_t n)
+{
+ if (n != 0)
+ {
+ if (strN)
+ //calltputs (tparm ( (char *) strN, n) );
+ calltparm (strN, n);
+ else
+ if (str)
+ for (size_t i= 0; i < n; ++i)
+ calltputs (str);
+ }
+}
+
+#endif
+
+} // namespace
+
+void cursor::movecharforward (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.X+= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveForwardN, strMoveForward, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::movecharback (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.X-= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveBackN, strMoveBack, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::movecharup (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.Y-= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveUpN, strMoveUp, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::movechardown (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.Y+= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveDownN, strMoveDown, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::savecursorpos ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strSaveCursorPos);
+
+ #endif
+}
+
+void cursor::restorecursorpos ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strRestoreCursorPos);
+
+ #endif
+}
+
+
+#ifndef BLASSIC_USE_WINDOWS
+
+namespace {
+
+static const int newcolor []=
+ { 0, 4, 2, 6, 1, 5, 3, 7};
+
+inline int mapcolor (int n)
+{
+ // Intensity bit unchanged
+ return newcolor [n & 7] | (n & 8);
+}
+
+} // namespace
+
+#endif
+
+void cursor::textcolor (int color)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ attributes= (attributes & WORD (0xF0) ) | WORD (color & 0x0F);
+ SetConsoleTextAttribute (h, attributes);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ color= mapcolor (color & 0xF);
+ bool intensity= color > 7;
+ if (intensity)
+ {
+ color&= 7;
+ calltputs (strEnterBold);
+ }
+ else
+ {
+ if (strExitBold)
+ {
+ calltputs (strExitBold);
+ // sgr0 reset the background, then we need to set it.
+ textbackground (background);
+ }
+ }
+ //if (strForeground)
+ // calltputs (tparm ( (char *) strForeground, color) );
+ calltparm (strForeground, color);
+
+ #else
+
+ touch (color);
+
+ #endif
+}
+
+void cursor::textbackground (int color)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ attributes= (attributes & WORD (0xF) ) | WORD ( (color & 0xF) << 4);
+ SetConsoleTextAttribute (h, attributes);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ background= color;
+ color= mapcolor (color & 0xF);
+ //if (strBackground)
+ // calltputs (tparm ( (char *) strBackground, color) );
+ calltparm (strBackground, color);
+
+ #else
+
+ touch (color);
+
+ #endif
+}
+
+namespace {
+
+enum ReadType { ReadWait, ReadNoWait };
+
+#ifdef BLASSIC_USE_WINDOWS
+
+std::string string_from_key_event (const KEY_EVENT_RECORD & kr)
+{
+
+ char c= kr.uChar.AsciiChar;
+ if (c != '\0')
+ return std::string (1, c);
+ WORD k= kr.wVirtualKeyCode;
+ std::string str= string_from_key (k);
+ if (! str.empty () )
+ return str;
+
+ if (k != VK_SHIFT &&
+ k != VK_CONTROL &&
+ k != VK_MENU &&
+ k != VK_CAPITAL &&
+ k != VK_NUMLOCK &&
+ k != VK_SCROLL)
+ {
+ std::string str (1, '\0');
+ str+= char (kr.wVirtualScanCode);
+ return str;
+ }
+ return std::string ();
+}
+
+std::string string_from_input (const INPUT_RECORD & input)
+{
+ std::string str;
+ if (input.EventType == KEY_EVENT && input.Event.KeyEvent.bKeyDown)
+ {
+ str= string_from_key_event (input.Event.KeyEvent);
+ }
+ return str;
+}
+
+std::string readkey (ReadType type)
+{
+ std::string str;
+
+ HANDLE h= GetStdHandle (STD_INPUT_HANDLE);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ showlasterror ();
+ throw ErrFileRead;
+ }
+
+ DWORD mode, orgmode;
+ GetConsoleMode (h, & mode);
+ orgmode= mode;
+ //mode&= ~ (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
+ mode= 0;
+ SetConsoleMode (h, mode);
+ DWORD n= 0;
+ INPUT_RECORD input;
+ if (type == ReadNoWait)
+ {
+ if (PeekConsoleInput (h, & input, 1, & n) == 0)
+ {
+ showlasterror ();
+ throw ErrFileRead;
+ }
+ }
+ else
+ n= 1;
+ if (n)
+ {
+ do
+ {
+ if (ReadConsoleInput (h, & input, 1, & n) == 0)
+ {
+ showlasterror ();
+ throw ErrFileRead;
+ }
+ str= string_from_input (input);
+ } while (type == ReadWait && str.empty () );
+ }
+ SetConsoleMode (h, orgmode);
+
+ return str;
+}
+
+#else
+
+#if defined BLASSIC_USE_TERMINFO
+
+class MapSpecial {
+public:
+ enum Result { NoMapped, Found, MoreNeeded };
+ void addkey (const std::string & str, std::string::size_type pos,
+ const std::string & keyname)
+ {
+ //TRACEFUNC (tr, "MapSpecial::addkey");
+
+ ASSERT (pos < str.size () );
+ char c= str [pos];
+ if (pos == str.size () - 1)
+ kname [c]= keyname;
+ else
+ {
+ //if (kmap.find (c) == kmap.end () )
+ // kmap [c]= MapSpecial ();
+ kmap [c].addkey (str, pos + 1, keyname);
+ }
+ }
+ Result findkey (const std::string & str, std::string::size_type pos,
+ std::string & keyname, std::string::size_type & consumed)
+ {
+ if (pos >= str.size () )
+ return MoreNeeded;
+ char c= str [pos];
+ //cout << "Buscando: " << c << endl;
+ {
+ kname_t::iterator it= kname.find (c);
+ if (it != kname.end () )
+ {
+ keyname= it->second;
+ consumed= pos;
+ return Found;
+ }
+ }
+ std::map <char, MapSpecial>::iterator it= kmap.find (c);
+ if (it != kmap.end () )
+ return it->second.findkey
+ (str, pos + 1, keyname, consumed);
+ else
+ return NoMapped;
+ }
+private:
+ typedef std::map <char, std::string> kname_t;
+ kname_t kname;
+ std::map <char, MapSpecial> kmap;
+};
+
+struct KeyDescription {
+ const char * tiId;
+ //const char * blName;
+ const std::string & blName;
+ KeyDescription (const char * tiId, const std::string & blName) :
+ tiId (tiId),
+ blName (blName)
+ { }
+};
+
+const std::string
+ strMULT ("*"),
+ strMINUS ("-"),
+ strPLUS ("+"),
+ strDIV ("/");
+
+#ifdef BLASSIC_CONFIG_USE_NCURSES
+
+const KeyDescription keyname [] = {
+ KeyDescription ("kpp", strPAGEUP), // previous-page key
+ KeyDescription ("knp", strPAGEDOWN), // next-page key
+ KeyDescription ("kend", strEND), // end key
+ KeyDescription ("kslt", strEND), // select key
+ KeyDescription ("kc1", strEND), // lower left of keypad
+ KeyDescription ("khome", strHOME), // home key
+ KeyDescription ("kfnd", strHOME), // find key
+ KeyDescription ("ka1", strHOME), // upper left of keypad
+ KeyDescription ("kcub1", strLEFT), // left-arrow key
+ KeyDescription ("kcuu1", strUP), // up-arrow key
+ KeyDescription ("kcuf1", strRIGHT), // right-arrow key
+ KeyDescription ("kcud1", strDOWN), // down-arrow key
+ KeyDescription ("kich1", strINSERT), // insert-character key
+ KeyDescription ("kdch1", strDELETE), // delete-character key
+ KeyDescription ("kent", strENTER), // enter/send key
+ KeyDescription ("kf1", strF1), // F1 function key
+ KeyDescription ("kf2", strF2), // F2 function key
+ KeyDescription ("kf3", strF3), // F3 function key
+ KeyDescription ("kf4", strF4), // F4 function key
+ KeyDescription ("kf5", strF5), // F5 function key
+ KeyDescription ("kf6", strF6), // F6 function key
+ KeyDescription ("kf7", strF7), // F7 function key
+ KeyDescription ("kf8", strF8), // F8 function key
+ KeyDescription ("kf9", strF9), // F9 function key
+ KeyDescription ("kf10", strF10), // F10 function key
+ KeyDescription ("kf11", strF11), // F11 function key
+ KeyDescription ("kf12", strF12), // F12 function key
+ KeyDescription ("kf54", strDIV), // F54 function key, / in xterm
+ KeyDescription ("kf55", strMULT), // F55 function key, * in xterm
+ KeyDescription ("kf56", strMINUS), // F56 function key, - in xterm
+ KeyDescription ("kf57", strPLUS), // f57 function key, + in xterm
+};
+
+#else
+
+const KeyDescription keyname [] = {
+ KeyDescription ("kP", strPAGEUP), // previous-page key
+ KeyDescription ("kN", strPAGEDOWN), // next-page key
+ KeyDescription ("@7", strEND), // end key
+ KeyDescription ("*6", strEND), // select key
+ KeyDescription ("K4", strEND), // lower left of keypad
+ KeyDescription ("kh", strHOME), // home key
+ KeyDescription ("@0", strHOME), // find key
+ KeyDescription ("K1", strHOME), // upper left of keypad
+ KeyDescription ("kl", strLEFT), // left-arrow key
+ KeyDescription ("ku", strUP), // up-arrow key
+ KeyDescription ("kr", strRIGHT), // right-arrow key
+ KeyDescription ("kd", strDOWN), // down-arrow key
+ KeyDescription ("kI", strINSERT), // insert-character key
+ KeyDescription ("kD", strDELETE), // delete-character key
+ KeyDescription ("@8", strENTER), // enter/send key
+ KeyDescription ("k1", strF1), // F1 function key
+ KeyDescription ("k2", strF2), // F2 function key
+ KeyDescription ("k3", strF3), // F3 function key
+ KeyDescription ("k4", strF4), // F4 function key
+ KeyDescription ("k5", strF5), // F5 function key
+ KeyDescription ("k6", strF6), // F6 function key
+ KeyDescription ("k7", strF7), // F7 function key
+ KeyDescription ("k8", strF8), // F8 function key
+ KeyDescription ("k9", strF9), // F9 function key
+ KeyDescription ("k;", strF10), // F10 function key
+ KeyDescription ("F1", strF11), // F11 function key
+ KeyDescription ("F2", strF12), // F12 function key
+ KeyDescription ("Fi", strDIV), // F54 function key, / in xterm
+ KeyDescription ("Fj", strMULT), // F55 function key, * in xterm
+ KeyDescription ("Fk", strMINUS), // F56 function key, - in xterm
+ KeyDescription ("Fl", strPLUS), // f57 function key, + in xterm
+};
+
+#endif
+
+#ifndef NDEBUG
+
+bool checktable ()
+{
+ const size_t nkeys= util::dim_array (keyname);
+
+ for (size_t i= 0; i < nkeys - 1; ++i)
+ for (size_t j= i + 1; j < nkeys; ++j)
+ if (strcmp (keyname [i].tiId, keyname [j].tiId) == 0)
+ {
+ std::cerr << "Code repeated in keyname: " <<
+ keyname [i].tiId << std::endl;
+ throw 1;
+ }
+ return true;
+}
+
+bool tablechecked= checktable ();
+
+#endif
+
+MapSpecial ms;
+
+void initkeytable ()
+{
+ TRACEFUNC (tr, "initkeytable");
+
+ const size_t nkeys= util::dim_array (keyname);
+
+ for (size_t i= 0; i < nkeys; ++i)
+ {
+ const KeyDescription & keydesc= keyname [i];
+ const char * const strkey= keydesc.tiId;
+ const char * str= calltigetstr (strkey);
+ if (str != NULL)
+ {
+ #if 0
+ cerr << keydesc.blName << "=";
+ for (size_t i= 0, l= strlen (str); i < l; ++i)
+ {
+ char c= str [i];
+ if (c >= 32) cerr << c;
+ else cerr << "\\(" << hex << int (c) << ')';
+ }
+ cerr << endl;
+ #endif
+ TRMESSAGE (tr, std::string ("Adding ") + keydesc.blName);
+ ms.addkey (str, 0, keydesc.blName);
+ }
+ }
+
+}
+
+#endif // BLASSIC_USE_TERMINFO
+
+class PollInput {
+public:
+ PollInput ()
+ {
+ pfd.fd= STDIN_FILENO;
+ pfd.events= POLLIN;
+ }
+ int poll ()
+ {
+ int r= ::poll (& pfd, 1, 100);
+ if (r == 1 && pfd.revents != POLLIN)
+ throw ErrFileRead;
+ return r;
+ }
+private:
+ struct pollfd pfd;
+};
+
+void wait_event ()
+{
+ PollInput pi;
+ int r;
+ do {
+ blassic::idle ();
+ } while ( (r= pi.poll () ) == 0);
+ if (r < 0)
+ {
+ std::cerr << "Error in poll: " << strerror (errno) <<
+ std::endl;
+ }
+}
+
+void do_poll ()
+{
+ PollInput ().poll ();
+}
+
+std::string readkey (ReadType type)
+{
+ checkinit ();
+
+ static std::string charpending;
+ std::string str;
+ bool reset_blocking_mode= false;
+ int l;
+ //char c;
+ const int lbuf= 32;
+ char buffer [lbuf + 1];
+
+ if (! charpending.empty () )
+ goto check_it;
+
+ #if 0
+
+ if (type == ReadWait)
+ {
+ //fcntl (STDIN_FILENO, F_SETFL, 0);
+ wait_event ();
+ }
+ else
+ {
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ reset_blocking_mode= true;
+ }
+
+ //read_another:
+
+ l= read (STDIN_FILENO, & c, 1);
+ if (l == 1)
+ str+= c;
+
+ #else
+
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ reset_blocking_mode= true;
+ //l= read (STDIN_FILENO, & c, 1);
+ l= read (STDIN_FILENO, buffer, lbuf);
+ //if (l != 1 && type == ReadWait)
+ if (l < 1 && type == ReadWait)
+ {
+ do {
+ //wait_event ();
+ //l= read (STDIN_FILENO, & c, 1);
+ do_poll ();
+ l= read (STDIN_FILENO, buffer, lbuf);
+ //} while (l != 1);
+ } while (l < 1);
+ }
+ //if (l == 1)
+ // str+= c;
+ if (l >= 1)
+ {
+ buffer [l]= '\0';
+ str+= buffer;
+ }
+
+ #endif
+
+ #ifdef BLASSIC_USE_TERMINFO
+ read_another:
+ #endif
+
+ //std::cerr << "Adding: >" << str << '<' << std::endl;
+ charpending+= str;
+ str.erase ();
+
+ check_it:
+
+ std::string keyname;
+ //std::string::size_type pos;
+ if (! charpending.empty () )
+ {
+ #ifdef BLASSIC_USE_TERMINFO
+ std::string::size_type pos;
+ MapSpecial::Result r=
+ ms.findkey (charpending, 0, keyname, pos);
+ switch (r)
+ {
+ case MapSpecial::NoMapped:
+ str= charpending [0];
+ charpending.erase (0, 1);
+ break;
+ case MapSpecial::Found:
+ str= keyname;
+ charpending.erase (0, pos + 1);
+ break;
+ case MapSpecial::MoreNeeded:
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ reset_blocking_mode= true;
+ do_poll ();
+ //l= read (STDIN_FILENO, & c, 1);
+ //if (l == 1)
+ //{
+ // str= c;
+ // goto read_another;
+ //}
+ l= read (STDIN_FILENO, buffer, lbuf);
+ if (l >= 1)
+ {
+ buffer [l]= '\0';
+ str= buffer;
+ goto read_another;
+ }
+ str= charpending [0];
+ charpending.erase (0, 1);
+ break;
+ }
+ #else
+ str= charpending [0];
+ charpending.erase (0, 1);
+ #endif
+ }
+
+ //if (type == ReadWait)
+ // cursorinvisible ();
+
+ if (reset_blocking_mode)
+ fcntl (STDIN_FILENO, F_SETFL, 0);
+
+ return str;
+}
+
+#endif // ! BLASSIC_USE_WINDOWS
+
+// A provisional solution to pollin
+
+std::queue <std::string> keypending;
+
+} // namespace
+
+std::string cursor::inkey ()
+{
+ if (! keypending.empty () )
+ {
+ std::string r= keypending.front ();
+ keypending.pop ();
+ return r;
+ }
+ else
+ return readkey (ReadNoWait);
+}
+
+std::string cursor::getkey ()
+{
+ if (! keypending.empty () )
+ {
+ std::string r= keypending.front ();
+ keypending.pop ();
+ return r;
+ }
+ return readkey (ReadWait);
+}
+
+bool cursor::pollin ()
+{
+ if (! keypending.empty () )
+ return true;
+ else
+ {
+ std::string key= readkey (ReadNoWait);
+ if (key.empty () )
+ return false;
+ else
+ {
+ keypending.push (key);
+ return true;
+ }
+ }
+}
+
+void cursor::clean_input ()
+{
+ TRACEFUNC (tr, "clean_input");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ Sleep (100);
+ HANDLE h= GetStdHandle (STD_INPUT_HANDLE);
+ INPUT_RECORD input;
+ DWORD n= 0;
+ PeekConsoleInput (h, & input, 1, & n);
+ if (n && input.EventType == KEY_EVENT &&
+ ! input.Event.KeyEvent.bKeyDown)
+ ReadConsoleInput (h, & input, 1, & n);
+
+ #else
+
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ int l;
+ const int lbuf= 32;
+ char buffer [lbuf + 1];
+ do
+ {
+ l= read (STDIN_FILENO, buffer, lbuf);
+ } while (l > 0);
+ fcntl (STDIN_FILENO, F_SETFL, 0);
+
+ #endif
+}
+
+void cursor::ring ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ MessageBeep (MB_ICONEXCLAMATION);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strBell);
+
+ #else
+
+ // Last resource
+ char c= '\a';
+ write (STDOUT_FILENO, & c, 1);
+
+ #endif
+}
+
+//************************************************
+// set_title
+//************************************************
+
+#ifdef BLASSIC_USE_TERMINFO
+
+// Escape sequences from the "How to change the title of an xterm",
+// by Ric Lister, http://www.tldp.org/HOWTO/mini/Xterm-Title.html
+
+namespace
+{
+
+void write_it (std::ostringstream & oss)
+{
+ const std::string & str (oss.str () );
+ write (STDOUT_FILENO, str.c_str (), str.size () );
+}
+
+void set_title_xterm (const std::string & title)
+{
+ std::ostringstream oss;
+ oss << "\x1B]0;" << title << "\x07";
+ write_it (oss);
+}
+
+void set_title_iris_ansi (const std::string & title)
+{
+ std::ostringstream oss;
+ oss << "\x1BP1.y" << title << "\x1B\\"; // Set window title
+ oss << "\x1BP3.y" << title << "\x1B\\"; // Set icon title
+ write_it (oss);
+}
+
+void set_title_sun_cmd (const std::string & title)
+{
+ std::ostringstream oss;
+ oss << "\x1B]l;" << title << "\x1B\\"; // Set window title
+ oss << "\x1B]L;" << title << "\x1B\\"; // Set icon title
+ write_it (oss);
+}
+
+void set_title_hpterm (const std::string & title)
+{
+ std::ostringstream oss;
+ const std::string::size_type l= title.size ();
+ oss << "\x1B&f0k" << l << 'D' << title; // Set window title
+ oss << "\x1B&f-1k" << l << 'D' << title; // Set icon title
+ write_it (oss);
+}
+
+typedef void (* set_title_t) (const std::string &);
+
+struct Cstring_less {
+ bool operator () (const char * p, const char * q)
+ { return strcmp (p, q) < 0; }
+};
+
+typedef std::map <const char *, set_title_t, Cstring_less> maptitle_t;
+maptitle_t maptitle;
+
+bool initmaptitle ()
+{
+ maptitle ["xterm"]= set_title_xterm;
+ maptitle ["aixterm"]= set_title_xterm;
+ maptitle ["dtterm"]= set_title_xterm;
+ maptitle ["iris-ansi"]= set_title_iris_ansi;
+ maptitle ["sun-cmd"]= set_title_sun_cmd;
+ maptitle ["hpterm"]= set_title_hpterm;
+ return true;
+}
+
+bool maptitle_inited= initmaptitle ();
+
+void set_title_terminfo (const std::string & title)
+{
+ TRACEFUNC (tr, "set_title_terminfo");
+
+ if (! isatty (STDOUT_FILENO) )
+ return;
+
+ if (const char * term= getenv ("TERM") )
+ {
+ maptitle_t::iterator it= maptitle.find (term);
+ if (it != maptitle.end () )
+ (* it->second) (title);
+ else
+ {
+ TRMESSAGE (tr, "TERM not found");
+ }
+ }
+}
+
+} // namespace
+
+#endif
+
+void cursor::set_title (const std::string & title)
+{
+ TRACEFUNC (tr, "set_title");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ SetConsoleTitle (title.c_str () );
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ set_title_terminfo (title);
+
+ #else
+
+ touch (title);
+
+ #endif
+}
+
+// Fin de cursor.cpp
diff --git a/cursor.h b/cursor.h
new file mode 100644
index 0000000..d0cd108
--- /dev/null
+++ b/cursor.h
@@ -0,0 +1,56 @@
+#ifndef INCLUDE_BLASSIC_CURSOR_H
+#define INCLUDE_BLASSIC_CURSOR_H
+
+// cursor.h
+// Revision 7-feb-2005
+
+
+#include <string>
+
+
+namespace cursor {
+
+void initconsole ();
+void quitconsole ();
+
+size_t getwidth ();
+
+void cursorvisible ();
+void cursorinvisible ();
+void showcursor ();
+void hidecursor ();
+
+void cls ();
+
+//void locate (int row, int col);
+void gotoxy (int x, int y);
+int getcursorx ();
+void movecharforward ();
+void movecharback ();
+void movecharforward (size_t n);
+void movecharback (size_t n);
+void movecharup ();
+void movechardown ();
+void movecharup (size_t n);
+void movechardown (size_t n);
+void savecursorpos ();
+void restorecursorpos ();
+
+void textcolor (int color);
+void textbackground (int color);
+
+std::string inkey ();
+std::string getkey ();
+bool pollin ();
+
+void clean_input ();
+
+void ring ();
+
+void set_title (const std::string & title);
+
+} // namespace cursor
+
+#endif
+
+// Fin de cursor.h
diff --git a/default.def b/default.def
new file mode 100644
index 0000000..ec487e1
--- /dev/null
+++ b/default.def
@@ -0,0 +1,2827 @@
+ 0
+
+01111110
+11000011
+10011001
+11110011
+11100111
+11111111
+11100111
+01111110
+
+ 1
+
+00000000
+01110110
+11011100
+00000000
+01110110
+11011100
+00000000
+00000000
+
+ 2
+
+01110110
+11011000
+11011000
+11011100
+11011000
+11011000
+01110110
+00000000
+
+ 3
+
+00000000
+00000000
+01101110
+11011000
+11011110
+11011000
+01101110
+00000000
+
+ 4
+
+00010000
+00111000
+01111100
+11111110
+01111100
+00111000
+00010000
+00000000
+
+ 5
+
+10100000
+10100000
+11100000
+10101110
+10100100
+00000100
+00000100
+00000100
+
+ 6
+
+11100000
+10000000
+11000000
+10001110
+10001000
+00001100
+00001000
+00001000
+
+ 7
+
+01100000
+10000000
+10000000
+10001100
+01101010
+00001100
+00001010
+00001010
+
+ 8
+
+10000000
+10000000
+10000000
+10001110
+11101000
+00001100
+00001000
+00001000
+
+ 9
+
+00100010
+10001000
+00100010
+10001000
+00100010
+10001000
+00100010
+10001000
+
+ 10
+
+01010101
+10101010
+01010101
+10101010
+01010101
+10101010
+01010101
+10101010
+
+ 11
+
+11101110
+10111011
+11101110
+10111011
+11101110
+10111011
+11101110
+10111011
+
+ 12
+
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+
+ 13
+
+00000000
+00000000
+00000000
+00000000
+11111111
+11111111
+11111111
+11111111
+
+ 14
+
+11111111
+11111111
+11111111
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 15
+
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+
+ 16
+
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+
+ 17
+
+10010000
+11010000
+11110000
+10110100
+10010100
+00000100
+00000100
+00000111
+
+ 18
+
+10100000
+10100000
+10100000
+10101110
+01000100
+00000100
+00000100
+00000100
+
+ 19
+
+00011000
+00110000
+01100000
+00110000
+00011000
+00000000
+11111100
+00000000
+
+ 20
+
+01100000
+00110000
+00011000
+00110000
+01100000
+00000000
+11111100
+00000000
+
+ 21
+
+00000000
+00001100
+11111110
+00011000
+00110000
+11111110
+01100000
+00000000
+
+ 22
+
+00000010
+00001110
+00111110
+11111110
+00111110
+00001110
+00000010
+00000000
+
+ 23
+
+10000000
+11100000
+11111000
+11111110
+11111000
+11100000
+10000000
+00000000
+
+ 24
+
+00011000
+00111100
+01111110
+00011000
+00011000
+00011000
+00011000
+00000000
+
+ 25
+
+00011000
+00011000
+00011000
+00011000
+01111110
+00111100
+00011000
+00000000
+
+ 26
+
+00000000
+00011000
+00001100
+11111110
+00001100
+00011000
+00000000
+00000000
+
+ 27
+
+00000000
+00110000
+01100000
+11111110
+01100000
+00110000
+00000000
+00000000
+
+ 28
+
+00011000
+00111100
+01111110
+00011000
+00011000
+01111110
+00111100
+00011000
+
+ 29
+
+00000000
+00100100
+01100110
+11111111
+01100110
+00100100
+00000000
+00000000
+
+ 30
+
+00000110
+00000110
+00110110
+01100110
+11111110
+01100000
+00110000
+00000000
+
+ 31
+
+00000000
+11000000
+01111100
+01101110
+01101100
+01101100
+01101100
+00000000
+
+ 32
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 33
+
+00110000
+01111000
+01111000
+00110000
+00110000
+00000000
+00110000
+00000000
+
+ 34
+
+01101100
+01101100
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 35
+
+01101100
+01101100
+11111110
+01101100
+11111110
+01101100
+01101100
+00000000
+
+ 36
+
+00110000
+01111100
+11000000
+01111000
+00001100
+11111000
+00110000
+00000000
+
+ 37
+
+00000000
+11000110
+11001100
+00011000
+00110000
+01100110
+11000110
+00000000
+
+ 38
+
+00111000
+01101100
+00111000
+01110110
+11011100
+11001100
+01110110
+00000000
+
+ 39
+
+00110000
+00110000
+01100000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 40
+
+00011000
+00110000
+01100000
+01100000
+01100000
+00110000
+00011000
+00000000
+
+ 41
+
+01100000
+00110000
+00011000
+00011000
+00011000
+00110000
+01100000
+00000000
+
+ 42
+
+00000000
+01100110
+00111100
+11111111
+00111100
+01100110
+00000000
+00000000
+
+ 43
+
+00000000
+00110000
+00110000
+11111100
+00110000
+00110000
+00000000
+00000000
+
+ 44
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00110000
+00110000
+01100000
+
+ 45
+
+00000000
+00000000
+00000000
+11111100
+00000000
+00000000
+00000000
+00000000
+
+ 46
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00110000
+00110000
+00000000
+
+ 47
+
+00000000
+00000110
+00001100
+00011000
+00110000
+01100000
+11000000
+00000000
+
+ 48
+
+01111100
+11000110
+11000110
+11010110
+11000110
+11000110
+01111100
+00000000
+
+ 49
+
+00110000
+01110000
+00110000
+00110000
+00110000
+00110000
+11111100
+00000000
+
+ 50
+
+01111000
+11001100
+00001100
+00111000
+01100000
+11001100
+11111100
+00000000
+
+ 51
+
+01111000
+11001100
+00001100
+00111000
+00001100
+11001100
+01111000
+00000000
+
+ 52
+
+00011100
+00111100
+01101100
+11001100
+11111110
+00001100
+00011110
+00000000
+
+ 53
+
+11111100
+11000000
+11111000
+00001100
+00001100
+11001100
+01111000
+00000000
+
+ 54
+
+00111000
+01100000
+11000000
+11111000
+11001100
+11001100
+01111000
+00000000
+
+ 55
+
+11111100
+11001100
+00001100
+00011000
+00110000
+00110000
+00110000
+00000000
+
+ 56
+
+01111000
+11001100
+11001100
+01111000
+11001100
+11001100
+01111000
+00000000
+
+ 57
+
+01111000
+11001100
+11001100
+01111100
+00001100
+00011000
+01110000
+00000000
+
+ 58
+
+00000000
+00110000
+00110000
+00000000
+00000000
+00110000
+00110000
+00000000
+
+ 59
+
+00000000
+00110000
+00110000
+00000000
+00000000
+00110000
+00110000
+01100000
+
+ 60
+
+00011000
+00110000
+01100000
+11000000
+01100000
+00110000
+00011000
+00000000
+
+ 61
+
+00000000
+00000000
+11111100
+00000000
+00000000
+11111100
+00000000
+00000000
+
+ 62
+
+01100000
+00110000
+00011000
+00001100
+00011000
+00110000
+01100000
+00000000
+
+ 63
+
+01111000
+11001100
+00001100
+00011000
+00110000
+00000000
+00110000
+00000000
+
+ 64
+
+01111100
+11000110
+11011110
+11011110
+11011110
+11000000
+01111000
+00000000
+
+ 65
+
+00110000
+01111000
+11001100
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 66
+
+11111100
+01100110
+01100110
+01111100
+01100110
+01100110
+11111100
+00000000
+
+ 67
+
+00111100
+01100110
+11000000
+11000000
+11000000
+01100110
+00111100
+00000000
+
+ 68
+
+11111000
+01101100
+01100110
+01100110
+01100110
+01101100
+11111000
+00000000
+
+ 69
+
+11111110
+01100010
+01101000
+01111000
+01101000
+01100010
+11111110
+00000000
+
+ 70
+
+11111110
+01100010
+01101000
+01111000
+01101000
+01100000
+11110000
+00000000
+
+ 71
+
+00111100
+01100110
+11000000
+11000000
+11001110
+01100110
+00111110
+00000000
+
+ 72
+
+11001100
+11001100
+11001100
+11111100
+11001100
+11001100
+11001100
+00000000
+
+ 73
+
+01111000
+00110000
+00110000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 74
+
+00011110
+00001100
+00001100
+00001100
+11001100
+11001100
+01111000
+00000000
+
+ 75
+
+11100110
+01100110
+01101100
+01111000
+01101100
+01100110
+11100110
+00000000
+
+ 76
+
+11110000
+01100000
+01100000
+01100000
+01100010
+01100110
+11111110
+00000000
+
+ 77
+
+11000110
+11101110
+11111110
+11111110
+11010110
+11000110
+11000110
+00000000
+
+ 78
+
+11000110
+11100110
+11110110
+11011110
+11001110
+11000110
+11000110
+00000000
+
+ 79
+
+00111000
+01101100
+11000110
+11000110
+11000110
+01101100
+00111000
+00000000
+
+ 80
+
+11111100
+01100110
+01100110
+01111100
+01100000
+01100000
+11110000
+00000000
+
+ 81
+
+01111000
+11001100
+11001100
+11001100
+11011100
+01111000
+00011100
+00000000
+
+ 82
+
+11111100
+01100110
+01100110
+01111100
+01101100
+01100110
+11100110
+00000000
+
+ 83
+
+01111000
+11001100
+11100000
+01110000
+00011100
+11001100
+01111000
+00000000
+
+ 84
+
+11111100
+10110100
+00110000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 85
+
+11001100
+11001100
+11001100
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 86
+
+11001100
+11001100
+11001100
+11001100
+11001100
+01111000
+00110000
+00000000
+
+ 87
+
+11000110
+11000110
+11000110
+11010110
+11111110
+11101110
+11000110
+00000000
+
+ 88
+
+11000110
+11000110
+01101100
+00111000
+01101100
+11000110
+11000110
+00000000
+
+ 89
+
+11001100
+11001100
+11001100
+01111000
+00110000
+00110000
+01111000
+00000000
+
+ 90
+
+11111110
+11000110
+00001100
+00011000
+00110000
+01100110
+11111110
+00000000
+
+ 91
+
+01111000
+01100000
+01100000
+01100000
+01100000
+01100000
+01111000
+00000000
+
+ 92
+
+00000000
+11000000
+01100000
+00110000
+00011000
+00001100
+00000110
+00000000
+
+ 93
+
+01111000
+00011000
+00011000
+00011000
+00011000
+00011000
+01111000
+00000000
+
+ 94
+
+00011000
+00111100
+01100110
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 95
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11111111
+
+ 96
+
+00110000
+00110000
+00011000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 97
+
+00000000
+00000000
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 98
+
+11100000
+01100000
+01100000
+01111100
+01100110
+01100110
+11011100
+00000000
+
+ 99
+
+00000000
+00000000
+01111000
+11001100
+11000000
+11001100
+01111000
+00000000
+
+ 100
+
+00011100
+00001100
+00001100
+01111100
+11001100
+11001100
+01110110
+00000000
+
+ 101
+
+00000000
+00000000
+01111000
+11001100
+11111100
+11000000
+01111000
+00000000
+
+ 102
+
+00111000
+01101100
+01100000
+11110000
+01100000
+01100000
+11110000
+00000000
+
+ 103
+
+00000000
+00000000
+01110110
+11001100
+11001100
+01111100
+00001100
+11111000
+
+ 104
+
+11100000
+01100000
+01101100
+01110110
+01100110
+01100110
+11100110
+00000000
+
+ 105
+
+00110000
+00000000
+01110000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 106
+
+00001100
+00000000
+00001100
+00001100
+00001100
+11001100
+11001100
+01111000
+
+ 107
+
+11100000
+01100000
+01100110
+01101100
+01111000
+01101100
+11100110
+00000000
+
+ 108
+
+01110000
+00110000
+00110000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 109
+
+00000000
+00000000
+11001100
+11111110
+11111110
+11010110
+11000110
+00000000
+
+ 110
+
+00000000
+00000000
+11111000
+11001100
+11001100
+11001100
+11001100
+00000000
+
+ 111
+
+00000000
+00000000
+01111000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 112
+
+00000000
+00000000
+11011100
+01100110
+01100110
+01111100
+01100000
+11110000
+
+ 113
+
+00000000
+00000000
+01110110
+11001100
+11001100
+01111100
+00001100
+00011110
+
+ 114
+
+00000000
+00000000
+11011100
+01110110
+01100110
+01100000
+11110000
+00000000
+
+ 115
+
+00000000
+00000000
+01111100
+11000000
+01111000
+00001100
+11111000
+00000000
+
+ 116
+
+00010000
+00110000
+01111100
+00110000
+00110000
+00110100
+00011000
+00000000
+
+ 117
+
+00000000
+00000000
+11001100
+11001100
+11001100
+11001100
+01110110
+00000000
+
+ 118
+
+00000000
+00000000
+11001100
+11001100
+11001100
+01111000
+00110000
+00000000
+
+ 119
+
+00000000
+00000000
+11000110
+11010110
+11111110
+11111110
+01101100
+00000000
+
+ 120
+
+00000000
+00000000
+11000110
+01101100
+00111000
+01101100
+11000110
+00000000
+
+ 121
+
+00000000
+00000000
+11001100
+11001100
+11001100
+01111100
+00001100
+11111000
+
+ 122
+
+00000000
+00000000
+11111100
+10011000
+00110000
+01100100
+11111100
+00000000
+
+ 123
+
+00011100
+00110000
+00110000
+11100000
+00110000
+00110000
+00011100
+00000000
+
+ 124
+
+00110000
+00110000
+00110000
+00110000
+00110000
+00110000
+00110000
+00000000
+
+ 125
+
+11100000
+00110000
+00110000
+00011100
+00110000
+00110000
+11100000
+00000000
+
+ 126
+
+01110110
+11011100
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 127
+
+11001100
+00000000
+11001100
+11001100
+01111000
+00110000
+01111000
+00000000
+
+ 128
+
+# Changed this to allow the use of the euro in windows.
+
+#00000000
+#11111111
+#00000000
+#00000000
+#00000000
+#00000000
+#00000000
+#00000000
+
+00111000
+01100100
+11110000
+01100000
+11110000
+01100100
+00111000
+00000000
+
+ 129
+
+00011000
+00011000
+00011000
+00011000
+00000000
+00000000
+00000000
+00000000
+
+ 130
+
+00000000
+00000000
+00000000
+00011111
+00000000
+00000000
+00000000
+00000000
+
+ 131
+
+00011000
+00011000
+00011000
+00011111
+00000000
+00000000
+00000000
+00000000
+
+ 132
+
+00000000
+00000000
+00000000
+00000000
+00011000
+00011000
+00011000
+00011000
+
+ 133
+
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+00011000
+
+ 134
+
+00000000
+00000000
+00000000
+00011111
+00011000
+00011000
+00011000
+00011000
+
+ 135
+
+00011000
+00011000
+00011000
+00011111
+00011000
+00011000
+00011000
+00011000
+
+ 136
+
+00000000
+00000000
+00000000
+11111000
+00000000
+00000000
+00000000
+00000000
+
+ 137
+
+00011000
+00011000
+00011000
+11111000
+00000000
+00000000
+00000000
+00000000
+
+ 138
+
+00000000
+00000000
+00000000
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 139
+
+00011000
+00011000
+00011000
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 140
+
+00000000
+00000000
+00000000
+11111000
+00011000
+00011000
+00011000
+00011000
+
+ 141
+
+00011000
+00011000
+00011000
+11111000
+00011000
+00011000
+00011000
+00011000
+
+ 142
+
+00000000
+00000000
+00000000
+11111111
+00011000
+00011000
+00011000
+00011000
+
+ 143
+
+00011000
+00011000
+00011000
+11111111
+00011000
+00011000
+00011000
+00011000
+
+ 144
+
+00000000
+00000000
+00000000
+00000000
+00000000
+11111111
+00000000
+00000000
+
+ 145
+
+01101100
+01101100
+01101100
+01101100
+01111100
+00000000
+00000000
+00000000
+
+ 146
+
+00000000
+00000000
+01111111
+01100000
+01111111
+00000000
+00000000
+00000000
+
+ 147
+
+01101100
+01101100
+01101111
+01100000
+01111111
+00000000
+00000000
+00000000
+
+ 148
+
+00000000
+00000000
+01111100
+01101100
+01101100
+01101100
+01101100
+01101100
+
+ 149
+
+01101100
+01101100
+01101100
+01101100
+01101100
+01101100
+01101100
+01101100
+
+ 150
+
+00000000
+00000000
+01111111
+01100000
+01101111
+01101100
+01101100
+01101100
+
+ 151
+
+01101100
+01101100
+01101111
+01100000
+01101111
+01101100
+01101100
+01101100
+
+ 152
+
+00000000
+00000000
+11111100
+00001100
+11111100
+00000000
+00000000
+00000000
+
+ 153
+
+01101100
+01101100
+11101100
+00001100
+11111100
+00000000
+00000000
+00000000
+
+ 154
+
+00000000
+00000000
+11111111
+00000000
+11111111
+00000000
+00000000
+00000000
+
+ 155
+
+01101100
+01101100
+11101111
+00000000
+11111111
+00000000
+00000000
+00000000
+
+ 156
+
+00000000
+00000000
+11111100
+00001100
+11101100
+01101100
+01101100
+01101100
+
+ 157
+
+01101100
+01101100
+11101100
+00001100
+11101100
+01101100
+01101100
+01101100
+
+ 158
+
+00000000
+00000000
+11111111
+00000000
+11101111
+01101100
+01101100
+01101100
+
+ 159
+
+01101100
+01101100
+11101111
+00000000
+11101111
+01101100
+01101100
+01101100
+
+ 160
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11000110
+11111110
+
+ 161
+
+00000000
+00110000
+00000000
+00110000
+00110000
+01111000
+01111000
+00110000
+
+ 162
+
+00110000
+01111000
+11001100
+11000000
+11001100
+01111000
+00110000
+00000000
+
+ 163
+
+00111000
+01101100
+01100100
+11110000
+01100000
+11100110
+11111100
+00000000
+
+ 164
+
+00111000
+01100100
+11110000
+01100000
+11110000
+01100100
+00111000
+00000000
+
+ 165
+
+11001100
+11001100
+01111000
+11111100
+00110000
+11111100
+00110000
+00110000
+
+ 166
+
+01001000
+01111000
+10000100
+01100000
+00011000
+10000100
+01111000
+00000000
+
+ 167
+
+00111110
+01100001
+00111100
+01100110
+01100110
+00111100
+10000110
+01111100
+
+ 168
+
+01111000
+00000000
+01111100
+11000000
+01111000
+00001100
+11111000
+00000000
+
+ 169
+
+01111100
+10000010
+10011010
+10100010
+10100010
+10011010
+10000010
+01111100
+
+ 170
+
+00111100
+01101100
+00111110
+00000000
+01111110
+00000000
+00000000
+00000000
+
+ 171
+
+00000000
+00110011
+01100110
+11001100
+01100110
+00110011
+00000000
+00000000
+
+ 172
+
+00000000
+00000000
+00000000
+11111100
+00001100
+00001100
+00000000
+00000000
+
+ 173
+
+00000000
+00000000
+00000000
+01111100
+00000000
+00000000
+00000000
+00000000
+
+ 174
+
+01111100
+10000010
+10110010
+10101010
+10110010
+10101010
+10000010
+01111100
+
+ 175
+
+11111111
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 176
+
+01110000
+11011000
+01110000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 177
+
+00110000
+00110000
+11111100
+00110000
+00110000
+00000000
+11111100
+00000000
+
+ 178
+
+01110000
+11011000
+00110000
+01100000
+11111000
+00000000
+00000000
+00000000
+
+ 179
+
+01110000
+11011000
+00110000
+11011000
+01110000
+00000000
+00000000
+00000000
+
+ 180
+
+01101100
+11111110
+11001100
+00011000
+00110000
+01100110
+11111110
+00000000
+
+ 181
+
+00000000
+00000000
+11001100
+11001100
+11001100
+11001100
+11110110
+11000000
+
+ 182
+
+01111111
+11011011
+01111011
+00111011
+00011011
+00011011
+00011011
+00000000
+
+ 183
+
+00000000
+00000000
+00000000
+00011000
+00011000
+00000000
+00000000
+00000000
+
+ 184
+
+01111000
+00000000
+11111100
+10011000
+00110000
+01100100
+11111100
+00000000
+
+ 185
+
+01100000
+11100000
+01100000
+01100000
+11110000
+00000000
+00000000
+00000000
+
+ 186
+
+00111000
+01101100
+00111000
+00000000
+01111100
+00000000
+00000000
+00000000
+
+ 187
+
+00000000
+11001100
+01100110
+00110011
+01100110
+11001100
+00000000
+00000000
+
+ 188
+
+01111110
+11011000
+11011000
+11011100
+11011000
+11011000
+01111110
+00000000
+
+ 189
+
+00000000
+00000000
+01111110
+11011011
+11011110
+11011000
+01111110
+00000000
+
+ 190
+
+11001100
+00000000
+11001100
+01111000
+00110000
+00110000
+01111000
+00000000
+
+ 191
+
+00000000
+00011000
+00000000
+00011000
+00110000
+01100000
+01100110
+00111100
+
+ 192
+
+01100000
+00110000
+01111000
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 193
+
+00011000
+00110000
+01111000
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 194
+
+01111000
+10000100
+01111000
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 195
+
+01110110
+11011100
+01111000
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 196
+
+11001100
+00000000
+01111000
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 197
+
+00110000
+01001000
+01111000
+11001100
+11111100
+11001100
+11001100
+00000000
+
+ 198
+
+00111110
+01111000
+11011000
+11111100
+11011000
+11011000
+11011110
+00000000
+
+ 199
+
+00111100
+01100110
+11000000
+11000000
+01100110
+00111100
+00001100
+01111000
+
+ 200
+
+01100000
+00110000
+11111110
+01100010
+01111000
+01100010
+11111110
+00000000
+
+ 201
+
+00001100
+00011000
+11111110
+01100010
+01111000
+01100010
+11111110
+00000000
+
+ 202
+
+00111000
+01101100
+11111110
+01100010
+01111000
+01100010
+11111110
+00000000
+
+ 203
+
+01101100
+00000000
+11111110
+01100010
+01111000
+01100010
+11111110
+00000000
+
+ 204
+
+01100000
+00110000
+01111000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 205
+
+00011000
+00110000
+01111000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 206
+
+01111000
+11001100
+01111000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 207
+
+11001100
+00000000
+01111000
+00110000
+00110000
+00110000
+01111000
+00000000
+
+ 208
+
+11111000
+01101100
+01100110
+11110110
+01100110
+01101100
+11111000
+00000000
+
+ 209
+
+01110110
+11011100
+11100110
+11110110
+11011110
+11001110
+11000110
+00000000
+
+ 210
+
+01100000
+00110000
+01111000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 211
+
+00011000
+00110000
+01111000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 212
+
+01111000
+11001100
+01111000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 213
+
+01110110
+11011100
+01111000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 214
+
+11001100
+00000000
+01111000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 215
+
+00000000
+01101100
+00111000
+00111000
+01101100
+00000000
+00000000
+00000000
+
+ 216
+
+00111110
+01101100
+11011110
+11010110
+11110110
+01101100
+11111000
+00000000
+
+ 217
+
+01100000
+00110000
+11001100
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 218
+
+00011000
+00110000
+11001100
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 219
+
+01111000
+11001100
+00000000
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 220
+
+11001100
+00000000
+11001100
+11001100
+11001100
+11001100
+01111000
+00000000
+
+ 221
+
+00011000
+00110000
+11001100
+11001100
+01111000
+00110000
+01111000
+00000000
+
+ 222
+
+11110000
+01100000
+01111100
+01100110
+01111100
+01100000
+11110000
+00000000
+
+ 223
+
+01111100
+11000110
+11000110
+11001100
+11000110
+11010110
+11011100
+10000000
+
+ 224
+
+01100000
+00110000
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 225
+
+00011000
+00110000
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 226
+
+01111000
+10000100
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 227
+
+01110110
+11011100
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 228
+
+01101100
+00000000
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 229
+
+00111000
+01101100
+01111000
+00001100
+01111100
+11001100
+01110110
+00000000
+
+ 230
+
+00000000
+00000000
+01111110
+00011011
+01111110
+11011000
+01111110
+00000000
+
+ 231
+
+00000000
+01111000
+11001100
+11000000
+11001100
+01111000
+00011000
+01110000
+
+ 232
+
+01100000
+00110000
+01111000
+11001100
+11111100
+11000000
+01111000
+00000000
+
+ 233
+
+00001100
+00011000
+01111000
+11001100
+11111100
+11000000
+01111000
+00000000
+
+ 234
+
+01111000
+10000100
+01111000
+11001100
+11111100
+11000000
+01111000
+00000000
+
+ 235
+
+11001100
+00000000
+01111000
+11001100
+11111100
+11000000
+01111000
+00000000
+
+ 236
+
+01100000
+00110000
+00000000
+01110000
+00110000
+00110000
+01111000
+00000000
+
+ 237
+
+00011000
+00110000
+00000000
+01110000
+00110000
+00110000
+01111000
+00000000
+
+ 238
+
+01110000
+11011000
+00000000
+01110000
+00110000
+00110000
+01111000
+00000000
+
+ 239
+
+00000000
+11011000
+00000000
+01110000
+00110000
+00110000
+01111000
+00000000
+
+ 240
+
+01111000
+01110000
+00011000
+01111100
+11001100
+11001100
+01111000
+00000000
+
+ 241
+
+01110110
+11011100
+11111000
+11001100
+11001100
+11001100
+11001100
+00000000
+
+ 242
+
+01100000
+00110000
+00000000
+01111000
+11001100
+11001100
+01111000
+00000000
+
+ 243
+
+00011000
+00110000
+00000000
+01111000
+11001100
+11001100
+01111000
+00000000
+
+ 244
+
+01111000
+11001100
+00000000
+01111000
+11001100
+11001100
+01111000
+00000000
+
+ 245
+
+01110110
+11011100
+00000000
+01111000
+11001100
+11001100
+01111000
+00000000
+
+ 246
+
+00000000
+11001100
+00000000
+01111000
+11001100
+11001100
+01111000
+00000000
+
+ 247
+
+00000000
+00110000
+00000000
+11111100
+00000000
+00110000
+00000000
+00000000
+
+ 248
+
+00000000
+00000000
+01111100
+11011100
+11111100
+11101100
+11111000
+00000000
+
+ 249
+
+01100000
+00110000
+11001100
+11001100
+11001100
+11001100
+01110110
+00000000
+
+ 250
+
+00011000
+00110000
+11001100
+11001100
+11001100
+11001100
+01110110
+00000000
+
+ 251
+
+01111000
+11001100
+00000000
+11001100
+11001100
+11001100
+01110110
+00000000
+
+ 252
+
+11001100
+00000000
+11001100
+11001100
+11001100
+11001100
+01110110
+00000000
+
+ 253
+
+00011000
+00110000
+11001100
+11001100
+11001100
+01111100
+00001100
+11111000
+
+ 254
+
+11110000
+01100000
+01111000
+01101100
+01101100
+01111000
+01100000
+11110000
+
+ 255
+
+11001100
+00000000
+11001100
+11001100
+11001100
+01111100
+00001100
+11111000
+
diff --git a/dim.cpp b/dim.cpp
new file mode 100644
index 0000000..5e2bedf
--- /dev/null
+++ b/dim.cpp
@@ -0,0 +1,64 @@
+// dim.cpp
+// Revision 14-oct-2003
+
+#include "dim.h"
+#include "error.h"
+
+#include <algorithm>
+
+class dim_calc {
+public:
+ dim_calc () : r (1) { }
+ void operator () (const size_t n)
+ { r*= n + 1; }
+ size_t value () { return r; }
+private:
+ size_t r;
+};
+
+size_t Dimension::elements () const
+{
+ dim_calc r= std::for_each (dim.begin (), dim.end (), dim_calc () );
+ return r.value ();
+}
+
+size_t Dimension::evalpos (const Dimension & d) const
+{
+ size_t n= size ();
+ if (d.size () != n)
+ throw ErrBadSubscript;
+ size_t pos= d [0];
+ if (pos > dim [0])
+ throw ErrBadSubscript;
+ for (size_t i= 1; i < n; ++i)
+ {
+ if (d [i] > dim [i] )
+ throw ErrBadSubscript;
+ pos*= dim [i] + 1;
+ pos+= d [i];
+ }
+ return pos;
+}
+
+// Only for debug.
+
+std::ostream & operator << (std::ostream & os, const Dimension & d)
+{
+ size_t s= d.size ();
+ if (s == 0)
+ os << "(empty)";
+ else
+ {
+ os << '(';
+ for (size_t i= 0; i < s; ++i)
+ {
+ os << d [i];
+ if (i < s -1)
+ os << ", ";
+ }
+ os << ')';
+ }
+ return os;
+}
+
+// Fin de dim.cpp
diff --git a/dim.h b/dim.h
new file mode 100644
index 0000000..c02dcb8
--- /dev/null
+++ b/dim.h
@@ -0,0 +1,29 @@
+#ifndef INCLUDE_BLASSIC_DIM_H
+#define INCLUDE_BLASSIC_DIM_H
+
+// dim.h
+// Revision 6-jul-2004
+
+#include <iostream>
+#include <cstddef>
+#include <vector>
+
+class Dimension {
+public:
+ void add (size_t n) { dim.push_back (n); }
+ size_t size () const { return dim.size (); }
+ bool empty () const { return dim.empty (); }
+ size_t elements () const;
+ size_t operator [] (size_t n) const { return dim [n]; }
+ size_t evalpos (const Dimension & d) const;
+ bool operator == (const Dimension & d) const
+ { return dim == d.dim; }
+private:
+ std::vector <size_t> dim;
+};
+
+std::ostream & operator << (std::ostream & os, const Dimension & d);
+
+#endif
+
+// Fin de dim.h
diff --git a/directory.cpp b/directory.cpp
new file mode 100644
index 0000000..694bc8e
--- /dev/null
+++ b/directory.cpp
@@ -0,0 +1,252 @@
+// directory.cpp
+// Revision 9-jan-2005
+
+#include "directory.h"
+
+#include "error.h"
+#include "showerror.h"
+
+#include "trace.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+// We use the unix style even on windows under cygwin.
+#if defined __unix__ || defined __linux__ || defined __NetBSD__ || \
+ defined __APPLE__
+#define USE_UNIX
+#endif
+
+#ifdef USE_UNIX
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <glob.h>
+
+#else
+
+#include <windows.h>
+#include <dir.h>
+#include <dos.h>
+
+#ifdef __MINGW32__
+#include <io.h>
+#else
+using std::unlink;
+#endif
+
+#endif
+
+// ********************* Directory::Internal *************************
+
+class Directory::Internal {
+public:
+ Internal ();
+ ~Internal ();
+ std::string findfirst (const std::string & str);
+ std::string findnext ();
+ void closesearch ();
+private:
+ Internal (const Internal &); // Forbidden
+ Internal & operator = (const Internal &); // Forbidden
+
+ bool finding;
+ #ifdef USE_UNIX
+ glob_t g;
+ size_t n;
+ #else
+ WIN32_FIND_DATA fd;
+ HANDLE h;
+ #endif
+};
+
+Directory::Internal::Internal () :
+ finding (false)
+{
+}
+
+Directory::Internal::~Internal ()
+{
+ TRACEFUNC (tr, "Directory::Internal::~Internal");
+
+ if (finding)
+ closesearch ();
+}
+
+std::string Directory::Internal:: findfirst (const std::string & str)
+{
+ if (finding)
+ closesearch ();
+ finding= true;
+ #ifdef USE_UNIX
+ glob (str.c_str (), 0, NULL, & g);
+ if (g.gl_pathc == 0)
+ {
+ closesearch ();
+ return std::string ();
+ }
+ n= 1;
+ return g.gl_pathv [0];
+ #else
+ h= FindFirstFile (str.c_str (), & fd);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ closesearch ();
+ return std::string ();
+ }
+ return fd.cFileName;
+ #endif
+}
+
+std::string Directory::Internal:: findnext ()
+{
+ if (! finding)
+ return std::string ();
+ #ifdef USE_UNIX
+ if (n >= static_cast <size_t> (g.gl_pathc) )
+ {
+ closesearch ();
+ return std::string ();
+ }
+ ++n;
+ return g.gl_pathv [n - 1];
+ #else
+ if (! FindNextFile (h, & fd) )
+ {
+ closesearch ();
+ return std::string ();
+ }
+ return fd.cFileName;
+ #endif
+}
+
+void Directory::Internal::closesearch ()
+{
+ #ifdef USE_UNIX
+ globfree (& g);
+ #else
+ if (h != INVALID_HANDLE_VALUE)
+ FindClose (h);
+ #endif
+ finding= false;
+}
+
+// ********************* Directory *************************
+
+Directory::Directory () :
+ pin (new Internal)
+{
+}
+
+Directory::~Directory ()
+{
+ delete pin;
+}
+
+std::string Directory::findfirst (const std::string & str)
+{
+ return pin->findfirst (str);
+}
+
+std::string Directory::findnext ()
+{
+ return pin->findnext ();
+}
+
+// ********************* Other functions *************************
+
+void remove_file (const std::string & filename)
+{
+ if (unlink (filename.c_str () ) != 0)
+ {
+ switch (errno)
+ {
+ case ENOENT:
+ throw ErrFileNotFound;
+ default:
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+ }
+}
+
+void rename_file (const std::string & orig, const std::string & dest)
+{
+ if (rename (orig.c_str (), dest.c_str () ) != 0)
+ {
+ switch (errno)
+ {
+ case ENOENT:
+ throw ErrFileNotFound;
+ default:
+ showlasterror ();
+ throw ErrRenameFile;
+ }
+ }
+}
+
+void change_dir (const std::string & dirname)
+{
+ if (chdir (dirname.c_str () ) != 0)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+void make_dir (const std::string & dirname)
+{
+ #ifdef USE_UNIX
+ int r= mkdir (dirname.c_str (), 0777);
+ #else
+ int r= mkdir (dirname.c_str () );
+ #endif
+ if (r != 0)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+void remove_dir (const std::string & dirname)
+{
+ if (rmdir (dirname.c_str () ) != 0)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+void sleep_milisec (unsigned long n)
+{
+ TRACEFUNC (tr, "sleep_milisec");
+
+ #ifdef USE_UNIX
+
+ if (n == 0)
+ {
+ usleep (0);
+ }
+ else
+ {
+ n*= 1000;
+ unsigned int sec= n / 1000000;
+ n%= 1000000;
+ TRMESSAGE (tr, util::to_string (sec) + " sec, " +
+ util::to_string (n) + " microsec");
+ if (sec > 0)
+ sleep (sec);
+ if (n > 0)
+ usleep (n);
+ }
+
+ #else
+
+ Sleep (static_cast <DWORD> (n) );
+
+ #endif
+}
+
+// End of directory.cpp
diff --git a/directory.h b/directory.h
new file mode 100644
index 0000000..51dbc4d
--- /dev/null
+++ b/directory.h
@@ -0,0 +1,38 @@
+#ifndef INCLUDE_BLASSIC_DIRECTORY_H
+#define INCLUDE_BLASSIC_DIRECTORY_H
+
+// directory.h
+// Revision 7-feb-2005
+
+
+#include <string>
+
+#include "util.h"
+
+
+class Directory {
+public:
+ Directory ();
+ ~Directory ();
+ std::string findfirst (const std::string & str);
+ std::string findnext ();
+private:
+ Directory (const Directory &); // Forbidden
+ Directory operator = (const Directory &); // Forbidden
+ class Internal;
+ Internal * pin;
+ //util::pimpl_ptr <Internal> pin;
+};
+
+void remove_file (const std::string & filename);
+void rename_file (const std::string & orig, const std::string & dest);
+
+void change_dir (const std::string & dirname);
+void make_dir (const std::string & dirname);
+void remove_dir (const std::string & dirname);
+
+void sleep_milisec (unsigned long n);
+
+#endif
+
+// End of directory.h
diff --git a/dynamic.cpp b/dynamic.cpp
new file mode 100644
index 0000000..da2c62e
--- /dev/null
+++ b/dynamic.cpp
@@ -0,0 +1,222 @@
+// dynamic.cpp
+// Revision 1-jan-2005
+
+#include "dynamic.h"
+#include "error.h"
+#include "showerror.h"
+
+// For debugging.
+#include <errno.h>
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+
+#if (defined __unix__ || defined __linux__ || defined __NetBSD__) && \
+ ! defined __CYGWIN__
+// Kylix defines only __linux__
+
+
+#ifdef __hpux__
+
+
+#include <dl.h>
+
+class DynamicHandle::Internal {
+ shl_t handle;
+public:
+ Internal (const std::string & name);
+ ~Internal ();
+ DynamicUsrFunc addr (const std::string & str);
+};
+
+DynamicHandle::Internal::Internal (const std::string & name)
+{
+ handle= shl_load (name.c_str (), BIND_DEFERRED, 0);
+ if (handle == NULL)
+ throw ErrNoDynamicLibrary;
+}
+
+DynamicHandle::Internal::~Internal ()
+{
+ // HP-UX seems to unload the library even if it was
+ // opened several times, then we don't unload it.
+ //shl_unload (handle);
+}
+
+DynamicUsrFunc DynamicHandle::Internal::addr (const std::string & str)
+{
+ void * value;
+ if (shl_findsym (& handle, str.c_str (), TYPE_UNDEFINED,
+ & value) == 0)
+ {
+ //return reinterpret_cast <DynamicUsrFunc> (value);
+ return (DynamicUsrFunc) (value);
+ }
+ else
+ throw ErrNoDynamicSymbol;
+}
+
+#else
+// Unix no hp-ux
+
+
+#include <dlfcn.h>
+
+class DynamicHandle::Internal {
+ void * handle;
+public:
+ Internal (const std::string & name);
+ ~Internal ();
+ DynamicUsrFunc addr (const std::string & str);
+};
+
+DynamicHandle::Internal::Internal (const std::string & name)
+{
+ handle= dlopen (name.c_str (), RTLD_LAZY);
+ if (handle == NULL)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "Error loading " << name << ": " <<
+ dlerror () << endl;
+ }
+ throw ErrNoDynamicLibrary;
+ }
+}
+
+DynamicHandle::Internal::~Internal ()
+{
+ dlclose (handle);
+}
+
+DynamicUsrFunc DynamicHandle::Internal::addr (const std::string & str)
+{
+ void * value;
+ if ( (value= dlsym (handle, str.c_str () ) ) != NULL)
+ {
+ //return reinterpret_cast <DynamicUsrFunc> (value);
+ return (DynamicUsrFunc) value;
+ }
+ else
+ throw ErrNoDynamicSymbol;
+}
+
+#endif
+
+
+#elif defined BLASSIC_USE_WINDOWS
+
+
+#include <windows.h>
+#undef min
+#undef max
+
+namespace {
+
+void * GetAddress (HMODULE handle, const std::string & str)
+{
+ FARPROC result= GetProcAddress (handle, str.c_str () );
+ if (result == NULL)
+ {
+ std::string str_ (1, '_');
+ str_+= str;
+ result= GetProcAddress (handle, str_.c_str () );
+ }
+ if (result == NULL)
+ {
+ showlasterror ();
+ throw ErrNoDynamicSymbol;
+ }
+ return (void *) (result);
+}
+
+} // namespace
+
+class DynamicHandle::Internal {
+ HMODULE handle;
+public:
+ Internal (const std::string & name);
+ ~Internal ();
+ DynamicUsrFunc addr (const std::string & str);
+};
+
+DynamicHandle::Internal::Internal (const std::string & name)
+{
+ handle= LoadLibrary (name.c_str () );
+ if (handle == NULL)
+ {
+ showlasterror ();
+ throw ErrNoDynamicLibrary;
+ }
+}
+
+DynamicHandle::Internal::~Internal ()
+{
+ FreeLibrary (handle);
+}
+
+DynamicUsrFunc DynamicHandle::Internal::addr (const std::string & str)
+{
+ return (DynamicUsrFunc) GetAddress (handle, str);
+}
+
+#else
+
+
+#warning Dynamic link unsupported
+
+class DynamicHandle::Internal {
+public:
+ Internal (const std::string & name);
+ ~Internal ();
+ DynamicUsrFunc addr (const std::string & str);
+};
+
+DynamicHandle::Internal::Internal (const std::string & name)
+{
+ throw ErrDynamicUnsupported;
+}
+
+DynamicHandle::Internal::~Internal ()
+{
+}
+
+DynamicUsrFunc DynamicHandle::Internal::addr (const std::string & str)
+{
+ throw ErrDynamicUnsupported;
+}
+
+#endif
+
+
+DynamicHandle::DynamicHandle () :
+ pin (0)
+{
+}
+
+DynamicHandle::DynamicHandle (const std::string & name) :
+ pin (new Internal (name) )
+{
+}
+
+void DynamicHandle::assign (const std::string & name)
+{
+ // Create the new before destructing the old, thus leaving
+ // intouched in case of exception.
+ Internal * npin= new Internal (name);
+ delete pin;
+ pin= npin;
+}
+
+DynamicHandle::~DynamicHandle ()
+{
+ delete pin;
+}
+
+DynamicUsrFunc DynamicHandle::addr (const std::string & str)
+{
+ return pin->addr (str);
+}
+
+// Fin de dymanic.cpp
diff --git a/dynamic.h b/dynamic.h
new file mode 100644
index 0000000..90744df
--- /dev/null
+++ b/dynamic.h
@@ -0,0 +1,108 @@
+#ifndef INCLUDE_BLASSIC_DYNAMIC_H
+#define INCLUDE_BLASSIC_DYNAMIC_H
+
+// dynamic.h
+// Revision 7-feb-2005
+
+
+#include "blassic.h"
+
+#include <string>
+
+//#if defined __WIN32__ || defined __CYGWIN__ || defined __MINGW32__
+
+#ifdef BLASSIC_USE_WINDOWS
+
+typedef __declspec (dllimport) int (* DynamicUsrFunc)
+ (int nparams, int * param);
+
+#else
+
+typedef int (* DynamicUsrFunc) (int nparams, int * param);
+
+#endif
+
+
+class DynamicHandle {
+public:
+ DynamicHandle ();
+ DynamicHandle (const std::string & name);
+ void assign (const std::string & name);
+ ~DynamicHandle ();
+ DynamicUsrFunc addr (const std::string & str);
+private:
+ class Internal;
+ Internal * pin;
+};
+
+#if 0
+
+#if (defined __unix__ || defined __linux__ || defined __NetBSD__) && \
+ ! defined __CYGWIN__
+// Kylix defines only __linux__
+
+#ifdef __hpux__
+
+#include <dl.h>
+
+typedef shl_t DynamicHandle;
+
+inline DynamicHandle dynamicload (const std::string & str)
+ { return shl_load (str.c_str (), BIND_DEFERRED, 0); }
+
+inline void * dynamicaddr (DynamicHandle & handle, const std::string & str)
+{
+ void * value;
+ if (shl_findsym (& handle, str.c_str (), TYPE_UNDEFINED, & value) == 0)
+ return value;
+ else return NULL;
+}
+
+inline void dynamicclose (DynamicHandle handle)
+ { shl_unload (handle); }
+
+#else
+
+#include <dlfcn.h>
+
+typedef void * DynamicHandle;
+
+inline DynamicHandle dynamicload (const std::string & str)
+ { return dlopen (str.c_str (), RTLD_LAZY); }
+
+inline void * dynamicaddr (DynamicHandle handle, const std::string & str)
+ { return dlsym (handle, str.c_str () ); }
+
+inline void dynamicclose (DynamicHandle handle)
+ { dlclose (handle); }
+
+#endif
+
+#elif defined __WIN32__ || defined __CYGWIN__
+
+#include <windows.h>
+#undef min
+#undef max
+
+typedef HMODULE DynamicHandle;
+
+inline DynamicHandle dynamicload (const std::string & str)
+ { return LoadLibrary (str.c_str () ); }
+
+inline void * dynamicaddr (DynamicHandle handle, const std::string & str)
+{
+ return (void *) GetProcAddress (handle, str.c_str () );
+}
+
+inline void dynamicclose (DynamicHandle handle)
+ { FreeLibrary (handle); }
+
+#else
+ #error Unknown operating system
+#endif
+
+#endif
+
+#endif
+
+// Fin de dymanic.h
diff --git a/edit.cpp b/edit.cpp
new file mode 100644
index 0000000..740a0f3
--- /dev/null
+++ b/edit.cpp
@@ -0,0 +1,515 @@
+// edit.cpp
+// Revision 7-feb-2005
+
+//#include "cursor.h"
+#include "graphics.h"
+#include "error.h"
+#include "trace.h"
+#include "util.h"
+#include "sysvar.h"
+
+#include "edit.h"
+
+using util::to_string;
+
+#include <sstream>
+#include <deque>
+
+#include <cassert>
+#define ASSERT assert
+
+namespace sysvar= blassic::sysvar;
+using namespace blassic::file;
+
+
+namespace {
+
+std::deque <std::string> history;
+
+size_t getmaxhistory ()
+{
+ return sysvar::get16 (sysvar::MaxHistory);
+}
+
+void showstring (BlFile & bf, const std::string & str)
+{
+ for (size_t i= 0, l= str.size (); i < l; ++i)
+ {
+ unsigned char c= str [i];
+ if (c < 32)
+ bf << '\\' << char (c + 'A');
+ else
+ bf << static_cast <char> (c);
+ }
+ bf.flush ();
+}
+
+class Edit {
+public:
+ Edit (BlFile & bf, std::string & str,
+ size_t npos, size_t inicol, bool lineend);
+ ~Edit ();
+ bool do_it ();
+private:
+ BlFile & bf;
+ std::string & str;
+ size_t npos;
+ size_t inicol;
+ size_t width;
+ bool textwindow;
+ size_t histsize;
+ size_t histpos;
+ bool intagmode;
+ bool lineend;
+
+ std::string savestr;
+
+ //void getwidth ();
+ void back ();
+ void forward ();
+ void deletechar ();
+ void showrest ();
+ void showinitial ();
+ void up ();
+ void down ();
+};
+
+Edit::Edit (BlFile & bf, std::string & str,
+ size_t npos, size_t inicol, bool lineend) :
+ bf (bf),
+ str (str),
+ npos (npos),
+ inicol (inicol),
+ width (bf.getwidth () ),
+ textwindow (bf.istextwindow () ),
+ histsize (history.size () ),
+ histpos (histsize),
+ intagmode (bf.istagactive () ),
+ lineend (lineend)
+{
+ TRACEFUNC (tr, "Edit::~Edit");
+ TRMESSAGE (tr, "lineend: " + to_string (lineend) );
+
+ if (textwindow)
+ graphics::synchronize_suspend ();
+ if (intagmode)
+ bf.tagoff ();
+}
+
+Edit::~Edit ()
+{
+ TRACEFUNC (tr, "Edit::~Edit");
+
+ if (textwindow)
+ graphics::synchronize_restart ();
+ if (intagmode)
+ bf.tag ();
+}
+
+void Edit::back ()
+{
+ if (textwindow)
+ {
+ --npos;
+ bf.movecharback ();
+ return;
+ }
+ if ( (npos-- + inicol) % width != 0)
+ bf.movecharback ();
+ else
+ {
+ bf.movecharup ();
+ bf.movecharforward (width - 1);
+ }
+}
+
+void Edit::forward ()
+{
+ ++npos;
+ if (textwindow)
+ {
+ bf.movecharforward ();
+ return;
+ }
+ if ( (npos + inicol) % width != 0)
+ bf.movecharforward ();
+ else
+ {
+ if (npos == str.size () )
+ {
+ //bf.movecharforward ();
+ //bf << '\n';
+ bf.endline ();
+ bf.flush ();
+ }
+ else
+ {
+ //bf << '\r';
+ //bf.flush ();
+ bf.movecharback (width - 1);
+ bf.movechardown ();
+ }
+ }
+}
+
+void Edit::deletechar ()
+{
+ if (npos < str.size () )
+ {
+ str.erase (npos, 1);
+ // Vil chapuza.
+ str+= ' ';
+ showrest ();
+ str.erase (str.size () - 1);
+ }
+}
+
+void Edit::showrest ()
+{
+ //TRACEFUNC (tr, "Edit::showrest");
+
+ if (npos == str.size () )
+ return;
+ //bf << str.substr (npos);
+ //bf.flush ();
+ showstring (bf, str.substr (npos) );
+
+ size_t l= str.size ();
+ size_t nlines= (l + inicol) / width;
+ size_t actualline= (npos + inicol) / width;
+ size_t actualcol= (npos + inicol) % width;
+ size_t lastcol= (l + inicol) % width;
+ if (lastcol == 0 && nlines > 0)
+ {
+ if (! textwindow)
+ {
+ #ifndef __WIN32__
+ --nlines;
+ // The cursor position remains
+ // in the last valid column.
+ lastcol= width - 1;
+ //lastcol= width;
+ #endif
+ }
+ }
+ bf.movecharup (nlines - actualline);
+ if (actualcol < lastcol)
+ {
+ //TRMESSAGE (tr, std::string ("moving back " +
+ // to_string (lastcol - actualcol) ) );
+ bf.movecharback (lastcol - actualcol);
+ }
+ else if (actualcol > lastcol)
+ {
+ //TRMESSAGE (tr, "moving forward");
+ bf.movecharforward (actualcol - lastcol);
+ }
+ else if (actualcol == width - 1)
+ {
+ // Without this the cursor sometimes keep in the next line.
+ bf.movecharback ();
+ bf.movecharforward ();
+ }
+}
+
+void Edit::showinitial ()
+{
+ //TRACEFUNC (tr, "Edit::showinitial");
+
+ //bf << '\r' << str;
+ //bf.flush ();
+
+ //bf << '\r';
+ //bf.movecharforward (inicol);
+
+ showstring (bf, str);
+
+ size_t l= str.size () + inicol;
+ size_t nlines= l / width;
+ size_t actualline= (npos + inicol) / width;
+ size_t actualcol= (npos + inicol) % width;
+ size_t lastcol= l % width;
+
+ #ifndef __WIN32__
+ if (lastcol == 0 && nlines > 0)
+ {
+ --nlines;
+ lastcol= width - 1;
+ }
+ #endif
+
+ bf.movecharup (nlines - actualline);
+ if (actualcol < lastcol)
+ bf.movecharback (lastcol - actualcol);
+ else
+ bf.movecharforward (actualcol - lastcol);
+ //bf << '\r';
+ //bf.flush ();
+ //movecharforward (npos);
+}
+
+void Edit::up ()
+{
+ if (histpos > 0)
+ {
+ if (histpos == histsize)
+ savestr= str;
+ std::string::size_type oldsize= str.size ();
+ --histpos;
+ str= history [histpos];
+ while (npos > 0)
+ back ();
+ std::string::size_type
+ actualsize= str.size ();
+ if (oldsize > actualsize)
+ {
+ showstring (bf, std::string (oldsize, ' ') );
+ npos= oldsize;
+ for (size_t i= 0; i < oldsize; ++i)
+ back ();
+ }
+ //showinitial ();
+ showstring (bf, str);
+ npos= actualsize;
+ }
+}
+
+void Edit::down ()
+{
+ if (histpos < histsize)
+ {
+ std::string::size_type oldsize= str.size ();
+ ++histpos;
+ if (histpos < histsize)
+ str= history [histpos];
+ else
+ str= savestr;
+ while (npos > 0)
+ back ();
+ std::string::size_type
+ actualsize= str.size ();
+ if (oldsize > actualsize)
+ {
+ showstring (bf, std::string (oldsize, ' ') );
+ npos= oldsize;
+ for (size_t i= 0; i < oldsize; ++i)
+ back ();
+ }
+ //showinitial ();
+ showstring (bf, str);
+ npos= actualsize;
+ }
+}
+
+bool Edit::do_it ()
+{
+ TRACEFUNC (tr, "Edit::do_it");
+
+ showinitial ();
+
+ bool editing= true;
+ bool retval= true;
+ while (editing)
+ {
+ bf.showcursor ();
+ //TRMESSAGE (tr, "Waiting key");
+ std::string key= bf.getkey ();
+ //TRMESSAGE (tr, "Received key");
+ bf.hidecursor ();
+ if (key.size () == 1)
+ {
+ unsigned char c= key [0];
+ switch (c)
+ {
+ case '\r': case '\n':
+ editing= false;
+ break;
+ case '\x1B':
+ editing= false;
+ retval= false;
+ break;
+ case '\t':
+ {
+ //size_t n= npos + 1;
+ //n+= 7 - (n % 8);
+ //n-= npos ;
+ size_t n= 8 - npos % 8;
+ str.insert (npos, n, ' ');
+ showrest ();
+ for (size_t i= 0; i < n; ++i)
+ forward ();
+ }
+ break;
+ case '\3': // Ctrl-C
+ editing= false;
+ retval= false;
+ break;
+ case '\5': // Ctrl-E, test debug
+ //bf << str.substr (npos) << '\n';
+ //bf.flush ();
+ showstring (bf, str.substr (npos) );
+ //bf << '\n';
+ bf.endline ();
+ bf.flush ();
+ showinitial ();
+ break;
+ case '\x8':
+ case '\x7F':
+ if (npos > 0)
+ {
+ back ();
+ deletechar ();
+ }
+ break;
+ default:
+ if (c >= ' ')
+ {
+ str.insert (npos, 1, c);
+ showrest ();
+ forward ();
+ }
+ }
+ }
+ else if (key == "RIGHT")
+ {
+ if (npos < str.size () )
+ {
+ forward ();
+ }
+ }
+ else if (key == "LEFT")
+ {
+ if (npos > 0)
+ {
+ back ();
+ }
+ }
+ else if (key == "DELETE")
+ {
+ if (npos < str.size () )
+ deletechar ();
+ }
+ else if (key == "HOME")
+ {
+ while (npos > 0)
+ back ();
+ }
+ else if (key == "END")
+ {
+ const size_t l= str.size ();
+ while (npos < l)
+ forward ();
+ }
+ else if (key == "UP")
+ up ();
+ else if (key == "DOWN")
+ down ();
+ }
+ //hidecursor ();
+
+ if (lineend)
+ {
+ // After exit, cursor must be positioned after the line edited.
+ //bf << str.substr (npos) << '\n';
+ bf << str.substr (npos);
+ bf.endline ();
+ bf.flush ();
+ }
+
+ if (retval)
+ {
+ size_t maxhist= getmaxhistory ();
+ if (maxhist == 0)
+ maxhist= 1;
+ if (histsize >= maxhist)
+ {
+ history.erase (history.begin (),
+ history.begin () + histsize - maxhist + 1);
+ }
+ if (! str.empty () && (history.empty () ||
+ history [history.size () - 1] != str) )
+ history.push_back (str);
+ }
+
+ return retval;
+}
+
+} // namespace
+
+bool blassic::edit::editline (BlFile & bf, std::string & str,
+ size_t npos, size_t inicol, bool lineend)
+{
+ TRACEFUNC (tr, "editline - string");
+ {
+ std::ostringstream oss;
+ oss << "Inicol: " << inicol;
+ TRMESSAGE (tr, oss.str () );
+ }
+
+ Edit edit (bf, str, npos, inicol, lineend);
+ return edit.do_it ();
+}
+
+#if 0
+
+bool editline (BlFile & bf, Program & program, BlLineNumber bln,
+ std::string & str)
+{
+ TRACEFUNC (tr, "editline - line number->string");
+
+ std::string buffer;
+ {
+ BlFileOutString bfos;
+ program.list (bln, bln, bfos);
+ buffer= bfos.str ();
+ if (buffer.empty () )
+ {
+ //bfos << bln << " \n";
+ bfos << bln << ' ';
+ bfos.endline ();
+ buffer= bfos.str ();
+ }
+ }
+ buffer.erase (buffer.size () - 1);
+ TRMESSAGE (tr, std::string (1, '\'') + buffer + '\'');
+
+ static const std::string number ("01234567890");
+ size_t inipos= buffer.find_first_of (number);
+ ASSERT (inipos != std::string::npos);
+ inipos= buffer.find_first_not_of (number, inipos);
+ ASSERT (inipos != std::string::npos);
+ ++inipos;
+
+ bool r;
+ if ( (r= editline (bf, buffer, inipos) ) == true)
+ str= buffer;
+ return r;
+}
+
+bool editline (BlFile & bf, Program & program, BlLineNumber bln)
+{
+ TRACEFUNC (tr, "editline - line number");
+
+ std::string buffer;
+ bool r;
+ if ( (r= editline (bf, program, bln, buffer) ) == true)
+ {
+ CodeLine code;
+ code.scan (buffer);
+ BlLineNumber nline= code.number ();
+ if (nline == LineDirectCommand)
+ throw ErrBlassicInternal;
+ else
+ {
+ if (code.empty () )
+ program.deletelines (nline, nline);
+ else
+ program.insert (code);
+ }
+ }
+ return r;
+}
+
+#endif
+
+// End of edit.cpp
diff --git a/edit.h b/edit.h
new file mode 100644
index 0000000..5d8076b
--- /dev/null
+++ b/edit.h
@@ -0,0 +1,23 @@
+#ifndef INCLUDE_BLASSIC_EDIT_H
+#define INCLUDE_BLASSIC_EDIT_H
+
+// edit.h
+// Revision 23-jul-2004
+
+#include "blassic.h"
+#include "file.h"
+
+namespace blassic {
+
+namespace edit {
+
+bool editline (blassic::file::BlFile & bf, std::string & str,
+ size_t npos, size_t inicol= 0, bool lineend= true);
+
+} // namespace blassic
+
+} // namespace edit
+
+#endif
+
+// End of edit.h
diff --git a/element.cpp b/element.cpp
new file mode 100644
index 0000000..6c53db2
--- /dev/null
+++ b/element.cpp
@@ -0,0 +1,87 @@
+// element.cpp
+// Revision 8-jan-2005
+
+#include "element.h"
+
+#include "var.h"
+#include "trace.h"
+
+ForElementNumber::ForElementNumber (const std::string & nvar,
+ ProgramPos pos,
+ BlNumber initial, BlNumber nmax, BlNumber nstep) :
+ ForElement (nvar, pos),
+ max (nmax),
+ step (nstep)
+{
+ varaddr= addrvarnumber (nvar);
+ * varaddr= initial;
+}
+
+ForElementNumberInc::ForElementNumberInc (const std::string & var,
+ ProgramPos pos,
+ BlNumber initial, BlNumber max, BlNumber step) :
+ ForElementNumber (var, pos, initial, max, step)
+{
+ //TRACEFUNC (tr, "ForElementNumberInc::ForElementNumberInc");
+}
+
+bool ForElementNumberInc::next ()
+{
+ * varaddr+= step;
+ return * varaddr <= max;
+}
+
+ForElementNumberDec::ForElementNumberDec (const std::string & var,
+ ProgramPos pos,
+ BlNumber initial, BlNumber max, BlNumber step) :
+ ForElementNumber (var, pos, initial, max, step)
+{
+ //TRACEFUNC (tr, "ForElementNumberDec::ForElementNumberDec");
+}
+
+bool ForElementNumberDec::next ()
+{
+ * varaddr+= step;
+ return * varaddr >= max;
+}
+
+ForElementInteger::ForElementInteger (const std::string & nvar,
+ ProgramPos pos,
+ BlInteger initial, BlInteger nmax, BlInteger nstep) :
+ ForElement (nvar, pos),
+ max (nmax),
+ step (nstep)
+{
+ varaddr= addrvarinteger (nvar);
+ * varaddr= initial;
+}
+
+ForElementIntegerInc::ForElementIntegerInc (const std::string & var,
+ ProgramPos pos,
+ BlInteger initial, BlInteger max, BlInteger step) :
+ ForElementInteger (var, pos, initial, max, step)
+{
+ //TRACEFUNC (tr, "ForElementIntegerInc::ForElementIntegerInc");
+}
+
+bool ForElementIntegerInc::next ()
+{
+ * varaddr+= step;
+ return * varaddr <= max;
+}
+
+ForElementIntegerDec::ForElementIntegerDec (const std::string & var,
+ ProgramPos pos,
+ BlInteger initial, BlInteger max, BlInteger step) :
+ ForElementInteger (var, pos, initial, max, step)
+{
+ //TRACEFUNC (tr, "ForElementIntegerDec::ForElementIntegerDec");
+}
+
+bool ForElementIntegerDec::next ()
+{
+ * varaddr+= step;
+ return * varaddr >= max;
+}
+
+// End of element.cpp
diff --git a/element.h b/element.h
new file mode 100644
index 0000000..25d903d
--- /dev/null
+++ b/element.h
@@ -0,0 +1,155 @@
+#ifndef INCLUDE_ELEMENT_H
+#define INCLUDE_ELEMENT_H
+
+// element.h
+// Revision 1-jan-2005
+
+#include "blassic.h"
+
+#include <string>
+
+class Element {
+public:
+ Element (ProgramPos ppos) :
+ ppos (ppos)
+ { }
+ void nextchunk () { ppos.nextchunk (); }
+ void nextline () { ppos.nextline (); }
+ ProgramPos getpos () const { return ppos; }
+private:
+ ProgramPos ppos;
+};
+
+class ForElement : public Element {
+public:
+ ForElement (const std::string & nvar, ProgramPos pos) :
+ Element (pos),
+ varname (nvar)
+ { }
+ virtual ~ForElement () { }
+ virtual bool next ()= 0;
+ const std::string var () const
+ { return varname; }
+ bool isvar (const std::string & nvar) const
+ { return varname == nvar; }
+private:
+ ForElement (const ForElement &); // Forbidden
+ ForElement & operator = (const ForElement &); // Forbidden
+ const std::string varname;
+};
+
+class ForElementNumber : public ForElement {
+public:
+ ForElementNumber (const std::string & nvar,
+ ProgramPos pos,
+ BlNumber initial, BlNumber nmax, BlNumber nstep);
+protected:
+ BlNumber * varaddr, max, step;
+};
+
+class ForElementNumberInc : public ForElementNumber {
+public:
+ ForElementNumberInc (const std::string & var, ProgramPos pos,
+ BlNumber initial, BlNumber max, BlNumber step);
+ bool next ();
+};
+
+class ForElementNumberDec : public ForElementNumber {
+public:
+ ForElementNumberDec (const std::string & var, ProgramPos pos,
+ BlNumber initial, BlNumber max, BlNumber step);
+ bool next ();
+};
+
+class ForElementInteger : public ForElement {
+public:
+ ForElementInteger (const std::string & nvar,
+ ProgramPos pos,
+ BlInteger initial, BlInteger nmax, BlInteger nstep);
+protected:
+ BlInteger * varaddr, max, step;
+};
+
+class ForElementIntegerInc : public ForElementInteger {
+public:
+ ForElementIntegerInc (const std::string & var, ProgramPos pos,
+ BlInteger initial, BlInteger max, BlInteger step);
+ bool next ();
+};
+
+class ForElementIntegerDec : public ForElementInteger {
+public:
+ ForElementIntegerDec (const std::string & var, ProgramPos pos,
+ BlInteger initial, BlInteger max, BlInteger step);
+ bool next ();
+};
+
+inline ForElementNumber * newForElementNumber (const std::string & var,
+ ProgramPos pos, BlNumber initial, BlNumber max, BlNumber step)
+{
+ if (step >= 0.0)
+ return new ForElementNumberInc (var, pos, initial, max, step);
+ else
+ return new ForElementNumberDec (var, pos, initial, max, step);
+}
+
+inline ForElementInteger * newForElementInteger (const std::string & var,
+ ProgramPos pos, BlInteger initial, BlInteger max, BlInteger step)
+{
+ if (step >= 0)
+ return new ForElementIntegerInc (var, pos, initial, max, step);
+ else
+ return new ForElementIntegerDec (var, pos, initial, max, step);
+}
+
+class RepeatElement : public Element {
+public:
+ RepeatElement (ProgramPos pos) :
+ Element (pos)
+ { }
+};
+
+class WhileElement : public Element {
+public:
+ WhileElement (ProgramPos pos) :
+ Element (pos)
+ { }
+};
+
+class LocalLevel {
+public:
+ LocalLevel ();
+ LocalLevel (const LocalLevel & ll);
+ ~LocalLevel ();
+ LocalLevel & operator= (const LocalLevel & ll);
+ void addlocalvar (const std::string & name);
+ void freelocalvars ();
+private:
+ class Internal;
+ Internal * pi;
+};
+
+class GosubElement : public Element, public LocalLevel {
+public:
+ GosubElement (ProgramPos pos, bool is_polled) :
+ Element (pos),
+ is_gosub (true),
+ is_polled (is_polled)
+ { }
+ GosubElement (LocalLevel & ll) :
+ Element (0),
+ LocalLevel (ll),
+ is_gosub (false),
+ is_polled (false)
+ { }
+ bool isgosub () const { return is_gosub; }
+ bool ispolled () const { return is_polled; }
+private:
+ bool is_gosub;
+ bool is_polled;
+};
+
+
+#endif
+
+// End of element.h
diff --git a/error.cpp b/error.cpp
new file mode 100644
index 0000000..40032b0
--- /dev/null
+++ b/error.cpp
@@ -0,0 +1,194 @@
+// error.cpp
+// Revision 7-feb-2005
+
+#include "error.h"
+#include "sysvar.h"
+#include "util.h"
+
+#include <sstream>
+#include <algorithm>
+
+namespace sysvar= blassic::sysvar;
+
+
+namespace {
+
+struct errcode {
+ const BlErrNo err;
+ const char * const str;
+ errcode (BlErrNo nerr, const char * nstr) :
+ err (nerr),
+ str (nstr)
+ { }
+};
+
+// Can't declare const or Borland can't expand find_if. Why?
+errcode table []= {
+ errcode (ErrNoError, "No error"),
+ errcode (ErrSyntax, "Syntax horror"),
+ errcode (ErrMismatch, "Type mismatch"),
+ errcode (ErrGosubWithoutReturn, "GOSUB without RETURN"),
+ errcode (ErrReturnWithoutGosub, "RETURN without GOSUB"),
+ errcode (ErrNextWithoutFor, "NEXT without FOR"),
+ errcode (ErrNotImplemented, "Not implemented"),
+ errcode (ErrDivZero, "Division by zero"),
+ errcode (ErrDataExhausted, "Data exhausted"),
+ errcode (ErrInvalidCommand, "Invalid command"),
+ errcode (ErrPolite, "Programmer is too polite"),
+ errcode (ErrBadSubscript, "Bad Subscript"),
+ errcode (ErrOutMemory, "Out of memory"),
+ errcode (ErrAlreadyDim, "Array already dimensioned"),
+ errcode (ErrNoContinue, "Cannot CONTinue"),
+ errcode (ErrFileNumber, "Bad file number"),
+ errcode (ErrFileMode, "Bad file mode"),
+ errcode (ErrFileAlreadyOpen, "File already open"),
+ errcode (ErrFileRead, "Error reading file"),
+ errcode (ErrFileWrite, "Error writing file"),
+ errcode (ErrUntilWithoutRepeat, "UNTIL without REPEAT"),
+ errcode (ErrWendWithoutWhile, "WEND without WHILE"),
+ errcode (ErrWhileWithoutWend, "WHILE without WEND"),
+ errcode (ErrBlassicInternal, "Internal Blassic error"),
+ errcode (ErrNoDynamicLibrary, "Dynamic library not found"),
+ errcode (ErrNoDynamicSymbol, "Symbol not found in dynamic library"),
+ errcode (ErrCannotResume, "Cannot RESUME"),
+ errcode (ErrNoLabel, "Label does not exist"),
+ errcode (ErrMisplacedLocal, "LOCAL out of subroutine"),
+ errcode (ErrFieldOverflow, "FIELD overflow"),
+ errcode (ErrFileNotFound, "File not found"),
+ errcode (ErrLineExhausted, "Line numbers exhausted"),
+ errcode (ErrFunctionNoDefined, "User function undefined"),
+ errcode (ErrIncompleteDef, "User function incomplete"),
+ errcode (ErrInvalidDirect, "Invalid direct command"),
+ errcode (ErrBadRecord, "Bad record number"),
+ errcode (ErrFunctionCall, "Illegal function call"),
+ errcode (ErrSocket, "Socket error"),
+ errcode (ErrRenameFile, "Rename file error"),
+ errcode (ErrOperatingSystem, "Operating system error"),
+ errcode (ErrPastEof, "Input past EOF"),
+ errcode (ErrNoGraphics, "Graphics mode required"),
+ errcode (ErrImproperArgument, "Improper argument"),
+ errcode (ErrDomain, "Domain error"),
+ errcode (ErrRange, "Result out of range"),
+ errcode (ErrLineNotExist, "Line does not exist"),
+ errcode (ErrFnRecursion, "FN recursion too deep"),
+ errcode (ErrOverflow, "Overflow"),
+ errcode (ErrRegexp, "Bad regular expression"),
+ errcode (ErrDynamicUnsupported, "Dymanic link not supported"),
+ errcode (ErrRepeatWithoutUntil, "REPEAT without UNTIL"),
+ errcode (ErrUnexpectedFnEnd, "FN END outside DEF FN"),
+ errcode (ErrNoFnEnd, "FN without FN END"),
+ errcode (ErrDuplicateLabel, "Duplicate LABEL"),
+ errcode (ErrNoTeDejo, "That won't work"),
+};
+
+errcode * table_end= table + util::dim_array (table);
+
+class is_err {
+public:
+ is_err (BlErrNo err) : err (err)
+ { }
+ bool operator () (const errcode & ec) const
+ { return ec.err == err; }
+private:
+ BlErrNo err;
+};
+
+} // namespace
+
+//***********************************************
+// class BlError
+//***********************************************
+
+BlError::BlError () :
+ err (ErrNoError)
+{ }
+
+BlError::BlError (BlErrNo nerr) :
+ err (nerr)
+{ }
+
+BlError::BlError (BlErrNo nerr, ProgramPos npos) :
+ err (nerr),
+ pos (npos)
+{ }
+
+void BlError::clear ()
+{
+ err= ErrNoError;
+ pos= ProgramPos ();
+}
+
+void BlError::set (BlErrNo nerr, ProgramPos npos)
+{
+ err= nerr;
+ pos= npos;
+}
+
+void BlError::seterr (BlErrNo nerr)
+{
+ err= nerr;
+}
+
+BlErrNo BlError::geterr () const
+{
+ return err;
+}
+
+ProgramPos BlError::getpos () const
+{
+ return pos;
+}
+
+std::ostream & operator << (std::ostream & os, const BlError & bl)
+{
+ os << ErrStr (bl.err);
+ const BlLineNumber line= bl.getpos ().getnum ();
+ if (line != LineDirectCommand)
+ os << " in " << line;
+ //os << '\n';
+ return os;
+}
+
+//***********************************************
+// class BlBreakInPos
+//***********************************************
+
+BlBreakInPos::BlBreakInPos (ProgramPos pos) :
+ pos (pos)
+{ }
+
+ProgramPos BlBreakInPos::getpos () const
+{
+ return pos;
+}
+
+std::ostream & operator << (std::ostream & os, const BlBreakInPos & bbip)
+{
+ os << "**BREAK**";
+ BlLineNumber line= bbip.getpos ().getnum ();
+ if (line != LineDirectCommand)
+ os << " in " << line;
+ return os;
+}
+
+//***********************************************
+// Other functions
+//***********************************************
+
+std::string ErrStr (BlErrNo err)
+{
+ const errcode * perr= std::find_if (table, table_end, is_err (err) );
+ if (perr != table_end)
+ return perr->str;
+ std::ostringstream strbuf;
+ strbuf << "Error " << err;
+ return strbuf.str ();
+}
+
+bool showdebuginfo ()
+{
+ //return sysvar::getFlags1 () & sysvar::ShowDebugInfo;
+ return sysvar::hasFlags1 (sysvar::ShowDebugInfo);
+}
+
+// Fin de error.cpp
diff --git a/error.h b/error.h
new file mode 100644
index 0000000..27882bb
--- /dev/null
+++ b/error.h
@@ -0,0 +1,105 @@
+#ifndef INCLUDE_BLASSIC_ERROR_H
+#define INCLUDE_BLASSIC_ERROR_H
+
+// error.h
+// Revision 7-feb-2005
+
+
+#include "blassic.h"
+
+#include <string>
+#include <iostream>
+
+
+const BlErrNo
+ ErrNoError= 0,
+ ErrSyntax= 1,
+ ErrMismatch= 2,
+ ErrGosubWithoutReturn= 3,
+ ErrReturnWithoutGosub= 4,
+ ErrNextWithoutFor= 5,
+ ErrNotImplemented= 6,
+ ErrDivZero= 7,
+ ErrDataExhausted= 8,
+ ErrInvalidCommand= 9,
+ ErrPolite= 10,
+ ErrBadSubscript= 11,
+ ErrOutMemory= 12,
+ ErrAlreadyDim= 13,
+ ErrNoContinue= 14,
+ ErrFileNumber= 15,
+ ErrFileMode= 16,
+ ErrFileAlreadyOpen= 17,
+ ErrFileRead= 18,
+ ErrFileWrite= 19,
+ ErrUntilWithoutRepeat= 20,
+ ErrWendWithoutWhile= 21,
+ ErrWhileWithoutWend= 22,
+ ErrBlassicInternal= 23,
+ ErrNoDynamicLibrary= 24,
+ ErrNoDynamicSymbol= 25,
+ ErrCannotResume= 26,
+ ErrNoLabel= 27,
+ ErrMisplacedLocal= 28,
+ ErrFieldOverflow= 29,
+ ErrFileNotFound= 30,
+ ErrLineExhausted= 31,
+ ErrFunctionNoDefined= 32,
+ ErrIncompleteDef= 33,
+ ErrInvalidDirect= 34,
+ ErrBadRecord= 35,
+ ErrFunctionCall= 36,
+ ErrSocket= 37,
+ ErrRenameFile= 38,
+ ErrOperatingSystem= 39,
+ ErrPastEof= 40,
+ ErrNoGraphics= 41,
+ ErrImproperArgument= 42,
+ ErrDomain= 43,
+ ErrRange= 44,
+ ErrLineNotExist= 45,
+ ErrFnRecursion= 46,
+ ErrOverflow= 48,
+ ErrRegexp= 49,
+ ErrDynamicUnsupported= 50,
+ ErrRepeatWithoutUntil= 51,
+ ErrUnexpectedFnEnd= 52,
+ ErrNoFnEnd= 53,
+ ErrDuplicateLabel= 54,
+ ErrNoTeDejo= 55;
+
+class BlError {
+public:
+ BlError ();
+ BlError (BlErrNo nerr);
+ BlError (BlErrNo nerr, ProgramPos npos);
+ void clear ();
+ void set (BlErrNo nerr, ProgramPos npos);
+ void seterr (BlErrNo nerr);
+ BlErrNo geterr () const;
+ ProgramPos getpos () const;
+ friend std::ostream & operator << (std::ostream & os,
+ const BlError & be);
+private:
+ BlErrNo err;
+ ProgramPos pos;
+};
+
+class BlBreak { };
+
+class BlBreakInPos {
+ ProgramPos pos;
+public:
+ BlBreakInPos (ProgramPos pos);
+ ProgramPos getpos () const;
+};
+
+std::ostream & operator << (std::ostream & os, const BlBreakInPos & bbip);
+
+std::string ErrStr (BlErrNo err);
+
+bool showdebuginfo ();
+
+#endif
+
+// Fin de error.h
diff --git a/file.cpp b/file.cpp
new file mode 100644
index 0000000..bf68bd6
--- /dev/null
+++ b/file.cpp
@@ -0,0 +1,903 @@
+// file.cpp
+// Revision 9-jan-2005
+
+#include "blassic.h"
+#include "file.h"
+#include "trace.h"
+#include "error.h"
+#include "var.h"
+
+//#include "cursor.h"
+//#include "edit.h"
+//#include "graphics.h"
+
+#include "sysvar.h"
+//#include "socket.h"
+#include "util.h"
+using util::to_string;
+
+#include <fstream>
+#include <iomanip>
+#include <sstream>
+#include <stdexcept>
+#include <algorithm>
+
+// para strerror (errno)
+#include <string.h>
+#include <errno.h>
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#include <cassert>
+#define ASSERT assert
+
+//***********************************************
+// Auxiliary functions
+//***********************************************
+
+namespace {
+
+BlInteger lengthoffileread (std::fstream & fs)
+{
+ // WARNING: The C++ standard does not guarantee that
+ // this method obtains the length of the file.
+ std::streamsize old= fs.tellg ();
+ fs.seekg (0, std::ios::end);
+ std::streamsize l= fs.tellg ();
+ fs.seekg (old, std::ios::beg);
+ // Not leave the file unusable in case something were wrong.
+ fs.clear ();
+ return static_cast <BlInteger> (l);
+}
+
+BlInteger lengthoffilewrite (std::fstream & fs)
+{
+ // WARNING: The C++ standard does not guarantee that
+ // this method obtains the length of the file.
+ std::streamsize old= fs.tellp ();
+ fs.seekp (0, std::ios::end);
+ std::streamsize l= fs.tellp ();
+ fs.seekp (old, std::ios::beg);
+ // Not leave the file unusable in case something were wrong.
+ fs.clear ();
+ return static_cast <BlInteger> (l);
+}
+
+} // namespace
+
+namespace blassic {
+
+namespace file {
+
+//***********************************************
+// BlFile
+//***********************************************
+
+BlFile::BlFile (OpenMode nmode) :
+ mode (nmode),
+ cDelimiter (','),
+ cQuote ('"'),
+ cEscape ('\0')
+{
+}
+
+BlFile::~BlFile ()
+{
+}
+
+void BlFile::closein ()
+ { throw ErrFileMode; }
+void BlFile::closeout ()
+ { throw ErrFileMode; }
+
+void BlFile::reset (int, int, int, int)
+ { throw ErrFileMode; }
+
+bool BlFile::istextwindow () const
+{
+ return false;
+}
+
+bool BlFile::eof ()
+{
+ if (showdebuginfo () )
+ cerr << "This file type does not implement EOF" << endl;
+ throw ErrFileMode;
+}
+
+size_t BlFile::loc ()
+ { throw ErrFileMode; }
+void BlFile::flush ()
+ { throw ErrFileMode; }
+void BlFile::getline (std::string &, bool)
+ { throw ErrFileMode; }
+void BlFile::outstring (const std::string &)
+ { throw ErrFileMode; }
+void BlFile::outchar (char)
+ { throw ErrFileMode; }
+
+#if 0
+
+void BlFile::outnumber (BlNumber n)
+{
+ //outstring (to_string (n) );
+ std::ostringstream oss;
+ oss << std::setprecision (16) << n;
+ outstring (oss.str () );
+}
+
+void BlFile::outinteger (BlInteger n)
+{
+ outstring (to_string (n) );
+}
+
+void BlFile::outlinenumber (BlLineNumber l)
+{
+ std::ostringstream oss;
+ oss << std::setw (7) << l;
+ outstring (oss.str () );
+}
+
+#endif
+
+BlFile & operator << (BlFile & bf, const std::string & str)
+{
+ TRACEFUNC (tr, "operator << (BlFile &, const string &)");
+
+ bf.outstring (str);
+ return bf;
+}
+
+BlFile & operator << (BlFile & bf, char c)
+{
+ bf.outchar (c);
+ return bf;
+}
+
+BlFile & operator << (BlFile & bf, BlNumber n)
+{
+ //bf.outnumber (n);
+ std::ostringstream oss;
+ oss << std::setprecision (16) << n;
+ bf.outstring (oss.str () );
+ return bf;
+}
+
+BlFile & operator << (BlFile & bf, BlInteger n)
+{
+ //bf.outinteger (n);
+ bf.outstring (to_string (n) );
+ return bf;
+}
+
+BlFile & operator << (BlFile & bf, BlLineNumber l)
+{
+ //bf.outlinenumber (l);
+ std::ostringstream oss;
+ oss << std::setw (7) << l;
+ bf.outstring (oss.str () );
+ return bf;
+}
+
+BlFile & operator << (BlFile & bf, unsigned short n)
+{
+ bf.outstring (to_string (n) );
+ return bf;
+}
+
+void BlFile::putspaces (size_t n)
+{
+ outstring (std::string (n, ' ') );
+}
+
+void BlFile::tab ()
+{
+ outchar ('\t');
+}
+
+void BlFile::tab (size_t n)
+{
+ // Provisional
+ outstring (std::string (n, ' ') );
+}
+
+void BlFile::endline ()
+{
+ outchar ('\n');
+}
+
+void BlFile::put (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::get (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::field_clear ()
+{ throw ErrFileMode; }
+
+void BlFile::field (const std::vector <field_element> &)
+{ throw ErrFileMode; }
+
+void BlFile::field_append (const std::vector <field_element> &)
+{ throw ErrFileMode; }
+
+// assign doesn't throw because we call it for all open files,
+// those that are no random files or does nor have the var in
+// their fields just ignore it.
+bool BlFile::assign (const std::string &, const Dimension &,
+ const std::string &, Align)
+{ return false; }
+bool BlFile::assign_mid (const std::string &, const Dimension &,
+ const std::string &, size_t, std::string::size_type)
+{ return false; }
+
+size_t BlFile::getwidth () const
+{ throw ErrFileMode; }
+
+void BlFile::movecharforward ()
+{ throw ErrFileMode; }
+
+void BlFile::movecharforward (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::movecharback ()
+{ throw ErrFileMode; }
+
+void BlFile::movecharback (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::movecharup ()
+{ throw ErrFileMode; }
+
+void BlFile::movecharup (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::movechardown ()
+{ throw ErrFileMode; }
+
+void BlFile::movechardown (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::showcursor ()
+{ throw ErrFileMode; }
+
+void BlFile::hidecursor ()
+{ throw ErrFileMode; }
+
+std::string BlFile::getkey ()
+{ throw ErrFileMode; }
+
+std::string BlFile::inkey ()
+{ throw ErrFileMode; }
+
+std::string BlFile::read (size_t)
+{ throw ErrFileMode; }
+
+void BlFile::gotoxy (int, int)
+{ throw ErrFileMode; }
+
+void BlFile::setcolor (int)
+{ throw ErrFileMode; }
+
+int BlFile::getcolor ()
+{ throw ErrFileMode; }
+
+void BlFile::setbackground (int)
+{ throw ErrFileMode; }
+
+int BlFile::getbackground ()
+{ throw ErrFileMode; }
+
+void BlFile::cls ()
+{ throw ErrFileMode; }
+
+std::string BlFile::copychr (BlChar, BlChar)
+{ throw ErrFileMode; }
+
+int BlFile::pos ()
+{ throw ErrFileMode; }
+
+int BlFile::vpos ()
+{ throw ErrFileMode; }
+
+void BlFile::tag ()
+{ throw ErrFileMode; }
+
+void BlFile::tagoff ()
+{ /* Ignored */ }
+
+bool BlFile::istagactive ()
+{ return false; }
+
+void BlFile::inverse (bool)
+{ throw ErrFileMode; }
+
+bool BlFile::getinverse ()
+{ throw ErrFileMode; }
+
+void BlFile::bright (bool)
+{ throw ErrFileMode; }
+
+bool BlFile::getbright ()
+{ throw ErrFileMode; }
+
+void BlFile::setwidth (size_t )
+{ }
+
+void BlFile::setmargin (size_t )
+{ }
+
+BlInteger BlFile::lof ()
+{ throw ErrFileMode; }
+
+bool BlFile::poll ()
+{
+ return false;
+}
+
+void BlFile::scroll (int)
+{ throw ErrFileMode; }
+
+
+//***********************************************
+// BlFileOut
+//***********************************************
+
+BlFileOut::BlFileOut () : BlFile (Output)
+{ }
+
+BlFileOut::BlFileOut (OpenMode mode) : BlFile (mode)
+{ }
+
+void BlFileOut::flush ()
+{
+ ofs () << std::flush;
+}
+
+void BlFileOut::outstring (const std::string & str)
+{
+ ofs () << str;
+}
+
+void BlFileOut::outchar (char c)
+{
+ ofs () << c;
+}
+
+#if 0
+
+void BlFileOut::outnumber (BlNumber n)
+{
+ ofs () << n;
+}
+
+void BlFileOut::outinteger (BlInteger n)
+{
+ ofs () << n;
+}
+
+void BlFileOut::outlinenumber (BlLineNumber l)
+{
+ ofs () << std::setw (7) << l;
+}
+
+#endif
+
+//***********************************************
+// BlFileOutString
+//***********************************************
+
+BlFile * newBlFileOutString ()
+{
+ return new BlFileOutString;
+}
+
+BlFileOutString::BlFileOutString ()
+{ }
+
+std::string BlFileOutString::str ()
+{
+ return oss.str ();
+}
+
+std::ostream & BlFileOutString::ofs ()
+{
+ return oss;
+}
+
+//***********************************************
+// BlFileOutput
+//***********************************************
+
+class BlFileOutput : public BlFileOut {
+public:
+ BlFileOutput (std::ostream & os);
+ bool isfile () const { return true; }
+private:
+ std::ostream & ofs ();
+ std::ostream & os;
+};
+
+class BlFileRegular : public BlFileOut {
+public:
+ BlFileRegular (const std::string & name, OpenMode mode);
+ bool isfile () const { return true; }
+ void getline (std::string & str, bool endline= true);
+ bool eof ();
+ void flush ();
+ virtual std::string getkey ();
+ virtual std::string inkey ();
+ std::string read (size_t n);
+ BlInteger lof ();
+private:
+ std::ostream & ofs ();
+ std::fstream fs;
+};
+
+BlFile * newBlFileOutput (std::ostream & os)
+{
+ return new BlFileOutput (os);
+}
+
+BlFileOutput::BlFileOutput (std::ostream & os) :
+ os (os)
+{
+}
+
+std::ostream & BlFileOutput::ofs ()
+{
+ return os;
+}
+
+//***********************************************
+// BlFileRegular
+//***********************************************
+
+BlFile * newBlFileRegular (const std::string & name, OpenMode mode)
+{
+ return new BlFileRegular (name, mode);
+}
+
+BlFileRegular::BlFileRegular (const std::string & name, OpenMode nmode) :
+ BlFileOut (nmode)
+{
+ TRACEFUNC (tr, "BlFileRegular::BlFileRegular");
+
+ using std::ios;
+
+ ios::openmode mode= ios::in;
+ switch (nmode & ~ Binary)
+ {
+ case Input:
+ mode= ios::in; break;
+ case Output:
+ mode= ios::out; break;
+ case Append:
+ //mode= ios::out | ios::ate; break;
+ mode= ios::out | ios::app; break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Unexpected mode value" << endl;
+ TRMESSAGE (tr, std::string ("Invalid mode ") +
+ util::to_string (nmode) );
+ throw ErrBlassicInternal;
+ }
+ if (nmode & Binary)
+ mode|= ios::binary;
+ fs.open (name.c_str (), mode);
+ if (! fs.is_open () )
+ {
+ if (showdebuginfo () )
+ cerr << "open (" << name << ", " << mode <<
+ ") failed: " << strerror (errno) <<
+ endl;
+ throw ErrFileNotFound;
+ }
+}
+
+bool BlFileRegular::eof ()
+{
+ int c= fs.get ();
+ if (! fs || c == EOF)
+ return true;
+ fs.unget ();
+ return false;
+}
+
+void BlFileRegular::flush ()
+{
+ fs << std::flush;
+}
+
+void BlFileRegular::getline (std::string & str, bool)
+{
+ std::getline (fs, str);
+ if (! fs)
+ {
+ if (fs.eof () )
+ throw ErrPastEof;
+ else
+ throw ErrFileRead;
+ }
+}
+
+std::string BlFileRegular::getkey ()
+{
+ return read (1);
+}
+
+std::string BlFileRegular::inkey ()
+{
+ int c= fs.get ();
+ if (! fs || c == EOF)
+ {
+ fs.clear (); // Allow further reads.
+ return std::string ();
+ }
+ return std::string (1, static_cast <char> (c) );
+}
+
+std::string BlFileRegular::read (size_t n)
+{
+ util::auto_buffer <char> buf (n);
+ fs.read (buf, n);
+ if (! fs)
+ {
+ if (fs.eof () )
+ throw ErrPastEof;
+ else
+ throw ErrFileRead;
+ }
+ return std::string (buf, n);
+}
+
+std::ostream & BlFileRegular::ofs ()
+{
+ return fs;
+}
+
+BlInteger BlFileRegular::lof ()
+{
+ if (getmode () & Input)
+ return lengthoffileread (fs);
+ else
+ return lengthoffilewrite (fs);
+}
+
+//***********************************************
+// BlFileRandom
+//***********************************************
+
+class BlFileRandom : public BlFile {
+public:
+ BlFileRandom (const std::string & name, size_t record_len);
+ bool isfile () const { return true; }
+ bool eof ();
+ virtual size_t loc ();
+ void put (size_t pos);
+ void get (size_t pos);
+ void field_clear ();
+ void field (const std::vector <field_element> & elem);
+ void field_append (const std::vector <field_element> & elem);
+ virtual bool assign (const std::string & name, const Dimension & dim,
+ const std::string & value, Align align);
+ virtual bool assign_mid (const std::string & name,
+ const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len);
+ struct field_chunk {
+ std::string name;
+ Dimension dim;
+ size_t pos;
+ size_t size;
+ inline void getvar (char * buf) const;
+ };
+ typedef std::vector <field_chunk> vchunk;
+ BlInteger lof ();
+private:
+ std::fstream fs;
+ size_t len;
+ size_t len_assigned;
+ bool used;
+ size_t actual;
+ //auto_array buf;
+ util::auto_buffer <char> buf;
+ vchunk chunk;
+};
+
+BlFile * newBlFileRandom (const std::string & name, size_t record_len)
+{
+ return new BlFileRandom (name, record_len);
+}
+
+inline void BlFileRandom::field_chunk::getvar (char * buf) const
+{
+ if (dim.empty () )
+ assignvarstring (name, std::string (buf + pos, size) );
+ else
+ assigndimstring (name, dim, std::string (buf + pos, size) );
+}
+
+BlFileRandom::BlFileRandom (const std::string & name, size_t record_len) :
+ BlFile (Random),
+ len (record_len),
+ len_assigned (0),
+ used (false),
+ actual (0),
+ buf (record_len)
+{
+ using std::ios;
+
+ const ios::openmode iobin (ios::in | ios::out | ios::binary);
+ fs.open (name.c_str (), iobin);
+ if (! fs.is_open () )
+ {
+ // This can be necessary or not depending of the compiler
+ // to create the file if not exist. We test it, anyway.
+ if (errno == ENOENT)
+ {
+ fs.clear ();
+ fs.open (name.c_str (), ios::out | ios::binary);
+ if (fs.is_open () )
+ {
+ fs.close ();
+ fs.open (name.c_str (), iobin);
+ }
+
+ }
+ if (! fs.is_open () )
+ {
+ if (showdebuginfo () )
+ cerr << "open " << name << " failed: " <<
+ strerror (errno) << endl;
+ throw ErrFileNotFound;
+ }
+ }
+ std::fill_n (buf.begin (), len, '\0');
+}
+
+bool BlFileRandom::eof ()
+{
+ fs.clear ();
+ fs.seekg (actual * len);
+ if (! fs)
+ {
+ if (fs.eof () )
+ return true;
+ throw ErrFileRead;
+ }
+ char testchar;
+ fs.read (& testchar, 1);
+ if (! fs)
+ {
+ if (fs.eof () )
+ return true;
+ throw ErrFileRead;
+ }
+ return fs.gcount () != 1;
+}
+
+size_t BlFileRandom::loc ()
+{
+ return used ? actual + 1 : size_t (0);
+}
+
+
+void BlFileRandom::put (size_t pos)
+{
+ used= true;
+ if (pos != 0)
+ {
+ actual= pos - 1;
+ fs.seekp (actual * len);
+ }
+ fs.write (buf, len);
+ ++actual;
+}
+
+namespace {
+
+class GetVar {
+public:
+ GetVar (char * buf) : buf (buf) { }
+ void operator () (const BlFileRandom::field_chunk & chunk)
+ {
+ chunk.getvar (buf);
+ }
+private:
+ char * buf;
+};
+
+} // namespace
+
+void BlFileRandom::get (size_t pos)
+{
+ using std::string;
+
+ used= true;
+ if (pos != 0)
+ actual= pos - 1;
+ fs.clear ();
+ fs.seekg (actual * len);
+ fs.read (buf, len);
+ std::streamsize r= fs.gcount ();
+ if (r < std::streamsize (len) )
+ std::fill_n (buf.begin () + r, len - r, ' ');
+ std::for_each (chunk.begin (), chunk.end (), GetVar (buf) );
+ ++actual;
+}
+
+namespace {
+
+class MakeChunk {
+public:
+ MakeChunk (size_t len, size_t & pos) :
+ len (len),
+ pos (pos)
+ { }
+ BlFileRandom::field_chunk operator ()
+ (const BlFile::field_element & elem)
+ {
+ size_t size= elem.size;
+ BlFileRandom::field_chunk fc;
+ fc.name= elem.name;
+ fc.dim= elem.dim;
+ fc.pos= pos;
+ fc.size= size;
+ pos+= size;
+ if (pos > len)
+ throw ErrFieldOverflow;
+ return fc;
+ }
+ size_t getpos () const { return pos; }
+private:
+ const size_t len;
+ size_t & pos;
+};
+
+} // namespace
+
+void BlFileRandom::field_clear ()
+{
+ chunk.clear ();
+ len_assigned= 0;
+}
+
+void BlFileRandom::field_append (const std::vector <field_element> & elem)
+{
+ TRACEFUNC (tr, "BlFileRandom::field_append");
+
+ // Create the field chunks.
+ //MakeChunk maker (len, len_assigned);
+ std::transform (elem.begin (), elem.end (),
+ std::back_inserter (chunk),
+ MakeChunk (len, len_assigned) );
+ // Check the assigned mark.
+ TRMESSAGE (tr, std::string ("len_assigned= ") +
+ util::to_string (len_assigned) );
+
+ // Assign initial values to the field variables (filled with
+ // zeroes if the file is opened and not touched).
+ // Do it for all fields, not only the added now.
+ std::for_each (chunk.begin (), chunk.end (), GetVar (buf) );
+}
+
+void BlFileRandom::field (const std::vector <field_element> & elem)
+{
+ field_clear ();
+ field_append (elem);
+}
+
+namespace {
+
+class field_var_is {
+public:
+ field_var_is (const std::string & name, const Dimension & dim) :
+ name (name), dim (dim)
+ { }
+ bool operator () (const BlFileRandom::field_chunk & chunk)
+ {
+ return chunk.name == name && chunk.dim == dim;
+ }
+private:
+ const std::string & name;
+ const Dimension & dim;
+};
+
+} // namespace
+
+bool BlFileRandom::assign (const std::string & name, const Dimension & dim,
+ const std::string & value, Align align)
+{
+ vchunk::iterator pe= std::find_if (chunk.begin (), chunk.end (),
+ field_var_is (name, dim) );
+ if (pe == chunk.end () )
+ return false;
+ if (pe->size == 0)
+ return true;
+ char * init= buf + pe->pos;
+ std::string str;
+
+ // Changed the behaviour: now does the same as gwbasic.
+
+ #if 0
+ std::string::size_type l= value.size ();
+ if (align == AlignLeft)
+ {
+ if (l < pe->size)
+ str= value + std::string (pe->size - l, ' ');
+ else
+ str= value.substr (0, pe->size);
+ }
+ else
+ {
+ if (l < pe->size)
+ str= std::string (pe->size - l, ' ') + value;
+ else
+ str= value.substr (l - pe->size);
+ }
+ #else
+ if (align == AlignLeft)
+ str= util::stringlset (value, pe->size);
+ else
+ str= util::stringrset (value, pe->size);
+ #endif
+ ASSERT (str.size () == pe->size);
+ #if 0
+ std::copy (str.begin (), str.end (), init);
+ #else
+ str.copy (init, pe->size);
+ #endif
+ // Now also assign to the standalone var, so that the
+ // value assiged can be checked.
+ if (dim.empty () )
+ assignvarstring (name, str);
+ else
+ assigndimstring (name, dim, str);
+ return true;
+}
+
+bool BlFileRandom::assign_mid (const std::string & name,
+ const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len)
+{
+ vchunk::iterator pe= std::find_if (chunk.begin (), chunk.end (),
+ field_var_is (name, dim) );
+ if (pe == chunk.end () )
+ return false;
+ const size_t size= pe->size;
+ if (size == 0)
+ return true;
+ if (inipos >= size)
+ return true;
+ char * const init= buf + pe->pos;
+ char * const initmid= init + inipos;
+ size_t l= size - inipos;
+ if (len > l)
+ len= l;
+ std::string str= value.substr (0, len);
+ if (str.size () < len)
+ str+= std::string (len - str.size (), ' ');
+ str.copy (initmid, str.size () );
+ // Now also assign to the standalone var, so that the
+ // value assiged can be checked.
+ if (dim.empty () )
+ assignvarstring (name, std::string (init, size) );
+ else
+ assigndimstring (name, dim, std::string (init, size) );
+ return true;
+}
+
+BlInteger BlFileRandom::lof ()
+{
+ return lengthoffileread (fs);
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// Fin de file.cpp
diff --git a/file.h b/file.h
new file mode 100644
index 0000000..50f543d
--- /dev/null
+++ b/file.h
@@ -0,0 +1,178 @@
+#ifndef INCLUDE_BLASSIC_FILE_H
+#define INCLUDE_BLASSIC_FILE_H
+
+// file.h
+// Revision 7-feb-2005
+
+#ifdef __BORLANDC__
+#pragma warn -8022
+#endif
+
+#include "blassic.h"
+
+#include "dim.h"
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <sstream>
+
+namespace blassic {
+
+namespace file {
+
+enum OpenMode {
+ Input= 1, Output= 2, InOut= 3,
+ Append= 6, Random= 8, Binary= 16,
+ WithErr= 32
+};
+
+class BlFile {
+public:
+ struct field_element {
+ size_t size;
+ std::string name;
+ Dimension dim;
+ field_element (size_t n,
+ const std::string & str, const Dimension & dim)
+ :
+ size (n), name (str), dim (dim)
+ { }
+ };
+ enum Align { AlignRight, AlignLeft };
+
+ BlFile (OpenMode nmode);
+ virtual ~BlFile ();
+
+ virtual void closein ();
+ virtual void closeout ();
+
+ virtual void reset (int x1, int x2, int y1, int y2);
+
+ virtual bool isfile () const = 0;
+ virtual bool istextwindow () const;
+ virtual bool eof ();
+ virtual size_t loc ();
+ virtual void flush ();
+ virtual size_t getwidth () const;
+ virtual void movecharforward ();
+ virtual void movecharforward (size_t n);
+ virtual void movecharback ();
+ virtual void movecharback (size_t n);
+ virtual void movecharup ();
+ virtual void movecharup (size_t n);
+ virtual void movechardown ();
+ virtual void movechardown (size_t n);
+ virtual void showcursor ();
+ virtual void hidecursor ();
+ virtual std::string getkey ();
+ virtual std::string inkey ();
+ virtual void getline (std::string & str, bool endline= true);
+ char delimiter () { return cDelimiter; }
+ void delimiter (char delim) { cDelimiter= delim; }
+ char quote () { return cQuote; }
+ void quote (char qu) { cQuote= qu; }
+ char escape () { return cEscape; }
+ void escape (char esc) { cEscape= esc; }
+ friend BlFile & operator << (BlFile & bf, const std::string & str);
+ friend BlFile & operator << (BlFile & bf, char c);
+ friend BlFile & operator << (BlFile & bf, BlNumber n);
+ friend BlFile & operator << (BlFile & bf, BlInteger n);
+ friend BlFile & operator << (BlFile & bf, BlLineNumber l);
+ friend BlFile & operator << (BlFile & bf, unsigned short n);
+ void putspaces (size_t n);
+ virtual void tab ();
+ virtual void tab (size_t n);
+ virtual void endline ();
+ virtual void put (size_t pos);
+ virtual void get (size_t pos);
+ virtual void field_clear ();
+ virtual void field (const std::vector <field_element> & elem);
+ virtual void field_append (const std::vector <field_element> & elem);
+ virtual bool assign (const std::string & name, const Dimension & dim,
+ const std::string & value, Align align);
+ virtual bool assign_mid (const std::string & name,
+ const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len);
+ virtual std::string read (size_t n);
+ virtual void gotoxy (int x, int y);
+ virtual void setcolor (int color);
+ virtual int getcolor ();
+ virtual void setbackground (int color);
+ virtual int getbackground ();
+ virtual void cls ();
+ virtual std::string copychr (BlChar from, BlChar to);
+ virtual int pos ();
+ virtual int vpos ();
+ virtual void tag ();
+ virtual void tagoff ();
+ virtual bool istagactive ();
+ virtual void inverse (bool active);
+ virtual bool getinverse ();
+ virtual void bright (bool active);
+ virtual bool getbright ();
+ virtual void setwidth (size_t w);
+ virtual void setmargin (size_t m);
+ virtual BlInteger lof ();
+ virtual bool poll ();
+ virtual void scroll (int nlines);
+private:
+ virtual void outstring (const std::string & str);
+ virtual void outchar (char c);
+
+ BlFile (const BlFile &); // Forbidden
+ void operator = (const BlFile &); // Forbidden.
+
+ OpenMode mode;
+ char cDelimiter, cQuote, cEscape;
+protected:
+ OpenMode getmode () const { return mode; }
+};
+
+// Create BlFile functions.
+
+BlFile * newBlFileConsole ();
+BlFile * newBlFileWindow (BlChannel ch);
+BlFile * newBlFileWindow (BlChannel ch, int x1, int x2, int y1, int y2);
+BlFile * newBlFileOutString ();
+BlFile * newBlFileOutput (std::ostream & os);
+BlFile * newBlFileRegular (const std::string & name, OpenMode mode);
+BlFile * newBlFileRandom (const std::string & name, size_t record_len);
+BlFile * newBlFilePopen (const std::string & name, OpenMode mode);
+BlFile * newBlFileSocket (const std::string & host, short port);
+BlFile * newBlFilePrinter ();
+
+class BlFileOut : public BlFile {
+public:
+ BlFileOut ();
+ BlFileOut (OpenMode mode);
+ void flush ();
+protected:
+ virtual std::ostream & ofs ()= 0;
+private:
+ void outstring (const std::string & str);
+ void outchar (char c);
+ //void outnumber (BlNumber n);
+ //void outinteger (BlInteger n);
+ //void outlinenumber (BlLineNumber l);
+};
+
+class BlFileOutString : public BlFileOut {
+public:
+ BlFileOutString ();
+ bool isfile () const { return false; }
+ std::string str ();
+private:
+ std::ostream & ofs ();
+ std::ostringstream oss;
+};
+
+} // namespace blassic
+
+} // namespace file
+
+#endif
+
+// Fin de file.h
diff --git a/fileconsole.cpp b/fileconsole.cpp
new file mode 100644
index 0000000..9032cb6
--- /dev/null
+++ b/fileconsole.cpp
@@ -0,0 +1,532 @@
+// fileconsole.cpp
+// Revision 6-feb-2005
+
+#ifdef __BORLANDC__
+#pragma warn -8022
+#endif
+
+#include "file.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "cursor.h"
+#include "edit.h"
+#include "sysvar.h"
+#include "util.h"
+
+#include "trace.h"
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+#include <string>
+#include <algorithm>
+
+#ifndef BLASSIC_USE_WINDOWS
+
+#include <unistd.h>
+
+#else
+
+#include <windows.h>
+#undef max
+#undef min
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if defined HAVE_IO_H || ! defined BLASSIC_CONFIG
+#include <io.h>
+#endif
+
+#endif
+
+//***********************************************
+// Auxiliary functions
+//***********************************************
+
+namespace {
+
+class updateposchar {
+public:
+ updateposchar (int & pos) :
+ pos (pos)
+ { }
+ void operator () (const char c)
+ {
+ switch (c)
+ {
+ case '\r':
+ case '\n':
+ pos= 0;
+ break;
+ case '\b':
+ if (pos > 0)
+ --pos;
+ break;
+ case '\a':
+ // Bell does not use space in screen.
+ break;
+ case '\t':
+ pos= ( (pos / 8) + 1) * 8;
+ break;
+ default:
+ ++pos;
+ }
+ }
+private:
+ int & pos;
+};
+
+void updatepos (int & pos, const std::string & str)
+{
+ std::for_each (str.begin (), str.end (), updateposchar (pos) );
+}
+
+} // namespace
+
+namespace blassic {
+
+namespace file {
+
+//***********************************************
+// BlFileConsole
+//***********************************************
+
+class BlFileConsole : public BlFile {
+public:
+ //BlFileConsole (std::istream & nin, std::ostream & nout);
+ BlFileConsole ();
+ bool isfile () const { return false; }
+ virtual bool eof ();
+ virtual void flush ();
+ virtual size_t getwidth () const;
+ virtual void movecharforward ();
+ virtual void movecharforward (size_t n);
+ virtual void movecharback ();
+ virtual void movecharback (size_t n);
+ virtual void movecharup ();
+ virtual void movecharup (size_t n);
+ virtual void movechardown ();
+ virtual void movechardown (size_t n);
+ virtual void showcursor ();
+ virtual void hidecursor ();
+ virtual std::string getkey ();
+ virtual std::string inkey ();
+ void getline (std::string & str, bool endline= true);
+ std::string read (size_t n);
+ void tab ();
+ void tab (size_t n);
+ void gotoxy (int x, int y);
+ virtual void setcolor (int color);
+ virtual void setbackground (int color);
+ virtual void cls ();
+ int pos ();
+ bool poll ();
+private:
+ void outstring (const std::string & str);
+ void outchar (char c);
+ //void outnumber (BlNumber n);
+ //void outinteger (BlInteger n);
+
+ std::istream & in;
+ std::ostream & out;
+ bool ttyin, ttyout;
+ #ifndef BLASSIC_USE_WINDOWS
+ int xpos;
+ #endif
+};
+
+BlFile * newBlFileConsole ()
+{
+ return new BlFileConsole ();
+}
+
+//BlFileConsole::BlFileConsole (std::istream & nin, std::ostream & nout) :
+BlFileConsole::BlFileConsole () :
+ BlFile (OpenMode (Input | Output) ),
+ //in (nin),
+ //out (nout),
+ in (std::cin),
+ out (std::cout),
+ ttyin (isatty (0) ),
+ ttyout (isatty (1) )
+ //#ifndef _Windows
+ #ifndef BLASSIC_USE_WINDOWS
+ , xpos (0)
+ #endif
+{
+ TRACEFUNC (tr, "BlFileConsole::BlFileConsole");
+ TRMESSAGE (tr, std::string ("ttyin ") +
+ (ttyin ? "is" : "is not") + " a tty");
+ TRMESSAGE (tr, std::string ("ttyout ") +
+ (ttyout ? "is" : "is not") + " a tty");
+}
+
+bool BlFileConsole::eof ()
+{
+ if (! ttyin)
+ {
+ int c= in.get ();
+ if (! in || c == EOF)
+ return true;
+ else
+ {
+ in.unget ();
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void BlFileConsole::flush ()
+{
+ out << std::flush;
+}
+
+size_t BlFileConsole::getwidth () const
+{
+ return cursor::getwidth ();
+}
+
+void BlFileConsole::movecharforward ()
+{
+ cursor::movecharforward ();
+}
+
+void BlFileConsole::movecharforward (size_t n)
+{
+ cursor::movecharforward (n);
+}
+
+void BlFileConsole::movecharback ()
+{
+ cursor::movecharback ();
+}
+
+void BlFileConsole::movecharback (size_t n)
+{
+ cursor::movecharback (n);
+}
+
+void BlFileConsole::movecharup ()
+{
+ cursor::movecharup ();
+}
+
+void BlFileConsole::movecharup (size_t n)
+{
+ cursor::movecharup (n);
+}
+
+void BlFileConsole::movechardown ()
+{
+ cursor::movechardown ();
+}
+
+void BlFileConsole::movechardown (size_t n)
+{
+ cursor::movechardown (n);
+}
+
+void BlFileConsole::showcursor ()
+{
+ cursor::showcursor ();
+}
+
+void BlFileConsole::hidecursor ()
+{
+ cursor::hidecursor ();
+}
+
+std::string BlFileConsole::getkey ()
+{
+ //TRACEFUNC (tr, "BlFileConsole::getkey");
+
+ if (ttyin)
+ {
+ std::string str= cursor::getkey ();
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ if (str.size () == 1)
+ {
+ char c= str [0];
+ OemToCharBuff (& c, & c, 1);
+ return std::string (1, c);
+ }
+
+ #endif
+
+ return str;
+ }
+ else
+ {
+ int c= in.get ();
+ if (! in || c == EOF)
+ throw ErrPastEof;
+ return std::string (1, static_cast <char> (c) );
+ }
+}
+
+std::string BlFileConsole::inkey ()
+{
+ std::string str= cursor::inkey ();
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ if (ttyin && str.size () == 1)
+ {
+ char c= str [0];
+ OemToCharBuff (& c, & c, 1);
+ return std::string (1, c);
+ }
+
+ #endif
+
+ return str;
+}
+
+void BlFileConsole::getline (std::string & str, bool endline)
+{
+ using blassic::edit::editline;
+
+ TRACEFUNC (tr, "BlFileConsole::getline");
+
+ if (ttyin)
+ {
+ std::string auxstr;
+ //int inicol= getcursorx ();
+ int inicol= pos ();
+ while (! editline (* this, auxstr, 0, inicol, endline) )
+ continue;
+ swap (str, auxstr);
+ }
+ else
+ {
+ std::getline (in, str);
+ if (! in)
+ throw ErrPastEof;
+ }
+
+ if (fInterrupted)
+ {
+ in.clear ();
+ str.erase ();
+ return;
+ }
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ if (ttyin)
+ {
+ size_t l= str.size ();
+ util::auto_buffer <char> aux (l);
+ OemToCharBuff (str.data (), aux, l);
+ str= std::string (aux, l);
+ }
+
+ #endif
+}
+
+std::string BlFileConsole::read (size_t n)
+{
+ util::auto_buffer <char> buf (n);
+ in.read (buf, n);
+ return std::string (buf, n);
+}
+
+void BlFileConsole::tab ()
+{
+ int zone= static_cast <int> (sysvar::get16 (sysvar::Zone) );
+ if (zone == 0)
+ {
+ outchar ('\t');
+ return;
+ }
+
+ #if 0
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ int newpos= getcursorx ();
+
+ #else
+
+ int pos= xpos;
+
+ #endif
+
+ #else
+
+ int newpos= pos ();
+
+ #endif
+
+ const int width= 80; // This may need another approach.
+ if (newpos >= (width / zone) * zone)
+ endline ();
+ else
+ {
+ do
+ {
+ outchar (' ');
+ ++newpos;
+ } while (newpos % zone);
+ }
+}
+
+void BlFileConsole::tab (size_t n)
+{
+ int p= pos ();
+ if (p > static_cast <int> (n) )
+ {
+ outchar ('\n');
+ p= pos ();
+ }
+ outstring (std::string (n - p, ' ') );
+}
+
+void BlFileConsole::outstring (const std::string & str)
+{
+ TRACEFUNC (tr, "BlFileConsole::outstring");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ if (ttyout)
+ {
+ size_t l= str.size ();
+ util::auto_buffer <char> aux (l + 1);
+ CharToOemBuff (str.data (), aux, l);
+ aux [l]= 0;
+ out << aux;
+ }
+ else
+ out << str;
+
+ #else
+
+ out << str;
+ updatepos (xpos, str);
+
+ #endif
+
+ #ifndef NDEBUG
+ out << std::flush;
+ #endif
+
+ if (! out)
+ {
+ out.clear ();
+ //throw std::runtime_error ("Al diablo");
+ }
+}
+
+void BlFileConsole::outchar (char c)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ if (ttyout)
+ CharToOemBuff (& c, & c, 1);
+
+ #endif
+
+ if (c == '\n')
+ out << endl;
+ else
+ out << c;
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ updateposchar (xpos).operator () (c);
+
+ #endif
+
+ if (! out)
+ {
+ out.clear ();
+ //throw std::runtime_error ("Al diablo");
+ }
+}
+
+#if 0
+
+void BlFileConsole::outnumber (BlNumber n)
+{
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::stringout (to_string (n) );
+ else
+ #endif
+ out << n;
+}
+
+void BlFileConsole::outinteger (BlInteger n)
+{
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::stringout (to_string (n) );
+ else
+ #endif
+ out << n;
+}
+
+#endif
+
+void BlFileConsole::gotoxy (int x, int y)
+{
+ cursor::gotoxy (x, y);
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ xpos= x;
+
+ #endif
+}
+
+void BlFileConsole::setcolor (int color)
+{
+ cursor::textcolor (color);
+}
+
+void BlFileConsole::setbackground (int color)
+{
+ cursor::textbackground (color);
+}
+
+void BlFileConsole::cls ()
+{
+ cursor::cls ();
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ xpos= 0;
+
+ #endif
+}
+
+int BlFileConsole::pos ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ return cursor::getcursorx ();
+
+ #else
+
+ return xpos;
+
+ #endif
+}
+
+bool BlFileConsole::poll ()
+{
+ return cursor::pollin ();
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// End of fileconsole.cpp
diff --git a/filepopen.cpp b/filepopen.cpp
new file mode 100644
index 0000000..afcd184
--- /dev/null
+++ b/filepopen.cpp
@@ -0,0 +1,1191 @@
+// filepopen.cpp
+// Revision 6-feb-2005
+
+#include "file.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "showerror.h"
+#include "sysvar.h"
+#include "util.h"
+using util::to_string;
+
+#include "trace.h"
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#ifndef BLASSIC_USE_WINDOWS
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+// Suggested in autoconf manual.
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(star_val) ((unsigned) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+
+#include <fcntl.h>
+#include <sys/poll.h>
+
+#else
+
+#include <windows.h>
+#undef min
+#undef max
+
+#endif
+
+// para strerror (errno)
+#include <string.h>
+#include <errno.h>
+
+#include <assert.h>
+
+#define ASSERT assert
+
+namespace blassic {
+
+namespace file {
+
+//***********************************************
+// BlFilePopen
+//***********************************************
+
+class BlFilePopen : public BlFile {
+protected:
+ virtual char getcharfrombuffer ()= 0;
+ virtual void outstring (const std::string & str)= 0;
+ virtual void outchar (char c)= 0;
+ bool forread;
+ bool forwrite;
+ bool witherr;
+public:
+ BlFilePopen (OpenMode nmode);
+ bool isfile () const { return true; }
+ virtual void closein ()= 0;
+ virtual void closeout ()= 0;
+ virtual bool eof ()= 0;
+ void flush ();
+ virtual void endline ()= 0;
+ virtual std::string read (size_t n)= 0;
+ virtual void getline (std::string & str, bool endline= true)= 0;
+ virtual bool poll ()= 0;
+};
+
+BlFilePopen::BlFilePopen (OpenMode nmode) :
+ BlFile (nmode)
+{
+ if (nmode & Input)
+ forread= true;
+ if (nmode & Output)
+ forwrite= true;
+ if (nmode & WithErr)
+ witherr= true;
+ const OpenMode checkmode= OpenMode (Input | Output | WithErr);
+ if ( (nmode | checkmode) != checkmode)
+ throw ErrFileMode;
+}
+
+void BlFilePopen::flush ()
+{
+}
+
+#ifdef BLASSIC_USE_WINDOWS
+
+//***********************************************
+// Auxiliary functions and classes for windows
+//***********************************************
+
+namespace {
+
+class ProtectHandle {
+public:
+ ProtectHandle () :
+ handle (INVALID_HANDLE_VALUE)
+ { }
+ ProtectHandle (HANDLE handle) :
+ handle (handle)
+ { }
+ ~ProtectHandle ()
+ {
+ close ();
+ }
+ void reset (HANDLE newhandle)
+ {
+ close ();
+ handle= newhandle;
+ }
+ void close ()
+ {
+ if (handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (handle);
+ handle= INVALID_HANDLE_VALUE;
+ }
+ }
+ void release ()
+ {
+ handle= INVALID_HANDLE_VALUE;
+ }
+private:
+ HANDLE handle;
+};
+
+std::string makecommand (const std::string & str)
+{
+ const char * comspec= getenv ("COMSPEC");
+ if (comspec == NULL)
+ comspec= "C:\\COMMAND.COM";
+ std::string command= comspec;
+ command+= " /C ";
+ command+= str;
+ return command;
+}
+
+void create_pipe (HANDLE & hread, HANDLE & hwrite)
+{
+ if (CreatePipe (& hread, & hwrite, NULL, 0) == 0)
+ {
+ showlasterror ("CreatePipe failed");
+ throw ErrFunctionCall;
+ }
+}
+
+HANDLE duplicate_inherit (HANDLE handle, HANDLE current)
+{
+ HANDLE newhandle;
+ if (DuplicateHandle (current, handle,
+ current, & newhandle,
+ 0,
+ TRUE, // Inherited
+ DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS) == 0)
+ {
+ showlasterror ("DuplicateHandle hread failed");
+ throw ErrFunctionCall;
+ }
+ return newhandle;
+}
+
+HANDLE createnull ()
+{
+ SECURITY_ATTRIBUTES sec;
+ sec.nLength= sizeof sec;
+ sec.lpSecurityDescriptor= NULL;
+ sec.bInheritHandle= TRUE;
+
+ const HANDLE hnull= CreateFile ("NUL",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ & sec, // Inheritable.
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hnull == INVALID_HANDLE_VALUE)
+ {
+ showlasterror ("Error creating /dev/null handle");
+ throw ErrOperatingSystem;
+ }
+ return hnull;
+}
+
+void launchchild (const std::string & str,
+ bool forread, bool forwrite, bool witherr,
+ HANDLE & hreadpipe, HANDLE & hwritepipe, HANDLE & childprocess)
+{
+ TRACEFUNC (tr, "launchchild");
+
+ const std::string command= makecommand (str);
+
+ HANDLE current= GetCurrentProcess ();
+ const HANDLE hnull= createnull ();
+ ProtectHandle prnull (hnull);
+
+ STARTUPINFO start;
+ start.cb= sizeof start;
+ GetStartupInfo (& start);
+ start.dwFlags= STARTF_USESTDHANDLES;
+ start.hStdInput= hnull;
+ start.hStdOutput= hnull;
+ start.hStdError= hnull;
+ DWORD creationflags= 0;
+
+ HANDLE hwritechild;
+ ProtectHandle prreadpipe;
+ ProtectHandle prwritechild;
+ if (forread)
+ {
+ TRMESSAGE (tr, "Creating pipe input");
+
+ HANDLE hwrite;
+ create_pipe (hreadpipe, hwrite);
+ prreadpipe.reset (hreadpipe);
+ hwritechild= duplicate_inherit (hwrite, current);
+ prwritechild.reset (hwritechild);
+ start.hStdOutput= hwritechild;
+ if (witherr)
+ start.hStdError= hwritechild;
+ }
+ HANDLE hreadchild;
+ ProtectHandle prwritepipe;
+ ProtectHandle prreadchild;
+ if (forwrite)
+ {
+ TRMESSAGE (tr, "Creating pipe output");
+
+ // In Windows 95 or 98 detach the process from the
+ // actual console, without that the parent process
+ // gets blocked.
+ // Now seems inneccessary, and conflicts with
+ // bidirectional mode.
+ #if 0
+ {
+ OSVERSIONINFO osv;
+ osv.dwOSVersionInfoSize= sizeof (OSVERSIONINFO);
+ GetVersionEx (& osv);
+ if (osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+ creationflags|= DETACHED_PROCESS;
+ }
+ #endif
+
+ HANDLE hread;
+ create_pipe (hread, hwritepipe);
+ prwritepipe.reset (hwritepipe);
+ hreadchild= duplicate_inherit (hread, current);
+ prreadchild.reset (hreadchild);
+ start.hStdInput= hreadchild;
+ }
+
+ TRMESSAGE (tr, "Creating pipe process");
+
+ PROCESS_INFORMATION procinfo;
+ if (CreateProcess (
+ NULL, (char *) command.c_str (),
+ NULL, NULL,
+ TRUE, // Inherit handles
+ creationflags,
+ NULL, NULL, & start, & procinfo) == 0)
+ {
+ showlasterror ( ("CreateProcess " + command +
+ " failed in POPEN").c_str () );
+ throw ErrFunctionCall;
+ }
+
+ // No need to close here the child handles, ProtectHandle
+ // takes care of him.
+
+ // Release protection of the parent handles.
+ prreadpipe.release ();
+ prwritepipe.release ();
+
+ childprocess= procinfo.hProcess;
+ CloseHandle (procinfo.hThread);
+}
+
+class CriticalSection {
+public:
+ CriticalSection ()
+ {
+ InitializeCriticalSection (& object);
+ }
+ ~CriticalSection ()
+ {
+ DeleteCriticalSection (& object);
+ }
+ CriticalSection (const CriticalSection &); // Forbidden
+ void operator= (const CriticalSection &); // Forbidden
+ void enter ()
+ {
+ EnterCriticalSection (& object);
+ }
+ void leave ()
+ {
+ LeaveCriticalSection (& object);
+ }
+private:
+ CRITICAL_SECTION object;
+};
+
+class CriticalLock {
+public:
+ CriticalLock (CriticalSection & crit) :
+ crit (crit)
+ {
+ crit.enter ();
+ }
+ ~CriticalLock ()
+ {
+ crit.leave ();
+ }
+private:
+ CriticalSection & crit;
+};
+
+class Event
+{
+public:
+ Event ()
+ {
+ hevent= CreateEvent (
+ NULL, // Default security
+ FALSE, // Automatic
+ FALSE, // Initially not signaled
+ NULL // Without name
+ );
+ if (hevent == NULL)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+ }
+ ~Event ()
+ {
+ CloseHandle (hevent);
+ }
+ void wait ()
+ {
+ WaitForSingleObject (hevent, INFINITE);
+ }
+ void set ()
+ {
+ SetEvent (hevent);
+ }
+ void reset ()
+ {
+ ResetEvent (hevent);
+ }
+private:
+ HANDLE hevent;
+};
+
+} // namespace
+
+//***********************************************
+// BlFilePopenWindows
+//***********************************************
+
+class BlFilePopenWindows : public BlFilePopen {
+public:
+ BlFilePopenWindows (const std::string & str, OpenMode mode);
+ ~BlFilePopenWindows ();
+ void closein ();
+ void closeout ();
+ bool eof ();
+ void endline ();
+ std::string read (size_t n);
+ void getline (std::string & str, bool endline= true);
+ bool poll ();
+private:
+ static const size_t bufsize= 4096;
+ char buffer [bufsize];
+ size_t bufpos, bufread;
+ void readbuffer ();
+ char getcharfrombuffer ();
+
+ void read_in_thread ();
+
+ void outstring (const std::string & str);
+ void outchar (char c);
+
+ CriticalSection critical;
+ Event canread;
+ bool nowreading;
+ Event hasread;
+ HANDLE hreadpipe, hwritepipe;
+ HANDLE hprocess;
+ HANDLE hreadthread;
+ bool finishthread;
+ bool error_reading;
+ bool eof_found;
+
+ friend DWORD WINAPI thread_popen_read (LPVOID param);
+ friend class ProtectThread;
+};
+
+class ProtectThread {
+public:
+ ProtectThread (BlFilePopenWindows & popen) :
+ popen (popen),
+ released (false)
+ { }
+ ~ProtectThread ()
+ {
+ if (! released && popen.hreadthread != NULL)
+ {
+ popen.finishthread= true;
+ ResumeThread (popen.hreadthread);
+ CloseHandle (popen.hreadthread);
+ }
+ }
+ void release ()
+ {
+ released= true;
+ }
+private:
+ BlFilePopenWindows & popen;
+ bool released;
+};
+
+DWORD WINAPI thread_popen_read (LPVOID param)
+{
+ BlFilePopenWindows & popen= *
+ reinterpret_cast <BlFilePopenWindows *> (param);
+ if (popen.finishthread)
+ return 0;
+
+ try
+ {
+ popen.read_in_thread ();
+ }
+ catch (...)
+ {
+ popen.error_reading= true;
+ popen.nowreading= false;
+ popen.hasread.set ();
+ }
+
+ return 0;
+}
+
+BlFilePopenWindows::BlFilePopenWindows
+ (const std::string & str, OpenMode nmode) :
+ BlFilePopen (nmode)
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::BlFilePopenWindows");
+
+ hprocess= INVALID_HANDLE_VALUE;
+ hreadpipe= INVALID_HANDLE_VALUE;
+ hwritepipe= INVALID_HANDLE_VALUE;
+ hreadthread= NULL;
+ nowreading= false;
+ finishthread= false;
+ error_reading= false;
+ eof_found= false;
+
+ if (forread)
+ {
+ DWORD idthread;
+ hreadthread= CreateThread (NULL, 1024,
+ thread_popen_read, this,
+ CREATE_SUSPENDED, & idthread);
+ if (hreadthread == NULL)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+ }
+ ProtectThread protect (* this);
+ launchchild (str, forread, forwrite, witherr,
+ hreadpipe, hwritepipe, hprocess);
+ if (forread)
+ {
+ ResumeThread (hreadthread);
+ nowreading= true;
+ canread.set ();
+ }
+ protect.release ();
+}
+
+BlFilePopenWindows::~BlFilePopenWindows ()
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::~BlFilePopenWindows");
+
+ // This is to workaround errors in C++ Builder.
+ if (hprocess == INVALID_HANDLE_VALUE)
+ return;
+
+ if (hreadthread != NULL)
+ {
+ finishthread= true;
+ CloseHandle (hreadthread);
+ hreadthread= NULL;
+ nowreading= true;
+ hasread.reset ();
+ canread.set ();
+ }
+ // Close the pipe before wait for termination,
+ // the child process can be waiting for
+ // input.
+ //CloseHandle (hpipe);
+ if (hreadpipe != INVALID_HANDLE_VALUE)
+ CloseHandle (hreadpipe);
+ if (hwritepipe != INVALID_HANDLE_VALUE)
+ CloseHandle (hwritepipe);
+
+ WaitForSingleObject (hprocess, INFINITE);
+ DWORD exitcode;
+ BOOL r= GetExitCodeProcess (hprocess, & exitcode);
+ if (r == 0)
+ {
+ showlasterror ();
+ }
+ CloseHandle (hprocess);
+ if (r == 0)
+ {
+ throw ErrOperatingSystem;
+ }
+ TRMESSAGE (tr, "Exit code: " + to_string (exitcode) );
+ sysvar::set (sysvar::ShellResult,
+ static_cast <BlChar> (exitcode & 0xFF) );
+}
+
+char BlFilePopenWindows::getcharfrombuffer ()
+{
+ {
+ CriticalLock lock (critical);
+ if (bufpos < bufread)
+ return buffer [bufpos++];
+ }
+
+ if (error_reading)
+ throw ErrOperatingSystem;
+ if (eof_found)
+ return 0;
+
+ readbuffer ();
+ hasread.wait ();
+
+ if (error_reading)
+ throw ErrOperatingSystem;
+ if (eof_found)
+ return 0;
+
+ return buffer [bufpos++];
+}
+
+void BlFilePopenWindows::closein ()
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::closein");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+ finishthread= true;
+ CloseHandle (hreadpipe);
+ hreadpipe= INVALID_HANDLE_VALUE;
+
+ critical.enter ();
+ nowreading= true;
+ hasread.reset ();
+ canread.set ();
+ critical.leave ();
+
+ CloseHandle (hreadthread);
+ hreadthread= INVALID_HANDLE_VALUE;
+}
+
+void BlFilePopenWindows::closeout ()
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::closeout");
+
+ if (! getmode () & Output)
+ throw ErrFileMode;
+ CloseHandle (hwritepipe);
+ hwritepipe= INVALID_HANDLE_VALUE;
+}
+
+bool BlFilePopenWindows::eof ()
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::eof");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ {
+ CriticalLock lock (critical);
+ if (bufpos < bufread)
+ return false;
+ }
+
+ readbuffer ();
+ hasread.wait ();
+
+ if (error_reading)
+ throw ErrOperatingSystem;
+ if (!eof_found)
+ {
+ ASSERT (bufpos < bufread);
+ }
+ return eof_found;
+}
+
+void BlFilePopenWindows::endline ()
+{
+ outstring ("\r\n");
+}
+
+std::string BlFilePopenWindows::read (size_t n)
+{
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ std::string str;
+ for (size_t i= 0; i < n; ++i)
+ {
+ char c= getcharfrombuffer ();
+ if (c == 0 && eof_found)
+ break;
+ str+= c;
+ }
+ return str;
+}
+
+void BlFilePopenWindows::getline (std::string & str, bool)
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::getline");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ str= std::string ();
+ char c;
+ while ( (c= getcharfrombuffer () ) != '\r' && c != '\n')
+ {
+ if (c == 0)
+ {
+ if (eof_found)
+ {
+ if (str.empty () )
+ throw ErrPastEof;
+ else
+ break;
+ }
+ }
+ else
+ str+= c;
+ }
+
+ if (c == '\r')
+ getcharfrombuffer ();
+}
+
+void BlFilePopenWindows::readbuffer ()
+{
+ if (finishthread | error_reading | eof_found)
+ return;
+ CriticalLock lock (critical);
+ if (nowreading)
+ return;
+ nowreading= true;
+ hasread.reset ();
+ canread.set ();
+}
+
+void BlFilePopenWindows::read_in_thread ()
+{
+ do
+ {
+ canread.wait ();
+ if (finishthread)
+ break;
+ if (hreadpipe == INVALID_HANDLE_VALUE)
+ break;
+ DWORD bytesread= 0;
+ if (ReadFile (hreadpipe, buffer, bufsize, & bytesread, NULL) == 0)
+ {
+ DWORD r= GetLastError ();
+ if (r != ERROR_BROKEN_PIPE)
+ {
+ error_reading= true;
+ }
+ else
+ {
+ eof_found= true;
+ }
+
+ CriticalLock lock (critical);
+ nowreading= false;
+ }
+ else
+ {
+ CriticalLock lock (critical);
+ if (bytesread == 0)
+ {
+ // This is not supposed to happen
+ // in an anonymous pipe.
+ error_reading= true;
+ }
+ bufpos= 0;
+ bufread= bytesread;
+ nowreading= false;
+ }
+ hasread.set ();
+ } while (! error_reading & ! eof_found & ! finishthread);
+}
+
+void BlFilePopenWindows::outstring (const std::string & str)
+{
+ TRACEFUNC (tr, "BlFilePopenWindows::outstring");
+
+ if (! getmode () & Output)
+ throw ErrFileMode;
+
+ const char * to= str.data ();
+ std::string::size_type l= str.size ();
+ DWORD written;
+ //WriteFile (hpipe, to, l, & written, NULL);
+ if (WriteFile (hwritepipe, to, l, & written, NULL) == 0)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+void BlFilePopenWindows::outchar (char c)
+{
+ if (! getmode () & Output)
+ throw ErrFileMode;
+
+ DWORD written;
+ //WriteFile (hpipe, & c, 1, & written, NULL);
+ if (WriteFile (hwritepipe, & c, 1, & written, NULL) == 0)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+bool BlFilePopenWindows::poll ()
+{
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ {
+ CriticalLock lock (critical);
+ if (bufpos < bufread)
+ return true;
+ }
+
+ readbuffer ();
+
+ return false;
+}
+
+#else
+// No Windows
+
+//***********************************************
+// Auxiliary functions and classes for unix
+//***********************************************
+
+namespace {
+
+class ProtectHandle {
+public:
+ ProtectHandle (int handle) :
+ handle (handle)
+ { }
+ ~ProtectHandle ()
+ {
+ close ();
+ }
+ void close ()
+ {
+ if (handle != -1)
+ {
+ ::close (handle);
+ handle= -1;
+ }
+ }
+ void release ()
+ {
+ handle= -1;
+ }
+private:
+ int handle;
+};
+
+void exec_command (const std::string & str)
+{
+ const char * strShell= getenv ("SHELL");
+ if (! strShell)
+ strShell= "/bin/sh";
+
+ execlp (strShell, strShell, "-c",
+ str.c_str (), (char *) 0);
+
+ // If something fails:
+ exit (127);
+}
+
+void createpipe (int & hread, int & hwrite)
+{
+ int handlepair [2];
+ if (pipe (handlepair) != 0)
+ {
+ showlasterror ("Creating pipe");
+ throw ErrOperatingSystem;
+ }
+ hread= handlepair [0];
+ hwrite= handlepair [1];
+}
+
+void duporfail (int oldfd, int newfd)
+{
+ if (dup2 (oldfd, newfd) == -1)
+ exit (127);
+}
+
+void stdtonull ()
+{
+ int newstd= open ("/dev/null", O_RDWR);
+ if (newstd == -1)
+ exit (127);
+ duporfail (newstd, STDIN_FILENO);
+ duporfail (newstd, STDOUT_FILENO);
+ duporfail (newstd, STDERR_FILENO);
+ close (newstd);
+}
+
+void launchchild (const std::string & str,
+ bool forread, bool forwrite, bool witherr,
+ int & readhandle, int & writehandle, pid_t & childpid)
+{
+ TRACEFUNC (tr, "launchchild");
+
+ if (! forread && ! forwrite)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ int writechild= -1;
+ if (forread)
+ createpipe (readhandle, writechild);
+ ProtectHandle prrhandle (readhandle);
+ ProtectHandle prwchild (writechild);
+
+ int readchild= -1;
+ if (forwrite)
+ createpipe (readchild, writehandle);
+ ProtectHandle prwhandle (writehandle);
+ ProtectHandle prrchild (readchild);
+
+ childpid= fork ();
+ switch (childpid)
+ {
+ case pid_t (-1):
+ // Fork has failed.
+ showlasterror ();
+ throw ErrOperatingSystem;
+ case pid_t (0):
+ // Child process.
+ // No need to take care of handles in case of fail
+ // here, the process will be terminated.
+ stdtonull ();
+ if (forread)
+ {
+ prrhandle.close ();
+ duporfail (writechild, STDOUT_FILENO);
+ if (witherr)
+ duporfail (writechild, STDERR_FILENO);
+ prwchild.close ();
+ }
+ if (forwrite)
+ {
+ prwhandle.close ();
+ duporfail (readchild, STDIN_FILENO);
+ prrchild.close ();
+ }
+ exec_command (str);
+ break; // To avoid warnings.
+ default:
+ // Parent process.
+ if (forread)
+ {
+ prwchild.close ();
+ prrhandle.release ();
+ }
+ if (forwrite)
+ {
+ prrchild.close ();
+ prwhandle.release ();
+ }
+ }
+}
+
+} // namespace
+
+//***********************************************
+// BlFilePopenUnix
+//***********************************************
+
+class BlFilePopenUnix : public BlFilePopen {
+public:
+ BlFilePopenUnix (const std::string & str, OpenMode mode);
+ ~BlFilePopenUnix ();
+ void closein ();
+ void closeout ();
+ bool eof ();
+ void endline ();
+ std::string read (size_t n);
+ void getline (std::string & str, bool endline= true);
+ bool poll ();
+private:
+ static const size_t bufsize= 4096;
+ char buffer [bufsize];
+ size_t bufpos, bufread;
+ void readbuffer ();
+ char getcharfrombuffer ();
+ size_t do_readbuffer (char * buffer, size_t bytes);
+
+ void closeread ();
+ void closewrite ();
+ void outstring (const std::string & str);
+ void outchar (char c);
+
+ int readhandle;
+ int writehandle;
+ pid_t childpid;
+};
+
+BlFilePopenUnix::BlFilePopenUnix
+ (const std::string & str, OpenMode nmode) :
+ BlFilePopen (nmode)
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::BlFilePopenUnix");
+ TRMESSAGE (tr, str);
+
+ readhandle= -1;
+ writehandle= -1;
+ childpid= -1;
+
+ launchchild (str, forread, forwrite, witherr,
+ readhandle, writehandle, childpid);
+}
+
+BlFilePopenUnix::~BlFilePopenUnix ()
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::~BlFilePopenUnix");
+
+ // First close the pipes, the child can be waiting for input.
+ closeread ();
+ closewrite ();
+
+ int status;
+ if (waitpid (childpid, & status, 0) == -1 || ! WIFEXITED (status) )
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+ TRMESSAGE (tr, "Exit code: " + to_string (WEXITSTATUS (status) ) );
+ sysvar::set (sysvar::ShellResult, WEXITSTATUS (status) );
+}
+
+char BlFilePopenUnix::getcharfrombuffer ()
+{
+ if (bufpos >= bufread)
+ {
+ readbuffer ();
+ if (bufread == 0)
+ return '\0';
+ }
+ return buffer [bufpos++];
+}
+
+void BlFilePopenUnix::closein ()
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::closein");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ closeread ();
+}
+
+void BlFilePopenUnix::closeout ()
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::closeout");
+
+ if (! getmode () & Output)
+ throw ErrFileMode;
+
+ closewrite ();
+}
+
+bool BlFilePopenUnix::eof ()
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::eof");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ if (bufpos < bufread)
+ return false;
+ readbuffer ();
+ return bufread == 0;
+}
+
+void BlFilePopenUnix::endline ()
+{
+ outchar ('\n');
+}
+
+std::string BlFilePopenUnix::read (size_t n)
+{
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ std::string str;
+ for (size_t i= 0; i < n; ++i)
+ {
+ char c= getcharfrombuffer ();
+ if (c == '\0')
+ {
+ if (eof () )
+ break;
+ else
+ str+= c;
+ }
+ else
+ str+= c;
+ }
+ return str;
+}
+
+void BlFilePopenUnix::getline (std::string & str, bool)
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::getline");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+
+ str= std::string ();
+ char c;
+ while ( (c= getcharfrombuffer () ) != '\r' && c != '\n')
+ {
+ if (c == '\0')
+ {
+ if (eof () )
+ {
+ if (str.empty () )
+ throw ErrPastEof;
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else
+ str+= c;
+ }
+}
+
+void BlFilePopenUnix::closeread ()
+{
+ if (readhandle != -1)
+ {
+ close (readhandle);
+ readhandle= -1;
+ }
+}
+
+void BlFilePopenUnix::closewrite ()
+{
+ if (writehandle != -1)
+ {
+ close (writehandle);
+ writehandle= -1;
+ }
+}
+
+void BlFilePopenUnix::readbuffer ()
+{
+ bufpos= 0;
+ bufread= do_readbuffer (buffer, bufsize);
+}
+
+size_t BlFilePopenUnix::do_readbuffer (char * buffer, size_t bytes)
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::do_readbuffer");
+
+ size_t bytesread= ::read (readhandle, buffer, bytes);
+ if (bytesread == size_t (-1) )
+ bytesread= 0;
+ return bytesread;
+}
+
+void BlFilePopenUnix::outstring (const std::string & str)
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::outstring");
+
+ if (! getmode () & Output)
+ throw ErrFileMode;
+
+ const char * to= str.data ();
+ std::string::size_type l= str.size ();
+ if (write (writehandle, to, l) == -1)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+void BlFilePopenUnix::outchar (char c)
+{
+ if (! getmode () & Output)
+ throw ErrFileMode;
+
+ if (write (writehandle, & c, 1) == -1)
+ {
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+bool BlFilePopenUnix::poll ()
+{
+ TRACEFUNC (tr, "BlFilePopenUnix::poll");
+
+ if (! getmode () & Input)
+ throw ErrFileMode;
+ struct pollfd data [1];
+ data [0].fd= readhandle;
+ data [0].events= POLLIN | POLLPRI;
+ switch (::poll (data, 1, 0) )
+ {
+ case 0:
+ return false;
+ case 1:
+ return true;
+ default:
+ showlasterror ();
+ throw ErrOperatingSystem;
+ }
+}
+
+#endif
+// Windows or unix
+
+//***********************************************
+// newBlFilePopen
+//***********************************************
+
+BlFile * newBlFilePopen (const std::string & name, OpenMode mode)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ return new BlFilePopenWindows (name, mode);
+
+ #else
+
+ return new BlFilePopenUnix (name, mode);
+
+ #endif
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// End of filepopen.cpp
diff --git a/fileprinter.cpp b/fileprinter.cpp
new file mode 100644
index 0000000..96d2a15
--- /dev/null
+++ b/fileprinter.cpp
@@ -0,0 +1,684 @@
+// fileprinter.cpp
+// Revision 9-jan-2005
+
+#include "file.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "sysvar.h"
+#include "showerror.h"
+
+#include "trace.h"
+
+// para strerror (errno)
+//#include <string.h>
+//#include <errno.h>
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#include <memory>
+using std::auto_ptr;
+
+#include <cassert>
+#define ASSERT assert
+
+#ifdef BLASSIC_USE_WINDOWS
+
+#include <windows.h>
+#undef min
+#undef max
+
+#else
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#endif
+
+//***********************************************
+// Auxiliary functions
+//***********************************************
+
+namespace {
+
+#ifdef BLASSIC_USE_WINDOWS
+
+class GuardCharp {
+public:
+ GuardCharp (char * pc) :
+ pc (pc)
+ { }
+ ~GuardCharp ()
+ {
+ delete [] pc;
+ }
+private:
+ char * pc;
+};
+
+class GuardHMODULE {
+public:
+ GuardHMODULE (HMODULE h) :
+ h (h)
+ { }
+ ~GuardHMODULE ()
+ {
+ FreeLibrary (h);
+ }
+private:
+ HMODULE h;
+};
+
+class GuardHPRINTER {
+public:
+ GuardHPRINTER (HANDLE h) :
+ h (h)
+ { }
+ ~GuardHPRINTER ()
+ {
+ ClosePrinter (h);
+ }
+private:
+ HANDLE h;
+};
+
+std::string getdefaultprinter ()
+{
+ // This routine is based in several founded on the web,
+ // correcting several errors and adapted to C++.
+ OSVERSIONINFO osv;
+ osv.dwOSVersionInfoSize= sizeof (OSVERSIONINFO);
+ GetVersionEx (& osv);
+ switch (osv.dwPlatformId)
+ {
+ case VER_PLATFORM_WIN32_WINDOWS:
+ // Windows 95 or 98, use EnumPrinters
+ {
+ SetLastError (0);
+ DWORD dwNeeded= 0, dwReturned= 0;
+ EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 2,
+ NULL, 0, & dwNeeded, & dwReturned);
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER ||
+ dwNeeded == 0)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "EnumPrinters get buffer "
+ "failed" <<
+ endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal; // Provisional
+ }
+ char * aux= new char [dwNeeded];
+ GuardCharp guardcharp (aux);
+ PRINTER_INFO_2 * ppi2=
+ reinterpret_cast <PRINTER_INFO_2 *> (aux);
+ if (! EnumPrinters (PRINTER_ENUM_DEFAULT, NULL, 2,
+ (LPBYTE) ppi2, dwNeeded,
+ &dwNeeded, & dwReturned) )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "EnumPrinters failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal; // Provisional
+ }
+ return ppi2->pPrinterName;
+ }
+ case VER_PLATFORM_WIN32_NT:
+ if (osv.dwMajorVersion >= 5) // Windows 2000 or later
+ {
+ HMODULE hWinSpool= LoadLibrary ("winspool.drv");
+ if (! hWinSpool)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "LoadLibrary failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ GuardHMODULE guardh (hWinSpool);
+ #ifdef UNICODE
+ static const TCHAR GETDEFAULTPRINTER []=
+ "GetDefaultPrinterW";
+ #else
+ static const TCHAR GETDEFAULTPRINTER []=
+ "GetDefaultPrinterA";
+ #endif
+ PROC fnGetDefaultPrinter= GetProcAddress (hWinSpool,
+ GETDEFAULTPRINTER);
+ if (! fnGetDefaultPrinter)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "GetProcAddress failed" <<
+ endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ typedef BOOL (* GetDefaultPrinter_t) (LPTSTR, LPDWORD);
+ GetDefaultPrinter_t callGetDefaultPrinter=
+ (GetDefaultPrinter_t) fnGetDefaultPrinter;
+ DWORD dwBufferLength= 0;
+ SetLastError (0);
+ callGetDefaultPrinter (NULL, & dwBufferLength);
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "GetDefaultPrinter get buffer "
+ "failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ char * buffer= new char [dwBufferLength];
+ GuardCharp guardcharp (buffer);
+ if (! callGetDefaultPrinter
+ (buffer, & dwBufferLength) )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "GetDefaultPrinter failed" <<
+ endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ return std::string (buffer);
+ }
+ else // NT 4.0 or earlier
+ {
+ const DWORD MAXBUFFERSIZE= 250;
+ TCHAR cBuffer [MAXBUFFERSIZE];
+ if (GetProfileString ("windows", "device", ",,,",
+ cBuffer, MAXBUFFERSIZE) <= 0)
+ {
+ if (showdebuginfo () )
+ cerr << "GetProfileString failed" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ strtok (cBuffer, ",");
+ return std::string (cBuffer);
+ }
+ default:
+ ASSERT (false);
+ return std::string (); // Make the compiler happy.
+ }
+}
+
+#else
+
+class GuardHandle {
+public:
+ GuardHandle (int handle) :
+ handle (handle)
+ {
+ TRACEFUNC (tr, "GuardHandle::GuardHandle");
+
+ if (handle == -1)
+ {
+ if (showdebuginfo () )
+ cerr << "GuardHandle with invalid handle" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ }
+ ~GuardHandle ()
+ {
+ do_close (true);
+ }
+ void close ()
+ {
+ do_close (false);
+ }
+private:
+ void do_close (bool destructing)
+ {
+ TRACEFUNC (tr, "GuardHandle::do_close");
+
+ if (handle != CLOSED)
+ {
+ int aux= handle;
+ handle= CLOSED;
+ if (::close (aux) != 0)
+ {
+ // Problem: this message can be lost because
+ // stdeerr may be redirected to null when
+ // using this.
+
+ #if 0
+ const char * message= strerror (errno);
+ TRMESSAGE (tr, message);
+ if (showdebuginfo () )
+ cerr << "Error closing handle: " <<
+ message << endl;
+ #else
+
+ showlasterror ("Error closing handle");
+
+ #endif
+
+ if (! destructing)
+ throw ErrBlassicInternal;
+ }
+ }
+ }
+
+ static const int CLOSED= -1;
+ int handle;
+};
+
+class Dup2Save {
+ // Checks are not done because the functions can fail
+ // if Blassic is running in detached mode.
+ // More work required to make checks that works in
+ // all cases.
+public:
+ Dup2Save (int newhandle, int oldhandle) :
+ oldhandle (oldhandle)
+ {
+ savedhandle= dup (oldhandle);
+ dup2 (newhandle, oldhandle);
+ }
+ ~Dup2Save ()
+ {
+ release ();
+ }
+ void release ()
+ {
+ if (savedhandle != RELEASED)
+ {
+ dup2 (savedhandle, oldhandle);
+ close (savedhandle);
+ savedhandle= RELEASED;
+ }
+ }
+private:
+ static const int RELEASED= -1;
+ int oldhandle;
+ int savedhandle;
+};
+
+#endif
+
+} // namespace
+
+namespace blassic {
+
+namespace file {
+
+class BlFilePrinter : public BlFile {
+public:
+ BlFilePrinter ();
+ ~BlFilePrinter ();
+ bool isfile () const { return false; }
+ void flush ();
+ size_t getwidth () const;
+ void tab ();
+ void tab (size_t n);
+ void endline ();
+ void setwidth (size_t w);
+ void setmargin (size_t m);
+private:
+ void outstring (const std::string & str);
+ void outchar (char c);
+
+ class Internal;
+ Internal * pin;
+};
+
+//***********************************************
+// BlFilePrinter::Internal
+//***********************************************
+
+class BlFilePrinter::Internal {
+public:
+ Internal () :
+ pos (0),
+ width (80),
+ margin (0)
+ { }
+ ~Internal ();
+ void close ();
+ size_t getwidth () const { return width; }
+ void checkmargin ();
+ void tab ();
+ void tab (size_t n);
+ void endline ();
+ void outstring (std::string str);
+ void outchar (char c);
+ void setwidth (size_t w)
+ { width= w; }
+ void setmargin (size_t m)
+ { margin= m - 1; }
+private:
+ void do_printing (const char * printcommand);
+
+ std::string text;
+ size_t pos;
+ size_t width;
+ size_t margin;
+};
+
+BlFilePrinter::Internal::~Internal ()
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::~Internal");
+
+ try
+ {
+ close ();
+ }
+ catch (...)
+ {
+ if (showdebuginfo () )
+ cerr << "Error closing printer buffer" << endl;
+ }
+}
+
+void BlFilePrinter::Internal::close ()
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::close");
+
+ static const char blassic_print_command []= "BLASSIC_PRINT_COMMAND";
+
+ // Print only if there is somethnig to print.
+ if (text.empty () )
+ {
+ TRMESSAGE (tr, "Nothing to print.");
+ return;
+ }
+ TRMESSAGE (tr, "Begin printing");
+
+ const char * printcommand= getenv (blassic_print_command);
+ do_printing (printcommand);
+}
+
+
+
+#ifdef BLASSIC_USE_WINDOWS
+
+void BlFilePrinter::Internal::do_printing (const char * printcommand)
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::do_printing");
+
+ if (printcommand != NULL)
+ {
+ TRMESSAGE (tr, std::string ("Popening to ") + printcommand);
+ //BlFilePopen bfp (printcommand, Output);
+ //bfp << text;
+ auto_ptr <BlFile> pbfp (newBlFilePopen (printcommand, Output) );
+ * pbfp << text;
+ return;
+ }
+
+ std::string printername= getdefaultprinter ();
+ TRMESSAGE (tr, std::string ("Printer is ") + printername);
+
+ HANDLE hPrinter;
+ if (! OpenPrinter ( (char *) printername.c_str (), & hPrinter, NULL) )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "OpenPrinter failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ GuardHPRINTER guardhprinter (hPrinter);
+ DOC_INFO_1 doc_info;
+ doc_info.pDocName= (char *) "Blassic printing output";
+ doc_info.pOutputFile= NULL;
+ doc_info.pDatatype= NULL;
+ DWORD jobid= StartDocPrinter (hPrinter, 1, (LPBYTE) & doc_info);
+ if (jobid == 0)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "StartDocPrinter failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ DWORD written= 0;
+ WritePrinter (hPrinter, (void *) text.data (), text.size (),
+ & written);
+ if (written != text.size () )
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "WritePrinter failed" << endl;
+ showlasterror ();
+ }
+ throw ErrBlassicInternal;
+ }
+ EndDocPrinter (hPrinter);
+ // ClosePrinter is done by the guard.
+}
+
+#else
+
+void BlFilePrinter::Internal::do_printing (const char * printcommand)
+{
+ TRACEFUNC (tr, "BlFilePrinter::Internal::do_printing");
+
+ if (printcommand == NULL)
+ printcommand= "lp";
+
+ FILE * f;
+
+ // Block opened to automatically restore
+ // saved handles when closing it.
+ {
+ // Redirect standard handles not used to /dev/null
+ int newstd= open ("/dev/null", O_RDWR);
+ if (newstd == -1)
+ {
+ #if 0
+ if (showdebuginfo () )
+ cerr << "open /dev/null failed: " <<
+ strerror (errno) << endl;
+ #else
+
+ showlasterror ("open /dev/null failed");
+
+ #endif
+
+ throw ErrFunctionCall;
+ }
+
+ // Save standard handles not used
+ #if 0
+ int savestdout= dup (STDOUT_FILENO);
+ int savestderr= dup (STDERR_FILENO);
+
+ dup2 (newstd, STDOUT_FILENO);
+ dup2 (newstd, STDERR_FILENO);
+ ::close (newstd);
+ #else
+ GuardHandle guardnew (newstd);
+ Dup2Save saveout (newstd, STDOUT_FILENO);
+ Dup2Save saveerr (newstd, STDERR_FILENO);
+ guardnew.close ();
+ #endif
+
+ f= popen (printcommand, "w");
+
+ #if 0
+ // Restore saved standard handles
+ dup2 (savestdout, STDOUT_FILENO);
+ dup2 (savestderr, STDERR_FILENO);
+ ::close (savestdout);
+ ::close (savestderr);
+ #endif
+ }
+
+ if (f == NULL)
+ {
+ if (showdebuginfo () )
+ cerr << "Error in popen print command" << endl;
+ throw ErrBlassicInternal;
+ }
+ size_t size= text.size ();
+ size_t written= write (fileno (f), text.data (), size);
+ if (written != size)
+ showlasterror ("Error writing to print command");
+ pclose (f);
+}
+
+#endif
+
+void BlFilePrinter::Internal::checkmargin ()
+{
+ if (pos == 0)
+ text+= std::string (margin, ' ');
+}
+
+void BlFilePrinter::Internal::tab ()
+{
+ size_t zone= sysvar::get16 (sysvar::Zone);
+ if (zone == 0)
+ {
+ outchar ('\t');
+ return;
+ }
+ if (width > 0 && pos >= (width / zone) * zone)
+ endline ();
+ else
+ {
+ do
+ {
+ outchar (' ');
+ } while (pos % zone);
+ }
+}
+
+void BlFilePrinter::Internal::tab (size_t n)
+{
+ if (pos > n)
+ endline ();
+ size_t maxpos= std::min (width, n);
+ while (pos < maxpos)
+ outchar (' ');
+}
+
+void BlFilePrinter::Internal::endline ()
+{
+ switch (sysvar::get (sysvar::PrinterLine) )
+ {
+ case 0:
+ text+= '\n'; break;
+ case 1:
+ text+= "\r\n"; break;
+ case 2:
+ text+= '\r'; break;
+ }
+ pos= 0;
+}
+
+void BlFilePrinter::Internal::outstring (std::string str)
+{
+ if (width > 0)
+ {
+ size_t l= str.size ();
+ while (pos + l > width)
+ {
+ checkmargin ();
+ text+= str.substr (0, width - pos);
+ str.erase (0, width - pos);
+ endline ();
+ l= str.size ();
+ }
+ }
+ checkmargin ();
+ text+= str;
+ pos+= str.size ();
+}
+
+void BlFilePrinter::Internal::outchar (char c)
+{
+ if (width > 0 && pos>= width)
+ endline ();
+ checkmargin ();
+ text+= c;
+ ++pos;
+}
+
+//***********************************************
+// BlFilePrinter
+//***********************************************
+
+BlFile * newBlFilePrinter ()
+{
+ return new BlFilePrinter;
+}
+
+BlFilePrinter::BlFilePrinter () :
+ BlFile (Output),
+ pin (new Internal)
+{ }
+
+BlFilePrinter::~BlFilePrinter ()
+{
+ delete pin;
+}
+
+void BlFilePrinter::flush ()
+{
+}
+
+size_t BlFilePrinter::getwidth () const
+{
+ return pin->getwidth ();
+}
+
+void BlFilePrinter::tab ()
+{
+ pin->tab ();
+}
+
+void BlFilePrinter::tab (size_t n)
+{
+ pin->tab (n);
+}
+
+void BlFilePrinter::endline ()
+{
+ pin->endline ();
+}
+
+void BlFilePrinter::outstring (const std::string & str)
+{
+ pin->outstring (str);
+}
+
+void BlFilePrinter::outchar (char c)
+{
+ pin->outchar (c);
+}
+
+void BlFilePrinter::setwidth (size_t w)
+{
+ pin->setwidth (w);
+}
+
+void BlFilePrinter::setmargin (size_t m)
+{
+ pin->setmargin (m);
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// End of fileprinter.cpp
diff --git a/filesocket.cpp b/filesocket.cpp
new file mode 100644
index 0000000..3ba37e6
--- /dev/null
+++ b/filesocket.cpp
@@ -0,0 +1,152 @@
+// filesocket.cpp
+// Revision 9-jan-2005
+
+//#include "filesocket.h"
+#include "file.h"
+
+#include "socket.h"
+#include "util.h"
+
+#include "trace.h"
+
+namespace blassic {
+
+namespace file {
+
+class BlFileSocket : public BlFile {
+public:
+ BlFileSocket (const std::string & host, short port);
+ ~BlFileSocket ();
+ bool isfile () const { return true; }
+ void getline (std::string & str, bool endline= true);
+ bool eof ();
+ void flush ();
+ std::string read (size_t n);
+private:
+ void outstring (const std::string & str);
+ void outchar (char c);
+
+ class Internal;
+ Internal * pin;
+};
+
+//***********************************************
+// BlFileSocket::Internal
+//***********************************************
+
+class BlFileSocket::Internal
+{
+ TcpSocketClient socket;
+public:
+ Internal (const std::string & host, short port);
+ ~Internal ();
+ void getline (std::string & str, bool endline);
+ bool eof ();
+ void flush ();
+ std::string read (size_t n);
+ void outstring (const std::string & str);
+ void outchar (char c);
+private:
+ Internal (const Internal &); // Forbidden
+ void operator = (const Internal &); // Forbidden
+};
+
+BlFileSocket::Internal::Internal (const std::string & host, short port) :
+ socket (host, port)
+{
+}
+
+BlFileSocket::Internal::~Internal ()
+{
+ TRACEFUNC (tr, "BlFileSocke::Internal::~Internal");
+}
+
+bool BlFileSocket::Internal::eof ()
+{
+ return socket.eof ();
+}
+
+void BlFileSocket::Internal::flush ()
+{
+ // There is no work to do.
+}
+
+void BlFileSocket::Internal::getline (std::string & str, bool)
+{
+ str= socket.readline ();
+}
+
+std::string BlFileSocket::Internal::read (size_t n)
+{
+ util::auto_buffer <char> buf (n);
+ int r= socket.read (buf, n);
+ std::string result;
+ if (r > 0)
+ result.assign (buf, r);
+ return result;
+}
+
+void BlFileSocket::Internal::outstring (const std::string & str)
+{
+ socket.write (str);
+}
+
+void BlFileSocket::Internal::outchar (char c)
+{
+ socket.write (& c, 1);
+}
+
+//***********************************************
+// BlFileSocket
+//***********************************************
+
+BlFile * newBlFileSocket (const std::string & host, short port)
+{
+ return new BlFileSocket (host, port);
+}
+
+BlFileSocket::BlFileSocket (const std::string & host, short port) :
+ BlFile (OpenMode (Input | Output) ),
+ pin (new Internal (host, port) )
+{ }
+
+BlFileSocket::~BlFileSocket ()
+{
+ delete pin;
+}
+
+bool BlFileSocket::eof ()
+{
+ return pin->eof ();
+}
+
+void BlFileSocket::flush ()
+{
+ pin->flush ();
+}
+
+void BlFileSocket::getline (std::string & str, bool endline)
+{
+ pin->getline (str, endline);
+}
+
+std::string BlFileSocket::read (size_t n)
+{
+ return pin->read (n);
+}
+
+void BlFileSocket::outstring (const std::string & str)
+{
+ pin->outstring (str);
+}
+
+void BlFileSocket::outchar (char c)
+{
+ pin->outchar (c);
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// End of filesocket.cpp
diff --git a/filewindow.cpp b/filewindow.cpp
new file mode 100644
index 0000000..817637d
--- /dev/null
+++ b/filewindow.cpp
@@ -0,0 +1,332 @@
+// filewindow.cpp
+// Revision 23-jan-2005
+
+#include "file.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "graphics.h"
+#include "edit.h"
+
+#include "trace.h"
+
+namespace blassic {
+
+namespace file {
+
+//***********************************************
+// BlFileWindow
+//***********************************************
+
+class BlFileWindow : public BlFile {
+public:
+ BlFileWindow (BlChannel ch);
+ BlFileWindow (BlChannel ch, int x1, int x2, int y1, int y2);
+ ~BlFileWindow ();
+ void reset (int x1, int x2, int y1, int y2);
+ bool isfile () const;
+ bool istextwindow () const;
+ virtual bool eof ();
+ virtual void flush ();
+ virtual size_t getwidth () const;
+ virtual void movecharforward ();
+ virtual void movecharforward (size_t n);
+ virtual void movecharback ();
+ virtual void movecharback (size_t n);
+ virtual void movecharup ();
+ virtual void movecharup (size_t n);
+ virtual void movechardown ();
+ virtual void movechardown (size_t n);
+ virtual void showcursor ();
+ virtual void hidecursor ();
+ virtual std::string getkey ();
+ virtual std::string inkey ();
+ void getline (std::string & str, bool endline= true);
+ std::string read (size_t n);
+ void tab ();
+ void tab (size_t n);
+ void endline ();
+ void gotoxy (int x, int y);
+ virtual void setcolor (int color);
+ virtual int getcolor ();
+ virtual void setbackground (int color);
+ virtual int getbackground ();
+ virtual void cls ();
+ std::string copychr (BlChar from, BlChar to);
+ int pos ();
+ int vpos ();
+ void tag ();
+ void tagoff ();
+ bool istagactive ();
+ void inverse (bool active);
+ bool getinverse ();
+ void bright (bool active);
+ bool getbright ();
+ bool poll ();
+ void scroll (int nlines);
+private:
+ void outstring (const std::string & str);
+ void outchar (char c);
+
+ BlChannel ch;
+};
+
+BlFile * newBlFileWindow (BlChannel ch)
+{
+ return new BlFileWindow (ch);
+}
+
+BlFile * newBlFileWindow (BlChannel ch, int x1, int x2, int y1, int y2)
+{
+ return new BlFileWindow (ch, x1, x2, y1, y2);
+}
+
+BlFileWindow::BlFileWindow (BlChannel ch) :
+ BlFile (OpenMode (Input | Output) ),
+ ch (ch)
+{
+ if (ch != 0)
+ throw ErrBlassicInternal;
+}
+
+BlFileWindow::BlFileWindow (BlChannel ch, int x1, int x2, int y1, int y2) :
+ BlFile (OpenMode (Input | Output) ),
+ ch (ch)
+{
+ graphics::definewindow (ch, x1, x2, y1, y2);
+}
+
+BlFileWindow::~BlFileWindow ()
+{
+ graphics::undefinewindow (ch);
+}
+
+void BlFileWindow::reset (int x1, int x2, int y1, int y2)
+{
+ graphics::definewindow (ch, x1, x2, y1, y2);
+}
+
+bool BlFileWindow::isfile () const
+{
+ return false;
+}
+
+bool BlFileWindow::istextwindow () const
+{
+ return true;
+}
+
+bool BlFileWindow::eof ()
+{
+ return false;
+}
+
+void BlFileWindow::flush ()
+{
+ // Nothing to do
+}
+
+size_t BlFileWindow::getwidth () const
+{
+ return graphics::getlinewidth (ch);
+}
+
+void BlFileWindow::movecharforward ()
+{
+ graphics::movecharforward (ch, 1);
+}
+
+void BlFileWindow::movecharforward (size_t n)
+{
+ graphics::movecharforward (ch, n);
+}
+
+void BlFileWindow::movecharback ()
+{
+ graphics::movecharback (ch, 1);
+}
+
+void BlFileWindow::movecharback (size_t n)
+{
+ graphics::movecharback (ch, n);
+}
+
+void BlFileWindow::movecharup ()
+{
+ graphics::movecharup (ch, 1);
+}
+
+void BlFileWindow::movecharup (size_t n)
+{
+ graphics::movecharup (ch, n);
+}
+
+void BlFileWindow::movechardown ()
+{
+ graphics::movechardown (ch, 1);
+}
+
+void BlFileWindow::movechardown (size_t n)
+{
+ graphics::movechardown (ch, n);
+}
+
+void BlFileWindow::showcursor ()
+{
+ graphics::showcursor (ch);
+}
+
+void BlFileWindow::hidecursor ()
+{
+ graphics::hidecursor (ch);
+}
+
+std::string BlFileWindow::getkey ()
+{
+ return graphics::getkey ();
+}
+
+std::string BlFileWindow::inkey ()
+{
+ return graphics::inkey ();
+}
+
+void BlFileWindow::getline (std::string & str, bool endline)
+{
+ using blassic::edit::editline;
+
+ std::string auxstr;
+ int inicol= graphics::xpos (ch);
+ while (! editline (* this, auxstr, 0, inicol, endline) )
+ continue;
+ swap (str, auxstr);
+}
+
+std::string BlFileWindow::read (size_t)
+{
+ throw ErrNotImplemented;
+}
+
+void BlFileWindow::tab ()
+{
+ graphics::tab (ch);
+}
+
+void BlFileWindow::tab (size_t n)
+{
+ graphics::tab (ch, n);
+}
+
+void BlFileWindow::endline ()
+{
+ outstring ("\r\n");
+}
+
+void BlFileWindow::gotoxy (int x, int y)
+{
+ graphics::gotoxy (ch, x, y);
+}
+
+void BlFileWindow::setcolor (int color)
+{
+ graphics::setcolor (ch, color);
+}
+
+int BlFileWindow::getcolor ()
+{
+ return graphics::getcolor (ch);
+}
+
+void BlFileWindow::setbackground (int color)
+{
+ graphics::setbackground (ch, color);
+}
+
+int BlFileWindow::getbackground ()
+{
+ return graphics::getbackground (ch);
+}
+
+void BlFileWindow::outstring (const std::string & str)
+{
+ TRACEFUNC (tr, "BlFileWindow::outstring");
+ TRMESSAGE (tr, str);
+
+ graphics::stringout (ch, str);
+}
+
+void BlFileWindow::outchar (char c)
+{
+ graphics::charout (ch, c);
+}
+
+void BlFileWindow::cls ()
+{
+ graphics::cls (ch);
+}
+
+std::string BlFileWindow::copychr (BlChar from, BlChar to)
+{
+ return graphics::copychr (ch, from, to);
+}
+
+int BlFileWindow::pos ()
+{
+ return graphics::xpos (ch);
+}
+
+int BlFileWindow::vpos ()
+{
+ return graphics::ypos (ch);
+}
+
+void BlFileWindow::tag ()
+{
+ graphics::tag (ch);
+}
+
+void BlFileWindow::tagoff ()
+{
+ graphics::tagoff (ch);
+}
+
+bool BlFileWindow::istagactive ()
+{
+ return graphics::istagactive (ch);
+}
+
+void BlFileWindow::inverse (bool active)
+{
+ graphics::inverse (ch, active);
+}
+
+bool BlFileWindow::getinverse ()
+{
+ return graphics::getinverse (ch);
+}
+
+void BlFileWindow::bright (bool active)
+{
+ graphics::bright (ch, active);
+}
+
+bool BlFileWindow::getbright ()
+{
+ return graphics::getbright (ch);
+}
+
+bool BlFileWindow::poll ()
+{
+ return graphics::pollin ();
+}
+
+void BlFileWindow::scroll (int nlines)
+{
+ graphics::scroll (ch, nlines);
+}
+
+} // namespace file
+
+} // namespace blassic
+
+// End of filewindow.cpp
diff --git a/function.cpp b/function.cpp
new file mode 100644
index 0000000..e666cff
--- /dev/null
+++ b/function.cpp
@@ -0,0 +1,249 @@
+// function.cpp
+// Revision 10-jul-2004
+
+#include "function.h"
+#include "error.h"
+
+#include <vector>
+#include <map>
+
+class ParameterList::Internal {
+public:
+ static Internal * getnew ();
+ void addref ();
+ void delref ();
+ void push_back (const std::string & name);
+ size_t size () const;
+ //const std::string & get (size_t n) const;
+ std::string get (size_t n) const;
+private:
+ Internal ();
+ Internal (const Internal &); // Forbidden
+ ~Internal () { }
+ void operator= (const Internal &); // Forbidden
+ size_t counter;
+ std::vector <std::string> element;
+};
+
+ParameterList::Internal::Internal () :
+ counter (1)
+{
+}
+
+void ParameterList::Internal::addref ()
+{
+ ++counter;
+}
+
+void ParameterList::Internal::delref ()
+{
+ if (--counter == 0)
+ delete this;
+}
+
+ParameterList::Internal * ParameterList::Internal::getnew ()
+{
+ return new Internal;
+}
+
+void ParameterList::Internal::push_back (const std::string & name)
+{
+ element.push_back (name);
+}
+
+size_t ParameterList::Internal::size () const
+{
+ return element.size ();
+}
+
+//const std::string & ParameterList::Internal::get (size_t n) const
+std::string ParameterList::Internal::get (size_t n) const
+{
+ if (n >= element.size () )
+ throw ErrBlassicInternal;
+ return element [n];
+}
+
+ParameterList::ParameterList () :
+ pin (Internal::getnew () )
+{
+}
+
+ParameterList::ParameterList (const ParameterList & pl) :
+ pin (pl.pin)
+{
+ pin->addref ();
+}
+
+ParameterList::~ParameterList ()
+{
+ pin->delref ();
+}
+
+ParameterList & ParameterList::operator= (const ParameterList & pl)
+{
+ pl.pin->addref ();
+ pin->delref ();
+ pin= pl.pin;
+ return * this;
+}
+
+void ParameterList::push_back (const std::string & name)
+{
+ pin->push_back (name);
+}
+
+size_t ParameterList::size () const
+{
+ return pin->size ();
+}
+
+//const std::string & ParameterList::operator [] (size_t n) const
+std::string ParameterList::operator [] (size_t n) const
+{
+ return pin->get (n);
+}
+
+class Function::Internal {
+public:
+ void addref ();
+ void delref ();
+ static Internal * getnew
+ (const std::string & strdef, const ParameterList & param)
+ {
+ return new Internal (strdef, param);
+ }
+ static Internal * getnew
+ (ProgramPos posfn, const ParameterList & param)
+ {
+ return new Internal (posfn, param);
+ }
+ DefType getdeftype () const { return deftype; }
+ CodeLine & getcode () { return code; }
+ ProgramPos getpos () const { return pos; }
+ const ParameterList & getparam () { return param; }
+protected:
+ // Protected to avoid a warning on certain versions of gcc.
+ Internal (const std::string & strdef, const ParameterList & param);
+ ~Internal () { }
+private:
+ Internal (ProgramPos posfn, const ParameterList & param);
+ Internal (const Internal &); // Forbidden
+ void operator = (const Internal &); // Forbidden
+ size_t counter;
+ DefType deftype;
+ CodeLine code;
+ ProgramPos pos;
+ ParameterList param;
+};
+
+Function::Internal::Internal
+ (const std::string & strdef, const ParameterList & param) :
+ counter (1),
+ deftype (DefSingle),
+ param (param)
+{
+ code.scan (strdef);
+}
+
+Function::Internal::Internal
+ (ProgramPos posfn, const ParameterList & param) :
+ counter (1),
+ deftype (DefMulti),
+ pos (posfn),
+ param (param)
+{
+}
+
+void Function::Internal::addref ()
+{
+ ++counter;
+}
+
+void Function::Internal::delref ()
+{
+ if (--counter == 0)
+ delete this;
+}
+
+Function::Function (const std::string & strdef, const ParameterList & param) :
+ pin (Internal::getnew (strdef, param) )
+{
+}
+
+Function::Function (ProgramPos posfn, const ParameterList & param) :
+ pin (Internal::getnew (posfn, param) )
+{
+}
+
+Function::Function (const Function & f) :
+ pin (f.pin)
+{
+ pin->addref ();
+}
+
+Function::~Function ()
+{
+ pin->delref ();
+}
+
+Function & Function::operator= (const Function & f)
+{
+ f.pin->addref ();
+ pin->delref ();
+ pin= f.pin;
+ return * this;
+}
+
+Function::DefType Function::getdeftype () const
+{
+ return pin->getdeftype ();
+}
+
+CodeLine & Function::getcode ()
+{
+ return pin->getcode ();
+}
+
+ProgramPos Function::getpos () const
+{
+ return pin->getpos ();
+}
+
+const ParameterList & Function::getparam ()
+{
+ return pin->getparam ();
+}
+
+namespace {
+
+typedef std::map <std::string, Function> mapfunction_t;
+mapfunction_t mapfunction;
+
+} // namespace
+
+void Function::clear ()
+{
+ mapfunction.clear ();
+}
+
+void Function::insert (const std::string & name)
+{
+ mapfunction_t::iterator it=
+ mapfunction.find (name);
+ if (it != mapfunction.end () )
+ it->second= * this;
+ else
+ mapfunction.insert (std::make_pair (name, * this) );
+}
+
+Function & Function::get (const std::string & name)
+{
+ mapfunction_t::iterator it=
+ mapfunction.find (name);
+ if (it != mapfunction.end () )
+ return it->second;
+ throw ErrFunctionNoDefined;
+}
+
+// Fin de function.cpp
diff --git a/function.h b/function.h
new file mode 100644
index 0000000..e350be2
--- /dev/null
+++ b/function.h
@@ -0,0 +1,50 @@
+#ifndef INCLUDE_BLASSIC_FUNCTION_H
+#define INCLUDE_BLASSIC_FUNCTION_H
+
+// function.h
+// Revision 7-feb-2005
+
+
+#include "codeline.h"
+
+#include <string>
+
+
+class ParameterList {
+public:
+ ParameterList ();
+ ParameterList (const ParameterList & pl);
+ ~ParameterList ();
+ ParameterList & operator= (const ParameterList & pl);
+ void push_back (const std::string & name);
+ size_t size () const;
+ //const std::string & operator [] (size_t n) const;
+ std::string operator [] (size_t n) const;
+private:
+ class Internal;
+ Internal * pin;
+};
+
+class Function {
+public:
+ enum DefType { DefSingle, DefMulti };
+ Function (const std::string & strdef, const ParameterList & param);
+ Function (ProgramPos posfn, const ParameterList & param);
+ Function (const Function & f);
+ ~Function ();
+ Function & operator= (const Function &);
+ DefType getdeftype () const;
+ CodeLine & getcode ();
+ ProgramPos getpos () const;
+ const ParameterList & getparam ();
+ static void clear ();
+ void insert (const std::string & name);
+ static Function & get (const std::string & name);
+private:
+ class Internal;
+ Internal * pin;
+};
+
+#endif
+
+// Fin de function.h
diff --git a/gencharset.cpp b/gencharset.cpp
new file mode 100644
index 0000000..716c2ac
--- /dev/null
+++ b/gencharset.cpp
@@ -0,0 +1,221 @@
+// gencharset.cpp
+// Revision 31-jul-2004
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <stdexcept>
+#include <sstream>
+// bitset in gcc 2.95 uses min whithout defining it.
+// Then we include something that does.
+#include <algorithm>
+#include <bitset>
+
+using std::istream;
+using std::ostream;
+using std::cerr;
+using std::endl;
+using std::string;
+using std::runtime_error;
+
+void gencharset (const string & fin, const string & fout,
+ const std::string & name);
+void readcharset (istream & in);
+void writecharset (ostream & out, const std::string & name);
+
+size_t linenumber= 0;
+
+int main (int argc, char * * argv)
+{
+ try
+ {
+ string fin, fout, name;
+ if (argc > 1) fin= argv [1];
+ if (argc > 2) fout= argv [2];
+ if (argc > 3) name= argv [3];
+ gencharset (fin, fout, name);
+ }
+ catch (std::exception & e)
+ {
+ cerr << e.what ();
+ if (linenumber != 0)
+ cerr << " in line " << linenumber;
+ cerr << endl;
+ }
+}
+
+typedef unsigned char chardata [8];
+
+chardata default_data;
+bool default_defined= false;
+chardata data [256];
+bool data_defined [256]= { false };
+
+void gencharset (const string & fin, const string & fout,
+ const std::string & name)
+{
+ istream * pin;
+ if (fin.empty () )
+ pin= & std::cin;
+ else
+ {
+ std::ifstream * pinf= new std::ifstream (fin.c_str () );
+ if (! pinf->is_open () )
+ throw runtime_error ("File not found");
+ pin= pinf;
+ }
+
+ readcharset (* pin);
+
+ if (! fin.empty () )
+ delete pin;
+
+ linenumber= 0;
+
+ ostream * pout;
+ if (fout.empty () )
+ pout= & std::cout;
+ else
+ {
+ std::ofstream * poutf= new std::ofstream (fout.c_str () );
+ if (! poutf->is_open () )
+ throw runtime_error ("Cannot create output file");
+ pout= poutf;
+ }
+
+ writecharset (* pout, name);
+
+ if (! fout.empty () )
+ delete pout;
+}
+
+bool readline (istream & in, string & str)
+{
+ do {
+ std::getline (in, str);
+ if (! in)
+ return false;
+ ++ linenumber;
+ string::size_type l= str.size ();
+ if (l > 0 && str [l - 1] == '\r')
+ str= str.substr (0, l - 1);
+ } while (str.empty () || str [0] == '#');
+ return true;
+}
+
+void readchar (istream & in, chardata & chd)
+{
+ string str;
+ bool invert= false;
+ for (int i= 0; i < 8; ++i)
+ {
+ if (! readline (in, str) )
+ throw runtime_error ("Unexpected eof");
+ if (str == "INVERT")
+ {
+ invert= true;
+ if (! readline (in, str) )
+ throw runtime_error ("Unexpected eof");
+ }
+ std::bitset <8> b (str);
+ unsigned long l= b.to_ulong ();
+ if (invert)
+ l= ~ l;
+ chd [i]= static_cast <unsigned char> (l);
+ }
+}
+
+unsigned char getcharcode (const string & str)
+{
+ if (str.size () == 1)
+ return str [0];
+ std::istringstream iss (str);
+ unsigned int u;
+ iss >> u;
+ if (! iss)
+ throw runtime_error ("Syntax error");
+ char c;
+ iss >> c;
+ if (! iss.eof () )
+ throw runtime_error ("Syntax error");
+ if (u > 255)
+ throw runtime_error ("Invalid char number");
+ return static_cast <unsigned char> (u);
+}
+
+void readcharset (istream & in)
+{
+ string str;
+ while (readline (in, str) )
+ {
+ //cerr << str << endl;
+ if (str == "DEFAULT")
+ {
+ if (default_defined)
+ throw runtime_error
+ ("Default already defined");
+ //cerr << "Defining default" << endl;
+ readchar (in, default_data);
+ default_defined= true;
+ }
+ else
+ {
+ unsigned char ch= getcharcode (str);
+ //cerr << "Defining char: ";
+ //if (ch >= 32) cerr << ch;
+ //else cerr << static_cast <unsigned int> (ch);
+ //cerr << endl;
+ if (data_defined [ch] )
+ throw runtime_error ("Char already defined");
+ readchar (in, data [ch] );
+ data_defined [ch]= true;
+ }
+ }
+}
+
+void writecharset (ostream & out, const std::string & name)
+{
+ if (name.empty () )
+ out <<
+ "// charset.cpp\n";
+ else
+ out <<
+ "// charset_" << name << ".cpp\n";
+
+ out <<
+ "// Automatically generated, do not edit.\n"
+ "\n"
+ "#include \"charset.h\"\n"
+ "\n"
+ "const charset::chardataset charset::";
+
+ if (name.empty () )
+ out << "default";
+ else
+ out << name;
+
+ out << "_data= {\n"
+ ;
+
+ for (int i= 0; i < 256; ++i)
+ {
+ out << "\t// char " << i << "\n\t{ ";
+ chardata * pdata;
+ if (data_defined [i] ) pdata= & data [i];
+ else pdata= & default_data;
+ for (int j= 0; j < 8; ++j)
+ {
+ out << static_cast <unsigned int> ( (* pdata) [j] );
+ if (j < 7) out << ", ";
+ }
+ out << " },\n";
+ }
+ out <<
+
+"};\n"
+"\n"
+"//End of charset.cpp\n"
+ ;
+}
+
+// End of gencharset.cpp
diff --git a/graphics.cpp b/graphics.cpp
new file mode 100644
index 0000000..e84423b
--- /dev/null
+++ b/graphics.cpp
@@ -0,0 +1,8110 @@
+// graphics.cpp
+// Revision 24-apr-2009
+
+#ifdef __BORLANDC__
+#pragma warn -8027
+#endif
+
+#include "graphics.h"
+#include "sysvar.h"
+#include "error.h"
+#include "var.h"
+#include "key.h"
+#include "charset.h"
+
+#include "util.h"
+using util::touch;
+using util::to_string;
+
+#include "trace.h"
+
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <sstream>
+#include <iomanip>
+
+#include <memory>
+using std::auto_ptr;
+
+#include <map>
+#include <queue>
+
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+
+// Para depuracion
+#include <iostream>
+using std::cerr;
+using std::endl;
+#if defined __unix__ || defined __linux__
+#include <unistd.h>
+#endif
+#include <cassert>
+#define ASSERT assert
+
+
+// This is controlled with the configure option --disable-graphics
+#ifndef BLASSIC_CONFIG_NO_GRAPHICS
+
+#if defined BLASSIC_USE_WINDOWS || defined BLASSIC_USE_X || \
+ defined BLASSIC_USE_SVGALIB
+
+// If configure is not used you can comment the following line
+// to disable graphics.
+
+#define BLASSIC_HAS_GRAPHICS
+
+#endif
+
+#endif
+
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+#ifdef BLASSIC_USE_SVGALIB
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <vga.h>
+#include <vgagl.h>
+
+#endif
+// BLASSIC_USE_SVGALIB
+
+#ifdef BLASSIC_USE_X
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#endif
+// BLASSIC_USE_X
+
+#ifdef BLASSIC_USE_WINDOWS
+
+#include <process.h>
+#include <windows.h>
+#undef min
+#undef max
+
+#if defined __CYGWIN32__ || defined __CYGWIN__
+// This macros are from Anders Norlander, modified to add
+// the cast to start_proc.
+/* Macro uses args se we can cast proc to LPTHREAD_START_ROUTINE
+ in order to avoid warings because of return type */
+#define _beginthreadex(security, stack_size, start_proc, arg, flags, pid) \
+CreateThread (security, stack_size, (LPTHREAD_START_ROUTINE) start_proc, \
+ arg, flags, (LPDWORD) pid)
+#define _endthreadex ExitThread
+#endif
+
+// Use Polyline to draw a point.
+#define USE_POLY
+
+#endif
+// BLASSIC_USE_WINDOWS
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+namespace sysvar= blassic::sysvar;
+
+
+// Character set
+
+charset::chardataset charset::data;
+
+const charset::chardataset * charset::default_charset=
+ & charset::default_data;
+
+namespace {
+
+#ifndef BLASSIC_HAS_GRAPHICS
+
+void no_graphics_support ()
+{
+ if (showdebuginfo () )
+ cerr << "This version of Blassic was compiled "
+ "without graphics support" << endl;
+ throw ErrFunctionCall;
+}
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+#ifdef BLASSIC_USE_SVGALIB
+
+char * font= NULL;
+
+#endif
+// BLASSIC_USE_SVGALIB
+
+#ifdef BLASSIC_USE_X
+
+Display * display= 0;
+XIM xim= 0;
+XIC xic= 0;
+int screen;
+Window window;
+Pixmap pixmap;
+bool pixmap_created= false;
+GC gc, gcp;
+XGCValues gcvalues, gcvaluesp;
+
+//XEvent x_event;
+
+long eventusedmask= StructureNotifyMask | ExposureMask |
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ PointerMotionMask | EnterWindowMask;
+long eventusedmaskactual;
+
+typedef XColor color_t;
+
+typedef unsigned long ColorValue;
+
+#endif
+// BLASSIC_USE_X
+
+#ifdef BLASSIC_USE_WINDOWS
+
+ATOM atomClass;
+HANDLE hEvent;
+HWND window;
+HDC hdc= 0;
+HBITMAP pixmap;
+HDC hdcPixmap= 0;
+typedef HPEN color_t;
+
+typedef COLORREF ColorValue;
+
+#endif
+// BLASSIC_USE_WINDOWS
+
+#if defined (BLASSIC_USE_WINDOWS) || defined (BLASSIC_USE_X)
+
+color_t xcBlack, xcBlue, xcGreen, xcCyan,
+ xcRed, xcMagenta, xcBrown, xcLightGrey,
+ xcDarkGrey, xcLightBlue, xcLightGreen, xcLightCyan,
+ xcLightRed, xcLightMagenta, xcYellow, xcWhite;
+
+typedef color_t * pcolor;
+
+pcolor pforeground, pbackground,
+ //default_foreground= & xcBlack, default_background= & xcWhite,
+ activecolor= NULL;
+
+int default_pen, default_paper;
+
+int graphics_pen, graphics_paper;
+
+#endif
+// defined BLASSIC_USE_WINDOWS || defined BLASSIC_USE_X
+
+std::string default_title ("blassic");
+
+bool fSynchro= false;
+
+#ifdef BLASSIC_USE_WINDOWS
+
+class CriticalSection {
+public:
+ CriticalSection ()
+ {
+ InitializeCriticalSection (& cs);
+ }
+ ~CriticalSection ()
+ {
+ DeleteCriticalSection (& cs);
+ }
+ void enter ()
+ {
+ EnterCriticalSection (& cs);
+ }
+ void leave ()
+ {
+ LeaveCriticalSection (& cs);
+ }
+private:
+ CRITICAL_SECTION cs;
+};
+
+class CriticalLock {
+public:
+ CriticalLock (CriticalSection & cs) :
+ cs (cs)
+ {
+ cs.enter ();
+ }
+ ~CriticalLock ()
+ {
+ cs.leave ();
+ }
+private:
+ CriticalSection & cs;
+};
+
+#else
+
+// Empty implementation, not using threads.
+
+class CriticalSection { };
+
+class CriticalLock {
+public:
+ CriticalLock (CriticalSection &)
+ { }
+};
+
+#endif
+
+class QueueKey {
+public:
+ QueueKey ()
+ {
+ }
+ void push (const std::string & str)
+ {
+ CriticalLock lock (cs);
+ touch (lock);
+ q.push (str);
+ }
+ std::string pop ()
+ {
+ CriticalLock lock (cs);
+ touch (lock);
+ std::string str= q.front ();
+ q.pop ();
+ return str;
+ }
+ bool empty ()
+ {
+ return q.empty ();
+ }
+ void erase ()
+ {
+ CriticalLock lock (cs);
+ touch (lock);
+ while (! q.empty () )
+ q.pop ();
+ }
+private:
+ std::queue <std::string> q;
+ CriticalSection cs;
+};
+
+#if 0
+const size_t MAXKEYSYM= 65535;
+std::vector <bool> keypressedmap (MAXKEYSYM);
+#endif
+
+const size_t MAXINKEYCODE= 79;
+
+#ifdef BLASSIC_USE_WINDOWS
+
+#if 0
+unsigned int presscode [MAXINKEYCODE + 1]= {
+};
+#endif
+
+#elif defined BLASSIC_USE_X
+
+#if 0
+const unsigned int KEYSYMUNUSED= 1;
+unsigned int presscode [MAXINKEYCODE + 1]= {
+ XK_Up, // 0
+ XK_Right, // 1
+ XK_Down, // 2
+ XK_KP_9, // 3
+ XK_KP_6, // 4
+ XK_KP_3, // 5
+ XK_Execute, // 6
+ XK_KP_Decimal, // 7
+ XK_Left, // 8
+ KEYSYMUNUSED, // 9 "Copy" key
+ XK_KP_7, // 10
+ XK_KP_8, // 11
+ XK_KP_5, // 12
+ XK_KP_1, // 13
+ XK_KP_2, // 14
+ XK_KP_0, // 15
+ XK_Delete, // 16
+ KEYSYMUNUSED, // 17
+ XK_Return, // 18
+ KEYSYMUNUSED, // 19
+ XK_KP_4, // 20
+ XK_Shift_L, // 21
+ KEYSYMUNUSED, // 22
+ XK_Control_L, // 23
+ KEYSYMUNUSED, // 24
+ KEYSYMUNUSED, // 25
+ KEYSYMUNUSED, // 26
+ XK_P, // 27
+ KEYSYMUNUSED, // 28
+ KEYSYMUNUSED, // 29
+ KEYSYMUNUSED, // 30
+ KEYSYMUNUSED, // 31
+ XK_0, // 32
+ XK_9, // 33
+ XK_O, // 34
+ XK_I, // 35
+ XK_L, // 36
+ XK_K, // 37
+ XK_M, // 38
+ KEYSYMUNUSED, // 39
+ XK_8, // 40
+ XK_7, // 41
+ XK_U, // 42
+ XK_Y, // 43
+ XK_H, // 44
+ XK_J, // 45
+ XK_N, // 46
+ KEYSYMUNUSED, // 47
+ XK_6, // 48
+ XK_5, // 49
+ XK_R, // 50
+ XK_T, // 51
+ XK_G, // 52
+ XK_F, // 53
+ XK_B, // 54
+ XK_V, // 55
+ XK_4, // 56
+ XK_3, // 57
+ XK_E, // 58
+ XK_W, // 59
+ XK_S, // 60
+ XK_D, // 61
+ XK_C, // 62
+ XK_X, // 63
+ XK_1, // 64
+ XK_2, // 65
+ XK_Escape, // 66
+ XK_Q, // 67
+ XK_Tab, // 68
+ XK_A, // 69
+ XK_Caps_Lock, // 70
+ XK_Z, // 71
+ KEYSYMUNUSED, // 72
+ KEYSYMUNUSED, // 73
+ KEYSYMUNUSED, // 74
+ KEYSYMUNUSED, // 75
+ KEYSYMUNUSED, // 76
+ KEYSYMUNUSED, // 77
+ KEYSYMUNUSED, // 78
+ XK_BackSpace, // 79
+};
+
+inline void keysymtoupper (KeySym & ks)
+{
+ KeySym discard;
+ // Convert to upper case.
+ XConvertCase (ks, & discard, & ks);
+}
+
+void set_pressed (KeySym ks)
+{
+ keysymtoupper (ks);
+ if (ks >= 0 && ks <= MAXKEYSYM)
+ keypressedmap [ks]= 1;
+}
+
+void reset_pressed (KeySym ks)
+{
+ keysymtoupper (ks);
+ if (ks >= 0 && ks <= MAXKEYSYM)
+ keypressedmap [ks]= 0;
+}
+
+#endif
+
+#endif
+
+#ifdef BLASSIC_USE_X
+const unsigned int MAXKEYCODE= 255;
+#elif defined BLASSIC_USE_WINDOWS
+const unsigned int MAXKEYCODE= 511;
+#endif
+
+std::vector <bool> keycode_pressed (MAXKEYCODE + 1);
+
+#ifdef BLASSIC_USE_X
+
+const unsigned int NOUS= 0xFF;
+
+const unsigned int inkeytocode [MAXINKEYCODE + 1]={
+ // The key symbols indicated are the corresponding
+ // to a spanish keyboard.
+ 0x62, // 0 Up
+ 0x66, // 1 Right
+ 0x68, // 2 Down
+ 0x51, // 3 Numeric 9
+ 0x55, // 4 Numeric 6
+ 0x59, // 5 Numeric 3
+ 0x6C, // 6 Intro
+ 0x5B, // 7 Numeric .
+ 0x64, // 8 Left
+ 0x00, // 9 Copy
+ 0x4F, // 10 Numeric 7
+ 0x50, // 11 Numeric 8
+ 0x54, // 12 Numeric 5
+ 0x57, // 13 Numeric 1
+ 0x58, // 14 Numeric 2
+ 0x5A, // 15 Numeric 0
+ 0x6B, // 16 Delete
+ 0x23, // 17 +
+ 0x24, // 18 Return
+ 0x33, // 19 0x53, // 20 Numeric 4
+ 0x3E, // 21 Shift
+ 0x5E, // 22 \ in the CPC, <>
+ 0x6D, // 23 Control
+ 0x15, // 24 0x14, // 25 '
+ 0x22, // 26 `[
+ 0x21, // 27 P
+ 0x30, // 28 '{
+ 0x2F, // 29 0x3D, // 30 -
+ 0x3C, // 31 .
+ 0x13, // 32 0
+ 0x12, // 33 9
+ 0x20, // 34 O
+ 0x1F, // 35 I
+ 0x2E, // 36 L
+ 0x2D, // 37 K
+ 0x3A, // 38 M
+ 0x3B, // 39 ,
+ 0x11, // 40 8
+ 0x10, // 41 7
+ 0x1E, // 42 U
+ 0x1D, // 43 Y
+ 0x2B, // 44 H
+ 0x2C, // 45 J
+ 0x39, // 46 N
+ 0x41, // 47 space
+ 0x0F, // 48 6
+ 0x0E, // 49 5
+ 0x1B, // 50 R
+ 0x1C, // 51 T
+ 0x2A, // 52 G
+ 0x29, // 53 F
+ 0x38, // 54 B
+ 0x37, // 55 V
+ 0x0D, // 56 4
+ 0x0C, // 57 3
+ 0x1A, // 58 E
+ 0x19, // 59 W
+ 0x27, // 60 S
+ 0x28, // 61 D
+ 0x36, // 62 C
+ 0x35, // 63 X
+ 0x0A, // 64 1
+ 0x0B, // 65 2
+ 0x09, // 66 Escape
+ 0x18, // 67 Q
+ 0x17, // 68 Tab
+ 0x26, // 69 A
+ 0x42, // 70 Caps lock
+ 0x34, // 71 Z
+ NOUS, // 72 joystick on cpc, unasigned
+ NOUS, // 73 joystick on cpc, unasigned
+ NOUS, // 74 joystick on cpc, unasigned
+ NOUS, // 75 joystick on cpc, unasigned
+ NOUS, // 76 joystick on cpc, unasigned
+ NOUS, // 77 joystick on cpc, unasigned
+ NOUS, // 78 Inexistent
+ 0x16, // 79 Backspace
+};
+
+#elif defined BLASSIC_USE_WINDOWS
+
+const unsigned int NOUS= 0x1FF;
+
+const unsigned int inkeytocode [MAXINKEYCODE + 1]={
+ // The key symbols indicated are the corresponding
+ // to a spanish keyboard.
+ 0x008, // 0 Up
+ 0x00D, // 1 Right
+ 0x068, // 2 Down
+ 0x049, // 3 Numeric 9
+ 0x04d, // 4 Numeric 6
+ 0x051, // 5 Numeric 3
+ 0x11C, // 6 Intro
+ 0x05B, // 7 Numeric .
+ 0x064, // 8 Left
+ 0x000, // 9 Copy
+ 0x047, // 10 Numeric 7
+ 0x048, // 11 Numeric 8
+ 0x04C, // 12 Numeric 5
+ 0x04F, // 13 Numeric 1
+ 0x050, // 14 Numeric 2
+ 0x052, // 15 Numeric 0
+ 0x153, // 16 Delete
+ 0x01B, // 17 +
+ 0x01C, // 18 Return
+ 0x02B, // 19 0x04B, // 20 Numeric 4
+ 0x02A, // 21 Shift
+ 0x056, // 22 \ on the CPC, <>
+ 0x01D, // 23 Control
+ 0x00D, // 24 0x00C, // 25 '
+ 0x01A, // 26 `[
+ 0x019, // 27 P
+ 0x028, // 28 '{
+ 0x027, // 29 0x035, // 30 -
+ 0x034, // 31 .
+ 0x00B, // 32 0
+ 0x00A, // 33 9
+ 0x018, // 34 O
+ 0x017, // 35 I
+ 0x026, // 36 L
+ 0x025, // 37 K
+ 0x032, // 38 M
+ 0x033, // 39 ,
+ 0x009, // 40 8
+ 0x008, // 41 7
+ 0x016, // 42 U
+ 0x015, // 43 Y
+ 0x023, // 44 H
+ 0x024, // 45 J
+ 0x031, // 46 N
+ 0x039, // 47 space
+ 0x007, // 48 6
+ 0x006, // 49 5
+ 0x013, // 50 R
+ 0x014, // 51 T
+ 0x022, // 52 G
+ 0x021, // 53 F
+ 0x030, // 54 B
+ 0x02F, // 55 V
+ 0x005, // 56 4
+ 0x004, // 57 3
+ 0x012, // 58 E
+ 0x011, // 59 W
+ 0x01F, // 60 S
+ 0x020, // 61 D
+ 0x02E, // 62 C
+ 0x02D, // 63 X
+ 0x002, // 64 1
+ 0x003, // 65 2
+ 0x001, // 66 Escape
+ 0x010, // 67 Q
+ 0x00F, // 68 Tab
+ 0x01E, // 69 A
+ 0x03A, // 70 Caps lock
+ 0x02C, // 71 Z
+ NOUS, // 72 joystick on cpc, unasigned
+ NOUS, // 73 joystick on cpc, unasigned
+ NOUS, // 74 joystick on cpc, unasigned
+ NOUS, // 75 joystick on cpc, unasigned
+ NOUS, // 76 joystick on cpc, unasigned
+ NOUS, // 77 joystick on cpc, unasigned
+ NOUS, // 78 Inexistent
+ 0x00E, // 79 Backspace
+};
+
+#endif
+
+void keycode_press (unsigned int keycode)
+{
+ //std::cerr << "Pressed " << std::hex << std::setfill ('0') <<
+ // std::setw (3) << keycode << std::endl;
+ if (keycode <= MAXKEYCODE)
+ keycode_pressed [keycode]= true;
+}
+
+void keycode_release (unsigned int keycode)
+{
+ //std::cerr << "Released " << std::hex << std::setfill ('0') <<
+ // std::setw (3) << keycode << std::endl;
+ if (keycode <= MAXKEYCODE)
+ keycode_pressed [keycode]= false;
+}
+
+int keypressed (int keynum)
+{
+ if (keynum < 0 || keynum > static_cast <int> (MAXINKEYCODE) )
+ return -1;
+ graphics::idle ();
+ //if (! keypressedmap [presscode [keynum] ] )
+ // return -1;
+
+ const int shiftpressed= 32, ctrlpressed= 128;
+
+ #ifdef BLASSIC_USE_X
+ const unsigned int
+ shift_left= 0x32, shift_right= 0x3E,
+ control_left= 0x25, control_right= 0x6D;
+ #else
+ const unsigned int
+ shift_left= 0x2A, shift_right= 0x36,
+ control_left= 0x1D, control_right= 0x11D;
+ #endif
+
+ bool shifted= keycode_pressed [shift_left] ||
+ keycode_pressed [shift_right];
+ bool controled= keycode_pressed [control_left] ||
+ keycode_pressed [control_right];
+
+ bool pressed;
+ switch (keynum) {
+ case 21:
+ pressed= shifted;
+ break;
+ case 23:
+ pressed= controled;
+ break;
+ default:
+ pressed= keycode_pressed [inkeytocode [keynum] ];
+ }
+ if (! pressed)
+ return -1;
+ int r= 0;
+ //if (keypressedmap [XK_Shift_L] || keypressedmap [XK_Shift_R] )
+ if (shifted)
+ r|= shiftpressed;
+ //if (keypressedmap [XK_Control_L] || keypressedmap [XK_Control_R] )
+ if (controled)
+ r|= ctrlpressed;
+
+ return r;
+}
+
+QueueKey queuekey;
+
+//#endif
+//// BLASSIC_HAS_GRAPHICS
+
+bool inited= false;
+bool window_created= false;
+bool opaquemode= true;
+
+int xmousepos, ymousepos;
+
+const int text_mode= 0, user_mode= -1;
+
+bool graphics_mode_active= false;
+int actualmode= text_mode;
+
+int screenwidth, screenheight;
+int realwidth, realheight;
+int originx= 0, originy= 0;
+
+bool limited= false;
+int limit_minx, limit_miny, limit_maxx, limit_maxy;
+
+enum RotateMode { RotateNone, Rotate90 };
+RotateMode rotate= RotateNone;
+
+template <class C>
+inline void do_rotate (C & x, C & y)
+{
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ {
+ //int newx= y;
+ C newx= y;
+ //y= screenheight - x;
+ y= static_cast <C> (screenwidth - x - 1);
+ x= newx;
+ }
+ break;
+ }
+}
+
+template <class C>
+inline void do_unrotate (C & x, C & y)
+{
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ {
+ //int newy= x;
+ C newy= x;
+ x= static_cast <C> (screenwidth - y - 1);
+ y= newy;
+ }
+ break;
+ }
+}
+
+template <class C>
+inline void do_rotate_rel (C & x, C & y)
+{
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ {
+ std::swap (x, y);
+ }
+ break;
+ }
+}
+
+enum TransformType { TransformIdentity, TransformInvertY };
+
+TransformType activetransform= TransformIdentity;
+
+inline void transform_x (int & x)
+{
+ x+= originx;
+}
+
+inline int transform_inverse_x (int x)
+{
+ return x - originx;
+}
+
+inline void adjust_y (int & y)
+{
+ switch (activetransform)
+ {
+ case TransformIdentity:
+ break; // Nothing to do
+ case TransformInvertY:
+ y= screenheight - 1 - y;
+ break;
+ }
+}
+
+inline void transform_y (int & y)
+{
+ y+= originy;
+ adjust_y (y);
+}
+
+inline int transform_inverse_y (int y)
+{
+ switch (activetransform)
+ {
+ case TransformIdentity:
+ break; // Nothing to do
+ case TransformInvertY:
+ y= screenheight - 1 - y;
+ break;
+ }
+ return y - originy;
+}
+
+inline void set_origin (int x, int y)
+{
+ originx= x;
+ //adjust_y (y);
+ originy= y;
+}
+
+void clear_limits ()
+{
+ limited= false;
+}
+
+void set_limits (int minx, int maxx, int miny, int maxy)
+{
+ limited= true;
+ if (minx > maxx)
+ std::swap (minx, maxx);
+ limit_minx= minx;
+ limit_maxx= maxx;
+ adjust_y (miny);
+ adjust_y (maxy);
+ if (miny > maxy)
+ std::swap (miny, maxy);
+ limit_miny= miny;
+ limit_maxy= maxy;
+ if (limit_minx <= 0 && limit_maxx >= screenwidth - 1 &&
+ limit_miny <= 0 && limit_maxy >= screenheight - 1)
+ {
+ limited= false;
+ }
+}
+
+inline bool check_limit (int x, int y)
+{
+ if (x < 0 || y < 0 || x >= screenwidth || y >= screenheight)
+ return false;
+ return (! limited) || (x >= limit_minx && x <= limit_maxx &&
+ y >= limit_miny && y <= limit_maxy);
+}
+
+#ifdef BLASSIC_USE_SVGALIB
+
+bool svgalib= false;
+
+#else
+
+//const bool svgalib= false;
+
+#endif
+
+int lastx, lasty;
+
+#if defined BLASSIC_USE_X
+
+static const int
+ drawmode_copy= GXcopy,
+ drawmode_xor= GXxor,
+ drawmode_and= GXand,
+ drawmode_or= GXor,
+ drawmode_invert= GXinvert;
+
+#elif defined BLASSIC_USE_WINDOWS
+
+static const int
+ drawmode_copy= R2_COPYPEN,
+ drawmode_xor= R2_XORPEN,
+ // Revisar los valores para and y or.
+ drawmode_and= R2_MASKPEN,
+ drawmode_or= R2_MERGEPEN,
+ drawmode_invert= R2_NOT;
+
+#endif
+
+//#ifdef BLASSIC_HAS_GRAPHICS
+
+int drawmode= drawmode_copy;
+
+// Numeric draw modes:
+// 0: normal copy mode.
+// 1: XOR
+// 2: AND
+// 3: OR
+// 0 to 3 are Amstrad CPC modes.
+// 4: INVERT, NOT.
+
+static int drawmodesbynumber []= { drawmode_copy, drawmode_xor,
+ drawmode_and, drawmode_or, drawmode_invert };
+
+int getdrawmode (int mode)
+{
+ if (mode < 0 || size_t (mode) >= util::dim_array (drawmodesbynumber) )
+ throw ErrFunctionCall;
+ return drawmodesbynumber [mode];
+}
+
+#ifdef BLASSIC_USE_WINDOWS
+
+static int bitbltmodesbynumber []= { SRCCOPY, SRCINVERT,
+ SRCAND, SRCPAINT, DSTINVERT };
+
+int getbitbltmode (int mode)
+{
+ if (mode < 0 ||
+ size_t (mode) >= util::dim_array (bitbltmodesbynumber) )
+ {
+ throw ErrFunctionCall;
+ }
+ return bitbltmodesbynumber [mode];
+}
+
+
+#endif
+// BLASSIC_USE_WINDOWS
+
+//#endif
+//// BLASSIC_HAS_GRAPHICS
+
+const int BASIC_COLORS= 16;
+
+const int LancelotsFavouriteColour= 0x0204FB;
+// http://mindprod.com/unmainnaming.html
+
+bool colors_inited= false;
+
+struct ColorRGB {
+ int r;
+ int g;
+ int b;
+};
+
+const ColorRGB assignRGB []= {
+ { 0, 0, 0 },
+ { 0, 0, 0xA8 },
+ { 0, 0xA8, 0 },
+ { 0, 0xA8, 0xA8 },
+ { 0xA8, 0, 0 },
+ { 0xA8, 0, 0xA8 },
+ { 0xA8, 0x54, 0 },
+ { 0xA8, 0xA8, 0xA8 },
+
+ { 0x54, 0x54, 0x54 },
+ { 0x54, 0x54, 0xFF },
+ { 0x54, 0xFF, 0x54 },
+ { 0x54, 0xFF, 0xFF },
+ { 0xFF, 0x54, 0x54 },
+ { 0xFF, 0x54, 0xFF },
+ { 0xFF, 0xFF, 0x54 },
+ { 0xFF, 0xFF, 0xFF }
+};
+
+//#ifdef BLASSIC_HAS_GRAPHICS
+
+struct ColorInUse {
+ pcolor pc;
+ ColorRGB rgb;
+};
+
+#ifdef BLASSIC_USE_X
+
+ColorValue getColorValue (const ColorInUse & c)
+{
+ return c.pc->pixel;
+}
+
+#elif defined BLASSIC_USE_WINDOWS
+
+ColorValue getColorValue (const ColorInUse & c)
+{
+ return RGB (c.rgb.r, c.rgb.g, c.rgb.b);
+}
+
+#endif
+
+typedef std::map <int, ColorInUse> definedcolor_t;
+
+definedcolor_t definedcolor;
+
+ColorInUse tablecolors []=
+{
+ { &xcBlack, { 0, 0, 0} },
+ { &xcBlue, { 0, 0, 0} },
+ { &xcGreen, { 0, 0, 0} },
+ { &xcCyan, { 0, 0, 0} },
+ { &xcRed, { 0, 0, 0} },
+ { &xcMagenta, { 0, 0, 0} },
+ { &xcBrown, { 0, 0, 0} },
+ { &xcLightGrey, { 0, 0, 0} },
+
+ { &xcDarkGrey, { 0, 0, 0} },
+ { &xcLightBlue, { 0, 0, 0} },
+ { &xcLightGreen, { 0, 0, 0} },
+ { &xcLightCyan, { 0, 0, 0} },
+ { &xcLightRed, { 0, 0, 0} },
+ { &xcLightMagenta, { 0, 0, 0} },
+ { &xcYellow, { 0, 0, 0} },
+ { &xcWhite, { 0, 0, 0} }
+};
+
+inline ColorInUse & mapcolor (int color)
+{
+ if (color >= 0 && color < BASIC_COLORS)
+ return tablecolors [color];
+ definedcolor_t::iterator it= definedcolor.find (color);
+ if (it != definedcolor.end () )
+ return it->second;
+ return tablecolors [0];
+}
+
+inline ColorInUse & mapnewcolor (int color)
+{
+ if (color >= 0 && color < BASIC_COLORS)
+ return tablecolors [color];
+ definedcolor_t::iterator it= definedcolor.find (color);
+ if (it != definedcolor.end () )
+ return it->second;
+ ColorInUse n= { new color_t, { 0, 0, 0} };
+ return definedcolor.insert (std::make_pair (color, n) ).first->second;
+}
+
+void setink (int inknum, const ColorRGB & rgb)
+{
+ ColorInUse & ciu= mapnewcolor (inknum);
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ ASSERT (hdcPixmap);
+ COLORREF newcolor=
+ GetNearestColor (hdcPixmap, RGB (rgb.r, rgb.g, rgb.b) );
+ ciu.rgb.r= GetRValue (newcolor);
+ ciu.rgb.g= GetGValue (newcolor);
+ ciu.rgb.b= GetBValue (newcolor);
+ HPEN newpen= CreatePen (PS_SOLID, 1, newcolor);
+ if (ciu.pc == pforeground)
+ {
+ //SelectObject (hdc, * ciu.pc);
+ //SelectObject (hdcPixmap, * ciu.pc);
+ SelectObject (hdc, newpen);
+ SelectObject (hdcPixmap, newpen);
+ }
+ if (* ciu.pc != NULL)
+ DeleteObject (* ciu.pc);
+ * ciu.pc= newpen;
+
+ #elif defined BLASSIC_USE_X
+
+ ciu.rgb= rgb;
+ ASSERT (display);
+ Colormap cm= DefaultColormap (display, screen);
+ XColor xc;
+ std::ostringstream namecolor;
+ namecolor << "rgb:" << std::hex << std::setfill ('0') <<
+ std::setw (2) << rgb.r << '/' <<
+ std::setw (2) << rgb.g << '/' <<
+ std::setw (2) << rgb.b;
+ XColor newpen;
+ XAllocNamedColor (display, cm,
+ namecolor.str ().c_str (), & newpen, & xc);
+ if (ciu.pc == pforeground)
+ {
+ //XSetForeground (display, gcp, ciu.pc->pixel);
+ //XSetForeground (display, gc, ciu.pc->pixel);
+ XSetForeground (display, gcp, newpen.pixel);
+ XSetForeground (display, gc, newpen.pixel);
+ }
+ // Not sure if previous color needs to be freed and why.
+ * ciu.pc= newpen;
+
+ #endif
+}
+
+void setcpcink (int inknum, int cpccolor)
+{
+ // These rgb values are taken from screen captures
+ // of the WinAPE2 Amstrad CPC emulator.
+ static const ColorRGB cpctable []= {
+ { 0, 0, 0 }, // Black
+ { 0, 0, 96 }, // Blue
+ { 0, 0, 255 }, // Bright blue
+ { 96, 0, 0 }, // Red
+ { 96, 0, 96 }, // Magenta
+ { 96, 0, 255 }, // Mauve
+ { 255, 0, 0 }, // Bright red
+ { 255, 0, 96 }, // Purple
+ { 255, 0, 255 }, // Bright magenta
+ { 0, 103, 0 }, // Green
+ { 0, 103, 96 }, // Cyan
+ { 0, 103, 255 }, // Sky blue
+ { 96, 103, 0 }, // Yellow
+ { 96, 103, 96 }, // White
+ { 96, 103, 255 }, // Pastel blue
+ { 255, 103, 0 }, // Orange
+ { 255, 103, 96 }, // Pink
+ { 255, 103, 255 }, // Pastel magenta
+ { 0, 255, 0 }, // Bright green
+ { 0, 255, 96 }, // Sea green
+ { 0, 255, 255 }, // Bright cyan
+ { 96, 255, 0 }, // Lime green
+ { 96, 255, 96 }, // Pastel green
+ { 96, 255, 255 }, // Pastel cyan
+ { 255, 255, 0 }, // Bright yellow
+ { 255, 255, 96 }, // Pastel yellow
+ { 255, 255, 255 }, // Brigth white
+ };
+ ASSERT (cpccolor >= 0 &&
+ cpccolor < static_cast <int> ( util::dim_array (cpctable) ) );
+ const ColorRGB & rgb= cpctable [cpccolor];
+
+ setink (inknum, rgb);
+}
+
+void cpc_default_inks ()
+{
+ static const int default_ink []=
+ { 1, 24, 20, 6, 26, 0, 2, 8, 10, 12, 14, 16, 18, 22, 1, 16 };
+ // The last two are blinking on the CPC, we use the first color.
+ for (int i= 0; i < int (util::dim_array (default_ink) ); ++i)
+ //for (int i= 0; i < 16; ++i)
+ setcpcink (i, default_ink [i] );
+}
+
+void spectrum_inks ()
+{
+ // Taken from a screen capture of the Spectaculator Spectrum Emulator.
+ static const ColorRGB spectrumtable []=
+ {
+ { 0, 0, 0 }, // Black
+ { 0, 0, 207 }, // Blue
+ { 207, 0, 0 }, // Red
+ { 207, 0, 207 }, // Magenta
+ { 0, 200, 0 }, // Green
+ { 0, 200, 207 }, // Cyan
+ { 207, 200, 0 }, // Yellow
+ { 207, 200, 207 }, // White
+ { 0, 0, 0 }, // Black bright
+ { 0, 0, 255 }, // Blue bright
+ { 255, 0, 0 }, // Red bright
+ { 255, 0, 255 }, // Magenta bright
+ { 0, 248, 0 }, // Green bright
+ { 0, 248, 255 }, // Cyan bright
+ { 255, 248, 0 }, // Yellow bright
+ { 255, 248, 255 }, // White bright
+ };
+ for (int i= 0; i < 16; ++i)
+ setink (i, spectrumtable [i] );
+}
+
+enum Inkset { InkStandard, InkCpc, InkSpectrum } inkset= InkStandard;
+
+void init_colors ()
+{
+ TRACEFUNC (tr, "init_colors");
+
+ ASSERT (sizeof (assignRGB) / sizeof (ColorRGB) == BASIC_COLORS);
+ ASSERT (sizeof (tablecolors) / sizeof (ColorInUse) == BASIC_COLORS);
+
+ switch (inkset)
+ {
+ case InkStandard:
+ for (int i= 0; i < BASIC_COLORS; ++i)
+ {
+ const ColorRGB & rgb= assignRGB [i];
+ setink (i, rgb);
+ }
+ break;
+ case InkCpc:
+ cpc_default_inks ();
+ break;
+ case InkSpectrum:
+ spectrum_inks ();
+ break;
+ }
+ colors_inited= true;
+ pforeground= mapcolor (default_pen).pc;
+ pbackground= mapcolor (default_paper).pc;
+}
+
+void reinit_pixmap ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ //RECT r = { 0, 0, screenwidth, screenheight };
+ RECT r = { 0, 0, realwidth, realheight };
+ FillRect (hdcPixmap, & r, (HBRUSH) GetStockObject (WHITE_BRUSH) );
+
+ #elif defined BLASSIC_USE_X
+
+ XSetForeground (display, gcp, WhitePixel (display, screen) );
+ XFillRectangle (display, pixmap, gcp, 0, 0, realwidth, realheight);
+ XSetForeground (display, gcp, BlackPixel (display, screen) );
+
+ #endif
+}
+
+void reinit_window ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ //BitBlt (hdc, 0, 0, screenwidth, screenheight, hdcPixmap,
+ BitBlt (hdc, 0, 0, realwidth, realheight, hdcPixmap,
+ 0, 0, SRCCOPY);
+
+ #elif defined BLASSIC_USE_X
+
+ XSetFunction (display, gc, drawmode_copy);
+ XCopyArea (display, pixmap, window, gc,
+ //0, 0, screenwidth, screenheight, 0, 0);
+ 0, 0, realwidth, realheight, 0, 0);
+ //XSetForeground (display, gc, BlackPixel (display, screen) );
+ //XSetForeground (display, gc, pforeground->pixel);
+ XFlush (display);
+ XSetFunction (display, gc, drawmode);
+
+ #endif
+}
+
+void reinit_window (int x, int y, int width, int height)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ BitBlt (hdc, x, y, width, height, hdcPixmap,
+ x, y, SRCCOPY);
+
+ #elif defined BLASSIC_USE_X
+
+ XSetFunction (display, gc, drawmode_copy);
+ XCopyArea (display, pixmap, window, gc,
+ x, y, width, height, x, y);
+ //XSetForeground (display, gc, BlackPixel (display, screen) );
+ //XSetForeground (display, gc, pforeground->pixel);
+ XFlush (display);
+ XSetFunction (display, gc, drawmode);
+
+ #endif
+}
+
+#ifdef BLASSIC_USE_WINDOWS
+
+const UINT
+ WM_USER_CREATE_WINDOW= WM_USER + 3,
+ WM_USER_DESTROY_WINDOW= WM_USER + 4;
+
+HANDLE hthread= NULL;
+DWORD idthread= 0;
+
+inline unsigned int getkeycode (LPARAM lParam)
+{
+ return (lParam & 0x001FF0000) >> 16;
+}
+
+LRESULT APIENTRY windowproc
+ (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int width, height;
+ switch (uMsg) {
+ case WM_SIZE:
+ width= LOWORD (lParam);
+ height= HIWORD (lParam);
+ return TRUE;
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_PAINT:
+ {
+ //err << "WM_PAINT " << width << ", " << height << endl;
+ PAINTSTRUCT paintstruct;
+ HDC hdc= BeginPaint (hwnd, & paintstruct);
+ BitBlt (hdc, 0, 0, width, height, hdcPixmap, 0, 0, SRCCOPY);
+ EndPaint (hwnd, & paintstruct);
+ }
+ return FALSE;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ keycode_press (getkeycode (lParam) );
+ {
+ WORD k= (WORD) wParam;
+ //std::string str= string_from_virtual_key (k);
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ switch (k)
+ {
+ case VK_LEFT:
+ k= VK_UP; break;
+ case VK_UP:
+ k= VK_RIGHT; break;
+ case VK_RIGHT:
+ k= VK_DOWN; break;
+ case VK_DOWN:
+ k= VK_LEFT; break;
+ }
+ break;
+ }
+ std::string str= string_from_key (k);
+ if (! str.empty () )
+ {
+ queuekey.push (str);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ case WM_KEYUP:
+ keycode_release (getkeycode (lParam) );
+ return FALSE;
+// case WM_SYSKEYDOWN:
+// keycode_press (getkeycode (lParam) );
+// return FALSE;
+ case WM_SYSKEYUP:
+ keycode_release (getkeycode (lParam) );
+ return FALSE;
+ case WM_CHAR:
+ {
+ char c= (char) wParam;
+ queuekey.push (std::string (1, c) );
+ }
+ return TRUE;
+ case WM_MOUSEMOVE:
+ xmousepos= LOWORD (lParam);
+ ymousepos= HIWORD (lParam);
+ do_unrotate (xmousepos, ymousepos);
+ return TRUE;
+ case WM_LBUTTONDOWN:
+ queuekey.push (strCLICK);
+ return TRUE;
+ case WM_RBUTTONDOWN:
+ queuekey.push (strSCLICK);
+ return TRUE;
+ case WM_LBUTTONUP:
+ queuekey.push (strRELEASE);
+ return TRUE;
+ case WM_RBUTTONUP:
+ queuekey.push (strSRELEASE);
+ return TRUE;
+ case WM_DESTROY:
+ SetEvent (hEvent);
+ return TRUE;
+ default:
+ return DefWindowProc (hwnd, uMsg, wParam, lParam);
+ }
+}
+
+class ProtectWindow {
+ HWND hwnd;
+public:
+ ProtectWindow (HWND hwnd) : hwnd (hwnd) { }
+ ~ProtectWindow ()
+ {
+ if (hwnd)
+ DestroyWindow (hwnd);
+ }
+ void release ()
+ {
+ hwnd= 0;
+ }
+};
+
+class ProtectPixmap {
+ HBITMAP & pixmap;
+ bool active;
+public:
+ ProtectPixmap (HBITMAP & pixmap) : pixmap (pixmap), active (true) { }
+ ~ProtectPixmap ()
+ {
+ if (active)
+ {
+ DeleteObject (pixmap);
+ pixmap= NULL;
+ }
+ }
+ void release ()
+ {
+ active= false;
+ }
+};
+
+void thread_create_window (int width, int height)
+{
+ window= CreateWindow (
+ LPCTSTR (atomClass),
+ default_title.c_str (),
+ /*WS_VISIBLE | */ WS_SYSMENU | WS_MINIMIZEBOX,
+ 0, 0,
+ width + GetSystemMetrics (SM_CXDLGFRAME) * 2,
+ height + GetSystemMetrics (SM_CYDLGFRAME) * 2 +
+ GetSystemMetrics (SM_CYCAPTION),
+ NULL,
+ NULL,
+ GetModuleHandle (0),
+ 0);
+ if (window)
+ {
+ ProtectWindow pw (window);
+ hdc= GetDC (window);
+ if (hdc == NULL)
+ return;
+ pixmap= CreateCompatibleBitmap (hdc, width, height);
+ if (pixmap == NULL)
+ return;
+ ProtectPixmap pp (pixmap);
+ hdcPixmap= CreateCompatibleDC (hdc);
+ if (hdcPixmap == NULL)
+ return;
+ SelectObject (hdcPixmap, pixmap);
+ init_colors ();
+ reinit_pixmap ();
+ window_created= true;
+ ShowWindow (window, SW_SHOWNORMAL);
+ //SetActiveWindow (window);
+ SetForegroundWindow (window);
+ pw.release ();
+ pp.release ();
+ }
+}
+
+// Testing new method of create and destroy windows.
+
+struct ThreadParams {
+ int width, height;
+};
+
+unsigned WINAPI threadproc (void * arg)
+{
+ MSG msg;
+ ThreadParams * tp= reinterpret_cast <ThreadParams *> (arg);
+ thread_create_window (tp->width, tp->height);
+ // Ensure the message queue exist before the main thread continues.
+ // Perhpas unnecesary with the new method, but...
+ PeekMessage (& msg, NULL, 0, UINT (-1), PM_NOREMOVE);
+ SetEvent (hEvent);
+ if (! window_created)
+ return 0;
+ while (GetMessage (& msg, NULL, 0, 0) )
+ {
+ switch (msg.message)
+ {
+ case WM_USER_CREATE_WINDOW:
+ //thread_create_window (msg.wParam, msg.lParam);
+ SetEvent (hEvent);
+ break;
+ case WM_USER_DESTROY_WINDOW:
+ if (DestroyWindow (window) == 0)
+ cerr << "Error destroying: " <<
+ GetLastError () << endl;
+ break;
+ default:
+ TranslateMessage (& msg);
+ DispatchMessage (& msg);
+ }
+ }
+ return 0;
+}
+
+void create_thread (int width, int height)
+{
+ ThreadParams tp= { width, height };
+ hthread= HANDLE (_beginthreadex (NULL, 0, threadproc,
+ & tp, 0, (unsigned int *) (& idthread) ) );
+ if (hthread == NULL)
+ {
+ if (showdebuginfo () )
+ cerr << "Error creating graphics thread" << endl;
+ throw ErrBlassicInternal;
+ }
+ WaitForSingleObject (hEvent, INFINITE);
+ if (! window_created)
+ {
+ WaitForSingleObject (hthread, INFINITE);
+ CloseHandle (hthread);
+ idthread= 0;
+ hthread= NULL;
+ }
+}
+
+void destroy_thread ()
+{
+ if (idthread)
+ {
+ BOOL r= PostThreadMessage (idthread, WM_QUIT, 0, 0);
+ if (r == 0)
+ {
+ TerminateThread (hthread, 0);
+ }
+ else
+ {
+ WaitForSingleObject (hthread, INFINITE);
+ }
+ CloseHandle (hthread);
+ idthread= 0;
+ hthread= NULL;
+ }
+}
+
+#endif // WINDOWS
+
+void create_window (int width, int height)
+{
+ TRACEFUNC (tr, "create_window");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ if (hthread == NULL)
+ {
+ create_thread (width, height);
+ if (hthread == NULL)
+ throw ErrBlassicInternal;
+ }
+ BOOL r= PostThreadMessage (idthread, WM_USER_CREATE_WINDOW,
+ WPARAM (width), LPARAM (height) );
+ if (r == 0)
+ {
+ cerr << "Error communicating with graphics thread"
+ "GetLastError =" << GetLastError () <<
+ endl;
+ destroy_thread ();
+ throw ErrBlassicInternal;
+ }
+ WaitForSingleObject (hEvent, INFINITE);
+ if (! window_created)
+ {
+ if (showdebuginfo () )
+ cerr << "Error creating window" << endl;
+ throw ErrBlassicInternal;
+ }
+
+ #elif defined BLASSIC_USE_X
+
+ #if 1
+ window= XCreateSimpleWindow (display,
+ RootWindow (display, screen),
+ 0, 0, width, height,
+ 5, BlackPixel (display, screen),
+ WhitePixel (display, screen) );
+ #else
+ int depth= 8;
+ window= XCreateWindow (display,
+ RootWindow (display, screen),
+ 0, 0, width, height,
+ 5,
+ depth,
+ InputOutput,
+ CopyFromParent,
+ 0,
+ NULL);
+ #endif
+ window_created= true;
+
+ #if 0
+ int depth= DefaultDepth (display, DefaultScreen (display) );
+ #else
+ unsigned int depth;
+ {
+ XWindowAttributes attr;
+ XGetWindowAttributes (display, window, & attr);
+ depth= attr.depth;
+ }
+ #endif
+ pixmap= XCreatePixmap (display, window,
+ width, height, depth);
+ pixmap_created= true;
+
+ gc= XCreateGC (display, window, 0, & gcvalues);
+ gcp= XCreateGC (display, pixmap, 0, & gcvaluesp);
+ init_colors ();
+ reinit_pixmap ();
+ XSetStandardProperties (display, window,
+ default_title.c_str (),
+ default_title.c_str (),
+ None,
+ 0, 0, NULL);
+
+ eventusedmaskactual= eventusedmask;
+
+ if (xim)
+ {
+ XIMStyle input_style= XIMPreeditNothing | XIMStatusNothing;
+ xic= XCreateIC (xim,
+ XNInputStyle, input_style,
+ XNClientWindow, window,
+ XNFocusWindow, window,
+ NULL);
+ }
+ if (xic != NULL)
+ {
+ TRMESSAGE (tr, "XIC created");
+
+ long filterevents;
+ if (XGetICValues (xic,
+ XNFilterEvents, & filterevents,
+ NULL)
+ == NULL);
+ {
+ eventusedmaskactual |= filterevents;
+ }
+ }
+ else
+ {
+ TRMESSAGE (tr, "XIC not created");
+ }
+
+ XSelectInput (display, window, eventusedmaskactual);
+ XMapWindow (display, window);
+
+ // Wait for window mapping.
+ {
+ XEvent e;
+ do
+ {
+ XNextEvent (display, & e);
+ } while (e.type != MapNotify);
+ }
+
+ graphics::idle ();
+
+ #endif
+}
+
+void destroy_window ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ PostThreadMessage (idthread, WM_USER_DESTROY_WINDOW, 0, 0);
+ WaitForSingleObject (hEvent, INFINITE);
+ DeleteDC (hdcPixmap);
+ DeleteObject (pixmap);
+ window= 0;
+ window_created= false;
+ destroy_thread ();
+
+ #elif defined BLASSIC_USE_X
+
+ XDestroyWindow (display, window);
+ window_created= false;
+ XFreePixmap (display, pixmap);
+ pixmap_created= false;
+ XFlush (display);
+ graphics::idle ();
+
+ #endif
+}
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+inline void requiregraphics ()
+{
+ #ifndef BLASSIC_HAS_GRAPHICS
+
+ no_graphics_support ();
+
+ #else
+
+ //if (actualmode == text_mode)
+ if (! graphics_mode_active)
+ throw ErrNoGraphics;
+
+ #endif
+}
+
+std::string program_name;
+
+#ifdef BLASSIC_USE_X
+
+std::string getDISPLAY ()
+{
+ const char * strdisplay= getenv ("DISPLAY");
+ if (strdisplay == NULL)
+ return std::string ();
+ else
+ return strdisplay;
+}
+
+std::string last_display;
+
+#endif
+
+void initialize_graphics ()
+{
+ TRACEFUNC (tr, "initialize_graphics");
+ // Does the real initialization of the graphics system.
+ // It will not be called until a graphics mode ise
+ // established.
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ ASSERT (! inited);
+
+ const bool showfailinfo= showdebuginfo ();
+
+ #ifdef BLASSIC_USE_SVGALIB
+
+ if (geteuid () == 0) {
+ std::string prog (program_name);
+ std::string::size_type l= prog.size ();
+ if (l > 3 && prog.substr (l - 3) == "vga") {
+ vga_init ();
+ inited= true;
+ svgalib= true;
+ return;
+ }
+ else
+ if (getuid () != 0)
+ seteuid (getuid () );
+ }
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ const char * strDisplay;
+ static const char WITHOUT_GRAPHICS []=
+ ", running without graphics support.";
+
+ if ( (strDisplay= getenv ("DISPLAY") ) != NULL &&
+ strDisplay [0] != '\0')
+ {
+ TRMESSAGE (tr, std::string ("Opening ") + strDisplay);
+ display= XOpenDisplay (0);
+ if (display)
+ {
+ last_display= strDisplay;
+ TRMESSAGE (tr, "Display opened");
+ inited= true;
+ XSetLocaleModifiers (""); // Testing.
+ XSetLocaleModifiers ("@im=none"); // Testing.
+ xim= XOpenIM (display, NULL, NULL, NULL);
+ if (xim != NULL)
+ {
+ TRMESSAGE (tr, "XIM opened");
+ }
+ screen= DefaultScreen (display);
+ //init_xcolors ();
+ //init_colors ();
+ }
+ else
+ {
+ static const char ERROR_OPEN []=
+ "Error opening DISPLAY '";
+ TRMESSAGE (tr, std::string (ERROR_OPEN) +
+ strDisplay+ '\'');
+ if (showfailinfo)
+ cerr << ERROR_OPEN <<
+ strDisplay << '\'' <<
+ WITHOUT_GRAPHICS <<
+ endl;
+ }
+ }
+ else
+ {
+ const char * const message= strDisplay ? "Empty" : "No";
+ static const char DISPLAY []= " DISPLAY value";
+ TRMESSAGE (tr, std::string (message) + DISPLAY);
+ if (showfailinfo)
+ cerr << message << DISPLAY << WITHOUT_GRAPHICS <<
+ endl;
+ }
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ WNDCLASS wndclass;
+ wndclass.style= CS_NOCLOSE | CS_OWNDC;
+ wndclass.lpfnWndProc= windowproc;
+ wndclass.cbClsExtra= 0;
+ wndclass.cbWndExtra= 0;
+ wndclass.hInstance= GetModuleHandle (0);
+ wndclass.hIcon= 0;
+ wndclass.hCursor= LoadCursor (NULL, IDC_ARROW);
+ wndclass.hbrBackground= HBRUSH (GetStockObject (WHITE_BRUSH) );
+ wndclass.lpszMenuName= 0;
+ wndclass.lpszClassName= program_name.c_str ();
+ atomClass= RegisterClass (& wndclass);
+ if (atomClass == 0)
+ {
+ if (showfailinfo)
+ cerr << "Error registering class" << endl;
+ }
+ else
+ {
+ inited= true;
+ //init_wincolors ();
+ //init_colors ();
+ }
+ hEvent= CreateEvent (NULL, FALSE, FALSE, NULL);
+ // Event automatic, initial nonsignaled
+ //create_thread ();
+
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ #endif
+}
+
+void destroy_text_windows ();
+
+void check_initialized ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (! inited)
+ initialize_graphics ();
+ else
+ {
+ #ifdef BLASSIC_USE_X
+ if (last_display != getDISPLAY () )
+ {
+ destroy_text_windows ();
+ graphics::setmode (text_mode);
+ graphics::uninitialize ();
+ initialize_graphics ();
+ }
+ #endif
+ }
+
+ #endif
+}
+
+} // namespace
+
+void graphics::initialize (const char * progname)
+{
+ TRACEFUNC (tr, "graphics::initialize");
+
+ // Default symbol after and charset initialization:
+ symbolafter (0);
+
+ // Now complete initialization is not done here.
+ #if 1
+
+ program_name= progname;
+
+ #else
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ ASSERT (! inited);
+
+ const bool showfailinfo= showdebuginfo ();
+
+ #ifdef BLASSIC_USE_SVGALIB
+
+ if (geteuid () == 0) {
+ std::string prog (progname);
+ std::string::size_type l= prog.size ();
+ if (l > 3 && prog.substr (l - 3) == "vga") {
+ vga_init ();
+ inited= true;
+ svgalib= true;
+ return;
+ }
+ else
+ if (getuid () != 0)
+ seteuid (getuid () );
+ }
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ touch (progname);
+ const char * strDisplay;
+ static const char WITHOUT_GRAPHICS []=
+ ", running without graphics support.";
+
+ if ( (strDisplay= getenv ("DISPLAY") ) != NULL &&
+ strDisplay [0] != '\0')
+ {
+ TRMESSAGE (tr, std::string ("Opening ") + strDisplay);
+ display= XOpenDisplay (0);
+ if (display)
+ {
+ TRMESSAGE (tr, "Display opened");
+ inited= true;
+ XSetLocaleModifiers (""); // Testing.
+ XSetLocaleModifiers ("@im=none"); // Testing.
+ xim= XOpenIM (display, NULL, NULL, NULL);
+ if (xim != NULL)
+ {
+ TRMESSAGE (tr, "XIM opened");
+ }
+ screen= DefaultScreen (display);
+ //init_xcolors ();
+ //init_colors ();
+ }
+ else
+ {
+ static const char ERROR_OPEN []=
+ "Error opening DISPLAY '";
+ TRMESSAGE (tr, std::string (ERROR_OPEN) +
+ strDisplay+ '\'');
+ if (showfailinfo)
+ cerr << ERROR_OPEN <<
+ strDisplay << '\'' <<
+ WITHOUT_GRAPHICS <<
+ endl;
+ }
+ }
+ else
+ {
+ const char * const message= strDisplay ? "Empty" : "No";
+ static const char DISPLAY []= " DISPLAY value";
+ TRMESSAGE (tr, std::string (message) + DISPLAY);
+ if (showfailinfo)
+ cerr << message << DISPLAY << WITHOUT_GRAPHICS <<
+ endl;
+ }
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ WNDCLASS wndclass;
+ wndclass.style= CS_NOCLOSE | CS_OWNDC;
+ wndclass.lpfnWndProc= windowproc;
+ wndclass.cbClsExtra= 0;
+ wndclass.cbWndExtra= 0;
+ wndclass.hInstance= GetModuleHandle (0);
+ wndclass.hIcon= 0;
+ wndclass.hCursor= LoadCursor (NULL, IDC_ARROW);
+ wndclass.hbrBackground= HBRUSH (GetStockObject (WHITE_BRUSH) );
+ wndclass.lpszMenuName= 0;
+ wndclass.lpszClassName= progname;
+ atomClass= RegisterClass (& wndclass);
+ if (atomClass == 0)
+ {
+ if (showfailinfo)
+ cerr << "Error registering class" << endl;
+ }
+ else
+ {
+ inited= true;
+ //init_wincolors ();
+ //init_colors ();
+ }
+ hEvent= CreateEvent (NULL, FALSE, FALSE, NULL);
+ // Event automatic, initial nonsignaled
+ //create_thread ();
+
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (progname);
+
+ #endif
+
+ #endif
+}
+
+void graphics::uninitialize ()
+{
+ TRACEFUNC (tr, "graphics::uninitialize");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (! inited) return;
+
+ //if (actualmode != 0)
+ if (graphics_mode_active)
+ setmode (0);
+
+ #ifdef BLASSIC_USE_SVGA
+ #if 0
+ if (svgalib)
+ //vga_setmode (TEXT);
+ setmode (0);
+ #endif
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ if (display)
+ {
+ clear_images ();
+ TRMESSAGE (tr, "closing display");
+ //if (window_created)
+ // destroy_window ();
+ if (xic)
+ XDestroyIC (xic);
+ if (xim)
+ XCloseIM (xim);
+ XCloseDisplay (display);
+ TRMESSAGE (tr, "display is closed");
+ display= 0;
+ }
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ //destroy_thread ();
+ //if (window_created)
+ // destroy_window ();
+
+ if (atomClass)
+ UnregisterClass (LPCTSTR (atomClass),
+ GetModuleHandle (0) );
+ #endif
+
+ inited= false;
+
+ #endif
+ // BLASSIC_HAS_GRAPHICS
+}
+
+void graphics::origin (int x, int y)
+{
+ TRACEFUNC (tr, "graphics::origin");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ set_origin (x, y);
+
+ #else
+
+ touch (x, y);
+ no_graphics_support ();
+
+ #endif
+}
+
+void graphics::limits (int minx, int maxx, int miny, int maxy)
+{
+ TRACEFUNC (tr, "graphics::limits");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ set_limits (minx, maxx, miny, maxy);
+
+ #else
+
+ touch (minx, maxx, miny, maxy);
+ no_graphics_support ();
+
+ #endif
+}
+
+void graphics::ink (int inknum, int cpccolor)
+{
+ requiregraphics ();
+
+ // Check not needed, is done in setcpcink.
+ //if (cpccolor < 0 || cpccolor > 26)
+ // throw ErrFunctionCall;
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ setcpcink (inknum, cpccolor);
+
+ #else
+
+ touch (inknum, cpccolor);
+
+ #endif
+}
+
+void graphics::ink (int inknum, int r, int g, int b)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ ColorRGB rgb= { r, g, b };
+ setink (inknum, rgb);
+
+ #else
+
+ touch (inknum, r, g, b);
+
+ #endif
+}
+
+void graphics::clearink ()
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ init_colors ();
+
+ #endif
+}
+
+namespace {
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+#ifdef BLASSIC_USE_X
+
+void keypress (XKeyPressedEvent & xk)
+{
+ TRACEFUNC (tr, "keypress");
+
+ KeySym ks= 0;
+ const int STRBUFSIZE= 500; // Value used in xterm.
+ char buffer [STRBUFSIZE];
+ int r;
+ if (xic != NULL)
+ {
+ Status status;
+ r= XmbLookupString (xic, & xk, buffer, STRBUFSIZE,
+ & ks, & status);
+ }
+ else
+ {
+ r= XLookupString (& xk, buffer, STRBUFSIZE - 1,
+ & ks, NULL);
+ }
+
+ // Change cursor keys if rotated.
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ switch (ks)
+ {
+ case XK_Left:
+ ks= XK_Up; break;
+ case XK_Up:
+ ks= XK_Right; break;
+ case XK_Right:
+ ks= XK_Down; break;
+ case XK_Down:
+ ks= XK_Left; break;
+
+ case XK_KP_Left:
+ ks= XK_KP_Up; break;
+ case XK_KP_Up:
+ ks= XK_KP_Right; break;
+ case XK_KP_Right:
+ ks= XK_KP_Down; break;
+ case XK_KP_Down:
+ ks= XK_KP_Left; break;
+ }
+ break;
+ }
+ #ifndef NDEBUG
+ {
+ std::ostringstream oss;
+ //oss << std::hex << std::setw (4) << ks;
+ oss << std::hex << std::setw (4) << xk.keycode;
+ //if (r > 0)
+ oss << " CHAR: " << buffer [0];
+ TRMESSAGE (tr, oss.str () );
+ }
+ #endif
+ //set_pressed (ks);
+
+ #if 0
+ std::string str= string_from_key (ks);
+ #else
+
+ // I don't know why XmbLookupString does not return
+ // the Euro sign as string, this is a dirty solution.
+ std::string str;
+ #ifdef XK_EuroSign
+ if (ks == XK_EuroSign)
+ {
+ const char eurochar (164);
+ str= std::string (1, eurochar);
+ }
+ else
+
+ #endif
+ str= string_from_key (ks);
+ #endif
+
+ if (! str.empty () )
+ {
+ TRMESSAGE (tr, std::string ("key") + str);
+ queuekey.push (str);
+ }
+ else
+ if (r > 0)
+ {
+ TRMESSAGE (tr, std::string ("key: ") +
+ std::string (buffer, r) );
+ queuekey.push (std::string (buffer, r) );
+ }
+}
+
+void keyrelease (XKeyReleasedEvent & xk)
+{
+ KeySym ks= 0;
+ const int STRBUFSIZE= 500; // Value used in xterm.
+ char buffer [STRBUFSIZE];
+ int r;
+ if (xic == NULL)
+ {
+ r= XLookupString (& xk, buffer, STRBUFSIZE - 1,
+ & ks, NULL);
+ }
+
+ // Change cursor keys if rotated.
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ switch (ks)
+ {
+ case XK_Left:
+ ks= XK_Up; break;
+ case XK_Up:
+ ks= XK_Right; break;
+ case XK_Right:
+ ks= XK_Down; break;
+ case XK_Down:
+ ks= XK_Left; break;
+
+ case XK_KP_Left:
+ ks= XK_KP_Up; break;
+ case XK_KP_Up:
+ ks= XK_KP_Right; break;
+ case XK_KP_Right:
+ ks= XK_KP_Down; break;
+ case XK_KP_Down:
+ ks= XK_KP_Left; break;
+ }
+ break;
+ }
+ //reset_pressed (ks);
+}
+
+void process_event (XEvent & x_event, bool & do_copy)
+{
+ // Set the state of pressed keys before checking XFilterEvent.
+ switch (x_event.type)
+ {
+ case KeyPress:
+ keycode_press (x_event.xkey.keycode);
+ break;
+ case KeyRelease:
+ keycode_release (x_event.xkey.keycode);
+ break;
+ }
+
+ if (XFilterEvent (& x_event, window) )
+ return;
+
+ switch (x_event.type)
+ {
+ case Expose:
+ do_copy= true;
+ break;
+ case KeyPress:
+ keypress (x_event.xkey);
+ break;
+ case KeyRelease:
+ keyrelease (x_event.xkey);
+ break;
+ case ButtonPress:
+ {
+ XButtonEvent & xbpe= x_event.xbutton;
+ //cerr << "ButtonPress event, button=" <<
+ // xbpe.button <<
+ // endl;
+ switch (xbpe.button)
+ {
+ case 1:
+ queuekey.push (strCLICK);
+ break;
+ case 3:
+ queuekey.push (strSCLICK);
+ break;
+ default:
+ ;
+ }
+ }
+ break;
+ case ButtonRelease:
+ {
+ XButtonEvent & xbpe= x_event.xbutton;
+ //cerr << "ButtonRelease event, button=" <<
+ // xbpe.button <<
+ // endl;
+ switch (xbpe.button)
+ {
+ case 1:
+ queuekey.push (strRELEASE);
+ break;
+ case 3:
+ queuekey.push (strSRELEASE);
+ break;
+ default:
+ ;
+ }
+ }
+ break;
+ case MotionNotify:
+ {
+ XMotionEvent & xme= x_event.xmotion;
+ //cerr << "MotionNotify event " <<
+ // xme.x << ", " << xme.y <<
+ // endl;
+ xmousepos= xme.x;
+ ymousepos= xme.y;
+ do_unrotate (xmousepos, ymousepos);
+ }
+ break;
+ case EnterNotify:
+ {
+ XCrossingEvent & xce= x_event.xcrossing;
+ //cerr << "EnterNotify event" << endl;
+ xmousepos= xce.x;
+ ymousepos= xce.y;
+ do_unrotate (xmousepos, ymousepos);
+ }
+ break;
+ default:
+ //cerr << "Another event." << endl;
+ ;
+ } // switch type of event
+}
+
+void wait_X_event ()
+{
+ ASSERT (window_created);
+
+ XEvent x_event;
+ bool do_copy= false;
+ XWindowEvent (display, window, eventusedmaskactual, & x_event);
+ process_event (x_event, do_copy);
+ if (do_copy && pixmap_created)
+ reinit_window ();
+}
+
+#endif
+// BLASSIC_USE_X
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+} // namespace
+
+//void graphics::idle ()
+void blassic::idle ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (! window_created)
+ return;
+
+ #ifdef BLASSIC_USE_X
+
+ XEvent x_event;
+ bool do_copy= false;
+ while (XCheckWindowEvent (display, window,
+ eventusedmaskactual, & x_event) )
+ {
+ process_event (x_event, do_copy);
+ } // while
+ if (do_copy && pixmap_created)
+ {
+ #if 0
+ XCopyArea (display, pixmap, window, gc,
+ 0, 0, screenwidth, screenheight, 0, 0);
+ XFlush (display);
+ #else
+ //XSetFunction (display, gc, drawmode_copy);
+ reinit_window ();
+ //XSetFunction (display, gc, drawmode);
+ #endif
+ //cerr << "Copied." << endl;
+ }
+
+ #endif
+
+ #ifdef BLASSIC_USE_WINDOWS
+ //UpdateWindow (window);
+ //Sleep (0);
+ #endif
+
+ #endif
+ // BLASSIC_HAS_GRAPHICS
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+void setactivecolor (pcolor pxc)
+{
+ activecolor= pxc;
+
+ #ifdef BLASSIC_USE_X
+
+ XSetForeground (display, gcp, pxc->pixel);
+ XSetForeground (display, gc, pxc->pixel);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ SelectObject (hdc, * pxc);
+ SelectObject (hdcPixmap, *pxc);
+
+ #endif
+}
+
+void textscroll ()
+{
+ #ifdef BLASSIC_USE_SVGALIB
+ if (svgalib)
+ {
+ // PENDIENTE
+ return;
+ }
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ int h= screenheight - 8;
+ //unsigned long white= WhitePixel (display, screen),
+ // black= BlackPixel (display, screen);
+
+ XSetFunction (display, gcp, drawmode_copy);
+ XCopyArea (display, pixmap, pixmap, gcp,
+ 0, 8, screenwidth, h, 0, 0);
+ setactivecolor (pbackground);
+ XFillRectangle (display, pixmap, gcp,
+ 0, h, screenwidth, 8);
+ setactivecolor (pforeground);
+ XSetFunction (display, gcp, drawmode);
+
+ if (! fSynchro)
+ reinit_window ();
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ RECT r = { 0, screenheight - 8, screenwidth, screenheight };
+
+ int h= screenheight - 8;
+ BitBlt (hdcPixmap, 0, 0, screenwidth, h,
+ hdcPixmap, 0, 8, SRCCOPY);
+ //HBRUSH hbrush= (HBRUSH) GetStockObject (WHITE_BRUSH);
+ LOGPEN logpen;
+ GetObject (* pbackground, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ FillRect (hdcPixmap, & r, hbrush);
+ DeleteObject (hbrush);
+ if (! fSynchro)
+ reinit_window ();
+
+ #endif
+
+}
+
+void do_fill_rectangle (int x1, int y1, int x2, int y2, bool limitable)
+{
+ using std::min;
+ using std::max;
+ if (limitable && limited)
+ {
+ x1= max (x1, limit_minx);
+ y1= max (y1, limit_miny);
+ x2= min (x2, limit_maxx);
+ y2= min (y2, limit_maxy);
+ if (x1 > limit_maxx || x2 < limit_minx ||
+ y1 > limit_maxy || y2 < limit_miny)
+ return;
+ }
+
+ do_rotate (x1, y1);
+ do_rotate (x2, y2);
+ if (x1 > x2)
+ std::swap (x1, x2);
+ if (y1 > y2)
+ std::swap (y1, y2);
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ RECT r = { x1, y1, x2 + 1, y2 + 1 };
+ LOGPEN logpen;
+ //GetObject (* pforeground, sizeof (LOGPEN), & logpen);
+ GetObject (* activecolor, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ FillRect (hdcPixmap, & r, hbrush);
+ if (! fSynchro)
+ FillRect (hdc, & r, hbrush);
+ DeleteObject (hbrush);
+
+ #elif defined BLASSIC_USE_X
+
+ //int w= std::abs (x2 - x1) + 1;
+ //int h= std::abs (y2 - y1) + 1;
+ int w= x2 - x1 + 1;
+ int h= y2 - y1 + 1;
+ XFillRectangle (display, pixmap, gcp,
+ x1, y1, w, h);
+ if (! fSynchro)
+ XFillRectangle (display, window, gc,
+ x1, y1, w, h);
+
+ #endif
+}
+
+#ifdef BLASSIC_USE_WINDOWS
+
+// Define in windows the struct used in X for XDrawPoints.
+struct XPoint {
+ short x, y;
+};
+
+#endif
+
+inline void do_plot (int x, int y)
+{
+ if (! check_limit (x, y) )
+ return;
+
+ do_rotate (x, y);
+
+ #ifdef BLASSIC_USE_SVGALIB
+
+ if (svgalib)
+ {
+ vga_drawpixel (x, y);
+ return;
+ }
+
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ if (! fSynchro)
+ XDrawPoint (display, window, gc, x, y);
+ XDrawPoint (display, pixmap, gcp, x, y);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ #ifdef USE_POLY
+ POINT p [2]= { {x, y}, {x + 1, y} };
+ #endif
+
+ if (! fSynchro)
+ {
+ #ifdef USE_POLY
+ Polyline (hdc, p, 2);
+ #else
+ MoveToEx (hdc, x, y, 0);
+ LineTo (hdc, x + 1, y);
+ #endif
+ }
+ #ifdef USE_POLY
+ Polyline (hdcPixmap, p, 2);
+ #else
+ MoveToEx (hdcPixmap, x, y, 0);
+ LineTo (hdcPixmap, x + 1, y);
+ #endif
+
+ #endif
+}
+
+// This are now not used, every text window has his own
+//int tcol, trow;
+
+int maxtcol= 40, maxtrow= 25;
+
+const int MAXZOOMTEXTY= 4;
+const int MAXZOOMTEXTX= 4;
+//const int MAXZOOMTEXT= std::max (MAXZOOMTEXTX, MAXZOOMTEXTY);
+// Borland C++ can't evaluate this at compile time.
+const int MAXZOOMTEXT= 4;
+
+// Default values are needed by the initialization of windowzero.
+int zoomtextx= 1, zoomtexty= 1;
+//int zoomtextxrot= 1, zoomtextyrot= 1;
+int charwidth= 8, charheight= 8;
+//int charwidthrot= 9, charheightrot= 8;
+
+#ifdef BLASSIC_USE_WINDOWS
+
+// Length of each segment: all are 2 points.
+DWORD poly_points [64 * MAXZOOMTEXT];
+bool init_poly_points ()
+{
+ std::fill_n (poly_points, util::dim_array (poly_points), 2);
+ return true;
+}
+bool poly_points_inited= init_poly_points ();
+
+#endif
+
+inline void do_plot_points (XPoint point [], int npoints, bool limitable)
+{
+ ASSERT (npoints < 64 * zoomtexty);
+
+ if (rotate != RotateNone)
+ for (int i= 0; i < npoints; ++i)
+ do_rotate (point [i].x, point [i].y);
+
+ #ifdef BLASSIC_USE_X
+
+ if (zoomtextx == 1)
+ {
+ XDrawPoints (display, pixmap, gcp,
+ point, npoints, CoordModeOrigin);
+ if (! fSynchro)
+ XDrawPoints (display, window, gc,
+ point, npoints, CoordModeOrigin);
+ }
+ else
+ {
+ // 64 points each char * max zoomtexty
+ XSegment seg [64 * MAXZOOMTEXT];
+ int inc= zoomtextx - 1;
+ int xinc= 0, yinc= 0;
+ switch (rotate)
+ {
+ case RotateNone:
+ xinc= inc; break;
+ case Rotate90:
+ yinc= -inc; break;
+ }
+ for (int i= 0; i < npoints; ++i)
+ {
+ int xpos= point [i].x;
+ int ypos= point [i].y;
+ seg [i].x1= xpos;
+ seg [i].y1= ypos;
+ //xpos+= zoomtextx - 1;
+ xpos+= xinc;
+ ypos+= yinc;
+ if (limitable && limited)
+ {
+ xpos= std::min (xpos, limit_maxx);
+ ypos= std::max (ypos, limit_miny);
+ }
+ seg [i].x2= xpos;
+ seg [i].y2= ypos;
+ }
+ XDrawSegments (display, pixmap, gcp, seg, npoints);
+ if (! fSynchro)
+ XDrawSegments (display, window, gc, seg, npoints);
+ }
+
+ #endif
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ // The PolyPolyline is a bit faster than doing each
+ // point separately.
+ // 64 * 2 points by segment * max zoomtexty
+ static POINT p [64 * 2 * MAXZOOMTEXT];
+ // 64 points each char * max zoomtexty
+
+ int inc= zoomtextx;
+ //if (zoomtextx > 1)
+ // ++inc;
+ int xinc= 0, yinc= 0;
+ switch (rotate)
+ {
+ case RotateNone:
+ xinc= inc; break;
+ case Rotate90:
+ yinc= -inc; break;
+ }
+ for (int i= 0; i < npoints; ++i)
+ {
+ int xpos= point [i].x;
+ int ypos= point [i].y;
+ p [2 * i].x= xpos;
+ p [2 * i].y= ypos;
+ //xpos+= zoomtextxrot;
+ //if (zoomtextxrot > 1) ++xpos;
+ xpos+= xinc;
+ ypos+= yinc;
+ if (limitable && limited)
+ {
+ xpos= std::min (xpos, limit_maxx);
+ ypos= std::max (ypos, limit_miny);
+ }
+ p [2 * i + 1].x= xpos;
+ p [2 * i + 1].y= ypos;
+ }
+ if (! fSynchro)
+ PolyPolyline (hdc, p, poly_points, npoints);
+ PolyPolyline (hdcPixmap, p, poly_points, npoints);
+
+ #endif
+}
+
+void printxy (int x, int y, unsigned char ch,
+ bool limitable, bool inverse= false, bool underline= false)
+{
+ TRACEFUNC (tr, "printxy");
+
+ static unsigned char mask [8]= { 128, 64, 32, 16, 8, 4, 2, 1 };
+
+ //charset::chardata & data= charset::data [ch];
+
+ charset::chardata data;
+ memcpy (data, charset::data [ch], sizeof (charset::chardata) );
+ if (underline)
+ data [7]= 255;
+
+ XPoint point [64 * MAXZOOMTEXT]; // 64 pixels * max zoom height
+ int n= 0, npoints= 0;
+ for (int i= 0, yi= y; i < 8; ++i, yi+= zoomtexty)
+ {
+ unsigned char c= data [i];
+ if (inverse)
+ c= static_cast <unsigned char> (~ c);
+
+ // Little optimization:
+ if (c == 0)
+ continue;
+
+ for (int j= 0, xj= x; j < 8; ++j, xj+= zoomtextx)
+ {
+ if (c & mask [j] )
+ {
+ for (int z= 0; z < zoomtexty; ++z)
+ {
+ int y= yi + z;
+ if (! limitable ||
+ check_limit (xj, y) )
+ {
+ point [n].x= static_cast
+ <short> (xj);
+ point [n].y= static_cast
+ <short> (y);
+ ++n;
+ }
+ }
+ ++npoints;
+ }
+ }
+ }
+ if (npoints < 64)
+ {
+ if (opaquemode)
+ {
+ setactivecolor (pbackground);
+ do_fill_rectangle (x, y,
+ x + charwidth - 1, y + charheight - 1,
+ limitable);
+ }
+ if (n > 0)
+ {
+ setactivecolor (pforeground);
+ do_plot_points (point, n, limitable);
+ }
+ else
+ setactivecolor (pforeground);
+ }
+ else
+ {
+ setactivecolor (pforeground);
+ do_fill_rectangle (x, y,
+ x + charwidth - 1, y + charheight - 1,
+ limitable);
+ }
+}
+
+inline void print (int col, int row, unsigned char ch,
+ bool inverse, bool underline= false)
+{
+ printxy (col * charwidth, row * charheight, ch, false,
+ inverse, underline);
+}
+
+void setmaxtext ()
+{
+ charwidth= 8 * zoomtextx;
+ charheight= 8 * zoomtexty;
+ //charwidthrot= charwidth;
+ //charheightrot= charheight;
+ //do_rotate_rel (charwidthrot, charheightrot);
+
+ //maxtcol= screenwidth / charwidthrot;
+ //maxtrow= screenheight / charheightrot;
+ maxtcol= screenwidth / charwidth;
+ maxtrow= screenheight / charheight;
+
+ #if 0
+ switch (rotate)
+ {
+ case RotateNone:
+ break;
+ case Rotate90:
+ std::swap (maxtcol, maxtrow);
+ break;
+ }
+ #endif
+}
+
+void recreate_windows ();
+
+void set_mode (int width, int height, int mode, int charx= 1, int chary= 1)
+{
+ TRACEFUNC (tr, "set_mode");
+
+ ASSERT (charx >= 1 && charx <= MAXZOOMTEXTX);
+ ASSERT (chary >= 1 && chary <= MAXZOOMTEXTY);
+
+ std::ostringstream oss;
+ oss << "Width " << short (width) << ", height " << short (height);
+ TRMESSAGE (tr, oss.str () );
+
+ if (mode != 0 && (width <= 0 || height <= 0) )
+ throw ErrImproperArgument;
+
+ if (mode != text_mode)
+ {
+ check_initialized ();
+ if (! inited)
+ {
+ if (showdebuginfo () )
+ cerr << "Graphics system not initialized" <<
+ endl;
+ throw ErrFunctionCall;
+ }
+ }
+
+ sysvar::set16 (sysvar::GraphicsWidth, short (width) );
+ sysvar::set16 (sysvar::GraphicsHeight, short (height) );
+ screenwidth= width;
+ screenheight= height;
+ switch (sysvar::get (sysvar::GraphRotate) )
+ {
+ case 0:
+ rotate= RotateNone;
+ // Nothing to do.
+ break;
+ case 1:
+ rotate= Rotate90;
+ // Rotate 90 degrees.
+ std::swap (width, height);
+ break;
+ default:
+ throw ErrFunctionCall;
+ }
+ realwidth= width;
+ realheight= height;
+ activetransform= TransformIdentity;
+ set_origin (0, 0);
+ fSynchro= false;
+ zoomtextx= charx;
+ zoomtexty= chary;
+ //zoomtextxrot= zoomtextx;
+ //zoomtextyrot= zoomtextyrot;
+ //do_rotate_rel (zoomtextxrot, zoomtextyrot);
+ clear_limits ();
+
+ #ifdef BLASSIC_USE_SVGALIB
+
+ if (svgalib) {
+ if (mode == user_mode)
+ throw ErrFunctionCall;
+ if (actualmode != text_mode)
+ {
+ free (font);
+ }
+ vga_setmode (mode);
+ if (mode != text_mode) {
+ setmaxtext ();
+ gl_setcontextvga (mode);
+ //font= new char [256 * 8 * 8 * BYTESPERPIXEL];
+ font= (char *)
+ malloc (2 * 256 * 8 * 8 * BYTESPERPIXEL);
+ gl_expandfont (8, 8, 15, gl_font8x8, font);
+ gl_setfont (8, 8, font);
+ //cout << "Listo" << endl;
+ graphics_mode_active= true;
+ }
+ else
+ graphics_mode_active= false;
+ actualmode= mode;
+ return;
+ }
+
+ #endif
+
+ if (mode != actualmode || mode == user_mode)
+ {
+ {
+ std::ostringstream oss;
+ oss << "Changing mode from " << actualmode <<
+ " to " << mode;
+ TRMESSAGE (tr, oss.str () );
+ }
+ if (window_created)
+ destroy_window ();
+ if (mode != text_mode)
+ {
+ create_window (width, height);
+ graphics_mode_active= true;
+ }
+ else
+ graphics_mode_active= false;
+ }
+ else
+ {
+ if (mode != text_mode)
+ {
+ //graphics::setcolor (0);
+ graphics::setdrawmode (0);
+ reinit_pixmap ();
+ reinit_window ();
+ }
+
+ #ifdef _Windows
+ else
+ if (actualmode != text_mode)
+ {
+ // REVISAR: ESTO NO PARECE VALIDO.
+ destroy_thread ();
+ graphics_mode_active= false;
+ }
+ #endif
+ }
+
+ actualmode= mode;
+
+ if (mode != text_mode)
+ {
+ //if (! colors_inited)
+ // init_colors ();
+ setmaxtext ();
+ //tcol= trow= 0;
+ lastx= lasty= 0;
+
+ #if defined (BLASSIC_USE_WINDOWS) || defined (BLASSIC_USE_X)
+ //pforeground= default_foreground;
+ //pbackground= default_background;
+ #endif
+
+ recreate_windows ();
+ }
+}
+
+} // namespace
+
+#endif
+
+void graphics::cls ()
+{
+ TRACEFUNC (tr, "graphics::cls");
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #ifdef BLASSIC_USE_SVGALIB
+
+ if (svgalib)
+ {
+ // PENDIENTE
+ return;
+ }
+
+ #endif
+
+ //tcol= trow= 0;
+ //reinit_pixmap ();
+
+ #if 0
+
+ int x1, y1, width, height;
+ if (limited)
+ {
+ TRMESSAGE (tr, "lmited");
+ x1= limit_minx; width= limit_maxx - limit_minx + 1;
+ y1= limit_miny; height= limit_maxy - limit_miny + 1;
+ }
+ else
+ {
+ TRMESSAGE (tr, "unlimited");
+ x1= 0; width= screenwidth;
+ y1= 0; height= screenheight;
+ }
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ //RECT r= { 0, 0, screenwidth, screenheight };
+ RECT r= { x1, y1, x1 + width + 1, y1 + height + 1 };
+ LOGPEN logpen;
+ GetObject (* pbackground, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ if (! fSynchro)
+ FillRect (hdc, & r, hbrush);
+ FillRect (hdcPixmap, & r, hbrush);
+ DeleteObject (hbrush);
+
+ #elif defined BLASSIC_USE_X
+
+ setactivecolor (pbackground);
+ XSetFunction (display, gcp, drawmode_copy);
+ XFillRectangle (display, pixmap, gcp,
+ //0, 0, screenwidth, screenheight);
+ x1, y1, width, height);
+ XSetFunction (display, gcp, drawmode);
+ if (! fSynchro)
+ {
+ XSetFunction (display, gc, drawmode_copy);
+ XFillRectangle (display, window, gc,
+ //0, 0, screenwidth, screenheight);
+ x1, y1, width, height);
+ XSetFunction (display, gc, drawmode);
+ // Inserted an idle call because without it
+ // the window sometimes is not updated.
+ graphics::idle ();
+ }
+ setactivecolor (pforeground);
+
+ #endif
+
+ #else
+
+ // Limit control is done by do_fill_rectangle.
+ setactivecolor (pbackground);
+ do_fill_rectangle (0, 0, screenwidth - 1, screenheight - 1, true);
+ setactivecolor (pforeground);
+
+ #endif
+
+ #endif
+ // BLASSIC_HAS_GRAPHICS
+}
+
+void graphics::setmode (int width, int height, bool inverty,
+ int zoomx, int zoomy)
+{
+ TRACEFUNC (tr, "graphics::setmode");
+
+ #ifndef BLASSIC_HAS_GRAPHICS
+
+ touch (width, height, inverty, zoomx, zoomy);
+ no_graphics_support ();
+
+ #else
+
+ #if 0
+ if (! inited)
+ {
+ if (showdebuginfo () )
+ cerr << "Graphics system not initialized" << endl;
+ throw ErrFunctionCall;
+ }
+ #endif
+
+ if (zoomx < 1 || zoomx > MAXZOOMTEXTX)
+ throw ErrImproperArgument;
+ if (zoomy < 1 || zoomy > MAXZOOMTEXTY)
+ throw ErrImproperArgument;
+
+ inkset= InkStandard;
+ //default_foreground= & xcBlack;
+ //default_background= & xcWhite;
+ default_pen= 0;
+ default_paper= 15;
+ ::set_mode (width, height, user_mode, zoomx, zoomy);
+ if (inverty)
+ activetransform= TransformInvertY;
+
+ #endif
+}
+
+void graphics::setmode (int mode)
+{
+ TRACEFUNC (tr, "graphics::setmode");
+
+ #ifndef BLASSIC_HAS_GRAPHICS
+
+ no_graphics_support ();
+ touch (mode);
+
+ #else
+
+ #if 0
+ if (! inited && mode != text_mode)
+ {
+ if (showdebuginfo () )
+ cerr << "Graphics system not initialized" << endl;
+ throw ErrFunctionCall;
+ }
+ #endif
+
+ int width, height;
+ switch (mode)
+ {
+ case 1:
+ width= 320; height= 200; break;
+ case 2:
+ width= 640; height= 200; break;
+ case 5:
+ width= 320; height= 200; break;
+ case 10:
+ width= 640; height= 480; break;
+ case 11:
+ width= 800; height= 600; break;
+ default:
+ width= 0; height= 0;
+ }
+ if (mode != 0 && width == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "Invalid mode number " << mode << endl;
+ throw ErrFunctionCall;
+ }
+
+ //default_foreground= & xcBlack;
+ //default_background= & xcWhite;
+ if (mode != text_mode)
+ {
+ inkset= InkStandard;
+ default_pen= 0;
+ default_paper= 15;
+ }
+ ::set_mode (width, height, mode);
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+struct SpecialMode {
+ std::string name;
+ Inkset inkset;
+ int pen;
+ int paper;
+ int width;
+ int height;
+ TransformType transform;
+ int zoomx;
+ int zoomy;
+ SpecialMode (const std::string & name, Inkset inkset,
+ int pen, int paper, int width, int height,
+ TransformType transform, int zoomx, int zoomy) :
+ name (name), inkset (inkset),
+ pen (pen), paper (paper), width (width), height (height),
+ transform (transform), zoomx (zoomx), zoomy (zoomy)
+ { }
+};
+
+const SpecialMode specialmodes []= {
+ SpecialMode ("spectrum", InkSpectrum, 0, 7, 256, 192,
+ TransformInvertY, 1, 1),
+ SpecialMode ("cpc0", InkCpc, 1, 0, 640, 400,
+ TransformInvertY, 4, 2),
+ SpecialMode ("cpc1", InkCpc, 1, 0, 640, 400,
+ TransformInvertY, 2, 2),
+ SpecialMode ("cpc2", InkCpc, 1, 0, 640, 400,
+ TransformInvertY, 1, 2),
+ SpecialMode ("pcw", InkStandard, 0, 15, 720, 248,
+ TransformIdentity, 1, 1),
+ SpecialMode ("pcw2", InkStandard, 0, 15, 720, 496,
+ TransformIdentity, 1, 2),
+};
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::setmode (const std::string & mode)
+{
+ TRACEFUNC (tr, "graphics::setmode (string)");
+ TRMESSAGE (tr, "mode: " + mode);
+
+ #ifndef BLASSIC_HAS_GRAPHICS
+
+ no_graphics_support ();
+ touch (mode);
+
+ #else
+
+ #if 0
+ if (! inited)
+ throw ErrFunctionCall;
+ #endif
+
+ for (size_t i= 0; i < util::dim_array (specialmodes); ++i)
+ {
+ const SpecialMode & m= specialmodes [i];
+ if (m.name == mode)
+ {
+ inkset= m.inkset;
+ default_pen= m.pen;
+ default_paper= m.paper;
+ ::set_mode (m.width, m.height, user_mode,
+ m.zoomx, m.zoomy);
+ activetransform= m.transform;
+ // Spectrum is an special case.
+ if (mode == "spectrum")
+ {
+ set_origin (0, 16);
+ set_limits (0, 256, 16, 192);
+ }
+ return;
+ }
+ }
+
+ TRMESSAGE (tr, "Invalid mode");
+ if (showdebuginfo () )
+ cerr << '\'' << mode << "' is not a valid graphics mode" <<
+ endl;
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+bool graphics::ingraphicsmode ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ //return actualmode != text_mode;
+ return graphics_mode_active;
+
+ #else
+
+ return false;
+
+ #endif
+}
+
+void graphics::setcolor (int color)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #ifdef BLASSIC_USE_SVGALIB
+
+ if (svgalib) {
+ vga_setcolor (color);
+ return;
+ }
+
+ #endif
+
+ graphics_pen= color;
+ pcolor pxc= mapcolor (color).pc;
+
+ setactivecolor (pxc);
+
+ #if defined (BLASSIC_USE_WINDOWS) || defined (BLASSIC_USE_X)
+ pforeground= pxc;
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (color);
+
+ #endif
+}
+
+int graphics::getcolor ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return graphics_pen;
+
+ #else
+
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+void graphics::setbackground (int color)
+{
+ //if (! inited) return;
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ graphics_paper= color;
+ pcolor pxc= mapcolor (color).pc;
+ pbackground= pxc;
+
+ #else
+
+ touch (color);
+
+ #endif
+}
+
+int graphics::getbackground ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return graphics_paper;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+void graphics::settransparent (int transpmode)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (! inited)
+ return;
+
+ opaquemode= ! (transpmode & 1);
+
+ #else
+
+ touch (transpmode);
+
+ #endif
+}
+
+void graphics::setdrawmode (int mode)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (! inited)
+ return;
+
+ #if 0
+ // Draw modes:
+ // 0: normal copy mode.
+ // 1: XOR
+ // 2: AND
+ // 3: OR
+ // 0 to 3 are Amstrad CPC modes.
+ // 4: INVERT, NOT.
+ static int modes []= { drawmode_copy, drawmode_xor,
+ drawmode_and, drawmode_or, drawmode_invert };
+
+ if (mode < 0 || size_t (mode) >= util::dim_array (modes) )
+ return;
+ drawmode= modes [mode];
+ #else
+
+ drawmode= getdrawmode (mode);
+
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ XSetFunction (display, gc, drawmode);
+ XSetFunction (display, gcp, drawmode);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ //HDC hdc= GetDC (window);
+ SetROP2 (hdc, drawmode);
+ //ReleaseDC (window, hdc);
+ SetROP2 (hdcPixmap, drawmode);
+
+ #endif
+
+ #else
+ // No graphics.
+
+ touch (mode);
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+void do_line_unmasked (int x, int y)
+{
+ int prevx= lastx, prevy= lasty;
+ lastx= x; lasty= y;
+
+ transform_x (x); transform_x (prevx);
+ transform_y (y); transform_y (prevy);
+
+ do_rotate (prevx, prevy);
+ do_rotate (x, y);
+
+ setactivecolor (pforeground);
+
+ #ifdef BLASSIC_USE_SVGALIB
+ if (svgalib)
+ {
+ vga_drawline (prevx, prevy, x, y);
+ return;
+ }
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ if (! fSynchro)
+ XDrawLine (display, window, gc, prevx, prevy, x, y);
+ XDrawLine (display, pixmap, gcp, prevx, prevy, x, y);
+ XFlush (display);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ if (! fSynchro)
+ {
+ MoveToEx (hdc, prevx, prevy, 0);
+ LineTo (hdc, x, y);
+ LineTo (hdc, x + 1, y); // Last point
+ }
+
+ MoveToEx (hdcPixmap, prevx, prevy, 0);
+ LineTo (hdcPixmap, x, y);
+ LineTo (hdcPixmap, x + 1, y); // Last point
+
+ #endif
+}
+
+const unsigned char maskvaluedefault= '\xFF';
+unsigned char maskvalue= maskvaluedefault;
+bool maskdrawfirst= true;
+unsigned maskpos= 0;
+unsigned char auxmask []= { 1, 2, 4, 8, 16, 32, 64, 128 };
+
+inline void impl_plot_mask (int x, int y)
+{
+ if (maskvalue == maskvaluedefault)
+ do_plot (x, y);
+ else
+ {
+ if (maskvalue & auxmask [maskpos] )
+ do_plot (x, y);
+ if (++maskpos == 8) maskpos= 0;
+ }
+}
+
+void do_line_mask (int x, int y)
+{
+ int prevx= lastx, prevy= lasty;
+ lastx= x; lasty= y;
+
+ transform_x (prevx); transform_x (x);
+ transform_y (prevy); transform_y (y);
+
+ setactivecolor (pforeground);
+
+ int px= x - prevx;
+ int py= y - prevy;
+ int d1x= px < 0 ? -1 : px > 0 ? 1 : 0;
+ int d1y= py < 0 ? -1 : py > 0 ? 1 : 0;
+ int d2x= d1x;
+ int d2y= 0;
+ int m= abs (px);
+ int n= abs (py);
+ if (m <= n)
+ {
+ d2x= 0;
+ d2y= d1y;
+ m= abs (py);
+ n= abs (px);
+ }
+ int s= m / 2;
+ for (int i= 0; i <= m; ++i)
+ {
+ if (i != 0 || maskdrawfirst)
+ {
+ //if (maskvalue & auxmask [maskpos] )
+ // do_plot (prevx, prevy);
+ //if (++maskpos == 8) maskpos= 0;
+ impl_plot_mask (prevx, prevy);
+ }
+ s+= n;
+ if (s >= m)
+ {
+ s-= m;
+ prevx+= d1x;
+ prevy+= d1y;
+ }
+ else
+ {
+ prevx+= d2x;
+ prevy+= d2y;
+ }
+ }
+}
+
+inline void do_line (int x, int y)
+{
+ // When limited we use line masked to simplify line unmasked.
+ if (! limited && (maskvalue == maskvaluedefault && maskdrawfirst) )
+ do_line_unmasked (x, y);
+ else
+ do_line_mask (x, y);
+}
+
+ // --------------------------------
+ // drawarc and auxiliary functions.
+ // --------------------------------
+
+// Mimic the Spectrum DRAW instruction, even with values
+// of angle greater than 2 * pi.
+
+// Workaround for a problem on gcc.
+double zero= 0.0; // Don't make this var const!
+
+inline int signum (double d)
+{
+ return d < zero ? -1 : d > zero ? 1 : 0;
+}
+
+inline int roundint (double d)
+{
+ double frac= modf (d, & d);
+ if (frac > 0.5)
+ ++d;
+ else
+ if (frac < -0.5)
+ --d;
+ return int (d);
+}
+
+inline void do_drawarcsegment (int xd, int yd,
+ int & coords_x, int & coords_y, bool & firstpoint)
+{
+ // This function is used instead of the other line
+ // draw functions to ensure exact compatibility with
+ // the Spectrum and because of first point of line
+ // treatement.
+
+ int b= abs (yd);
+ int c= abs (xd);
+ int d= signum (yd);
+ int e= signum (xd);
+ //std::cerr << "do_drawarcsegment " << c << ' ' << b << ' ' <<
+ // e << ' ' << d << std::endl;
+ int h, l, hvx, hvy;
+ if (c >= b)
+ {
+ h= c; l= b; hvx= e; hvy= 0;
+ }
+ else
+ {
+ if (b == 0)
+ return;
+ h= b; l= c; hvx= 0; hvy= d;
+ }
+ b= h;
+ int a= h / 2;
+ for (int i= 0; i < b; ++i)
+ {
+ a+= l;
+ if (a < h)
+ {
+ // Horizontal or vertical step.
+ coords_x+= hvx;
+ coords_y+= hvy;
+ }
+ else
+ {
+ // Diagonal step.
+ a-= h;
+ coords_x+= e;
+ coords_y+= d;
+ }
+ if (firstpoint)
+ firstpoint= false;
+ else
+ {
+ int x= coords_x; int y= coords_y;
+ transform_x (x);
+ transform_y (y);
+ impl_plot_mask (x, y);
+ }
+ }
+}
+
+void do_drawarc (int x, int y, double g)
+{
+ // The original algorithm uses the Spectrum cooordinates,
+ // then the angle is inverted when using non inverted
+ // coordinates.
+ // To an explanation of the algorithm used, see "The Complete
+ // Spectrum ROM Disassembly" or some other disassembly of the
+ // Spectrum ROM (the book has more complete comments).
+
+ switch (activetransform)
+ {
+ case TransformIdentity:
+ g= -g;
+ break;
+ case TransformInvertY:
+ break; // Nothing to do
+ }
+
+ setactivecolor (pforeground);
+
+ // If drawing of first point is active, no special treatement
+ // for the first point by marking as if not were the first.
+ bool firstpoint= ! maskdrawfirst;
+
+ int xend= lastx + x, yend= lasty + y;
+
+ double sing2= sin (g / 2);
+ double z;
+ if (sing2 != 0 && (z= fabs ( (abs (x) + abs (y) ) / sing2) ) >= 1)
+ {
+ int a= roundint (fabs (g * sqrt (z) / 2) );
+ if (a <= 255)
+ {
+ a= (a & 0xFC) + 4;
+ if (a >= 256)
+ a= 252;
+ }
+ else
+ a= 252;
+
+ double singa= sin (g / a);
+ double cosga= cos (g / a);
+ double w= sin (g / (2.0 * a) ) / sing2;
+ double f= g / 2 - g / (2.0 * a);
+ double sinf= sin (f);
+ double cosf= cos (f);
+ double un= y * w * sinf + x * w * cosf;
+ double vn= y * w * cosf - x * w * sinf;
+
+ double uv= fabs (un) + fabs (vn);
+ if (uv >= 1)
+ {
+ double xn= lastx;
+ double yn= lasty;
+ a= a - 1;
+ while (a > 0)
+ {
+ xn= xn + un;
+ yn= yn + vn;
+ do_drawarcsegment (
+ roundint (xn - lastx),
+ roundint (yn - lasty),
+ lastx, lasty, firstpoint);
+ a= a - 1;
+ if (a > 0)
+ {
+ double un1= un;
+ un= un1 * cosga - vn * singa;
+ vn= un1 * singa + vn * cosga;
+ }
+ }
+ }
+ }
+ // Draw the last segment (can be the entire arc).
+ do_drawarcsegment (xend - lastx, yend - lasty,
+ lastx, lasty, firstpoint);
+}
+
+#ifdef BLASSIC_USE_X
+
+inline void do_rotate_in_char (int & x, int & y)
+{
+ switch (rotate)
+ {
+ case RotateNone:
+ break;
+ case Rotate90:
+ #if 1
+ int newx= y;
+ y= charwidth - x - 1;
+ x= newx;
+ #else
+ int newy= x;
+ x= charwidth - y - 1;
+ y= newy;
+ #endif
+ break;
+ }
+}
+
+inline bool load_char_image (int x, int y, unsigned char (& ch) [8] )
+{
+ TRACEFUNC (tr, "load_char_image");
+
+ class ImageGuard {
+ public:
+ ImageGuard (XImage * img) :
+ img (img)
+ { }
+ ~ImageGuard ()
+ {
+ XDestroyImage (img);
+ }
+ private:
+ XImage * img;
+ };
+
+ int width= charwidth, height= charheight;
+ do_rotate_rel (width, height);
+ do_rotate (x, y);
+ switch (rotate)
+ {
+ case RotateNone:
+ break;
+ case Rotate90:
+ y-= height - 1;
+ break;
+ }
+ TRMESSAGE (tr, "at " + to_string (x) + ", " + to_string (y) );
+
+ XImage * img= XGetImage (display, pixmap, x, y,
+ width, height, AllPlanes, XYPixmap);
+ if (img == NULL)
+ throw ErrNoGraphics; // Not a good idea, provisional.
+ ImageGuard guard (img);
+ unsigned long back= XGetPixel (img, 0, 0);
+ bool fFore= false;
+ unsigned long fore= 0;
+ for (int i= 0, ipos= 0; i < 8; ++i, ipos+= zoomtexty)
+ for (int j= 0, jpos= 0; j < 8; ++j, jpos+= zoomtextx)
+ {
+ int rjpos= jpos, ripos= ipos;
+ do_rotate_in_char (rjpos, ripos);
+ unsigned long c= XGetPixel (img, rjpos, ripos);
+ bool bit;
+ if (c == back)
+ {
+ bit= false;
+ }
+ else
+ {
+ if (! fFore)
+ {
+ fFore= true;
+ fore= c;
+ }
+ if (c != fore)
+ return false;
+ bit= true;
+ }
+ #if 1
+ // Quitado provisionalmente
+ if (zoomtextx > 1 || zoomtexty > 1)
+ {
+ int zx= zoomtextx, zy= zoomtexty;
+ //do_rotate_rel (zx, zy);
+ const int iend= ipos + zy;
+ const int jend= jpos + zx;
+ for (int ii= ipos; ii < iend; ++ii)
+ for (int jj= jpos; jj < jend; ++jj)
+ {
+ int rj= jj, ri= ii;
+ do_rotate_in_char (rj, ri);
+ if (XGetPixel (img, rj, ri)
+ != c)
+ return false;
+ }
+ }
+ #endif
+ ch [i]<<= 1;
+ ch [i]|= bit;
+ }
+ //XDestroyImage (img);
+ return true;
+}
+
+#elif defined BLASSIC_USE_WINDOWS
+
+inline bool load_char_image (int x, int y, unsigned char (& ch) [8] )
+{
+ //COLORREF back= GetPixel (hdcPixmap, x, y);
+ int rx= x, ry= y;
+ do_rotate (rx, ry);
+ COLORREF back= GetPixel (hdcPixmap, rx, ry);
+ bool fFore= false;
+ COLORREF fore= 0;
+ for (int i= 0, ipos= y; i < 8; ++i, ipos+= zoomtexty)
+ for (int j= 0, jpos= x; j < 8; ++j, jpos+= zoomtextx)
+ {
+ //COLORREF c= GetPixel (hdcPixmap, jpos, ipos);
+ int rjpos= jpos, ripos= ipos;
+ do_rotate (rjpos, ripos);
+ COLORREF c= GetPixel (hdcPixmap, rjpos, ripos);
+ bool bit;
+ if (c == back)
+ bit= false;
+ else
+ {
+ if (! fFore)
+ {
+ fFore= true;
+ fore= c;
+ }
+ if (c != fore)
+ //return std::string ();
+ return false;
+ bit= true;
+ }
+ if (zoomtextx > 1 || zoomtexty > 1)
+ {
+ const int iend= ipos + zoomtexty;
+ const int jend= jpos + zoomtextx;
+ for (int ii= ipos; ii < iend; ++ii)
+ for (int jj= jpos; jj < jend; ++jj)
+ {
+ int rj= jj, ri= ii;
+ do_rotate (rj, ri);
+ if (GetPixel (hdcPixmap,
+ rj, ri) != c)
+ return false;
+ }
+ }
+ ch [i]<<= 1;
+ ch [i]|= bit;
+ }
+ return true;
+}
+
+#else
+
+inline bool load_char_image (int, int, unsigned char (&) [8] )
+{
+ return false;
+}
+
+#endif
+
+std::string copychrat (int x, int y, BlChar from, BlChar to)
+{
+ TRACEFUNC (tr, "copychrat");
+ {
+ std::ostringstream oss;
+ oss << "at " << x << ", " << y;
+ TRMESSAGE (tr, oss.str () );
+ }
+
+ unsigned char ch [8]= {0};
+
+ //if (x < 0 || x > screenwidth - 8 || y < 0 || y > screenheight - 8)
+ if (x < 0 || x > screenwidth - charwidth ||
+ y < 0 || y > screenheight - charheight)
+ return std::string ();
+
+ if (! load_char_image (x, y, ch) )
+ return std::string ();
+
+ #ifndef NDEBUG
+ {
+ std::ostringstream oss;
+ oss << "Char: " << std::hex;
+ for (int i= 0; i < 8; ++i)
+ {
+ oss << std::setw (2) << std::setfill ('0') <<
+ static_cast <unsigned int> (ch [i]) << ", ";
+ }
+ TRMESSAGE (tr, oss.str () );
+ }
+ #endif
+
+ char chinv [8];
+ for (int i= 0; i < 8; ++i)
+ chinv [i]= static_cast <unsigned char> (~ ch [i]);
+
+ //for (int i= 0; i < 256; ++i)
+ int iFrom= static_cast <int> (from);
+ int iTo= static_cast <int> (to) + 1;
+ for (int i= iFrom; i < iTo; ++i)
+ {
+ if (memcmp (charset::data [i], ch, 8) == 0 ||
+ memcmp (charset::data [i], chinv, 8) == 0)
+ {
+ return std::string (1, static_cast <char> (i) );
+ }
+ }
+
+ return std::string ();
+}
+
+class ColorTester {
+ #ifdef BLASSIC_USE_X
+ XImage * img;
+ #define TYPETESTER 2
+ #endif
+public:
+ ColorTester ()
+ {
+ #ifdef BLASSIC_USE_X
+ #if TYPETESTER == 1
+ img= XGetImage (display, pixmap,
+ 0, 0, 1, 1,
+ AllPlanes, XYPixmap);
+ #else
+ int width= screenwidth, height= screenheight;
+ do_rotate_rel (width, height);
+ img= XGetImage (display, pixmap,
+ 0, 0, width, height,
+ AllPlanes, XYPixmap);
+ #endif
+ if (img == NULL)
+ throw ErrNoGraphics;
+ #endif
+ }
+ ~ColorTester ()
+ {
+ #ifdef BLASSIC_USE_X
+ XDestroyImage (img);
+ #endif
+ }
+ ColorValue operator () (int x, int y)
+ {
+ do_rotate (x, y);
+ #ifdef BLASSIC_USE_X
+ #if TYPETESTER == 1
+ XGetSubImage (display, pixmap, x, y, 1, 1,
+ AllPlanes,XYPixmap,
+ img, 0, 0);
+ return XGetPixel (img, 0, 0);
+ #else
+ return XGetPixel (img, x, y);
+ #endif
+ #elif defined BLASSIC_USE_WINDOWS
+ return GetPixel (hdcPixmap, x, y);
+ #endif
+ }
+};
+
+ColorValue do_test_color (int x, int y)
+{
+ do_rotate (x, y);
+
+ #ifdef BLASSIC_USE_X
+
+ XImage * img= XGetImage (display, pixmap, x, y, 1, 1,
+ AllPlanes, XYPixmap);
+ if (img == NULL)
+ throw ErrNoGraphics; // Not a good idea, provisional.
+ unsigned long color= XGetPixel (img, 0, 0);
+ XDestroyImage (img);
+ return color;
+
+ #else
+
+ return GetPixel (hdcPixmap, x, y);
+
+ #endif
+}
+
+int do_test (int x, int y)
+{
+ //int x= lastx;
+ //int y= lasty;
+ //transform_x (x);
+ //transform_y (y);
+
+ if (x < 0 || x >= screenwidth || y < 0 || y >= screenheight)
+ return 0;
+
+ do_rotate (x, y);
+
+ #ifdef BLASSIC_USE_X
+
+ XImage * img= XGetImage (display, pixmap, x, y, 1, 1,
+ AllPlanes, XYPixmap);
+ if (img == NULL)
+ throw ErrNoGraphics; // Not a good idea, provisional.
+ unsigned long color= XGetPixel (img, 0, 0);
+ XDestroyImage (img);
+ for (int i= 0; i < 16; ++i)
+ if (mapcolor (i).pc->pixel == color)
+ return i;
+ for (definedcolor_t::iterator it= definedcolor.begin ();
+ it != definedcolor.end (); ++it)
+ {
+ if (it->second.pc->pixel == color)
+ return it->first;
+ }
+ return -1;
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ COLORREF color= GetPixel (hdcPixmap, x, y);
+ for (int i= 0; i < 16; ++i)
+ {
+ //const ColorRGB & c= assignRGB [i];
+ const ColorRGB & c= mapcolor (i).rgb;
+ if (RGB (c.r, c.g, c.b) == color)
+ //if (GetNearestColor (hdcPixmap, RGB (c.r, c.g, c.b) ) ==
+ // color)
+ return i;
+ }
+ for (definedcolor_t::iterator it= definedcolor.begin ();
+ it != definedcolor.end (); ++it)
+ {
+ const ColorRGB & c= it->second.rgb;
+ if (RGB (c.r, c.g, c.b) == color)
+ return it->first;
+ }
+ return -1;
+
+ #else
+
+ return -1;
+
+ #endif
+}
+
+int test ()
+{
+ int x= lastx;
+ int y= lasty;
+ transform_x (x);
+ transform_y (y);
+ return do_test (x, y);
+}
+
+} // namespace
+
+#endif
+//BLASSIC_HAS_GRAPHICS
+
+void graphics::line (int x, int y)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ do_line (x, y);
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+void graphics::liner (int x, int y)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ line (lastx + x, lasty + y);
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+void graphics::drawarc (int x, int y, double g)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ do_drawarc (x, y, g);
+
+ #else
+
+ touch (x, y, g);
+
+ #endif
+}
+
+void graphics::rectangle (Point org, Point dest)
+{
+ TRACEFUNC (tr, "graphics::rectangle");
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ int x1= org.x;
+ int y1= org.y;
+ int x2= dest.x;
+ int y2= dest.y;
+ lastx= x2; lasty= y2;
+
+ transform_x (x1); transform_x (x2);
+ transform_y (y1); transform_y (y2);
+
+ do_rotate (x1, y1);
+ do_rotate (x2, y2);
+
+ if (x1 > x2) std::swap (x1, x2);
+ if (y1 > y2) std::swap (y1, y2);
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HBRUSH hold= (HBRUSH) SelectObject (hdcPixmap, GetStockObject (NULL_BRUSH) );
+ Rectangle (hdcPixmap, x1, y1, x2 + 1, y2 + 1);
+ SelectObject (hdc, hold);
+ if (! fSynchro)
+ {
+
+ hold= (HBRUSH) SelectObject (hdc, GetStockObject (NULL_BRUSH) );
+ Rectangle (hdc, x1, y1, x2 + 1, y2 + 1);
+ SelectObject (hdc, hold);
+ }
+
+ #elif defined BLASSIC_USE_X
+
+ XDrawRectangle (display, pixmap, gcp,
+ x1, y1, x2 - x1, y2 - y1);
+ if (! fSynchro)
+ XDrawRectangle (display, window, gc,
+ x1, y1, x2 - x1, y2 - y1);
+
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (org, dest);
+
+ #endif
+}
+
+void graphics::rectanglefilled (Point org, Point dest)
+{
+ TRACEFUNC (tr, "graphics::rectanglefilled");
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ int x1= org.x;
+ int y1= org.y;
+ int x2= dest.x;
+ int y2= dest.y;
+ lastx= x2; lasty= y2;
+
+ transform_x (x1); transform_x (x2);
+ transform_y (y1); transform_y (y2);
+
+ if (x1 > x2) std::swap (x1, x2);
+ if (y1 > y2) std::swap (y1, y2);
+ do_fill_rectangle (x1, y1, x2, y2, true);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (org, dest);
+
+ #endif
+}
+
+void graphics::zxplot (Point p)
+{
+ TRACEFUNC (tr, "graphics::zxplot");
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ int x= p.x / 2 + 1;
+ int y= 21 - p.y / 2;
+ p.x*= 4;
+ p.y*= 4;
+ Point p2 (p);
+ p2.x+= 3;
+ p2.y+= 3;
+ rectanglefilled (p, p2);
+ gotoxy (BlChannel (0), x, y);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (p);
+
+ #endif
+}
+
+void graphics::zxunplot (Point p)
+{
+ TRACEFUNC (tr, "graphics::zxunplot");
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ setactivecolor (pbackground);
+ zxplot (p);
+ setactivecolor (pforeground);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (p);
+
+ #endif
+}
+
+
+void graphics::move (int x, int y)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ lastx= x; lasty= y;
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+void graphics::mover (int x, int y)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ lastx+= x; lasty+= y;
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+void graphics::plot (int x, int y)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ lastx= x; lasty= y;
+ transform_x (x);
+ transform_y (y);
+ setactivecolor (pforeground);
+ do_plot (x, y);
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+void graphics::plotr (int x, int y)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ // No need to check here, plot will do
+ plot (lastx + x, lasty + y);
+
+ #else
+
+ touch (x, y);
+ no_graphics_support ();
+
+ #endif
+}
+
+int graphics::test (int x, int y, bool relative)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ // Check for graphics mode is done when calling move.
+ if (relative)
+ {
+ x+= lastx;
+ y+= lasty;
+ }
+ move (x, y);
+
+ return ::test ();
+
+ #else
+
+ no_graphics_support ();
+ touch (x, y, relative);
+ throw ErrBlassicInternal; // Make the compiler happy.
+
+ #endif
+}
+
+namespace {
+
+void line_to_point (const graphics::Point & p)
+{
+ graphics::line (p.x, p.y);
+}
+
+} // namespace
+
+void graphics::plot (std::vector <Point> & points)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ ASSERT (points.size () != 0);
+ lastx= points [0].x;
+ lasty= points [0].y;
+ std::for_each (points.begin () + 1, points.end (), line_to_point);
+
+ #else
+
+ // Must not come here, requiregraphics must throw.
+ ASSERT (false);
+ touch (points);
+
+ #endif
+}
+
+//#define DEBUG_CIRCLE
+
+#ifdef DEBUG_CIRCLE
+
+#include <unistd.h>
+
+namespace { inline void pausec () { usleep (100000); } }
+
+#else
+
+namespace { inline void pausec () { } }
+
+#endif
+
+void graphics::circle (int x, int y, int radius)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ setactivecolor (pforeground);
+
+ lastx= x + radius;
+ lasty= y;
+
+ transform_x (x);
+ transform_y (y);
+
+ if (radius == 0)
+ {
+ impl_plot_mask (x, y);
+ return;
+ }
+
+ // sq2_2 is sin (pi/4)
+ #ifdef M_SQRT2
+ static const double sq2_2= M_SQRT2 / 2.0;
+ #else
+ static const double sq2_2= sqrt (2.0) / 2.0;
+ #endif
+ //int r= int (radius * sq2_2 + .5) + 1;
+ int r= int (radius * sq2_2 + 1.0);
+ int rr= int (sqrt (radius * radius - r * r) + .5);
+ int dim= r;
+ if (rr >= r) ++dim;
+
+ #ifdef DEBUG_CIRCLE
+ cerr << "Circle: " << radius << ", " << r << endl;
+ #endif
+
+ util::auto_buffer <int> p (dim);
+
+ // Bresenham algorithm.
+ for (int i= 0, j= radius, d= 1 - radius; i < dim; ++i)
+ {
+ p [i]= j;
+ if (d < 0)
+ d+= 2 * i + 3;
+ else
+ {
+ d+= 2 * (i - j) + 5;
+ --j;
+ }
+ }
+
+ rr= p [r - 1] - 1;
+ ASSERT (rr <= dim - 1);
+
+ // The first point in each quadrant is plotted independently.
+ // In the first quadrant is omitted, we plot it at the end.
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (4);
+ #endif
+ for (int j= 1; j < r; ++j)
+ {
+ //do_line (x + p [j], y - j);
+ impl_plot_mask (x + p [j], y - j);
+ pausec ();
+ }
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (0);
+ #endif
+ for (int i= rr; i > 0; --i)
+ {
+ //do_line (x + i, y - p [i] );
+ impl_plot_mask (x + i, y - p [i] );
+ pausec ();
+ }
+
+ //do_line (x, y - radius);
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (4);
+ #endif
+ impl_plot_mask (x, y - radius);
+ for (int i= 1; i < r; ++i)
+ {
+ //do_line (x - i, y - p [i] );
+ impl_plot_mask (x - i, y - p [i] );
+ pausec ();
+ }
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (0);
+ #endif
+ for (int j= rr; j > 0; --j)
+ {
+ //do_line (x - p [j], y - j);
+ impl_plot_mask (x - p [j], y - j);
+ pausec ();
+ }
+
+ //do_line (x - radius, y);
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (4);
+ #endif
+ impl_plot_mask (x - radius, y);
+ for (int j= 1; j < r; ++j)
+ {
+ //do_line (x - p [j], y + j);
+ impl_plot_mask (x - p [j], y + j);
+ pausec ();
+ }
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (0);
+ #endif
+ for (int i= rr; i > 0; --i)
+ {
+ //do_line (x - i, y + p [i] );
+ impl_plot_mask (x - i, y + p [i] );
+ pausec ();
+ }
+
+ //do_line (x, y + radius);
+ impl_plot_mask (x, y + radius);
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (4);
+ #endif
+ for (int i= 1; i < r; ++i)
+ {
+ //do_line (x + i, y + p [i] );
+ impl_plot_mask (x + i, y + p [i] );
+ pausec ();
+ }
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (0);
+ #endif
+ for (int j= rr; j > 0; --j)
+ {
+ //do_line (x + p [j], y + j);
+ impl_plot_mask (x + p [j], y + j);
+ pausec ();
+ }
+ //do_line (x + radius, y);
+ #ifdef DEBUG_CIRCLE
+ graphics::setcolor (4);
+ #endif
+ impl_plot_mask (x + radius, y);
+
+ #else
+ // BLASSIC_HAS_GRAPHICS
+
+ touch (x, y, radius);
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+inline void get_point_on_arc (int r, BlNumber a, int & out_x, int & out_y)
+{
+ BlNumber s= sin (a) * r, c= cos (a) * r;
+ out_x= static_cast <int> (c < 0 ? c - .5 : c + .5);
+ out_y= static_cast <int> (s < 0 ? s - .5 : s + .5);
+}
+
+inline int get_quadrant (int x, int y)
+{
+ if (x >= 0)
+ {
+ if (y >= 0)
+ return 0;
+ else
+ return 3;
+ }
+ else
+ {
+ if (y > 0)
+ return 1;
+ else
+ return 2;
+ }
+}
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::arccircle (int x, int y, int radius,
+ BlNumber arcbeg, BlNumber arcend)
+{
+ /*
+ The code for this function and his auxiliarys
+ is taken from the Allegro library.
+ Many thanks.
+ */
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ setactivecolor (pforeground);
+
+ //#define DEBUG_ARCCIRCLE
+
+ #ifdef DEBUG_ARCCIRCLE
+ cerr << "arccircle: " << x << ", " << y << ", " << radius << ", " <<
+ arcbeg << ", " << arcend << endl;
+ #endif
+
+ lastx= x + radius;
+ lasty= y;
+ transform_x (x);
+ transform_y (y);
+
+ int px, py; // Current position and auxiliary.
+ get_point_on_arc (radius, arcend, px, py);
+ const int ex= px, ey= py; // End position.
+ get_point_on_arc (radius, arcbeg, px, py);
+ const int sx= px, sy= py; // Start position.
+ // Current position start at start position.
+
+ const int sq= get_quadrant (sx, sy); // Start quadrant.
+ // Calculate end quadrant, considering that end point
+ // must be after start point.
+ int q= get_quadrant (ex, ey);
+ if (sq > q)
+ // Quadrant end must be greater or equal.
+ q+= 4;
+ else if (sq == q && arcbeg > arcend)
+ // If equal, consider the angle.
+ q+= 4;
+ const int qe= q;
+ q= sq; // Current cuadrant.
+
+ #ifdef DEBUG_ARCCIRCLE
+ cerr << "Quadrant from " << sq << " to " << qe << endl;
+ #endif
+
+ // Direction of movement.
+ int dy = ( ( (q + 1) & 2) == 0) ? 1 : -1;
+ int dx= ( (q & 2) == 0) ? -1 : 1;
+
+ const int rr= radius * radius;
+ int xx= px * px;
+ int yy= py * py - rr;
+
+ while (true)
+ {
+ // Change quadrant when needed, adjusting directions.
+ if ( (q & 1) == 0)
+ {
+ if (px == 0)
+ {
+ if (qe == q)
+ break;
+ ++q;
+ dy= -dy;
+ }
+ }
+ else
+ {
+ if (py == 0)
+ {
+ if (qe == q)
+ break;
+ ++q;
+ dx= -dx;
+ }
+ }
+ // If we are in the end quadrant, check if at the end position.
+ if (qe == q)
+ {
+ int det= 0;
+ if (dy > 0)
+ {
+ if (py >= ey)
+ ++det;
+ }
+ else
+ {
+ if (py <= ey)
+ ++det;
+ }
+ if (dx > 0)
+ {
+ if (px >= ex)
+ ++det;
+ }
+ else
+ {
+ if (px <= ex)
+ ++det;
+ }
+ if (det == 2)
+ break;
+ }
+
+ impl_plot_mask (x + px, y - py);
+
+ int xx_new= (px + dx) * (px + dx);
+ int yy_new= (py + dy) * (py + dy) - rr;
+ int rr1= xx_new + yy;
+ int rr2= xx_new + yy_new;
+ int rr3= xx + yy_new;
+ if (rr1 < 0) rr1= -rr1;
+ if (rr2 < 0) rr2= -rr2;
+ if (rr3 < 0) rr3= -rr3;
+ if (rr3 >= std::min (rr1, rr2) )
+ {
+ px+= dx;
+ xx= xx_new;
+ }
+ if (rr1 > std::min (rr2, rr3) )
+ {
+ py+= dy;
+ yy= yy_new;
+ }
+ }
+ if (px != sx || py != sy || sq == qe)
+ impl_plot_mask (x + px, y - py);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (x, y, radius, arcbeg, arcend);
+
+ #endif
+}
+
+void graphics::ellipse (int ox, int oy, int rx, int ry)
+{
+ // Based on "A fast Bresenham type algorithm
+ // for drawing ellipses", by John Kennedy.
+
+ //#define DEBUG_ELLIPSE
+
+ #ifdef DEBUG_ELLIPSE
+ cerr << "Ellipse: " << rx << ", " << ry << endl;
+ #endif
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ setactivecolor (pforeground);
+ lastx= ox+ rx;
+ lasty= oy;
+
+ transform_x (ox);
+ transform_y (oy);
+
+ const int ry2= ry * ry;
+ const int rx2= rx * rx;
+ //const int dimy= int (ry2 / sqrt (ry2 + rx2) + 0.5);
+ const int dimy= int (ry2 / sqrt (ry2 + rx2) ) + 1;
+
+ #ifdef DEBUG_ELLIPSE
+ cerr << "Dimy: " << dimy << endl;
+ #endif
+
+ util::auto_buffer <int> py (dimy);
+ //#define SIMPLER
+ #ifndef SIMPLER
+ const int ry2_2= ry2 * 2;
+ const int rx2_2= rx2 * 2;
+ int xchange= ry2 * (1 - 2 * rx);
+ int ychange= rx2;
+ int ellipseerror= 0;
+ for (int y= 0, x= rx; y < dimy; ++y)
+ {
+ py [y]= x;
+ if (x == 0) // Needed for little rx
+ continue;
+ ellipseerror+= ychange;
+ ychange+= rx2_2;
+ if (2 * ellipseerror + xchange > 0)
+ {
+ --x;
+ ellipseerror+= xchange;
+ xchange+= ry2_2;
+ }
+ }
+ #else
+ for (int y= 0; y < dimy; ++y)
+ py [y]= int (rx * sqrt (ry * ry - y * y) / ry + 0.5);
+ #endif
+
+ int aux= dimy > 0 ? py [dimy - 1] : rx;
+ const int dimx= aux < 0 ? 0 : aux;
+
+ #ifdef DEBUG_ELLIPSE
+ cerr << "Dimx: " << dimx << endl;
+ #endif
+
+ util::auto_buffer <int> px (dimx);
+ #ifndef SIMPLER
+ xchange= ry2;
+ ychange= rx2 * (1 - 2 * ry);
+ ellipseerror= 0;
+ for (int x= 0, y= ry; x < dimx; ++x)
+ {
+ px [x]= y;
+ if (y == 0) // Needed for little ry
+ continue;
+ ellipseerror+= xchange;
+ xchange+= ry2_2;
+ if (2 * ellipseerror + ychange > 0)
+ {
+ --y;
+ ellipseerror+= ychange;
+ ychange+= rx2_2;
+ }
+ }
+ #else
+ for (int x= 0; x < dimx; ++x)
+ px [x]= int (ry * sqrt (rx * rx - x * x) / rx + 0.5);
+ #endif
+
+ for (int y= 1; y < dimy; ++y)
+ impl_plot_mask (ox + py [y], oy - y);
+ for (int x= dimx - 1; x > 0; --x)
+ impl_plot_mask (ox + x, oy - px [x] );
+ impl_plot_mask (ox, oy - ry);
+ for (int x= 1; x < dimx; ++x)
+ impl_plot_mask (ox - x, oy - px [x] );
+ for (int y= dimy - 1; y > 0; --y)
+ impl_plot_mask (ox - py [y], oy - y);
+ impl_plot_mask (ox - rx, oy);
+ for (int y= 1; y < dimy; ++y)
+ impl_plot_mask (ox - py [y], oy + y);
+ for (int x= dimx - 1; x > 0; --x)
+ impl_plot_mask (ox - x, oy + px [x] );
+ impl_plot_mask (ox, oy + ry);
+ for (int x= 1; x < dimx; ++x)
+ impl_plot_mask (ox + x, oy + px [x] );
+ for (int y= dimy - 1; y > 0; --y)
+ impl_plot_mask (ox + py [y], oy + y);
+ impl_plot_mask (ox + rx, oy);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (ox, oy, rx, ry);
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+inline void get_point_on_arc (int rx, int ry, BlNumber a,
+ int & out_x, int & out_y)
+{
+ BlNumber s= sin (a) * ry, c= cos (a) * rx;
+ out_x= static_cast <int> (c < 0 ? c - .5 : c + .5);
+ out_y= static_cast <int> (s < 0 ? s - .5 : s + .5);
+}
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::arcellipse (int ox, int oy, int rx, int ry,
+ BlNumber arcbeg, BlNumber arcend)
+{
+ /*
+ Adapted from the arccircle algorithm,
+ not optimal but works.
+ */
+ //#define DEBUG_ARCELLIPSE
+
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ setactivecolor (pforeground);
+ lastx= ox+ rx;
+ lasty= oy;
+
+ transform_x (ox);
+ transform_y (oy);
+
+ int px, py; // Current position and auxiliary
+ get_point_on_arc (rx, ry, arcend, px, py);
+ const int ex= px, ey= py; // End position
+ get_point_on_arc (rx, ry, arcbeg, px, py);
+ const int sx= px, sy= py; // Start position
+
+ const int sq= get_quadrant (sx, sy); // Start quadrant.
+ // Calculate end quadrant, considering that end point
+ // must be after start point.
+ int q= get_quadrant (ex, ey);
+ if (sq > q)
+ // Quadrant end must be greater or equal.
+ q+= 4;
+ else if (sq == q && arcbeg > arcend)
+ // If equal, consider the angle.
+ q+= 4;
+ const int qe= q;
+ q= sq; // Current cuadrant.
+
+ #ifdef DEBUG_ARCELLIPSE
+ cerr << "Arc llipse from: " << arcbeg << " to " << arcend << endl;
+ cerr << "Quadrant from " << sq << " to " << qe << endl;
+ #endif
+
+ // Direction of movement.
+ int dy = ( ( (q + 1) & 2) == 0) ? 1 : -1;
+ int dx= ( (q & 2) == 0) ? -1 : 1;
+
+ const int rx2= rx * rx;
+ const int ry2= ry * ry;
+ const int rxy2= rx2 * ry2;
+
+ while (true)
+ {
+ // Change quadrant when needed, adjusting directions.
+ if ( (q & 1) == 0)
+ {
+ // Take care that in very eccentric ellipses
+ // can be in 0 before the extreme point.
+ if (px == 0 && abs (py) == ry)
+ {
+ if (qe == q)
+ break;
+ ++q;
+ dy= -dy;
+ }
+ }
+ else
+ {
+ if (py == 0 && abs (px) == rx)
+ {
+ if (qe == q)
+ break;
+ ++q;
+ dx= -dx;
+ }
+ }
+ // If we are in the end quadrant, check if at the end position.
+ if (qe == q)
+ {
+ int det= 0;
+ if (dy > 0)
+ {
+ if (py >= ey)
+ ++det;
+ }
+ else
+ {
+ if (py <= ey)
+ ++det;
+ }
+ if (dx > 0)
+ {
+ if (px >= ex)
+ ++det;
+ }
+ else
+ {
+ if (px <= ex)
+ ++det;
+ }
+ if (det == 2)
+ break;
+ }
+
+ impl_plot_mask (ox + px, oy - py);
+
+ int rr1= ry2 * (px + dx) * (px + dx) +
+ rx2 * py * py - rxy2;
+ int rr2= ry2 * (px + dx) * (px + dx) +
+ rx2 * (py + dy) * (py + dy) - rxy2;
+ int rr3= ry2 * px * px +
+ rx2 * (py + dy) * (py + dy) - rxy2;
+ if (rr1 < 0) rr1= -rr1;
+ if (rr2 < 0) rr2= -rr2;
+ if (rr3 < 0) rr3= -rr3;
+ if (rr3 >= std::min (rr1, rr2) )
+ {
+ px+= dx;
+ //xx= xx_new;
+ }
+ if (rr1 > std::min (rr2, rr3) )
+ {
+ py+= dy;
+ //yy= yy_new;
+ }
+ }
+ if (px != sx || py != sy || sq == qe)
+ impl_plot_mask (ox + px, oy - py);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (ox, oy, rx, ry, arcbeg, arcend);
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+#if 0
+
+class Painter {
+ ColorValue paint, border;
+ std::vector <std::vector <bool> > visited;
+ ColorTester test;
+public:
+ Painter (ColorValue paint, ColorValue border) :
+ paint (paint),
+ border (border),
+ visited (screenwidth, std::vector <bool> (screenheight) )
+ {
+ }
+
+ bool check (int x, int y)
+ {
+ if (! check_limit (x, y) )
+ return false;
+ std::vector <bool>::reference v= visited [x] [y];
+ if (v)
+ return false;
+ v= true;
+ ColorValue c= test (x, y);
+ if (c == border || c == paint)
+ return false;
+ return true;
+ }
+
+void do_paint_it (int x, int y/*, int xd, int yd*/)
+{
+ //if (! check_limit (x, y) )
+ // return;
+ //int c= do_test (x, y);
+ //if (c == borderattr || c == paintattr)
+ // return;
+
+ do_plot (x, y);
+ //visited [x] [y]= true;
+
+ //ColorValue c;
+ //if (xd != -1)
+ #if 0
+ for (int i=1; /*check_limit (x - i, y)*/ i < 2; ++i)
+ {
+ if (visited [x - i] [y] )
+ break;
+ visited [x - i] [y]= true;
+ //c= do_test_color (x - i, y);
+ c= test (x - i, y);
+ if (c != border && c != paint)
+ do_paint_it (x - i, y, 1, 0);
+ else
+ break;
+ }
+ #else
+ if (check (x - 1, y) )
+ do_paint_it (x - 1, y/*, 1, 0*/);
+ #endif
+ //if (xd != 1)
+ #if 0
+ for (int i= 1; /*check_limit (x + i, y)*/ i < 2; ++i)
+ {
+ if (visited [x + i] [y] )
+ break;
+ visited [x + i] [y]= true;
+ //c= do_test_color (x + i, y);
+ c= test (x + i, y);
+ if (c != border && c != paint)
+ do_paint_it (x + i, y, -1, 0);
+ else
+ break;
+ }
+ #else
+ if (check (x + 1, y) )
+ do_paint_it (x + 1, y/*, 1, 0*/);
+ #endif
+ //if (yd != -1)
+ #if 0
+ for (int i= 1; /*check_limit (x, y - i)*/ i < 2; ++i)
+ {
+ if (visited [x] [y - i] )
+ break;
+ visited [x] [y - i]= true;
+ //c= do_test_color (x, y - i);
+ c= test (x, y - i);
+ if (c != border && c != paint)
+ do_paint_it (x, y - i, 0, 1);
+ else
+ break;
+ }
+ #else
+ if (check (x, y - 1) )
+ do_paint_it (x, y - 1/*, 0, 1*/);
+ #endif
+ //if (yd != 1)
+ #if 0
+ for (int i= 1; /*check_limit (x, y + i)*/ i < 2; ++i)
+ {
+ if (visited [x] [y + i] )
+ break;
+ visited [x] [y + i]= true;
+ //c= do_test_color (x, y + i);
+ c= test (x, y + i);
+ if (c != border && c != paint)
+ do_paint_it (x, y + i, 0, -1);
+ else
+ break;
+ }
+ #else
+ if (check (x, y + 1) )
+ do_paint_it (x, y + 1/*, 0, -1*/);
+ #endif
+}
+
+ void do_paint (int x, int y)
+ {
+ if (check (x, y) )
+ do_paint_it (x, y/*, 0, 0*/);
+ }
+
+};
+
+#elif 0
+
+class Painter {
+ ColorValue paint, border;
+ std::vector <std::vector <bool> > visited;
+ ColorTester test;
+public:
+ Painter (ColorValue paint, ColorValue border) :
+ paint (paint),
+ border (border),
+ visited (screenwidth, std::vector <bool> (screenheight) )
+ {
+ }
+
+//void paintN (int x, int y);
+//void paintS (int x, int y);
+//void paintE (int x, int y);
+//void paintW (int x, int y);
+
+void do_paint (int x, int y)
+{
+ if (! check_limit (x, y) )
+ return;
+ //ColorValue c= do_test_color (x, y);
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return;
+ do_plot (x, y);
+ visited [x] [y]= true;
+ paintN (x, y - 1);
+ paintS (x, y + 1);
+ paintE (x + 1, y);
+ paintW (x - 1, y);
+}
+
+void paintN (int x, int y)
+{
+ if (! check_limit (x, y) )
+ return;
+ if (visited [x] [y] )
+ return;
+ visited [x] [y]= true;
+ //ColorValue c= do_test_color (x, y);
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return;
+ do_plot (x, y);
+ paintN (x, y - 1);
+ paintE (x + 1, y);
+ paintW (x - 1, y);
+}
+
+void paintS (int x, int y)
+{
+ if (! check_limit (x, y) )
+ return;
+ if (visited [x] [y] )
+ return;
+ visited [x] [y]= true;
+ //ColorValue c= do_test_color (x, y);
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return;
+ do_plot (x, y);
+ paintS (x, y + 1);
+ paintE (x + 1, y);
+ paintW (x - 1, y);
+}
+
+void paintE (int x, int y)
+{
+ if (! check_limit (x, y) )
+ return;
+ if (visited [x] [y] )
+ return;
+ visited [x] [y]= true;
+ //ColorValue c= do_test_color (x, y);
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return;
+ do_plot (x, y);
+ paintN (x, y - 1);
+ paintS (x, y + 1);
+ paintE (x + 1, y);
+}
+
+void paintW (int x, int y)
+{
+ if (! check_limit (x, y) )
+ return;
+ if (visited [x] [y] )
+ return;
+ visited [x] [y]= true;
+ //ColorValue c= do_test_color (x, y);
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return;
+ do_plot (x, y);
+ paintN (x, y - 1);
+ paintS (x, y + 1);
+ paintW (x - 1, y);
+}
+
+};
+
+#else
+
+struct PPoint {
+ int x;
+ int y;
+ PPoint () { }
+ PPoint (int x, int y) : x (x), y (y) { }
+ //PPoint (const PPoint & p) : x (p.x), y (p.y) { }
+ bool check (ColorValue paint, ColorValue border,
+ std::vector <std::vector <bool> > & visit,
+ ColorTester & test)
+ {
+ if (! check_limit (x, y) )
+ return false;
+ std::vector <bool>::reference v= visit [x] [y];
+ if (v)
+ return false;
+ v= true;
+ //ColorValue c= do_test_color (x, y);
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return false;
+ return true;
+ }
+ void plot () { do_plot (x, y); }
+};
+
+#if 0
+
+class Painter {
+ ColorValue paint, border;
+ ColorTester test;
+ struct seg {
+ int y, xl, xr, dy;
+ seg () { }
+ seg (int y, int xl, int xr, int dy) :
+ y (y), xl (xl), xr (xr), dy (dy)
+ { }
+ };
+ std::deque <seg> stack;
+ bool check (int x, int y)
+ {
+ if (! check_limit (x, y) )
+ return false;
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return false;
+ return true;
+ }
+public:
+ Painter (ColorValue paint, ColorValue border) :
+ paint (paint),
+ border (border)
+ {
+ }
+
+void do_paint (int x, int y)
+{
+ seg s;
+ int l, x1, x2, dy;
+ if (! check_limit (x, y) )
+ return;
+ ColorValue ov;
+ ov= test (x, y);
+ if (ov == paint || ov == border)
+ return;
+ stack.push_back (seg (y, x, x, 1) );
+ stack.push_back (seg (y + 1, x, x, -1) );
+ while (! stack.empty () )
+ {
+ s= stack.back ();
+ stack.pop_back ();
+ y= s.y + s.dy; x1= s.xl; x2= s.xr; dy= s.dy;
+ for (x= x1; check (x, y); --x)
+ do_plot (x, y);
+ if (x >= x1)
+ goto skip;
+ l= x + 1;
+ if (l < x1)
+ stack.push_back (seg (y, l, x1 - 1, -dy) );
+ x= x1 + 1;
+ do {
+ for ( ; check (x, y); ++x)
+ do_plot (x, y);
+ stack.push_back (seg (y, l, x - 1, dy) );
+ if (x > x2 + 1)
+ stack.push_back (seg (y, x2 + 1, x - 1, -dy) );
+ skip:
+ for (x++; x <= x2 && ! test (x, y); ++x)
+ continue;
+ l= x;
+ } while (x <= x2);
+ }
+}
+
+};
+
+
+#elif 0
+
+class Painter {
+ ColorValue paint, border;
+ ColorTester test;
+public:
+ Painter (ColorValue paint, ColorValue border) :
+ paint (paint),
+ border (border)
+ {
+ }
+
+void do_paint (int x, int y)
+{
+ using std::vector;
+ vector <vector <bool> >
+ visit (screenwidth, vector <bool> (screenheight) );
+ std::deque <PPoint> stack;
+ PPoint pt, pn;
+ stack.push_back (PPoint (x, y) );
+ while (! stack.empty () )
+ {
+ pt= stack.back ();
+ stack.pop_back ();
+
+ pt.plot ();
+ pn= PPoint (pt.x, pt.y + 1);
+ if (pn.check (paint, border, visit, test) )
+ stack.push_back (pn);
+
+ pn= PPoint (pt.x, pt.y - 1);
+ if (pn.check (paint, border, visit, test) )
+ stack.push_back (pn);
+
+ pn= PPoint (pt.x + 1, pt.y);
+ if (pn.check (paint, border, visit, test) )
+ stack.push_back (pn);
+
+ pn= PPoint (pt.x - 1, pt.y);
+ if (pn.check (paint, border, visit, test) )
+ stack.push_back (pn);
+ }
+}
+
+};
+
+#else
+
+class Painter {
+ ColorValue paint, border;
+ std::vector <std::vector <bool> > visited;
+ std::deque <PPoint> processlist, nextlist;
+ ColorTester test;
+public:
+ Painter (ColorValue paint, ColorValue border) :
+ paint (paint),
+ border (border),
+ visited (screenwidth, std::vector <bool> (screenheight) )
+ {
+ }
+ bool check (int x, int y)
+ {
+ if (! check_limit (x, y) )
+ return false;
+ std::vector <bool>::reference v= visited [x] [y];
+ if (v)
+ return false;
+ v= true;
+ ColorValue c= test (x, y);
+ if (c == paint || c == border)
+ return false;
+ return true;
+ }
+ void gf (PPoint p)
+ {
+ //if (! p.check (paint, border, visited, test) )
+ if (! check (p.x, p.y) )
+ return;
+ p.plot ();
+ nextlist.push_back ( PPoint (p.x, p.y - 1) );
+ nextlist.push_back ( PPoint (p.x, p.y + 1) );
+ nextlist.push_back ( PPoint (p.x - 1, p.y) );
+ nextlist.push_back ( PPoint (p.x + 1, p.y) );
+
+ }
+ void do_paint (int x, int y)
+ {
+ processlist.push_back (PPoint (x, y) );
+ while (! processlist.empty () )
+ {
+ nextlist.clear ();
+ while (! processlist.empty () )
+ {
+ PPoint cp= processlist.back ();
+ processlist.pop_back ();
+ gf (cp);
+ }
+ processlist= nextlist;
+ }
+ }
+};
+
+#endif
+
+#endif
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::paint (int x, int y, int paintattr, int borderattr)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ transform_x (x);
+ transform_y (y);
+
+ ColorValue paint= getColorValue (mapcolor (paintattr) );
+ ColorValue border= getColorValue (mapcolor (borderattr) );
+
+ setactivecolor (mapcolor (paintattr).pc);
+ //do_paint (x, y /*, 0, 0*/, paint, border);
+ Painter p (paint, border);
+ p.do_paint (x, y /*, 0, 0*/ );
+ setactivecolor (pforeground);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (x, y, paintattr, borderattr);
+
+ #endif
+}
+
+void graphics::mask (int m)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ maskvalue= static_cast <unsigned char> (m);
+ maskpos= 0;
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (m);
+
+ #endif
+}
+
+void graphics::maskdrawfirstpoint (bool f)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ maskdrawfirst= f;
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (f);
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+char skipblank (const char * & s)
+{
+ char c;
+ while ( (c= * s) == ' ' || c == '\t')
+ ++s;
+ return c;
+}
+
+int getnum (const char * & s)
+{
+ int r= 0;
+ char c;
+ if (! isdigit (* s) )
+ {
+ if (showdebuginfo () )
+ cerr << "Inavlid number in DRAW string" << endl;
+ throw ErrSyntax;
+ }
+ while ( isdigit (c= * s) )
+ {
+ r*= 10;
+ r+= c - '0';
+ ++s;
+ }
+ //cerr << r;
+ return r;
+}
+
+void drawsyntaxerror ()
+{
+ if (showdebuginfo () )
+ cerr << "Invalid syntax in DRAW string" << endl;
+ throw ErrSyntax;
+}
+
+enum TypeMove { MoveAbs, MovePos, MoveNeg };
+
+TypeMove gettypemove (const char * & s)
+{
+ TypeMove typemove= MoveAbs;
+ char c= skipblank (s);
+ switch (c)
+ {
+ case '+':
+ //cerr << '+';
+ typemove= MovePos;
+ ++s;
+ skipblank (s);
+ break;
+ case '-':
+ //cerr << '-';
+ typemove= MoveNeg;
+ ++s;
+ skipblank (s);
+ break;
+ }
+ return typemove;
+}
+
+inline void adjust (int & value, TypeMove t, int last)
+{
+ switch (t)
+ {
+ case MoveAbs:
+ break;
+ case MovePos:
+ value= last + value;
+ break;
+ case MoveNeg:
+ value= last - value;
+ break;
+ }
+}
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::draw (const std::string & str)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ const char * s= str.c_str ();
+ char c;
+ int i;
+ while ( (c= skipblank (s) ) != '\0')
+ {
+ //cerr << c;
+ ++s;
+ bool nopaint= false;
+ if (c == 'B')
+ {
+ c= skipblank (s);
+ //cerr << c;
+ ++s;
+ nopaint= true;
+ }
+ switch (c)
+ {
+ case 'M':
+ {
+ TypeMove mx= gettypemove (s);
+ int x= getnum (s);
+ adjust (x, mx, lastx);
+ c= skipblank (s);
+ if (c != ',')
+ //throw ErrSyntax;
+ drawsyntaxerror ();
+ //cerr << ',';
+ ++s;
+ TypeMove my= gettypemove (s);
+ int y= getnum (s);
+ adjust (y, my, lasty);
+ if (nopaint)
+ graphics::move (x, y);
+ else
+ graphics::line (x, y);
+ }
+ break;
+ case 'U':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx, lasty - i);
+ else
+ graphics::line (lastx, lasty - i);
+ break;
+ case 'D':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx, lasty + i);
+ else
+ graphics::line (lastx, lasty + i);
+ break;
+ case 'R':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx + i, lasty);
+ else
+ graphics::line (lastx + i, lasty);
+ break;
+ case 'L':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx - i, lasty);
+ else
+ graphics::line (lastx - i, lasty);
+ break;
+ case 'E':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx + i, lasty - i);
+ else
+ graphics::line (lastx + i, lasty - i);
+ break;
+ case 'F':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx + i, lasty + i);
+ else
+ graphics::line (lastx + i, lasty + i);
+ break;
+ case 'G':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx - i, lasty + i);
+ else
+ graphics::line (lastx - i, lasty + i);
+ break;
+ case 'H':
+ skipblank (s);
+ i= getnum (s);
+ if (nopaint)
+ graphics::move (lastx - i, lasty - i);
+ else
+ graphics::line (lastx - i, lasty - i);
+ break;
+ case 'C':
+ c= skipblank (s);
+ if (! isdigit (c) )
+ //throw ErrSyntax;
+ drawsyntaxerror ();
+ graphics::setcolor (c - '0');
+ ++s;
+ break;
+ case 'X':
+ {
+ std::string x;
+ while ( (c= *s) != ';' && c != '\0')
+ {
+ x+= c;
+ ++s;
+ }
+ if (c != ';')
+ //throw ErrSyntax;
+ drawsyntaxerror ();
+ ++s;
+ if (typeofvar (x) != VarString)
+ throw ErrMismatch;
+ std::string xx= evaluatevarstring (x);
+ draw (xx);
+ }
+ break;
+ case ';':
+ break;
+ default:
+ //throw ErrSyntax;
+ drawsyntaxerror ();
+ }
+ }
+ //cerr << endl;
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (str);
+
+ #endif
+}
+
+graphics::Point graphics::getlast ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return Point (lastx, lasty);
+
+ #else
+
+ return Point (0, 0);
+
+ #endif
+}
+
+std::string graphics::inkey ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ idle ();
+ if (queuekey.empty () )
+ return std::string ();
+
+ #if 0
+
+ std::string str= queuekey.front ();
+ queuekey.pop ();
+ return str;
+
+ #else
+
+ return queuekey.pop ();
+
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ ASSERT (false);
+ throw ErrBlassicInternal; // Make the compiler happy.
+
+ #endif
+}
+
+bool graphics::pollin ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ idle ();
+ return ! queuekey.empty ();
+
+ #else
+
+ throw ErrBlassicInternal; // Make the compiler happy.
+
+ #endif
+}
+
+std::string graphics::getkey ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #ifdef BLASSIC_USE_X
+
+ while (queuekey.empty () )
+ wait_X_event ();
+ return queuekey.pop ();
+
+ #else
+
+ for (;;)
+ {
+ idle ();
+ if (! queuekey.empty () )
+ return queuekey.pop ();
+
+ // Reduces cpu usage.
+ #ifdef BLASSIC_USE_WINDOWS
+ Sleep (0);
+ #endif
+ }
+
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ ASSERT (false); // Must not came here.
+ throw ErrBlassicInternal; // Make the compiler happy.
+
+ #endif
+}
+
+int graphics::keypressed (int keynum)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #if 0
+
+ if (keynum < 0 || keynum > static_cast <int> (MAXINKEYCODE) )
+ return -1;
+ idle ();
+ if (! keypressedmap [presscode [keynum] ] )
+ return -1;
+ int r= 0;
+ const int shiftpressed= 32, ctrlpressed= 128;
+
+ #ifdef BLASSIC_USE_X
+ if (keypressedmap [XK_Shift_L] || keypressedmap [XK_Shift_R] )
+ r|= shiftpressed;
+ if (keypressedmap [XK_Control_L] || keypressedmap [XK_Control_R] )
+ r|= ctrlpressed;
+ #endif
+
+ return r;
+
+ #else
+ return ::keypressed (keynum);
+ #endif
+
+ #else
+ // No graphics.
+
+ touch (keynum);
+ ASSERT (false); // Must not came here.
+ throw ErrBlassicInternal; // Make the compiler happy.
+
+ #endif
+}
+
+namespace {
+
+int symbol_after_is;
+
+inline bool iscontrolchar (char c)
+{
+ //return iscntrl (static_cast <unsigned char> (c) );
+ unsigned char c1= static_cast <unsigned char> (c);
+ return c1 < 32;
+}
+
+} // namespace
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+class BlWindow {
+ size_t collecting_params;
+ std::string params;
+ unsigned char actual_control;
+ struct DefControlChar {
+ size_t nparams;
+ bool force;
+ void (BlWindow::* action) ();
+ DefControlChar (size_t nparams, bool force,
+ void (BlWindow::* action) () ) :
+ nparams (nparams),
+ force (force),
+ action (action)
+ { }
+ // Default constructor required by the initialization
+ // of the escape map (I don't want to use insert
+ // instead of [ ] ).
+ DefControlChar ()
+ { }
+ };
+ static const DefControlChar control [];
+ typedef std::map <char, DefControlChar> escape_t;
+ static const escape_t escape;
+ static escape_t init_escape ();
+ void ignore ()
+ { /* Nothing to do */ }
+ void do_SOH () // 1
+ {
+ do_charout (params [0] );
+ }
+ void do_STX () // 2
+ {
+ cursor_visible= false;
+ }
+ void do_ETX () // 3
+ {
+ cursor_visible= true;
+ }
+ void do_ENQ () // 5
+ {
+ tag_charout (params [0] );
+ }
+ void do_BEL () // 7
+ {
+ graphics::ring ();
+ }
+ void do_BS () // 8
+ {
+ --x;
+ }
+ void do_TAB () // 9
+ {
+ ++x;
+ }
+ void do_LF () // 10
+ {
+ //x= 0;
+ ++y;
+ }
+ void do_VT () // 11
+ {
+ --y;
+ }
+ void do_FF () // 12
+ {
+ cls ();
+ }
+ void do_CR () // 13
+ {
+ x= 0;
+ }
+ void do_SO () // 14
+ {
+ setbackground (static_cast <unsigned char> (params [0] ) % 16);
+ }
+ void do_SI () // 15
+ {
+ setcolor (static_cast <unsigned char> (params [0] ) % 16 );
+ }
+ void do_DLE () // 16
+ {
+ clear_rectangle (x, x, y, y);
+ }
+ void do_DC1 () // 17
+ {
+ clear_from_left ();
+ }
+ void do_DC2 () // 18
+ {
+ clear_to_right ();
+ }
+ void do_DC3 () // 19
+ {
+ clear_from_begin ();
+ }
+ void do_DC4 () // 20
+ {
+ clear_to_end ();
+ }
+ void do_SYN () // 22
+ {
+ graphics::settransparent
+ (static_cast <unsigned char> (params [0] ) );
+ }
+ void do_ETB () // 23
+ {
+ // Ink mode, only CPC modes are allowed.
+ graphics::setdrawmode
+ (static_cast <unsigned char> (params [0] ) % 4);
+ }
+ void do_CAN () // 24
+ {
+ std::swap (foreground, background);
+ }
+ void do_EM () // 25
+ {
+ int symbol= static_cast <unsigned char> (params [0] );
+ // Avoid generate an error if out of range.
+ if (symbol < symbol_after_is)
+ return;
+ unsigned char byte [8];
+ params.copy (reinterpret_cast <char *> (& byte [0] ), 8, 1);
+ graphics::definesymbol (symbol, byte);
+ }
+ void do_SUB () // 26
+ {
+ set (static_cast <unsigned char> (params [0] ),
+ static_cast <unsigned char> (params [1] ),
+ static_cast <unsigned char> (params [2] ),
+ static_cast <unsigned char> (params [3] ) );
+ }
+ void do_ESC () // 27
+ {
+ char c= params [0];
+ escape_t::const_iterator it= escape.find (c);
+ if (it == escape.end () )
+ {
+ do_charout (c);
+ return;
+ }
+ const DefControlChar & defcontrol= it->second;
+ if (defcontrol.nparams == 0)
+ {
+ if (defcontrol.force)
+ forcelegalposition ();
+ (this->* defcontrol.action) ();
+ return;
+ }
+ collecting_params= defcontrol.nparams;
+ // All escapes used have non-control codes,
+ // then we can use the character code
+ // without confusion.
+ ASSERT (! iscontrolchar (c) );
+
+ actual_control= c;
+ params.erase ();
+ }
+ void do_FS () // 28
+ {
+ int ink= static_cast <unsigned char> (params [0] ) % 16;
+ int color= static_cast <unsigned char> (params [1] ) % 32;
+ if (color > 26)
+ return;
+ // Third parameter (flashing ink) ignored.
+ graphics::ink (ink, color);
+ }
+ void do_RS () // 30
+ {
+ x= 0; y= 0;
+ }
+ void do_US () // 31
+ {
+ int xx= static_cast <unsigned char> (params [0] );
+ int yy= static_cast <unsigned char> (params [1] );
+ if (xx == 0 || yy == 0)
+ return;
+ x= xx - 1; y= yy - 1;
+ }
+ void do_ESC_A ()
+ {
+ if (y > 0)
+ --y;
+ }
+ void do_ESC_B ()
+ {
+ if (y < height - 1)
+ ++y;
+ }
+ void do_ESC_C ()
+ {
+ if (x < width - 1)
+ ++x;
+ }
+ void do_ESC_D ()
+ {
+ if (x > 0)
+ --x;
+ }
+ void do_ESC_E ()
+ {
+ clear_rectangle (0, width - 1, 0, height - 1);
+ }
+ void do_ESC_H ()
+ {
+ x= 0; y= 0;
+ }
+ void do_ESC_I ()
+ {
+ --y;
+ }
+ void do_ESC_J ()
+ {
+ clear_to_end ();
+ }
+ void do_ESC_K ()
+ {
+ clear_to_right ();
+ }
+ void do_ESC_L ()
+ {
+ textscrollinverse (y);
+ }
+ void do_ESC_M ()
+ {
+ textscroll (y);
+ }
+ void do_ESC_N ()
+ {
+ deletechar ();
+ }
+ void do_ESC_Y ()
+ {
+ y= static_cast <unsigned char> (params [0] ) - 32;
+ x= static_cast <unsigned char> (params [1] ) - 32;
+ if (y > height - 1)
+ y= height - 1;
+ if (x > width - 1)
+ x= width - 1;
+ }
+ void do_ESC_d ()
+ {
+ clear_from_begin ();
+ }
+ void do_ESC_e ()
+ {
+ cursor_visible= true;
+ }
+ void do_ESC_f ()
+ {
+ cursor_visible= false;
+ }
+ void do_ESC_j ()
+ {
+ savex= x; savey= y;
+ }
+ void do_ESC_k ()
+ {
+ x= savex; y= savey;
+ }
+ void do_ESC_l ()
+ {
+ clear_rectangle (0, width - 1, y, y);
+ }
+ void do_ESC_o ()
+ {
+ clear_from_left ();
+ }
+ void do_ESC_p ()
+ {
+ inverse= true;
+ //std::swap (foreground, background);
+ }
+ void do_ESC_q ()
+ {
+ inverse= false;
+ }
+ void do_ESC_r ()
+ {
+ underline= true;
+ }
+ void do_ESC_u ()
+ {
+ underline= false;
+ }
+ void do_ESC_x ()
+ {
+ // set mode 24 x 80
+ setdefault ();
+ cls ();
+ set (0, 79, 0, 23);
+ }
+ void do_ESC_y ()
+ {
+ // unset mode 24 x 80
+ setdefault ();
+ cls ();
+ }
+public:
+ BlWindow () :
+ collecting_params (0),
+ fTag (false),
+ cursor_visible (true),
+ inverse (false),
+ bright (false),
+ underline (false)
+ {
+ setdefault ();
+ defaultcolors ();
+ }
+ BlWindow (int x1, int x2, int y1, int y2) :
+ collecting_params (0),
+ fTag (false),
+ cursor_visible (true),
+ inverse (false),
+ bright (false),
+ underline (false)
+ {
+ set (x1, x2, y1, y2);
+ defaultcolors ();
+ }
+ void setdefault ()
+ {
+ TRACEFUNC (tr, "BlWindow::setdefault");
+
+ set (0, maxtcol - 1, 0, maxtrow - 1);
+ }
+ void set (int x1, int x2, int y1, int y2)
+ {
+ TRACEFUNC (tr, "BlWindow::set");
+
+ if (x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0)
+ {
+ TRMESSAGE (tr, "Invalid window values");
+ throw ErrImproperArgument;
+ }
+ if (x1 > x2) std::swap (x1, x2);
+ if (y1 > y2) std::swap (y1, y2);
+ if (x1 >= maxtcol) x1= maxtcol - 1;
+ if (x2 >= maxtcol) x2= maxtcol - 1;
+ if (y1 >= maxtrow) y1= maxtrow - 1;
+ if (y2 >= maxtrow) y2= maxtrow - 1;
+ orgx= x1; orgy= y1;
+ width= x2 - x1 + 1;
+ height= y2 - y1 + 1;
+ x= y= 0;
+ }
+ void defaultcolors ()
+ {
+ pen= default_pen;
+ paper= default_paper;
+ foreground= mapcolor (default_pen).pc;
+ background= mapcolor (default_paper).pc;
+ }
+ void setinverse (bool active) { inverse= active; }
+ bool getinverse () { return inverse; }
+ void setbright (bool active)
+ {
+ bool previous= bright;
+ bright= active;
+ // PENDIENTE
+ if (bright != previous)
+ {
+ int color= pen;
+ if (color >= 0 && color <= 7)
+ {
+ if (bright)
+ color+= 8;
+ foreground= mapcolor (color).pc;
+ }
+ color= paper;
+ if (color >= 0 && color <= 7)
+ {
+ if (bright)
+ color+= 8;
+ background= mapcolor (color).pc;
+ }
+ }
+ }
+ bool getbright () { return bright; }
+ int getwidth () const { return width; }
+ int getxpos () const { return x; }
+ int getypos () const { return y; }
+ void gotoxy (int x, int y)
+ {
+ this->x= x; this->y= y;
+ }
+ void forcelegalposition ()
+ {
+ if (x >= width)
+ { x= 0; ++y; }
+ if (x < 0)
+ { x= width - 1; --y; }
+ if (y < 0)
+ {
+ y= 0;
+ textscrollinverse (0);
+ }
+ if (y >= height)
+ {
+ textscroll (0);
+ y= height - 1;
+ }
+ }
+ void tab ()
+ {
+ forcelegalposition ();
+ int zone= sysvar::get16 (sysvar::Zone);
+ if (zone == 0)
+ zone= 8;
+ if (x >= (width / zone) * zone)
+ {
+ //cerr << "Fin de linea" << endl;
+ int yy= orgy + y;
+ for ( ; x < width; ++x)
+ print (orgx + x, yy, ' ', inverse, underline);
+ x= 0;
+ ++y;
+ }
+ else
+ {
+ int yy= orgy + y;
+ do {
+ print (orgx + x, yy, ' ', inverse, underline);
+ ++x;
+ } while (x % zone);
+ }
+ }
+ void tab (size_t n)
+ {
+ forcelegalposition ();
+ int col= n;
+ if (x > col)
+ {
+ do {
+ charout (' ');
+ } while (x < width);
+ }
+ int maxpos= std::min (col, width);
+ while (x < maxpos)
+ charout (' ');
+ x= col;
+ }
+ void setcolor (int color)
+ {
+ pen= color;
+ if (bright && color >=0 && color <= 7)
+ color+= 8;
+ foreground= mapcolor (color).pc;
+ }
+ int getcolor ()
+ {
+ return pen;
+ }
+ void setbackground (int color)
+ {
+ paper= color;
+ if (bright && color >=0 && color <= 7)
+ color+= 8;
+ background= mapcolor (color).pc;
+ }
+ int getbackground ()
+ {
+ return paper;
+ }
+ void movecharforward ()
+ {
+ forcelegalposition ();
+ ++x;
+ }
+ void movecharforward (size_t n)
+ {
+ for ( ; n > 0; --n)
+ movecharforward ();
+ }
+ void movecharback ()
+ {
+ forcelegalposition ();
+ --x;
+ }
+ void movecharback (size_t n)
+ {
+ for ( ; n > 0; --n)
+ movecharback ();
+ }
+ void movecharup ()
+ {
+ forcelegalposition ();
+ --y;
+ }
+ void movecharup (size_t n)
+ {
+ for ( ; n > 0; --n)
+ movecharup ();
+ }
+ void movechardown ()
+ {
+ forcelegalposition ();
+ ++y;
+ }
+ void movechardown (size_t n)
+ {
+ for ( ; n > 0; --n)
+ movechardown ();
+ }
+ void clear_from_left ()
+ {
+ clear_rectangle (0, x, y, y);
+ }
+ void clear_to_right ()
+ {
+ clear_rectangle (x, width - 1, y, y);
+ }
+ void clear_from_begin ()
+ {
+ if (y > 0)
+ clear_rectangle (0, width - 1, 0, y - 1);
+ clear_from_left ();
+ }
+ void clear_to_end ()
+ {
+ clear_to_right ();
+ if (y < height - 1)
+ clear_rectangle (0, width - 1, y + 1, height - 1);
+ }
+ void cls ()
+ {
+ x= y= 0;
+ clear_rectangle (0, width - 1, 0, height - 1);
+ }
+ void clear_rectangle (int left, int right, int top, int bottom)
+ {
+ #if 1
+
+ int x1= (orgx + left) * charwidth;
+ int x2= (orgx + right + 1) * charwidth;
+ int y1= (orgy + top) * charheight;
+ int y2= (orgy + bottom + 1) * charheight;
+ setactivecolor (background);
+ do_fill_rectangle (x1, y1, x2 - 1, y2 - 1, false);
+ setactivecolor (pforeground);
+
+ #else
+
+ int x1= (orgx + left) * charwidth;
+ int w= (right - left + 1) * charwidth;
+ int y1= (orgy + top) * charheight;
+ int h= (bottom - top + 1) * charheight;
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ RECT r= { x1, y1, x1 + w, y1 + h };
+ LOGPEN logpen;
+ GetObject (* background, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ if (! fSynchro)
+ FillRect (hdc, & r, hbrush);
+ FillRect (hdcPixmap, & r, hbrush);
+ DeleteObject (hbrush);
+
+ #endif
+
+ #ifdef BLASSIC_USE_X
+
+ setactivecolor (background);
+ XSetFunction (display, gcp, drawmode_copy);
+ XFillRectangle (display, pixmap, gcp,
+ x1, y1, w, h);
+ XSetFunction (display, gcp, drawmode);
+ if (! fSynchro)
+ {
+ XSetFunction (display, gc, drawmode_copy);
+ XFillRectangle (display, window, gc,
+ x1, y1, w, h);
+ XSetFunction (display, gc, drawmode);
+ // Inserted an idle call because without it
+ // the window sometimes is not updated.
+ graphics::idle ();
+ }
+ setactivecolor (pforeground);
+
+ #endif
+
+ #endif
+ }
+ void deletechar ()
+ {
+ int x1= (orgx + x) * charwidth;
+ int y1= (orgy + y) * charheight;
+ int w= (width - x - 1) * charwidth;
+ int h= charheight;
+
+ #ifdef BLASSIC_USE_X
+
+ XSetFunction (display, gcp, drawmode_copy);
+ XCopyArea (display, pixmap, pixmap, gcp,
+ x1 + charwidth, y1, w, h, x1, y1);
+ setactivecolor (background);
+ XFillRectangle (display, pixmap, gcp,
+ x1 + w, y1, charwidth, h);
+ if (! fSynchro)
+ reinit_window (x1, y1, w + charwidth, h);
+ setactivecolor (foreground);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ RECT r= { x1 + w, y1, x1 + w + charwidth, y1 + h };
+ BitBlt (hdcPixmap, x1, y1, w, h,
+ hdcPixmap, x1 + charwidth, y1, SRCCOPY);
+ LOGPEN logpen;
+ GetObject (* background, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ FillRect (hdcPixmap, & r, hbrush);
+ DeleteObject (hbrush);
+ if (! fSynchro)
+ reinit_window (x1, y1, w + charwidth, h);
+
+ #endif
+ }
+ void textscroll (int fromline)
+ {
+ int x1= orgx * charwidth;
+ int y1= (orgy + fromline) * charheight;
+ int w= width * charwidth;
+ int h= (height - 1 - fromline) * charheight;
+ int x2= x1 + w;
+ int y2= y1 + h;
+
+ // Reinit rectangle. This are not rotated because
+ // do_fill_rectangle will do it.
+ int x1reinit= x1;
+ int y1reinit= y1;
+ int x2reinit= x1 + w;
+ int y2reinit= y1 + h + charheight;
+
+ int x1fill= x1;
+ int y1fill= y1 + h;
+ int x2fill= x1 + w - 1;
+ int y2fill= y1 + h + charheight - 1;
+
+ do_rotate (x1, y1);
+ do_rotate (x2, y2);
+ if (x1 > x2)
+ std::swap (x1, x2);
+ if (y1 > y2)
+ std::swap (y1, y2);
+ do_rotate_rel (w, h);
+
+ int x1src= x1;
+ int y1src= y1;
+ switch (rotate)
+ {
+ case RotateNone:
+ y1src+= charheight;
+ break;
+ case Rotate90:
+ x1src+= charheight;
+ break;
+ }
+
+ do_rotate (x1reinit, y1reinit);
+ do_rotate (x2reinit, y2reinit);
+ if (x1reinit > x2reinit)
+ std::swap (x1reinit, x2reinit);
+ if (y1reinit > y2reinit)
+ std::swap (y1reinit, y2reinit);
+
+ // Operate only in the pixmap, when finished update
+ // the visible window if not in synchro mode.
+
+ // Do the scrolling.
+
+ #ifdef BLASSIC_USE_X
+
+ XSetFunction (display, gcp, drawmode_copy);
+ XCopyArea (display, pixmap, pixmap, gcp,
+ x1src, y1src, w, h, x1, y1);
+
+ #if 0
+ setactivecolor (background);
+ XFillRectangle (display, pixmap, gcp,
+ x1, y1 + h, w, charheight);
+ #endif
+
+ XSetFunction (display, gcp, drawmode);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ BitBlt (hdcPixmap, x1, y1, w, h,
+ hdcPixmap, x1src, y1src, SRCCOPY);
+
+ #if 0
+ LOGPEN logpen;
+ GetObject (* background, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ RECT r = { x1, y1 + h, x1 + w, y1 + h + charheight};
+ FillRect (hdcPixmap, & r, hbrush);
+ DeleteObject (hbrush);
+ #endif
+
+ #endif
+
+ // Fill the new line with the background color.
+ setactivecolor (background);
+ do_fill_rectangle (x1fill, y1fill, x2fill, y2fill, false);
+ setactivecolor (foreground);
+
+ // Test.
+ //#ifdef BLASSIC_USE_X
+ #if 0
+
+ // Generate a expose event for the scrolled area.
+ XExposeEvent event;
+ event.type= Expose;
+ event.display= display;
+ event.window= window;
+ event.x= x1;
+ event.y= y1;
+ event.width= w;
+ event.height= h;
+ event.count= 0;
+ XSendEvent (display, window, False, 0,
+ reinterpret_cast <XEvent *> (& event) );
+
+ #else
+
+ // And update window if not in synchro mode.
+ if (! fSynchro)
+ //reinit_window (x1, y1, w, h + charheight);
+ reinit_window (x1reinit, y1reinit,
+ x2reinit - x1reinit, y2reinit - y1reinit);
+
+ #endif
+ }
+ void textscrollinverse (int fromline)
+ {
+ int x1= orgx * charwidth;
+ int y1= (orgy + fromline) * charheight;
+ int w= width * charwidth;
+ int h= (height - 1 - fromline) * charheight;
+
+ do_rotate (x1, y1);
+ do_rotate (w, h);
+
+ #ifdef BLASSIC_USE_X
+
+ XSetFunction (display, gcp, drawmode_copy);
+ XCopyArea (display, pixmap, pixmap, gcp,
+ x1, y1, w, h, x1, y1 + charheight);
+ setactivecolor (background);
+ XFillRectangle (display, pixmap, gcp,
+ x1, y1, w, charheight);
+ XSetFunction (display, gcp, drawmode);
+
+ if (! fSynchro)
+ reinit_window (x1, y1, w, h + charheight);
+ setactivecolor (foreground);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ RECT r = { x1, y1, x1 + w, y1 + charheight};
+ BitBlt (hdcPixmap, x1, y1 + charheight, w, h,
+ hdcPixmap, x1, y1, SRCCOPY);
+ LOGPEN logpen;
+ GetObject (* background, sizeof (LOGPEN), & logpen);
+ HBRUSH hbrush= CreateSolidBrush (logpen.lopnColor);
+ FillRect (hdcPixmap, & r, hbrush);
+ DeleteObject (hbrush);
+ if (! fSynchro)
+ reinit_window (x1, y1, w, h + charheight);
+
+ #endif
+ }
+ void scroll (int n)
+ {
+ forcelegalposition ();
+ if (n < 0)
+ {
+ for ( ; n < 0; ++n)
+ textscrollinverse (0);
+ gotoxy (0, 0);
+ }
+ else
+ {
+ for ( ; n > 0; --n)
+ textscroll (0);
+ gotoxy (0, height - 1);
+ }
+ }
+ void tag_charout (char c)
+ {
+ int x= lastx, y= lasty;
+ lastx+= charwidth;
+ transform_x (x);
+ transform_y (y);
+ printxy (x, y, c, true);
+ }
+ void charout (char c)
+ {
+ TRACEFUNC (tr, "BlWindow::charout");
+
+ if (fTag)
+ {
+ tag_charout (c);
+ return;
+ }
+ if (collecting_params)
+ {
+ TRMESSAGE (tr, "collecting params");
+ params+= c;
+ if (--collecting_params == 0)
+ {
+ const DefControlChar & defcontrol=
+ actual_control < 32 ?
+ control [actual_control] :
+ escape.find (actual_control)->second;
+ if (defcontrol.force)
+ forcelegalposition ();
+ (this->* defcontrol.action) ();
+ }
+ return;
+ }
+ if (iscontrolchar (c) )
+ {
+ TRMESSAGE (tr, "Is control char");
+ actual_control= c;
+ params.erase ();
+ const DefControlChar & defcontrol=
+ control [actual_control];
+ if (defcontrol.nparams > 0)
+ collecting_params= defcontrol.nparams;
+ else
+ {
+ if (defcontrol.force)
+ forcelegalposition ();
+ (this->* defcontrol.action) ();
+ }
+ return;
+ }
+ forcelegalposition ();
+ pcolor foresave= pforeground;
+ pforeground= foreground;
+ pcolor backsave= pbackground;
+ pbackground= background;
+ #if 0
+ switch (c)
+ {
+ case '\n':
+ x= 0;
+ ++y;
+ break;
+ case '\b':
+ --x;
+ break;
+ case '\r':
+ x= 0;
+ break;
+ case '\t':
+ if (x >= (width / zone) * zone)
+ {
+ //cerr << "Fin de linea" << endl;
+ int yy= orgy + y;
+ for ( ; x < width; ++x)
+ print (orgx + x, yy, ' ',
+ inverse, underline);
+ x= 0;
+ ++y;
+ }
+ else
+ {
+ int yy= orgy + y;
+ do {
+ print (orgx + x, yy, ' ',
+ inverse, underline);
+ ++x;
+ } while (x % zone);
+ }
+ break;
+ default:
+ #endif
+ print (orgx + x, orgy + y, c, inverse, underline);
+ ++x;
+ #if 0
+ }
+ #endif
+ pforeground= foresave;
+ pbackground= backsave;
+ }
+ void do_charout (char c)
+ {
+ pcolor foresave= pforeground;
+ pforeground= foreground;
+ pcolor backsave= pbackground;
+ pbackground= background;
+ print (orgx + x, orgy + y, c, inverse, underline);
+ pforeground= foresave;
+ pbackground= backsave;
+ ++x;
+ }
+ void invertcursor ()
+ {
+ forcelegalposition ();
+ if (! cursor_visible)
+ return;
+ int x1= (orgx + x) * charwidth;
+ int y1= (orgy + y) * charheight;
+ int x1ini= x1;
+ int y1ini= y1 + charheight - 2;
+ int x1end= x1 + charwidth;
+ int y1end= y1 + charheight;
+ do_rotate (x1, y1);
+ do_rotate (x1ini, y1ini);
+ do_rotate (x1end, y1end);
+ if (x1ini > x1end)
+ std::swap (x1ini, x1end);
+ if (y1ini > y1end)
+ std::swap (y1ini, y1end);
+
+ #ifdef BLASSIC_USE_X
+
+ XSetFunction (display, gc, drawmode_invert);
+ XSetFunction (display, gcp, drawmode_invert);
+ XFillRectangle (display, window, gc,
+ x1ini, y1ini, x1end - x1ini, y1end - y1ini);
+ XFillRectangle (display, pixmap, gcp,
+ x1ini, y1ini, x1end - x1ini, y1end - y1ini);
+ XSetFunction (display, gc, drawmode);
+ XSetFunction (display, gcp, drawmode);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ HBRUSH hbrush= (HBRUSH) GetStockObject (BLACK_BRUSH);
+ HDC ahdc [2]= { hdc, hdcPixmap };
+ for (size_t i= 0; i < 2; ++i)
+ {
+ HDC hdc= ahdc [i];
+ SetROP2 (hdc, drawmode_invert);
+ HBRUSH hold= (HBRUSH) SelectObject (hdc, hbrush);
+ //Rectangle (hdc, x1, y1 + 6, x1 + 8, y1 + 8);
+ Rectangle (hdc, x1ini, y1ini, x1end, y1end);
+ SelectObject (hdc, hold);
+ SetROP2 (hdc, drawmode);
+ }
+
+ #endif
+ }
+ std::string copychr (BlChar from, BlChar to)
+ {
+ // I don't tested yet if that is done in the cpc
+ forcelegalposition ();
+
+ int x1= (orgx + x) * charwidth;
+ int y1= (orgy + y) * charheight;
+ return copychrat (x1, y1, from , to);
+ }
+ void tag ()
+ {
+ fTag= true;
+ }
+ void tagoff ()
+ {
+ fTag= false;
+ }
+ bool istagactive ()
+ {
+ return fTag;
+ }
+private:
+ int orgx, orgy, width, height;
+ pcolor foreground;
+ pcolor background;
+ int x, y, savex, savey;
+ bool fTag;
+ bool cursor_visible;
+ bool inverse;
+ bool bright;
+ bool underline;
+ int pen;
+ int paper;
+};
+
+const BlWindow::DefControlChar BlWindow::control [32]= {
+ BlWindow::DefControlChar (0, false, & BlWindow::ignore), // NUL
+ BlWindow::DefControlChar (1, true, & BlWindow::do_SOH), // SOH
+ BlWindow::DefControlChar (0, false, & BlWindow::do_STX), // STX
+ BlWindow::DefControlChar (0, false, & BlWindow::do_ETX), // ETX
+ BlWindow::DefControlChar (1, false, & BlWindow::ignore), // EOT
+ BlWindow::DefControlChar (1, false, & BlWindow::do_ENQ), // ENQ
+ BlWindow::DefControlChar (0, false, & BlWindow::ignore), // ACK
+ BlWindow::DefControlChar (0, false, & BlWindow::do_BEL), // BEL
+ BlWindow::DefControlChar (0, true, & BlWindow::do_BS ), // BS
+ BlWindow::DefControlChar (0, true, & BlWindow::do_TAB), // TAB
+ BlWindow::DefControlChar (0, true, & BlWindow::do_LF ), // LF
+ BlWindow::DefControlChar (0, true, & BlWindow::do_VT ), // VT
+ BlWindow::DefControlChar (0, false, & BlWindow::do_FF ), // FF
+ BlWindow::DefControlChar (0, true, & BlWindow::do_CR ), // CR
+ BlWindow::DefControlChar (1, false, & BlWindow::do_SO ), // SO
+ BlWindow::DefControlChar (1, false, & BlWindow::do_SI ), // SI
+ BlWindow::DefControlChar (0, true, & BlWindow::do_DLE), // DLE
+ BlWindow::DefControlChar (0, true, & BlWindow::do_DC1), // DC1
+ BlWindow::DefControlChar (0, true, & BlWindow::do_DC2), // DC2
+ BlWindow::DefControlChar (0, true, & BlWindow::do_DC3), // DC3
+ BlWindow::DefControlChar (0, true, & BlWindow::do_DC4), // DC4
+ BlWindow::DefControlChar (0, false, & BlWindow::ignore), // NAK
+ BlWindow::DefControlChar (1, false, & BlWindow::do_SYN), // SYN
+ BlWindow::DefControlChar (1, false, & BlWindow::do_ETB), // ETB
+ BlWindow::DefControlChar (0, false, & BlWindow::do_CAN), // CAN
+ BlWindow::DefControlChar (9, false, & BlWindow::do_EM ), // EM
+ BlWindow::DefControlChar (4, false, & BlWindow::ignore), // SUB
+ BlWindow::DefControlChar (1, false, & BlWindow::do_ESC), // ESC
+ BlWindow::DefControlChar (3, false, & BlWindow::do_FS ), // FS
+ BlWindow::DefControlChar (2, false, & BlWindow::ignore), // GS
+ BlWindow::DefControlChar (0, false, & BlWindow::do_RS ), // RS
+ BlWindow::DefControlChar (2, false, & BlWindow::do_US ), // US
+};
+
+BlWindow::escape_t BlWindow::init_escape ()
+{
+ escape_t aux;
+ DefControlChar ignore0 (0, false, & BlWindow::ignore);
+ DefControlChar ignore1 (1, false, & BlWindow::ignore);
+ aux ['0']= ignore0; // Status line inactive.
+ aux ['1']= ignore0; // Status line active.
+ aux ['2']= ignore1; // Select national character set
+ aux ['3']= ignore1; // Set mode
+ aux ['A']= DefControlChar (0, true, & BlWindow::do_ESC_A);
+ aux ['B']= DefControlChar (0, true, & BlWindow::do_ESC_B);
+ aux ['C']= DefControlChar (0, true, & BlWindow::do_ESC_C);
+ aux ['D']= DefControlChar (0, true, & BlWindow::do_ESC_D);
+ aux ['E']= DefControlChar (0, false, & BlWindow::do_ESC_E);
+ aux ['H']= DefControlChar (0, false, & BlWindow::do_ESC_H);
+ aux ['I']= DefControlChar (0, true, & BlWindow::do_ESC_I);
+ aux ['J']= DefControlChar (0, true, & BlWindow::do_ESC_J);
+ aux ['K']= DefControlChar (0, true, & BlWindow::do_ESC_K);
+ aux ['L']= DefControlChar (0, true, & BlWindow::do_ESC_L);
+ aux ['M']= DefControlChar (0, true, & BlWindow::do_ESC_M);
+ aux ['N']= DefControlChar (0, true, & BlWindow::do_ESC_N);
+ aux ['Y']= DefControlChar (2, false, & BlWindow::do_ESC_Y);
+ aux ['d']= DefControlChar (0, true, & BlWindow::do_ESC_d);
+ aux ['e']= DefControlChar (0, false, & BlWindow::do_ESC_e);
+ aux ['f']= DefControlChar (0, false, & BlWindow::do_ESC_f);
+ aux ['j']= DefControlChar (0, false, & BlWindow::do_ESC_j);
+ aux ['k']= DefControlChar (0, false, & BlWindow::do_ESC_k);
+ aux ['l']= DefControlChar (0, true, & BlWindow::do_ESC_l);
+ aux ['o']= DefControlChar (0, true, & BlWindow::do_ESC_o);
+ aux ['p']= DefControlChar (0, false, & BlWindow::do_ESC_p);
+ aux ['q']= DefControlChar (0, false, & BlWindow::do_ESC_q);
+ aux ['r']= DefControlChar (0, false, & BlWindow::do_ESC_r);
+ aux ['u']= DefControlChar (0, false, & BlWindow::do_ESC_u);
+ aux ['x']= DefControlChar (0, false, & BlWindow::do_ESC_x);
+ aux ['y']= DefControlChar (0, false, & BlWindow::do_ESC_y);
+ return aux;
+}
+
+const BlWindow::escape_t BlWindow::escape= BlWindow::init_escape ();
+
+BlWindow windowzero;
+
+//typedef std::map <BlChannel, BlWindow *> MapWindow;
+
+// Map encapsultated to check access. Windows must be accessed only
+// throug file, then accesing a window that not exists is a internal
+// error. Also destruction of windows is now granted.
+
+class MapWindow {
+ typedef std::map <BlChannel, BlWindow *> map_type;
+ map_type mw;
+public:
+ typedef map_type::iterator iterator;
+ typedef map_type::const_iterator const_iterator;
+ typedef map_type::value_type value_type;
+ typedef map_type::key_type key_type;
+ typedef map_type::mapped_type mapped_type;
+
+ ~MapWindow ();
+ iterator begin ();
+ iterator end ();
+ const_iterator begin () const;
+ const_iterator end () const;
+ // operators [] are checked, fail if the key not exist.
+ mapped_type operator [] (key_type n) const;
+ iterator find (key_type n);
+ static void killwindowifnotzero (const value_type & vt);
+ void clear ();
+ void insert (const value_type & val);
+ void erase (iterator pos);
+};
+
+MapWindow::~MapWindow ()
+{
+ // Ensure window destruction on exit.
+ clear ();
+}
+
+MapWindow::iterator MapWindow::begin ()
+{
+ return mw.begin ();
+}
+
+MapWindow::iterator MapWindow::end ()
+{
+ return mw.end ();
+}
+
+MapWindow::const_iterator MapWindow::begin () const
+{
+ return mw.begin ();
+}
+
+MapWindow::const_iterator MapWindow::end () const
+{
+ return mw.end ();
+}
+
+MapWindow::mapped_type MapWindow::operator [] (key_type n) const
+{
+ const_iterator it= mw.find (n);
+ if (it == end () )
+ {
+ if (showdebuginfo () )
+ cerr << "Trying to access to window " <<
+ n << " that not exists" << endl;
+ throw ErrBlassicInternal;
+ }
+ return it->second;
+}
+
+MapWindow::iterator MapWindow::find (key_type n)
+{
+ return mw.find (n);
+}
+
+void MapWindow::killwindowifnotzero (const value_type & vt)
+{
+ if (vt.first != BlChannel (0) )
+ delete vt.second;
+}
+
+void MapWindow::clear ()
+{
+ std::for_each (begin (), end (),
+ & MapWindow::killwindowifnotzero);
+ mw.clear ();
+}
+
+void MapWindow::insert (const value_type & val)
+{
+ // Fail if already exist.
+ std::pair <iterator, bool> r= mw.insert (val);
+ if (! r.second)
+ {
+ if (showdebuginfo () )
+ cerr << "Trying to create window " <<
+ val.first << " that already exists" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+}
+
+void MapWindow::erase (iterator pos)
+{
+ // Unchecked, actually.
+ mw.erase (pos);
+}
+
+
+MapWindow mapwindow;
+
+void destroy_text_windows ()
+{
+ mapwindow.clear ();
+}
+
+void recreate_windows ()
+{
+ TRACEFUNC (tr, "recreate_windows");
+
+ windowzero.setdefault ();
+ windowzero.defaultcolors ();
+ windowzero.cls ();
+
+ //std::for_each (mapwindow.begin (), mapwindow.end (),
+ // killwindowifnotzero);
+ //mapwindow.clear ();
+ destroy_text_windows ();
+
+ //mapwindow [0]= & windowzero;
+ mapwindow.insert (std::make_pair (BlChannel (0), & windowzero) );
+}
+
+#if 0
+inline void do_charout (char c)
+{
+ switch (c)
+ {
+ case '\n':
+ tcol= 0;
+ if (++trow >= maxtrow)
+ {
+ textscroll ();
+ trow= maxtrow - 1;
+ }
+ return;
+ case '\r':
+ tcol= 0;
+ return;
+ case '\t':
+ {
+ int zone= sysvar::get16 (sysvar::Zone);
+ if (zone == 0)
+ zone= 8;
+ if (tcol >= (maxtcol / zone) * zone)
+ {
+ //cerr << "Fin de linea" << endl;
+ for ( ; tcol < maxtcol; ++tcol)
+ print (tcol, trow, ' ', false);
+ tcol= 0;
+ if (++trow >= maxtrow)
+ {
+ textscroll ();
+ trow= maxtrow - 1;
+ }
+ }
+ else
+ {
+ do {
+ print (tcol, trow, ' ', false);
+ ++tcol;
+ } while (tcol % zone);
+ }
+ return;
+ }
+ }
+ print (tcol, trow, c, false);
+ if (++tcol >= maxtcol)
+ {
+ tcol= 0;
+ if (++trow >= maxtrow)
+ {
+ textscroll ();
+ trow= maxtrow - 1;
+ }
+ }
+}
+#endif
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::setcolor (BlChannel ch, int color)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->setcolor (color);
+
+ #else
+
+ touch (ch, color);
+ no_graphics_support ();
+
+ #endif
+}
+
+int graphics::getcolor (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getcolor ();
+
+ #else
+
+ touch (ch);
+ no_graphics_support ();
+ throw ErrBlassicInternal; // Make the compiler happy
+
+ #endif
+}
+
+void graphics::setbackground (BlChannel ch, int color)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->setbackground (color);
+
+ #else
+
+ touch (ch, color);
+ no_graphics_support ();
+
+ #endif
+}
+
+int graphics::getbackground (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getbackground ();
+
+ #else
+
+ touch (ch);
+ no_graphics_support ();
+ throw ErrBlassicInternal;
+
+ #endif
+}
+
+void graphics::cls (BlChannel n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [n]->cls ();
+
+ #else
+
+ touch (n);
+ no_graphics_support ();
+
+ #endif
+}
+
+void graphics::definewindow (BlChannel n, int x1, int x2, int y1, int y2)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ --x1; --x2; --y1; --y2;
+ MapWindow::iterator it= mapwindow.find (n);
+ if (it != mapwindow.end () )
+ it->second->set (x1, x2, y1, y2);
+ else
+ {
+ //mapwindow [n]= new BlWindow (x1, x2, y1, y2);
+
+ // auto_ptr protects the new window in case
+ // that mapwindows.insert throws.
+ auto_ptr <BlWindow> pwin (new BlWindow (x1, x2, y1, y2) );
+ mapwindow.insert (std::make_pair (n, pwin.get () ) );
+ pwin.release ();
+ }
+
+ #else
+
+ touch (n, x1, x2, y1, y2);
+
+ #endif
+}
+
+void graphics::undefinewindow (BlChannel n)
+{
+ if (n == 0)
+ return;
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ MapWindow::iterator it= mapwindow.find (n);
+ if (it != mapwindow.end () )
+ {
+ delete it->second;
+ mapwindow.erase (it);
+ }
+
+ #else
+
+ ASSERT (false);
+ no_graphics_support ();
+
+ #endif
+}
+
+#if 0
+size_t graphics::getlinewidth ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #if 0
+ return maxtcol;
+ #else
+ return windowzero.getwidth ();
+ #endif
+
+ #else
+
+ return 0;
+
+ #endif
+}
+#endif
+
+size_t graphics::getlinewidth (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getwidth ();
+
+ #else
+
+ touch (ch);
+ no_graphics_support ();
+ return 0; // Make the compiler happy
+
+ #endif
+}
+
+#if 0
+void graphics::charout (char c)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ //do_charout (c);
+ windowzero.charout (c);
+ //idle ();
+
+ #else
+
+ touch (c);
+
+ #endif
+}
+
+void graphics::stringout (const std::string & str)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ for (std::string::size_type i= 0, l= str.size (); i < l; ++i)
+ windowzero.charout (str [i]);
+
+ #else
+
+ touch (str);
+
+ #endif
+}
+#endif
+
+void graphics::charout (BlChannel ch, char c)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->charout (c);
+
+ #else
+
+ touch (ch, c);
+
+ #endif
+}
+
+void graphics::stringout (BlChannel ch, const std::string & str)
+{
+ TRACEFUNC (tr, "graphics::stringout");
+ TRMESSAGE (tr, "Channel: " + to_string (ch) );
+ TRMESSAGE (tr, "String: " + str);
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ BlWindow * pwin= mapwindow [ch];
+ if (pwin == NULL)
+ throw ErrBlassicInternal;
+ for (std::string::size_type i= 0, l= str.size (); i < l; ++i)
+ pwin->charout (str [i]);
+
+ #else
+
+ touch (ch, str);
+
+ #endif
+}
+
+std::string graphics::copychr (BlChannel ch, BlChar from, BlChar to)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ BlWindow * pwin= mapwindow [ch];
+ return pwin->copychr (from, to);
+
+ #else
+
+ touch (ch, from, to);
+ ASSERT (false);
+ throw ErrBlassicInternal;
+
+ #endif
+}
+
+std::string graphics::screenchr (int x, int y)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return copychrat (x * charwidth, y * charheight, 0, 255);
+
+ #else
+
+ touch (x, y);
+ ASSERT (false);
+ throw ErrBlassicInternal;
+
+ #endif
+}
+
+#if 0
+void graphics::gotoxy (int x, int y)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ trow= y;
+ tcol= x;
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+#endif
+
+void graphics::gotoxy (BlChannel ch, int x, int y)
+{
+ TRACEFUNC (tr, "graphics::gotoxy");
+ TRMESSAGE (tr, "Channel: " + to_string (ch) + ", x= " +
+ to_string (x) + ", y= " + to_string (y) );
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->gotoxy (x, y);
+
+ #else
+
+ touch (ch, x, y);
+
+ #endif
+}
+
+#if 0
+void graphics::tab (size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ int col (n - 1);
+ if (tcol >= col)
+ {
+ do {
+ do_charout (' ');
+ } while (tcol > 0);
+ }
+ if (col >= maxtcol)
+ throw ErrFunctionCall;
+ do {
+ do_charout (' ');
+ } while (tcol < col);
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (n);
+
+ #endif
+}
+#endif
+
+void graphics::tab (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->tab ();
+
+ #else
+
+ touch (ch);
+
+ #endif
+}
+
+void graphics::tab (BlChannel ch, size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->tab (n);
+
+ #else
+
+ touch (ch, n);
+
+ #endif
+}
+
+#if 0
+void graphics::movecharforward (size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ windowzero.movecharforward (n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+#endif
+
+void graphics::movecharforward (BlChannel ch, size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->movecharforward (n);
+
+ #else
+
+ touch (ch, n);
+
+ #endif
+}
+
+#if 0
+void graphics::movecharback (size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ windowzero.movecharback (n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+#endif
+
+void graphics::movecharback (BlChannel ch, size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->movecharback (n);
+
+ #else
+
+ touch (ch, n);
+
+ #endif
+}
+
+#if 0
+void graphics::movecharup (size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ windowzero.movecharup (n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+#endif
+
+void graphics::movecharup (BlChannel ch, size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->movecharup (n);
+
+ #else
+
+ touch (ch, n);
+
+ #endif
+}
+
+#if 0
+void graphics::movechardown (size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ windowzero.movechardown (n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+#endif
+
+void graphics::movechardown (BlChannel ch, size_t n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->movechardown (n);
+
+ #else
+
+ touch (ch, n);
+
+ #endif
+}
+
+void graphics::scroll (BlChannel ch, int n)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->scroll (n);
+
+ #else
+
+ touch (ch, n);
+
+ #endif
+}
+
+void graphics::symbolafter (int symbol)
+{
+ if (symbol < 0 || symbol > 256)
+ throw ErrFunctionCall;
+ memcpy (charset::data, * charset::default_charset,
+ sizeof (charset::chardataset) );
+ symbol_after_is= symbol;
+}
+
+void graphics::definesymbol (int symbol, const unsigned char (& byte) [8] )
+{
+ if (symbol < 0 || symbol > 255)
+ throw ErrFunctionCall;
+ if (symbol < symbol_after_is)
+ throw ErrImproperArgument;
+ memcpy (charset::data + symbol, byte, sizeof (byte) );
+}
+
+void graphics::synchronize (bool mode)
+{
+ TRACEFUNC (tr, "graphics::synchronize");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ bool previous= fSynchro;
+ TRMESSAGE (tr, "Was " + to_string (previous) );
+
+ fSynchro= mode;
+
+ if (previous == true && mode == false && ingraphicsmode () )
+ reinit_window ();
+
+ TRMESSAGE (tr, "Set to " + to_string (mode) );
+
+ #else
+
+ touch (mode);
+
+ #endif
+}
+
+void graphics::synchronize ()
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ reinit_window ();
+ idle ();
+
+ #endif
+}
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+size_t synchrosaved= 0;
+bool fSynchroSaved= false;
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::synchronize_suspend ()
+{
+ TRACEFUNC (tr, "graphics::synchronize_suspend");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (synchrosaved++ > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "synchronize_suspend called several times" <<
+ endl;
+ }
+ else
+ fSynchroSaved= fSynchro;
+
+ //if (fSynchro)
+ // reinit_window ();
+ //fSynchro= false;
+ synchronize (false);
+
+ #endif
+}
+
+void graphics::synchronize_restart ()
+{
+ TRACEFUNC (tr, "graphics::synchronize_restart");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ if (synchrosaved == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "uexpected call to synchronize_restart" <<
+ endl;
+ }
+ else
+ {
+ if (--synchrosaved == 0)
+ //fSynchro= fSynchroSaved;
+ synchronize (fSynchroSaved);
+ }
+
+ #endif
+}
+
+int graphics::xmouse ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return xmousepos;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+int graphics::ymouse ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return ymousepos;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+int graphics::xpos ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return lastx;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+int graphics::xpos (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getxpos ();
+
+ #else
+
+ touch (ch);
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+int graphics::ypos ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return lasty;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+int graphics::ypos (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getypos ();
+
+ #else
+
+ touch (ch);
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+void graphics::tag (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->tag ();
+
+ #else
+
+ touch (ch);
+
+ #endif
+}
+
+void graphics::tagoff (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->tagoff ();
+
+ #else
+
+ touch (ch);
+
+ #endif
+}
+
+bool graphics::istagactive (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->istagactive ();
+
+ #else
+
+ touch (ch);
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+#if 0
+void graphics::showcursor ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+ windowzero.invertcursor ();
+ #endif
+}
+
+void graphics::hidecursor ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+ windowzero.invertcursor ();
+ #endif
+}
+#endif
+
+void graphics::showcursor (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->invertcursor ();
+
+ #else
+
+ touch (ch);
+
+ #endif
+}
+
+void graphics::hidecursor (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->invertcursor ();
+
+ #else
+
+ touch (ch);
+
+ #endif
+}
+
+void graphics::inverse (BlChannel ch, bool active)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->setinverse (active);
+
+ #else
+
+ touch (ch, active);
+
+ #endif
+}
+
+bool graphics::getinverse (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getinverse ();
+
+ #else
+
+ touch (ch);
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+void graphics::bright (BlChannel ch, bool active)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ mapwindow [ch]->setbright (active);
+
+ #else
+
+ touch (ch, active);
+
+ #endif
+}
+
+bool graphics::getbright (BlChannel ch)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ return mapwindow [ch]->getbright ();
+
+ #else
+
+ touch (ch);
+ throw ErrFunctionCall;
+
+ #endif
+}
+
+void graphics::clean_input ()
+{
+ TRACEFUNC (tr, "graphics::clean_input");
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ graphics::idle ();
+ queuekey.erase ();
+
+ #endif
+}
+
+void graphics::ring ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #ifdef BLASSIC_USE_X
+
+ XBell (display, 100);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ MessageBeep (MB_ICONEXCLAMATION);
+
+ #endif
+
+ #endif
+}
+
+void graphics::set_title (const std::string & title)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ SetWindowText (window, title.c_str () );
+
+ #elif defined BLASSIC_USE_X
+
+ XmbSetWMProperties (display, window, title.c_str (), title.c_str (),
+ NULL, 0, NULL, NULL, NULL);
+
+ #endif
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (title);
+
+ #endif
+}
+
+void graphics::set_default_title (const std::string & title)
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ default_title= title;
+
+ #else
+
+ touch (title);
+
+ #endif
+}
+
+//*********************************************************
+// Graphics get and put.
+//*********************************************************
+
+#ifdef BLASSIC_HAS_GRAPHICS
+
+namespace {
+
+class Image {
+public:
+ Image (int x1, int y1, int x2, int y2);
+ ~Image ();
+ void put (int x, int y, int mode);
+private:
+ int width;
+ int height;
+
+ #ifdef BLASSIC_USE_X
+
+ XImage * img;
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ HBITMAP img;
+ HDC hdcImg;
+
+ #endif
+};
+
+Image::Image (int x1, int y1, int x2, int y2)
+{
+ // Adjust coordinates to current rotate mode.
+ do_rotate (x1, y1);
+ do_rotate (x2, y2);
+ if (x1 > x2) std::swap (x1, x2);
+ if (y1 > y2) std::swap (y1, y2);
+ if (x1 >= screenwidth || y1 >= screenheight)
+ throw ErrFunctionCall;
+ if (x2 >= screenwidth)
+ x2= screenwidth - 1;
+ if (y2 >= screenheight)
+ y2= screenheight - 1;
+
+ width= x2 - x1 + 1;
+ height= y2 - y1 + 1;
+
+ #ifdef BLASSIC_USE_X
+
+ img= XGetImage (display, pixmap, x1, y1, width, height,
+ AllPlanes, XYPixmap);
+ if (img == NULL)
+ throw ErrFunctionCall;
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ img= CreateCompatibleBitmap (hdcPixmap, width, height);
+ if (img == NULL)
+ throw ErrFunctionCall;
+ hdcImg= CreateCompatibleDC (hdcPixmap);
+ if (hdcImg == NULL)
+ {
+ DeleteObject (img);
+ throw ErrFunctionCall;
+ }
+ HGDIOBJ hgdiobj= SelectObject (hdcImg, img);
+ if (hgdiobj == NULL ||
+ hgdiobj == reinterpret_cast <HGDIOBJ> (GDI_ERROR) )
+ {
+ DeleteDC (hdcImg);
+ DeleteObject (img);
+ throw ErrFunctionCall;
+ }
+
+ if (BitBlt (hdcImg, 0, 0, width, height, hdcPixmap, x1, y1, SRCCOPY)
+ == 0)
+ {
+ DeleteDC (hdcImg);
+ DeleteObject (img);
+ throw ErrFunctionCall;
+ }
+
+ #endif
+}
+
+Image::~Image ()
+{
+ #ifdef BLASSIC_USE_X
+
+ XDestroyImage (img);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ DeleteDC (hdcImg);
+ DeleteObject (img);
+
+ #endif
+}
+
+void Image::put (int x, int y, int mode)
+{
+ TRACEFUNC (tr, "Image::put");
+
+ TRMESSAGE (tr, "at " + to_string (x) + ',' + to_string (y) );
+
+ // Adjust coordinates to current rotate mode.
+ do_rotate (x, y);
+ switch (rotate)
+ {
+ case RotateNone:
+ // Nothing to do.
+ break;
+ case Rotate90:
+ y-= width - 1;
+ break;
+ }
+ if (x >= screenwidth || y >= screenheight)
+ throw ErrFunctionCall;
+ int maxwidth= screenwidth - x + 1;
+ int maxheight= screenheight - y + 1;
+ int w= std::min (width, maxwidth);
+ int h= std::min (height, maxheight);
+
+ TRMESSAGE (tr, "At " + to_string (x) + ',' + to_string (y) );
+
+ #ifdef BLASSIC_USE_X
+
+ int modeused= getdrawmode (mode);
+
+ XSetFunction (display, gcp, modeused);
+ XPutImage (display, pixmap, gcp, img,
+ 0, 0, x, y, w, h);
+ XSetFunction (display, gcp, drawmode);
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ int modeused= getbitbltmode (mode);
+
+ if (BitBlt (hdcPixmap, x, y, w, h, hdcImg, 0, 0, modeused) == 0)
+ throw ErrFunctionCall;
+
+ #endif
+
+ if (! fSynchro)
+ reinit_window (x, y, width, height);
+}
+
+typedef std::map <std::string, Image *> imagemap_t;
+imagemap_t imagemap;
+
+} // namespace
+
+#endif
+// BLASSIC_HAS_GRAPHICS
+
+void graphics::get_image (int x1, int y1, int x2, int y2,
+ const std::string & name)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ imagemap_t::iterator it= imagemap.find (name);
+ if (it != imagemap.end () )
+ {
+ delete it->second;
+ imagemap.erase (it);
+ }
+
+ auto_ptr <Image> pimg (new Image (x1, y1, x2, y2) );
+ imagemap [name]= pimg.get ();
+ pimg.release ();
+
+ #else
+ // No BLASSIC_HAS_GRAPHICS
+
+ touch (x1, y1, x2, y2, name);
+
+ #endif
+}
+
+void graphics::put_image (int x, int y, const std::string & name, int mode)
+{
+ requiregraphics ();
+
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ imagemap_t::iterator it= imagemap.find (name);
+ if (it != imagemap.end () )
+ {
+ it->second->put (x, y, mode);
+ }
+ else
+ throw ErrFunctionCall;
+
+ #else
+
+ touch (x, y, name, mode);
+
+ #endif
+ // BLASSIC_HAS_GRAPHICS
+}
+
+void graphics::clear_images ()
+{
+ #ifdef BLASSIC_HAS_GRAPHICS
+
+ for (imagemap_t::iterator it= imagemap.begin ();
+ it != imagemap.end ();
+ ++it)
+ {
+ delete it->second;
+ }
+ imagemap.clear ();
+
+ #endif
+ // BLASSIC_HAS_GRAPHICS
+}
+
+// Fin de graphics.cpp
diff --git a/graphics.h b/graphics.h
new file mode 100644
index 0000000..f0c3dfe
--- /dev/null
+++ b/graphics.h
@@ -0,0 +1,164 @@
+#ifndef INCLUDE_BLASSIC_GRAPHICS_H
+#define INCLUDE_BLASSIC_GRAPHICS_H
+
+// graphics.h
+// Revision 9-jan-2005
+
+#include "blassic.h"
+
+namespace graphics {
+
+struct Point {
+ int x, y;
+ Point (int xx, int yy) : x (xx), y (yy) { }
+ Point (): x (0), y (0) { }
+};
+
+void initialize (const char * progname);
+void uninitialize ();
+
+void origin (int x, int y);
+void limits (int minx, int maxx, int miny, int maxy);
+
+void ink (int inknum, int cpccolor);
+void ink (int inknum, int r, int g, int b);
+void clearink ();
+
+//void idle ();
+using blassic::idle;
+
+void cls ();
+void cls (BlChannel n);
+void setmode (int width, int height, bool inverty,
+ int zoomx= 1, int zoomy= 1);
+void setmode (int mode);
+void setmode (const std::string & mode);
+bool ingraphicsmode ();
+
+void setcolor (int color);
+int getcolor ();
+void setcolor (BlChannel ch, int color);
+int getcolor (BlChannel ch);
+void setbackground (int color);
+int getbackground ();
+void setbackground (BlChannel ch, int color);
+int getbackground (BlChannel ch);
+
+void settransparent (int transpmode);
+void setdrawmode (int mode);
+
+void line (int x, int y);
+void liner (int x, int y);
+void drawarc (int x, int y, double g);
+
+void rectangle (Point org, Point dest);
+void rectanglefilled (Point org, Point dest);
+
+void zxplot (Point p);
+void zxunplot (Point p);
+
+void move (int x, int y);
+void mover (int x, int y);
+void plot (int x, int y);
+void plotr (int x, int y);
+void plot (std::vector <Point> & points);
+int test (int x, int y, bool relative);
+
+void circle (int x, int y, int radius);
+void arccircle (int x, int y, int radius,
+ BlNumber arcbeg, BlNumber arcend);
+void ellipse (int x, int y, int rx, int ry);
+void arcellipse (int x, int y, int rx, int ry,
+ BlNumber arcbeg, BlNumber arcend);
+
+void paint (int x, int y, int paintattr, int borderattr);
+
+void mask (int m);
+void maskdrawfirstpoint (bool f);
+void draw (const std::string & str);
+Point getlast ();
+
+std::string getkey ();
+std::string inkey ();
+bool pollin ();
+int keypressed (int keynum);
+
+void charout (char c);
+void stringout (const std::string & str);
+
+void charout (BlChannel ch, char c);
+void stringout (BlChannel ch, const std::string & str);
+std::string copychr (BlChannel ch, BlChar from, BlChar to);
+
+std::string screenchr (int x, int y);
+
+void definewindow (BlChannel n, int x1, int x2, int y1, int y2);
+void undefinewindow (BlChannel ch);
+
+size_t getlinewidth ();
+size_t getlinewidth (BlChannel ch);
+
+//void locate (int row, int col);
+void gotoxy (int x, int y);
+void tab (size_t n);
+void movecharforward (size_t n);
+void movecharback (size_t n);
+void movecharup (size_t n);
+void movechardown (size_t n);
+
+void gotoxy (BlChannel ch, int x, int y);
+void tab (BlChannel ch);
+void tab (BlChannel ch, size_t x);
+void movecharforward (BlChannel ch, size_t n);
+void movecharback (BlChannel ch, size_t n);
+void movecharup (BlChannel ch, size_t n);
+void movechardown (BlChannel ch, size_t n);
+
+void scroll (BlChannel ch, int n);
+
+void symbolafter (int symbol);
+void definesymbol (int symbol, const unsigned char (& byte) [8] );
+void synchronize (bool mode);
+void synchronize ();
+void synchronize_suspend ();
+void synchronize_restart ();
+
+int xmouse ();
+int ymouse ();
+
+int xpos ();
+int xpos (BlChannel ch);
+int ypos ();
+int ypos (BlChannel ch);
+
+void tag (BlChannel ch);
+void tagoff (BlChannel ch);
+bool istagactive (BlChannel ch);
+
+void showcursor ();
+void hidecursor ();
+
+void showcursor (BlChannel ch);
+void hidecursor (BlChannel ch);
+
+void inverse (BlChannel ch, bool active);
+bool getinverse (BlChannel ch);
+void bright (BlChannel ch, bool active);
+bool getbright (BlChannel ch);
+
+void clean_input ();
+
+void ring ();
+
+void set_title (const std::string & title);
+void set_default_title (const std::string & title);
+
+void get_image (int x1, int y1, int x2, int y2, const std::string & name);
+void put_image (int x, int y, const std::string & name, int mode);
+void clear_images ();
+
+} // namespace graphics
+
+#endif
+
+// Fin de graphics.h
diff --git a/key.cpp b/key.cpp
new file mode 100644
index 0000000..b7946e5
--- /dev/null
+++ b/key.cpp
@@ -0,0 +1,155 @@
+// key.cpp
+// Revision 9-jan-2005
+
+#include "key.h"
+#include "trace.h"
+#include "blassic.h"
+
+#include <map>
+
+#include <iostream> // For debug info only.
+
+//#ifdef _Windows
+#ifdef BLASSIC_USE_WINDOWS
+
+#include <windows.h>
+
+#elif defined BLASSIC_USE_X
+
+#include <X11/keysym.h>
+
+#endif
+
+const std::string
+ strPAGEUP ("PAGEUP"),
+ strPAGEDOWN ("PAGEDOWN"),
+ strEND ("END"),
+ strHOME ("HOME"),
+ strLEFT ("LEFT"),
+ strUP ("UP"),
+ strRIGHT ("RIGHT"),
+ strDOWN ("DOWN"),
+ strINSERT ("INSERT"),
+ strDELETE ("DELETE"),
+ strF1 ("F1"),
+ strF2 ("F2"),
+ strF3 ("F3"),
+ strF4 ("F4"),
+ strF5 ("F5"),
+ strF6 ("F6"),
+ strF7 ("F7"),
+ strF8 ("F8"),
+ strF9 ("F9"),
+ strF10 ("F10"),
+ strF11 ("F11"),
+ strF12 ("F12"),
+ strENTER ("\n"),
+ strCLICK ("CLICK"),
+ strSCLICK ("SCLICK"),
+ strRELEASE ("RELEASE"),
+ strSRELEASE ("SRELEASE");
+
+namespace {
+
+typedef std::map <unsigned int, std::string> mapkey_t;
+
+mapkey_t mapkey;
+
+inline void assignmapkey (unsigned int code, const std::string & name)
+{
+ #ifndef NDEBUG
+ mapkey_t::iterator it;
+ if ( (it= mapkey.find (code) ) != mapkey.end () )
+ {
+ std::cerr << "Error: key " << name <<
+ " has equal code than " << it->second <<
+ std::endl;
+ throw 1;
+ }
+ #endif
+ mapkey [code]= name;
+}
+
+bool initmapkey ()
+{
+ TRACEFUNC (tr, "initmapkey");
+
+ //#ifdef _Windows
+ #ifdef BLASSIC_USE_WINDOWS
+
+ assignmapkey (VK_PRIOR, strPAGEUP);
+ assignmapkey (VK_NEXT, strPAGEDOWN);
+ assignmapkey (VK_END, strEND);
+ assignmapkey (VK_HOME, strHOME);
+ assignmapkey (VK_LEFT, strLEFT);
+ assignmapkey (VK_UP, strUP);
+ assignmapkey (VK_RIGHT, strRIGHT);
+ assignmapkey (VK_DOWN, strDOWN);
+ assignmapkey (VK_INSERT, strINSERT);
+ assignmapkey (VK_DELETE, strDELETE);
+ assignmapkey (VK_F1, strF1);
+ assignmapkey (VK_F2, strF2);
+ assignmapkey (VK_F3, strF3);
+ assignmapkey (VK_F4, strF4);
+ assignmapkey (VK_F5, strF5);
+ assignmapkey (VK_F6, strF6);
+ assignmapkey (VK_F7, strF7);
+ assignmapkey (VK_F8, strF8);
+ assignmapkey (VK_F9, strF9);
+ assignmapkey (VK_F10, strF10);
+ assignmapkey (VK_F11, strF11);
+ assignmapkey (VK_F12, strF12);
+
+ #elif defined BLASSIC_USE_X
+
+ assignmapkey (XK_Prior, strPAGEUP);
+ assignmapkey (XK_KP_Prior, strPAGEUP);
+ assignmapkey (XK_Next, strPAGEDOWN);
+ assignmapkey (XK_KP_Next, strPAGEDOWN);
+ assignmapkey (XK_End, strEND);
+ assignmapkey (XK_KP_End, strEND);
+ assignmapkey (XK_Home, strHOME);
+ assignmapkey (XK_KP_Home, strHOME);
+ assignmapkey (XK_Left, strLEFT);
+ assignmapkey (XK_KP_Left, strLEFT);
+ assignmapkey (XK_Up, strUP);
+ assignmapkey (XK_KP_Up, strUP);
+ assignmapkey (XK_Right, strRIGHT);
+ assignmapkey (XK_KP_Right, strRIGHT);
+ assignmapkey (XK_Down, strDOWN);
+ assignmapkey (XK_KP_Down, strDOWN);
+ assignmapkey (XK_Insert, strINSERT);
+ assignmapkey (XK_KP_Insert, strINSERT);
+ assignmapkey (XK_Delete, strDELETE);
+ assignmapkey (XK_KP_Delete, strDELETE);
+ assignmapkey (XK_F1, strF1);
+ assignmapkey (XK_F2, strF2);
+ assignmapkey (XK_F3, strF3);
+ assignmapkey (XK_F4, strF4);
+ assignmapkey (XK_F5, strF5);
+ assignmapkey (XK_F6, strF6);
+ assignmapkey (XK_F7, strF7);
+ assignmapkey (XK_F8, strF8);
+ assignmapkey (XK_F9, strF9);
+ assignmapkey (XK_F10, strF10);
+ assignmapkey (XK_F11, strF11);
+ assignmapkey (XK_F12, strF12);
+
+ #endif
+
+ return true;
+}
+
+const bool mapkeyinited= initmapkey ();
+
+} // namespace
+
+std::string string_from_key (unsigned int key)
+{
+ mapkey_t::const_iterator it= mapkey.find (key);
+ if (it != mapkey.end () )
+ return it->second;
+ return std::string ();
+}
+
+// End of key.cpp
diff --git a/key.h b/key.h
new file mode 100644
index 0000000..9e94c0f
--- /dev/null
+++ b/key.h
@@ -0,0 +1,43 @@
+#ifndef INCLUDE_BLASSIC_KEY_H
+#define INCLUDE_BLASSIC_KEY_H
+
+// key.h
+// Revision 7-feb-2005
+
+#include <string>
+
+
+std::string string_from_key (unsigned int key);
+
+extern const std::string
+ strPAGEUP,
+ strPAGEDOWN,
+ strEND,
+ strHOME,
+ strLEFT,
+ strUP,
+ strRIGHT,
+ strDOWN,
+ strINSERT,
+ strDELETE,
+ strF1,
+ strF2,
+ strF3,
+ strF4,
+ strF5,
+ strF6,
+ strF7,
+ strF8,
+ strF9,
+ strF10,
+ strF11,
+ strF12,
+ strENTER,
+ strCLICK,
+ strSCLICK,
+ strRELEASE,
+ strSRELEASE;
+
+#endif
+
+// End of key.h
diff --git a/keyword.cpp b/keyword.cpp
new file mode 100644
index 0000000..f6971ac
--- /dev/null
+++ b/keyword.cpp
@@ -0,0 +1,378 @@
+// keyword.cpp
+// Revision 7-feb-2005
+
+#include "keyword.h"
+#include "util.h"
+#include "sysvar.h"
+#include "trace.h"
+
+#include <iostream>
+#include <set>
+#include <algorithm>
+#include <iterator>
+#include <functional>
+#include <cctype>
+
+// I don't understand why, but with this using the older version
+// of C++ Builder fails.
+#if __BORLANDC__ >= 0x0560
+using std::toupper;
+#endif
+
+namespace sysvar= blassic::sysvar;
+using util::dim_array;
+
+
+namespace {
+
+struct keycode {
+ std::string key;
+ BlCode code;
+ keycode (const char * str, BlCode c) :
+ key (str), code (c)
+ { }
+};
+
+// Can't declare const on Borland or fail at instantiate find_if,
+// don't know why.
+#ifdef __BORLANDC__
+#define const_keycode keycode
+#else
+#define const_keycode const keycode
+#endif
+
+#define m_keycode(n) keycode (#n, key ## n)
+
+#define m_keycode_s(n) keycode (#n "$", key ## n ## _S)
+
+const_keycode table []= {
+ m_keycode (END),
+ m_keycode (LIST),
+ m_keycode (REM),
+ m_keycode (LOAD),
+ m_keycode (SAVE),
+ m_keycode (EXIT),
+ m_keycode (NEW),
+ m_keycode (RUN),
+ m_keycode (PRINT),
+ m_keycode (FOR),
+ m_keycode (NEXT),
+ m_keycode (TO),
+ m_keycode (STEP),
+ m_keycode (IF),
+ m_keycode (THEN),
+ m_keycode (ELSE),
+ m_keycode (TRON),
+ m_keycode (TROFF),
+ m_keycode (LET),
+ m_keycode (GOTO),
+ m_keycode (STOP),
+ m_keycode (CONT),
+ m_keycode (CLEAR),
+ m_keycode (GOSUB),
+ m_keycode (RETURN),
+ m_keycode (POKE),
+ m_keycode (DATA),
+ m_keycode (READ),
+ m_keycode (RESTORE),
+ m_keycode (INPUT),
+ m_keycode (LINE),
+ m_keycode (RANDOMIZE),
+ m_keycode (PLEASE),
+ m_keycode (AUTO),
+ m_keycode (DIM),
+ m_keycode (SYSTEM),
+ m_keycode (ON),
+ m_keycode (ERROR),
+ m_keycode (OPEN),
+ m_keycode (CLOSE),
+ m_keycode (OUTPUT),
+ m_keycode (AS),
+ m_keycode (LOCATE),
+ m_keycode (CLS),
+ m_keycode (APPEND),
+ m_keycode (WRITE),
+ m_keycode (MODE),
+ m_keycode (MOVE),
+ m_keycode (COLOR),
+ m_keycode (GET),
+ m_keycode (LABEL),
+ m_keycode (DELIMITER),
+ m_keycode (REPEAT),
+ m_keycode (UNTIL),
+ m_keycode (WHILE),
+ m_keycode (WEND),
+ m_keycode (PLOT),
+ m_keycode (POPEN),
+ m_keycode (RESUME),
+ m_keycode (DELETE),
+ m_keycode (LOCAL),
+ m_keycode (RANDOM),
+ m_keycode (PUT),
+ m_keycode (FIELD),
+ m_keycode (LSET),
+ m_keycode (RSET),
+ m_keycode (SOCKET),
+ m_keycode (DRAW),
+ m_keycode (DEF),
+ m_keycode (FN),
+ m_keycode (ERASE),
+ m_keycode (SWAP),
+ m_keycode (SYMBOL),
+ m_keycode (ZONE),
+ m_keycode (POP),
+ m_keycode (NAME),
+ m_keycode (KILL),
+ m_keycode (FILES),
+ m_keycode (PAPER),
+ m_keycode (PEN),
+ m_keycode (SHELL),
+ m_keycode (MERGE),
+ m_keycode (CHDIR),
+ m_keycode (MKDIR),
+ m_keycode (RMDIR),
+ m_keycode (BREAK),
+ m_keycode (SYNCHRONIZE),
+ m_keycode (PAUSE),
+ m_keycode (CHAIN),
+ m_keycode (STR),
+ m_keycode (REAL),
+ m_keycode (ENVIRON),
+ m_keycode (EDIT),
+ m_keycode (DRAWR),
+ m_keycode (PLOTR),
+ m_keycode (MOVER),
+ m_keycode (POKE16),
+ m_keycode (POKE32),
+ m_keycode (RENUM),
+ m_keycode (CIRCLE),
+ m_keycode (MASK),
+ m_keycode (WINDOW),
+ m_keycode (GRAPHICS),
+ m_keycode (AFTER),
+ m_keycode (BEEP),
+ m_keycode (DEFINT),
+ m_keycode (DEFSTR),
+ m_keycode (DEFREAL),
+ m_keycode (DEFSNG),
+ m_keycode (DEFDBL),
+ m_keycode (INK),
+ m_keycode (SET_TITLE),
+ m_keycode (TAG),
+ m_keycode (TAGOFF),
+ m_keycode (ORIGIN),
+ m_keycode (DEG),
+ m_keycode (RAD),
+ m_keycode (INVERSE),
+ m_keycode (IF_DEBUG),
+ m_keycode (LPRINT),
+ m_keycode (LLIST),
+ m_keycode (WIDTH),
+ m_keycode (BRIGHT),
+ m_keycode (BINARY),
+ m_keycode (DRAWARC),
+ m_keycode (PULL),
+ m_keycode (PAINT),
+ m_keycode (FREE_MEMORY),
+ m_keycode (SCROLL),
+ m_keycode (ZX_PLOT),
+ m_keycode (ZX_UNPLOT),
+
+ m_keycode_s (MID),
+ m_keycode_s (LEFT),
+ m_keycode_s (RIGHT),
+ m_keycode_s (CHR),
+ m_keycode_s (ENVIRON),
+ m_keycode_s (STRING),
+ m_keycode_s (OSFAMILY),
+ m_keycode_s (HEX),
+ m_keycode_s (SPACE),
+ m_keycode_s (UPPER),
+ m_keycode_s (LOWER),
+ m_keycode_s (STR),
+ m_keycode_s (OCT),
+ m_keycode_s (BIN),
+ m_keycode_s (INKEY),
+ m_keycode_s (PROGRAMARG),
+ m_keycode_s (DATE),
+ m_keycode_s (TIME),
+ m_keycode_s (INPUT),
+ m_keycode_s (MKI),
+ m_keycode_s (MKS),
+ m_keycode_s (MKD),
+ m_keycode_s (MKL),
+ m_keycode_s (TRIM),
+ m_keycode_s (LTRIM),
+ m_keycode_s (RTRIM),
+ m_keycode_s (OSNAME),
+ m_keycode_s (FINDFIRST),
+ m_keycode_s (FINDNEXT),
+ m_keycode_s (COPYCHR),
+ m_keycode_s (STRERR),
+ m_keycode_s (DEC),
+ m_keycode_s (VAL),
+ m_keycode_s (SCREEN),
+ m_keycode_s (MKSMBF),
+ m_keycode_s (MKDMBF),
+ m_keycode_s (REGEXP_REPLACE),
+ m_keycode_s (UCASE),
+ m_keycode_s (LCASE),
+
+ m_keycode (ASC),
+ m_keycode (LEN),
+ m_keycode (PEEK),
+ m_keycode (PROGRAMPTR),
+ m_keycode (RND),
+ m_keycode (INT),
+ m_keycode (SIN),
+ m_keycode (COS),
+ m_keycode (PI),
+ m_keycode (TAN),
+ m_keycode (SQR),
+ m_keycode (ASIN),
+ m_keycode (ACOS),
+ m_keycode (INSTR),
+ m_keycode (ATAN),
+ m_keycode (ABS),
+ m_keycode (USR),
+ m_keycode (VAL),
+ m_keycode (EOF),
+ m_keycode (VARPTR),
+ m_keycode (SYSVARPTR),
+ m_keycode (SGN),
+ m_keycode (LOG),
+ m_keycode (LOG10),
+ m_keycode (EXP),
+ m_keycode (TIME),
+ m_keycode (ERR),
+ m_keycode (ERL),
+ m_keycode (CVI),
+ m_keycode (CVS),
+ m_keycode (CVD),
+ m_keycode (CVL),
+ m_keycode (MIN),
+ m_keycode (MAX),
+ m_keycode (CINT),
+ m_keycode (FIX),
+ m_keycode (XMOUSE),
+ m_keycode (YMOUSE),
+ m_keycode (XPOS),
+ m_keycode (YPOS),
+ m_keycode (PEEK16),
+ m_keycode (PEEK32),
+ m_keycode (RINSTR),
+ m_keycode (FIND_FIRST_OF),
+ m_keycode (FIND_LAST_OF),
+ m_keycode (FIND_FIRST_NOT_OF),
+ m_keycode (FIND_LAST_NOT_OF),
+ m_keycode (SINH),
+ m_keycode (COSH),
+ m_keycode (TANH),
+ m_keycode (ASINH),
+ m_keycode (ACOSH),
+ m_keycode (ATANH),
+ m_keycode (ATAN2),
+ m_keycode (TEST),
+ m_keycode (TESTR),
+ m_keycode (POS),
+ m_keycode (VPOS),
+ m_keycode (LOF),
+ m_keycode (FREEFILE),
+ m_keycode (INKEY),
+ m_keycode (ROUND),
+ m_keycode (CVSMBF),
+ m_keycode (CVDMBF),
+ m_keycode (REGEXP_INSTR),
+ m_keycode (ALLOC_MEMORY),
+ m_keycode (LOC),
+
+ m_keycode (NOT),
+ m_keycode (OR),
+ m_keycode (AND),
+ m_keycode (TAB),
+ m_keycode (SPC),
+ m_keycode (AT),
+ m_keycode (XOR),
+ m_keycode (MOD),
+ m_keycode (USING),
+
+ keycode ("<>", keyDISTINCT),
+ keycode ("<=", keyMINOREQUAL),
+ keycode (">=", keyGREATEREQUAL),
+ keycode ("=<", keyEQUALMINOR),
+ keycode ("=>", keyEQUALGREATER),
+ keycode ("><", keyGREATERMINOR),
+
+ // table_end points here, then if find_if (table, table_end, ...)
+ // fails the result is:
+ keycode ("???", 0)
+};
+
+const_keycode * table_end= table + dim_array (table) - 1;
+
+class key_is : public std::unary_function <keycode, bool> {
+public:
+ key_is (const std::string & str) : str (str)
+ { }
+ bool operator () (const keycode & k) const
+ { return k.key == str; }
+private:
+ const std::string & str;
+};
+
+class code_is : public std::unary_function <keycode, bool> {
+public:
+ code_is (BlCode code) : code (code)
+ { }
+ bool operator () (const keycode & k) const
+ { return k.code == code; }
+private:
+ BlCode code;
+};
+
+inline std::string stringupper (const std::string & str)
+{
+ std::string u (str.size (), 0);
+ std::transform (str.begin (), str.end (), u.begin (), toupper);
+ return u;
+}
+
+std::set <std::string> exclude;
+
+} // namespace
+
+void excludekeyword (const std::string & str)
+{
+ TRACEFUNC (tr, "excludekeyword");
+
+ std::string stru= stringupper (str);
+ if (find_if (table, table_end, key_is (stru) ) != table_end)
+ {
+ exclude.insert (stru);
+ TRMESSAGE (tr, std::string ("Excluding ") + stru);
+ }
+}
+
+BlCode keyword (const std::string & str)
+{
+ std::string stru= stringupper (str);
+ BlCode code= std::find_if (table, table_end, key_is (stru) )->code;
+ if (code != 0)
+ if (exclude.find (stru) != exclude.end () )
+ return 0;
+ return code;
+}
+
+std::string decodekeyword (BlCode s)
+{
+ if (s == keyGOTO || s == keyGOSUB)
+ {
+ if (sysvar::hasFlags2 (sysvar::SeparatedGoto) )
+ return (s == keyGOTO) ?
+ "GO TO" :
+ "GO SUB";
+ }
+ return std::find_if (table, table_end, code_is (s) )->key;
+}
+
+// Fin de keyword.cpp
diff --git a/keyword.h b/keyword.h
new file mode 100644
index 0000000..7ca062d
--- /dev/null
+++ b/keyword.h
@@ -0,0 +1,305 @@
+#ifndef INCLUDE_BLASSIC_KEYWORD_H
+#define INCLUDE_BLASSIC_KEYWORD_H
+
+// keyword.h
+// Revision 9-jan-2005
+
+#include "blassic.h"
+
+const BlCode
+ keyColon= ':',
+ keyPlus= '+',
+ keyMinus= '-',
+ keyMult= '*',
+ keyDiv= '/',
+ keyDivInt= '\\',
+ keyEqual= '=',
+ keyMinor= '<',
+ keyGreater= '>',
+ keyOpenPar= '(',
+ keyClosePar= ')',
+ keyComma= ',',
+ keySharp= '#',
+ keyPower= '^',
+
+ keyEND= 0x0101,
+ keyLIST= 0x0102,
+ keyREM= 0x0103,
+ keyLOAD= 0x0104,
+ keySAVE= 0x0105,
+ keyNEW= 0x0106,
+ keyEXIT= 0x0107,
+ keyRUN= 0x0108,
+ keyPRINT= 0x0109,
+ keyFOR= 0x010A,
+ keyNEXT= 0x010B,
+ keyTO= 0x010C,
+ keySTEP= 0x010D,
+ keyIF= 0x010E,
+ keyTHEN= 0x010F,
+ keyELSE= 0x0110,
+ keyTRON= 0x0111,
+ keyTROFF= 0x0112,
+ keyLET= 0x0113,
+ keyGOTO= 0x0114,
+ keySTOP= 0x0115,
+ keyCONT= 0x0116,
+ keyCLEAR= 0x0117,
+ keyGOSUB= 0x0118,
+ keyRETURN= 0x0119,
+ keyPOKE= 0x011A,
+ keyDATA= 0x011B,
+ keyREAD= 0x011C,
+ keyRESTORE= 0x011D,
+ keyINPUT= 0x011E,
+ keyLINE= 0x011F,
+ keyRANDOMIZE= 0x0120,
+ keyPLEASE= 0x0121,
+ keyAUTO= 0x0122,
+ keyDIM= 0x0123,
+ keySYSTEM= 0x0124,
+ keyON= 0x0125,
+ keyERROR= 0x0126,
+ keyOPEN= 0x0127,
+ keyCLOSE= 0x0128,
+ keyOUTPUT= 0x0129,
+ keyAS= 0x012A,
+ keyLOCATE= 0x012B,
+ keyCLS= 0x012C,
+ keyAPPEND= 0x012D,
+ keyWRITE= 0x012E,
+ keyMODE= 0x012F,
+ keyMOVE= 0x0130,
+ keyCOLOR= 0x0131,
+ keyGET= 0x0132,
+ keyLABEL= 0x0133,
+ keyDELIMITER= 0x0134,
+ keyREPEAT= 0x0135,
+ keyUNTIL= 0x0136,
+ keyWHILE= 0x0137,
+ keyWEND= 0x0138,
+ keyPLOT= 0x0139,
+ keyPOPEN= 0x013A,
+ keyRESUME= 0x013B,
+ keyDELETE= 0x013C,
+ keyLOCAL= 0x013D,
+ keyRANDOM= 0x013E,
+ keyPUT= 0x013F,
+ keyFIELD= 0x0140,
+ keyLSET= 0x0141,
+ keyRSET= 0x0142,
+ keySOCKET= 0x0143,
+ keyDRAW= 0x0144,
+ keyDEF= 0x0145,
+ keyFN= 0x0146,
+ keyERASE= 0x0147,
+ keySWAP= 0x0148,
+ keySYMBOL= 0x0149,
+ keyZONE= 0x014A,
+ keyPOP= 0x014B,
+ keyNAME= 0x014C,
+ keyKILL= 0x014D,
+ keyFILES= 0x014E,
+ keyPAPER= 0x014F,
+ keyPEN= 0x0150,
+ keySHELL= 0x0151,
+ keyMERGE= 0x0152,
+ keyCHDIR= 0x0153,
+ keyMKDIR= 0x0154,
+ keyRMDIR= 0x0155,
+ keyBREAK= 0x0156,
+ keySYNCHRONIZE= 0x0157,
+ keyPAUSE= 0x0158,
+ keyCHAIN= 0x0159,
+ keySTR= 0x015A,
+ keyREAL= 0x015B,
+ keyENVIRON= 0x015C,
+ keyEDIT= 0x015D,
+ keyDRAWR= 0x015E,
+ keyPLOTR= 0x015F,
+ keyMOVER= 0x0160,
+ keyPOKE16= 0x0161,
+ keyPOKE32= 0x0162,
+ keyRENUM= 0x0163,
+ keyCIRCLE= 0x0164,
+ keyMASK= 0x0165,
+ keyWINDOW= 0x0166,
+ keyGRAPHICS= 0x0167,
+ keyAFTER= 0x0168,
+ keyBEEP= 0x0169,
+ keyDEFINT= 0x016A,
+ keyDEFSTR= 0x016B,
+ keyDEFREAL= 0x016C,
+ keyDEFSNG= 0x016D,
+ keyDEFDBL= 0x016E,
+ keyINK= 0x016F,
+ keySET_TITLE= 0x0170,
+ keyTAG= 0x0171,
+ keyTAGOFF= 0x0172,
+ keyORIGIN= 0x0173,
+ keyDEG= 0x0174,
+ keyRAD= 0x0175,
+ keyINVERSE= 0x0176,
+ keyIF_DEBUG= 0x0177,
+ keyLPRINT= 0x0178,
+ keyLLIST= 0x0179,
+ keyWIDTH= 0x017A,
+ keyBRIGHT= 0x017B,
+ keyBINARY= 0x017C,
+ keyDRAWARC= 0x017D,
+ keyPULL= 0x017E,
+ keyPAINT= 0x017F,
+ keyFREE_MEMORY= 0x0180,
+ keySCROLL= 0x0181,
+ keyZX_PLOT= 0x0182,
+ keyZX_UNPLOT= 0x0183,
+
+ keyMID_S= 0x0201,
+ keyLEFT_S= 0x0202,
+ keyRIGHT_S= 0x0203,
+ keyCHR_S= 0x0204,
+ keyENVIRON_S= 0x0205,
+ keySTRING_S= 0x0206,
+ keyOSFAMILY_S= 0x0207,
+ keyHEX_S= 0x0208,
+ keySPACE_S= 0x0209,
+ keyUPPER_S= 0x020A,
+ keyLOWER_S= 0x020B,
+ keySTR_S= 0x020C,
+ keyOCT_S= 0x020D,
+ keyBIN_S= 0x020E,
+ keyINKEY_S= 0x020F,
+ keyPROGRAMARG_S= 0x0210,
+ keyDATE_S= 0x0211,
+ keyTIME_S= 0x0212,
+ keyINPUT_S= 0x0213,
+ keyMKI_S= 0x0214,
+ keyMKS_S= 0x0215,
+ keyMKD_S= 0x0216,
+ keyMKL_S= 0x0217,
+ keyTRIM_S= 0x0218,
+ keyLTRIM_S= 0x0219,
+ keyRTRIM_S= 0x021A,
+ keyOSNAME_S= 0x021B,
+ keyFINDFIRST_S= 0x021C,
+ keyFINDNEXT_S= 0x021D,
+ keyCOPYCHR_S= 0x021E,
+ keySTRERR_S= 0x021F,
+ keyDEC_S= 0x0220,
+ keyVAL_S= 0x0221,
+ keySCREEN_S= 0x0222,
+ keyMKSMBF_S= 0x0223,
+ keyMKDMBF_S= 0x0224,
+ keyREGEXP_REPLACE_S= 0x0225,
+ keyUCASE_S= 0x0226,
+ keyLCASE_S= 0x0227,
+
+ keyASC= 0x0301,
+ keyLEN= 0x0302,
+ keyPEEK= 0x0303,
+ keyPROGRAMPTR= 0x0304,
+ keyRND= 0x0305,
+ keyINT= 0x0306,
+ keySIN= 0x0307,
+ keyCOS= 0x0308,
+ keyPI= 0x0309,
+ keyTAN= 0x030A,
+ keySQR= 0x030B,
+ keyASIN= 0x030C,
+ keyACOS= 0x030D,
+ keyINSTR= 0x030E,
+ keyATAN= 0x030F,
+ keyABS= 0x0310,
+ keyUSR= 0x0311,
+ keyVAL= 0x0312,
+ keyEOF= 0x0313,
+ keyVARPTR= 0x0314,
+ keySYSVARPTR= 0x0315,
+ keySGN= 0x0316,
+ keyLOG= 0x0317,
+ keyLOG10= 0x0318,
+ keyEXP= 0x0319,
+ keyTIME= 0x031A,
+ keyERR= 0x031B,
+ keyERL= 0x031C,
+ keyCVI= 0x031D,
+ keyCVS= 0x031E,
+ keyCVD= 0x031F,
+ keyCVL= 0x0320,
+ keyMIN= 0x0321,
+ keyMAX= 0x0322,
+ keyCINT= 0x0323,
+ keyFIX= 0x0324,
+ keyXMOUSE= 0x0325,
+ keyYMOUSE= 0x0326,
+ keyXPOS= 0x0327,
+ keyYPOS= 0x0328,
+ keyPEEK16= 0x0329,
+ keyPEEK32= 0x032A,
+ keyRINSTR= 0x032B,
+ keyFIND_FIRST_OF= 0x032C,
+ keyFIND_LAST_OF= 0x032D,
+ keyFIND_FIRST_NOT_OF= 0x032E,
+ keyFIND_LAST_NOT_OF= 0x032F,
+ keySINH= 0x0330,
+ keyCOSH= 0x0331,
+ keyTANH= 0x0332,
+ keyASINH= 0x0333,
+ keyACOSH= 0x0334,
+ keyATANH= 0x0335,
+ keyATAN2= 0x0336,
+ keyTEST= 0x0337,
+ keyTESTR= 0x0338,
+ keyPOS= 0x0339,
+ keyVPOS= 0x033A,
+ keyLOF= 0x033B,
+ keyFREEFILE= 0x033C,
+ keyINKEY= 0x033D,
+ keyROUND= 0x033E,
+ keyCVSMBF= 0x033F,
+ keyCVDMBF= 0x0340,
+ keyREGEXP_INSTR= 0x0341,
+ keyALLOC_MEMORY= 0x0342,
+ keyLOC= 0x0343,
+
+ keyNOT= 0x0401,
+ keyOR= 0x0402,
+ keyAND= 0x0403,
+ keyTAB= 0x0404,
+ keySPC= 0x0405,
+ keyAT= 0x0406,
+ keyXOR= 0x0407,
+ keyMOD= 0x0408,
+ keyUSING= 0x0409,
+
+ keyIDENTIFIER= 0x0601, // Not in program.
+ keyNUMBER= 0x0602, // Not in program.
+ keySTRING= 0x0603, // Not in program.
+ keyDISTINCT= 0x0604,
+ keyMINOREQUAL= 0x0605,
+ keyGREATEREQUAL= 0x0606,
+ keyINTEGER= 0x0607, // Not in program.
+ keyEQUALMINOR= 0x0608,
+ keyEQUALGREATER= 0x0609,
+ keyGREATERMINOR= 0x060A,
+ keyENDLINE= 0x06FF, // Not in program.
+
+ keyMAX_CODE_USED= 0x06FF;
+
+
+inline bool iskey (unsigned char c)
+{
+ // Por ahora.
+ return c == '\x01' || c == '\x02' || c == '\x03' ||
+ c == '\x04' || c == '\x06';
+}
+
+const BlChar INTEGER_PREFIX= '\x05';
+
+void excludekeyword (const std::string & str);
+BlCode keyword (const std::string & str);
+std::string decodekeyword (BlCode s);
+
+#endif
+
+// Fin de keyword.h
diff --git a/mbf.cpp b/mbf.cpp
new file mode 100644
index 0000000..039a024
--- /dev/null
+++ b/mbf.cpp
@@ -0,0 +1,158 @@
+// mbf.cpp
+// Revision 9-jul-2004
+
+#include "mbf.h"
+#include "error.h"
+
+#include <math.h>
+
+// For debugging:
+#include <iostream>
+#include <iomanip>
+
+double mbf::mbf_s (const std::string & s)
+{
+ if (s.size () != 4)
+ throw ErrFunctionCall;
+ unsigned char b0= s [0], b1= s [1], b2= s [2], b3= s [3];
+ double n= (b2 & 0x7F) | 0x80;
+ n= 256 * n + b1;
+ n= 256 * n + b0;
+ short e= static_cast <short> (b3 - 128 - 24);
+ if (e > 0)
+ for ( ; e > 0; --e)
+ n*= 2;
+ else
+ for ( ; e < 0; ++e)
+ n/= 2;
+ if (b2 & 0x80)
+ n= -n;
+ return n;
+}
+
+double mbf::mbf_d (const std::string & s)
+{
+ if (s.size () != 8)
+ throw ErrFunctionCall;
+ unsigned char b0= s [0], b1= s [1], b2= s [2], b3= s [3],
+ b4= s [4], b5= s [5], b6= s [6], b7= s [7];
+ double n= (b6 & 0x7F) | 0x80;
+ n= 256 * n + b5;
+ n= 256 * n + b4;
+ n= 256 * n + b3;
+ n= 256 * n + b2;
+ n= 256 * n + b1;
+ n= 256 * n + b0;
+ short e= static_cast <short> (b7 - 128 - 56);
+ if (e > 0)
+ for ( ; e > 0; --e)
+ n*= 2;
+ else
+ for ( ; e < 0; ++e)
+ n/= 2;
+ if (b6 & 0x80)
+ n= -n;
+ return n;
+}
+
+namespace {
+
+double zero= 0.0;
+
+} // namespace
+
+std::string mbf::to_mbf_s (double v)
+{
+ bool negative= v < 0;
+ if (negative)
+ v= -v;
+ int e= static_cast <int> (log (v) / log (2) );
+ v/= pow (2, e - 23);
+ unsigned long l= static_cast <unsigned long> (v);
+
+ #if 0
+ std::cerr << "e= " << std::dec << e <<
+ " l= " << std::hex <<
+ std::setw (8) << std::setfill ('0') <<
+ l << std::endl;
+ #endif
+
+ unsigned char b3= static_cast <unsigned char> (e + 128 + 1);
+ unsigned char b2= static_cast <unsigned char> (l / (256 * 256) );
+ unsigned char b1= static_cast <unsigned char> ((l / 256) % 256);
+ unsigned char b0= static_cast <unsigned char> (l % 256);
+ b2&= 0x7F;
+ if (negative)
+ b2|= 0x80;
+ #if 0
+ std::cerr << std::setw (2) << int (b0) << int (b1) <<
+ int (b2) << int (b3) << std::endl;
+ #endif
+
+ return std::string (1, char (b0) ) + char (b1) + char (b2) + char (b3);
+}
+
+std::string mbf::to_mbf_d (double v)
+{
+ bool negative= v < 0;
+ if (negative)
+ v= -v;
+ int e= static_cast <int> (log (v) / log (2) );
+ v/= pow (2, e - 55);
+ //unsigned long l= static_cast <unsigned long> (v);
+ double l;
+ modf (v, & l);
+
+ #if 0
+ std::cerr << "e= " << std::dec << e <<
+ " l= " << std::hex <<
+ std::setw (8) << std::setfill ('0') <<
+ l << std::endl;
+ #endif
+
+ unsigned char b7= static_cast <unsigned char> (e + 128 + 1);
+
+ #if 0
+ unsigned char b6= l / (256.0 * 256 * 256 * 256 * 256 * 256);
+ unsigned char b5= (l / (256.0 * 256 * 256 * 256 * 256) ) % 256.0;
+ unsigned char b4= (l / (256.0 * 256 * 256 * 256) ) % 256.0;
+ unsigned char b3= (l / (256UL * 256 * 256) ) % 256.0;
+ unsigned char b2= (l / (256 * 256) ) % 256.0;
+ unsigned char b1= (l / 256) % 256.0;
+ unsigned char b0= l % 256.0;
+ #else
+ double ll;
+ modf (l / 256, & ll);
+ unsigned char b0= static_cast <unsigned char> (l - 256 * ll);
+ l= ll;
+ modf (l / 256, & ll);
+ unsigned char b1= static_cast <unsigned char> (l - 256 * ll);
+ l= ll;
+ modf (l / 256, & ll);
+ unsigned char b2= static_cast <unsigned char> (l - 256 * ll);
+ l= ll;
+ modf (l / 256, & ll);
+ unsigned char b3= static_cast <unsigned char> (l - 256 * ll);
+ l= ll;
+ modf (l / 256, & ll);
+ unsigned char b4= static_cast <unsigned char> (l - 256 * ll);
+ l= ll;
+ modf (l / 256, & ll);
+ unsigned char b5= static_cast <unsigned char> (l - 256 * ll);
+ l= ll;
+ unsigned char b6= static_cast <unsigned char> (l);
+ #endif
+ b6&= 0x7F;
+ if (negative)
+ b6|= 0x80;
+
+ #if 0
+ std::cerr << std::setw (2) << int (b0) << int (b1) <<
+ int (b2) << int (b3) << std::endl;
+ #endif
+
+ return std::string (1, char (b0) ) + char (b1) + char (b2) +
+ char (b3) + char (b4) + char (b5) + char (b6) + char (b7);
+}
+
+// End of mbf.cpp
diff --git a/mbf.h b/mbf.h
new file mode 100644
index 0000000..d02b489
--- /dev/null
+++ b/mbf.h
@@ -0,0 +1,25 @@
+#ifndef INCLUDE_BLASSIC_MBF_H
+#define INCLUDE_BLASSIC_MBF_H
+
+// mbf.h
+// Revision 7-feb-2005
+
+// Routines to convert from/to Microsoft Binary Format.
+
+
+#include <string>
+
+
+namespace mbf {
+
+double mbf_s (const std::string & s);
+double mbf_d (const std::string & s);
+
+std::string to_mbf_s (double v);
+std::string to_mbf_d (double v);
+
+} // namespace mbf
+
+#endif
+
+// End of mbf.h
diff --git a/memory.cpp b/memory.cpp
new file mode 100644
index 0000000..80f8cef
--- /dev/null
+++ b/memory.cpp
@@ -0,0 +1,166 @@
+// memory.cpp
+// Revision 24-apr-2009
+
+#include "memory.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "trace.h"
+
+//#ifdef HAVE_SYS_MMAN_H
+#ifdef HAVE_MMAP
+
+#include <sys/mman.h>
+
+#if ! defined MAP_ANON
+
+#if defined MAP_ANONYMOUS
+
+#define MAP_ANON MAP_ANONYMOUS
+
+#else
+
+#error "Don't know how to flag anonymous map."
+
+#endif
+
+#endif
+
+#endif
+// HAVE_SYS_MMAN_H
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#include <string.h>
+#include <errno.h>
+
+//#include <set>
+#include <map>
+
+namespace {
+
+//typedef std::set <void *> memused_t;
+typedef std::map <void *, size_t> memused_t;
+
+memused_t memused;
+
+#ifdef HAVE_SYS_MMAN_H
+
+void do_munmap (void * start, size_t length)
+{
+ TRACEFUNC (tr, "do_munmap");
+
+ int r= munmap (start, length);
+ if (r != 0)
+ {
+ const char * errormessage= strerror (errno);
+ TRMESSAGE (tr, std::string ("munmap failed: ") + errormessage);
+ if (showdebuginfo () )
+ cerr << "munmap (" << start << ", " <<
+ length << ") failed: " << errormessage <<
+ endl;
+ }
+}
+
+#endif
+
+} // namespace
+
+size_t blassic::memory::dyn_alloc (size_t memsize)
+{
+ TRACEFUNC (tr, "memory::alloc");
+
+ if (memsize == 0)
+ throw ErrFunctionCall;
+
+ #ifndef HAVE_SYS_MMAN_H
+
+ void * aux= malloc (memsize);
+
+ #else
+
+ void * aux= mmap (NULL, memsize, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (aux == (void *) -1)
+ aux= NULL;
+
+ #endif
+
+ if (aux == NULL)
+ {
+ if (showdebuginfo () )
+ cerr << "Failed allocation of " << memsize <<
+ " bytes: " << strerror (errno) << endl;
+ throw ErrOutMemory;
+ }
+
+ //memused.insert (aux);
+ memused [aux]= memsize;
+ return reinterpret_cast <size_t> (aux);
+}
+
+void blassic::memory::dyn_free (size_t mempos)
+{
+ TRACEFUNC (tr, "memory::free");
+
+ void * aux= reinterpret_cast <void *> (mempos);
+ memused_t::iterator it= memused.find (aux);
+ if (it == memused.end () )
+ {
+ if (showdebuginfo () )
+ cerr << "Trying to free address " << mempos <<
+ " but is not allocated" << endl;
+ throw ErrFunctionCall;
+ }
+
+ #ifdef HAVE_SYS_MMAN_H
+
+ size_t memsize= it->second;
+
+ #endif
+
+ memused.erase (it);
+
+ #ifndef HAVE_SYS_MMAN_H
+
+ ::free (aux);
+
+ #else
+
+ //munmap (aux, memsize);
+ do_munmap (aux, memsize);
+
+ #endif
+}
+
+void blassic::memory::dyn_freeall ()
+{
+ TRACEFUNC (tr, "memory::freeall");
+
+ bool something= false;
+ while (! memused.empty () )
+ {
+ something= true;
+ memused_t::iterator it= memused.begin ();
+
+ #ifndef HAVE_SYS_MMAN_H
+
+ ::free (it->first);
+
+ #else
+
+ //munmap (it->first, it->second);
+ do_munmap (it->first, it->second);
+
+ #endif
+
+ memused.erase (it);
+ }
+
+ if (! something)
+ TRMESSAGE (tr, "Nothing to free");
+}
+
+// End of memory.cpp
diff --git a/memory.h b/memory.h
new file mode 100644
index 0000000..ab52085
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,23 @@
+#ifndef INCLUDE_BLASSIC_MEMORY_H
+#define INCLUDE_BLASSIC_MEMORY_H
+
+// memory.h
+// Revision 1-feb-2005
+
+#include "blassic.h"
+
+namespace blassic {
+
+namespace memory {
+
+size_t dyn_alloc (size_t memsize);
+void dyn_free (size_t mempos);
+void dyn_freeall ();
+
+} // namespace memory
+
+} // namespace blassic
+
+#endif
+
+// End of memory.h
diff --git a/msx.def b/msx.def
new file mode 100644
index 0000000..be50075
--- /dev/null
+++ b/msx.def
@@ -0,0 +1,2816 @@
+
+ 0
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 1
+
+00111100
+01000010
+10100101
+10000001
+10100101
+10011001
+01000010
+00111100
+
+ 2
+
+00111100
+01111110
+11011011
+11111111
+11111111
+11011011
+01100110
+00111100
+
+ 3
+
+01101100
+11111110
+11111110
+11111110
+01111100
+00111000
+00010000
+00000000
+
+ 4
+
+00010000
+00111000
+01111100
+11111110
+01111100
+00111000
+00010000
+00000000
+
+ 5
+
+00010000
+00111000
+01010100
+11111110
+01010100
+00010000
+00111000
+00000000
+
+ 6
+
+00010000
+00111000
+01111100
+11111110
+11111110
+00010000
+00111000
+00000000
+
+ 7
+
+00000000
+00000000
+00000000
+00110000
+00110000
+00000000
+00000000
+00000000
+
+ 8
+
+11111111
+11111111
+11111111
+11100111
+11100111
+11111111
+11111111
+11111111
+
+ 9
+
+00111000
+01000100
+10000010
+10000010
+10000010
+01000100
+00111000
+00000000
+
+ 10
+
+11000111
+10111011
+01111101
+01111101
+01111101
+10111011
+11000111
+11111111
+
+ 11
+
+00001111
+00000011
+00000101
+01111001
+10001000
+10001000
+10001000
+01110000
+
+ 12
+
+00111000
+01000100
+01000100
+01000100
+00111000
+00010000
+01111100
+00010000
+
+ 13
+
+00110000
+00101000
+00100100
+00100100
+00101000
+00100000
+11100000
+11000000
+
+ 14
+
+00111100
+00100100
+00111100
+00100100
+00100100
+11100100
+11011100
+00011000
+
+ 15
+
+00010000
+01010100
+00111000
+11101110
+00111000
+01010100
+00010000
+00000000
+
+ 16
+
+00010000
+00010000
+00010000
+01111100
+00010000
+00010000
+00010000
+00010000
+
+ 17
+
+00010000
+00010000
+00010000
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 18
+
+00000000
+00000000
+00000000
+11111111
+00010000
+00010000
+00010000
+00010000
+
+ 19
+
+00010000
+00010000
+00010000
+11110000
+00010000
+00010000
+00010000
+00010000
+
+ 20
+
+00010000
+00010000
+00010000
+00011111
+00010000
+00010000
+00010000
+00010000
+
+ 21
+
+00010000
+00010000
+00010000
+11111111
+00010000
+00010000
+00010000
+00010000
+
+ 22
+
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+00010000
+
+ 23
+
+00000000
+00000000
+00000000
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 24
+
+00000000
+00000000
+00000000
+00011111
+00010000
+00010000
+00010000
+00010000
+
+ 25
+
+00000000
+00000000
+00000000
+11110000
+00010000
+00010000
+00010000
+00010000
+
+ 26
+
+00010000
+00010000
+00010000
+00011111
+00000000
+00000000
+00000000
+00000000
+
+ 27
+
+00010000
+00010000
+00010000
+11110000
+00000000
+00000000
+00000000
+00000000
+
+ 28
+
+10000001
+01000010
+00100100
+00011000
+00011000
+00100100
+01000010
+10000001
+
+ 29
+
+00000001
+00000010
+00000100
+00001000
+00010000
+00100000
+01000000
+10000000
+
+ 30
+
+10000000
+01000000
+00100000
+00010000
+00001000
+00000100
+00000010
+00000001
+
+ 31
+
+00000000
+00010000
+00010000
+11111111
+00010000
+00010000
+00000000
+00000000
+
+ 32
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 33
+
+00100000
+00100000
+00100000
+00100000
+00000000
+00000000
+00100000
+00000000
+
+ 34
+
+01010000
+01010000
+01010000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 35
+
+01010000
+01010000
+11111000
+01010000
+11111000
+01010000
+01010000
+00000000
+
+ 36
+
+00100000
+01111000
+10100000
+01110000
+00101000
+11110000
+00100000
+00000000
+
+ 37
+
+11000000
+11001000
+00010000
+00100000
+01000000
+10011000
+00011000
+00000000
+
+ 38
+
+01000000
+10100000
+01000000
+10101000
+10010000
+10011000
+01100000
+00000000
+
+ 39
+
+00010000
+00100000
+01000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 40
+
+00010000
+00100000
+01000000
+01000000
+01000000
+00100000
+00010000
+00000000
+
+ 41
+
+01000000
+00100000
+00010000
+00010000
+00010000
+00100000
+01000000
+00000000
+
+ 42
+
+00100000
+10101000
+01110000
+00100000
+01110000
+10101000
+00100000
+00000000
+
+ 43
+
+00000000
+00100000
+00100000
+11111000
+00100000
+00100000
+00000000
+00000000
+
+ 44
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00100000
+00100000
+01000000
+
+ 45
+
+00000000
+00000000
+00000000
+01111000
+00000000
+00000000
+00000000
+00000000
+
+ 46
+
+00000000
+00000000
+00000000
+00000000
+00000000
+01100000
+01100000
+00000000
+
+ 47
+
+00000000
+00000000
+00001000
+00010000
+00100000
+01000000
+10000000
+00000000
+
+ 48
+
+01110000
+10001000
+10011000
+10101000
+11001000
+10001000
+01110000
+00000000
+
+ 49
+
+00100000
+01100000
+10100000
+00100000
+00100000
+00100000
+11111000
+00000000
+
+ 50
+
+01110000
+10001000
+00001000
+00010000
+01100000
+10000000
+11111000
+00000000
+
+ 51
+
+01110000
+10001000
+00001000
+00110000
+00001000
+10001000
+01110000
+00000000
+
+ 52
+
+00010000
+00110000
+01010000
+10010000
+11111000
+00010000
+00010000
+00000000
+
+ 53
+
+11111000
+10000000
+11100000
+00010000
+00001000
+00010000
+11100000
+00000000
+
+ 54
+
+00110000
+01000000
+10000000
+11110000
+10001000
+10001000
+01110000
+00000000
+
+ 55
+
+11111000
+10001000
+00010000
+00100000
+00100000
+00100000
+00100000
+00000000
+
+ 56
+
+01110000
+10001000
+10001000
+01110000
+10001000
+10001000
+01110000
+00000000
+
+ 57
+
+01110000
+10001000
+10001000
+01111000
+00001000
+00010000
+01100000
+00000000
+
+ 58
+
+00000000
+00000000
+00100000
+00000000
+00000000
+00100000
+00000000
+00000000
+
+ 59
+
+00000000
+00000000
+00100000
+00000000
+00000000
+00100000
+00100000
+01000000
+
+ 60
+
+00011000
+00110000
+01100000
+11000000
+01100000
+00110000
+00011000
+00000000
+
+ 61
+
+00000000
+00000000
+11111000
+00000000
+11111000
+00000000
+00000000
+00000000
+
+ 62
+
+11000000
+01100000
+00110000
+00011000
+00110000
+01100000
+11000000
+00000000
+
+ 63
+
+01110000
+10001000
+00001000
+00010000
+00100000
+00000000
+00100000
+00000000
+
+ 64
+
+01110000
+10001000
+00001000
+01101000
+10101000
+10101000
+01110000
+00000000
+
+ 65
+
+00100000
+01010000
+10001000
+10001000
+11111000
+10001000
+10001000
+00000000
+
+ 66
+
+11110000
+01001000
+01001000
+01110000
+01001000
+01001000
+11110000
+00000000
+
+ 67
+
+00110000
+01001000
+10000000
+10000000
+10000000
+01001000
+00110000
+00000000
+
+ 68
+
+11100000
+01010000
+01001000
+01001000
+01001000
+01010000
+11100000
+00000000
+
+ 69
+
+11111000
+10000000
+10000000
+11110000
+10000000
+10000000
+11111000
+00000000
+
+ 70
+
+11111000
+10000000
+10000000
+11110000
+10000000
+10000000
+10000000
+00000000
+
+ 71
+
+01110000
+10001000
+10000000
+10111000
+10001000
+10001000
+01110000
+00000000
+
+ 72
+
+10001000
+10001000
+10001000
+11111000
+10001000
+10001000
+10001000
+00000000
+
+ 73
+
+01110000
+00100000
+00100000
+00100000
+00100000
+00100000
+01110000
+00000000
+
+ 74
+
+00111000
+00010000
+00010000
+00010000
+10010000
+10010000
+01100000
+00000000
+
+ 75
+
+10001000
+10010000
+10100000
+11000000
+10100000
+10010000
+10001000
+00000000
+
+ 76
+
+10000000
+10000000
+10000000
+10000000
+10000000
+10000000
+11111000
+00000000
+
+ 77
+
+10001000
+11011000
+10101000
+10101000
+10001000
+10001000
+10001000
+00000000
+
+ 78
+
+10001000
+11001000
+11001000
+10101000
+10011000
+10011000
+10001000
+00000000
+
+ 79
+
+01110000
+10001000
+10001000
+10001000
+10001000
+10001000
+01110000
+00000000
+
+ 80
+
+11110000
+10001000
+10001000
+11110000
+10000000
+10000000
+10000000
+00000000
+
+ 81
+
+01110000
+10001000
+10001000
+10001000
+10101000
+10010000
+01101000
+00000000
+
+ 82
+
+11110000
+10001000
+10001000
+11110000
+10100000
+10010000
+10001000
+00000000
+
+ 83
+
+01110000
+10001000
+10000000
+01110000
+00001000
+10001000
+01110000
+00000000
+
+ 84
+
+11111000
+00100000
+00100000
+00100000
+00100000
+00100000
+00100000
+00000000
+
+ 85
+
+10001000
+10001000
+10001000
+10001000
+10001000
+10001000
+01110000
+00000000
+
+ 86
+
+10001000
+10001000
+10001000
+10001000
+01010000
+01010000
+00100000
+00000000
+
+ 87
+
+10001000
+10001000
+10001000
+10101000
+10101000
+11011000
+10001000
+00000000
+
+ 88
+
+10001000
+10001000
+01010000
+00100000
+01010000
+10001000
+10001000
+00000000
+
+ 89
+
+10001000
+10001000
+10001000
+01110000
+00100000
+00100000
+00100000
+00000000
+
+ 90
+
+11111000
+00001000
+00010000
+00100000
+01000000
+10000000
+11111000
+00000000
+
+ 91
+
+01110000
+01000000
+01000000
+01000000
+01000000
+01000000
+01110000
+00000000
+
+ 92
+
+00000000
+00000000
+10000000
+01000000
+00100000
+00010000
+00001000
+00000000
+
+ 93
+
+01110000
+00010000
+00010000
+00010000
+00010000
+00010000
+01110000
+00000000
+
+ 94
+
+00100000
+01010000
+10001000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 95
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11111000
+00000000
+
+ 96
+
+01000000
+00100000
+00010000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 97
+
+00000000
+00000000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 98
+
+10000000
+10000000
+10110000
+11001000
+10001000
+11001000
+10110000
+00000000
+
+ 99
+
+00000000
+00000000
+01110000
+10001000
+10000000
+10001000
+01110000
+00000000
+
+ 100
+
+00001000
+00001000
+01101000
+10011000
+10001000
+10011000
+01101000
+00000000
+
+ 101
+
+00000000
+00000000
+01110000
+10001000
+11111000
+10000000
+01110000
+00000000
+
+ 102
+
+00010000
+00101000
+00100000
+11111000
+00100000
+00100000
+00100000
+00000000
+
+ 103
+
+00000000
+00000000
+01101000
+10011000
+10011000
+01101000
+00001000
+01110000
+
+ 104
+
+10000000
+10000000
+11110000
+10001000
+10001000
+10001000
+10001000
+00000000
+
+ 105
+
+00100000
+00000000
+01100000
+00100000
+00100000
+00100000
+01110000
+00000000
+
+ 106
+
+00010000
+00000000
+00110000
+00010000
+00010000
+00010000
+10010000
+01100000
+
+ 107
+
+01000000
+01000000
+01001000
+01010000
+01100000
+01010000
+01001000
+00000000
+
+ 108
+
+01100000
+00100000
+00100000
+00100000
+00100000
+00100000
+01110000
+00000000
+
+ 109
+
+00000000
+00000000
+11010000
+10101000
+10101000
+10101000
+10101000
+00000000
+
+ 110
+
+00000000
+00000000
+10110000
+11001000
+10001000
+10001000
+10001000
+00000000
+
+ 111
+
+00000000
+00000000
+01110000
+10001000
+10001000
+10001000
+01110000
+00000000
+
+ 112
+
+00000000
+00000000
+10110000
+11001000
+11001000
+10110000
+10000000
+10000000
+
+ 113
+
+00000000
+00000000
+01101000
+10011000
+10011000
+01101000
+00001000
+00001000
+
+ 114
+
+00000000
+00000000
+10110000
+11001000
+10000000
+10000000
+10000000
+00000000
+
+ 115
+
+00000000
+00000000
+01111000
+10000000
+11110000
+00001000
+11110000
+00000000
+
+ 116
+
+01000000
+01000000
+11110000
+01000000
+01000000
+01001000
+00110000
+00000000
+
+ 117
+
+00000000
+00000000
+10010000
+10010000
+10010000
+10010000
+01101000
+00000000
+
+ 118
+
+00000000
+00000000
+10001000
+10001000
+10001000
+01010000
+00100000
+00000000
+
+ 119
+
+00000000
+00000000
+10001000
+10101000
+10101000
+10101000
+01010000
+00000000
+
+ 120
+
+00000000
+00000000
+10001000
+01010000
+00100000
+01010000
+10001000
+00000000
+
+ 121
+
+00000000
+00000000
+10001000
+10001000
+10011000
+01101000
+00001000
+01110000
+
+ 122
+
+00000000
+00000000
+11111000
+00010000
+00100000
+01000000
+11111000
+00000000
+
+ 123
+
+00011000
+00100000
+00100000
+01000000
+00100000
+00100000
+00011000
+00000000
+
+ 124
+
+00100000
+00100000
+00100000
+00000000
+00100000
+00100000
+00100000
+00000000
+
+ 125
+
+11000000
+00100000
+00100000
+00010000
+00100000
+00100000
+11000000
+00000000
+
+ 126
+
+01000000
+10101000
+00010000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 127
+
+00000000
+00000000
+00100000
+01010000
+11111000
+00000000
+00000000
+00000000
+
+ 128
+
+01110000
+10001000
+10000000
+10000000
+10001000
+01110000
+00100000
+01100000
+
+ 129
+
+10010000
+00000000
+00000000
+10010000
+10010000
+10010000
+01101000
+00000000
+
+ 130
+
+00010000
+00100000
+01110000
+10001000
+11111000
+10000000
+01110000
+00000000
+
+ 131
+
+00100000
+01010000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 132
+
+01001000
+00000000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 133
+
+00100000
+00010000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 134
+
+00100000
+00000000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 135
+
+00000000
+01110000
+10000000
+10000000
+10000000
+01110000
+00010000
+01100000
+
+ 136
+
+00100000
+01010000
+01110000
+10001000
+11111000
+10000000
+01110000
+00000000
+
+ 137
+
+01010000
+00000000
+01110000
+10001000
+11111000
+10000000
+01110000
+00000000
+
+ 138
+
+00100000
+00010000
+01110000
+10001000
+11111000
+10000000
+01110000
+00000000
+
+ 139
+
+01010000
+00000000
+00000000
+01100000
+00100000
+00100000
+01110000
+00000000
+
+ 140
+
+00100000
+01010000
+00000000
+01100000
+00100000
+00100000
+01110000
+00000000
+
+ 141
+
+01000000
+00100000
+00000000
+01100000
+00100000
+00100000
+01110000
+00000000
+
+ 142
+
+01010000
+00000000
+00100000
+01010000
+10001000
+11111000
+10001000
+00000000
+
+ 143
+
+00100000
+00000000
+00100000
+01010000
+10001000
+11111000
+10001000
+00000000
+
+ 144
+
+00010000
+00100000
+11111000
+10000000
+11110000
+10000000
+11111000
+00000000
+
+ 145
+
+00000000
+00000000
+01101100
+00010010
+01111110
+10010000
+01101110
+00000000
+
+ 146
+
+00111110
+01010000
+10010000
+10011100
+11110000
+10010000
+10011110
+00000000
+
+ 147
+
+01100000
+10010000
+00000000
+01100000
+10010000
+10010000
+01100000
+00000000
+
+ 148
+
+10010000
+00000000
+00000000
+01100000
+10010000
+10010000
+01100000
+00000000
+
+ 149
+
+01000000
+00100000
+00000000
+01100000
+10010000
+10010000
+01100000
+00000000
+
+ 150
+
+01000000
+10100000
+00000000
+10100000
+10100000
+10100000
+01010000
+00000000
+
+ 151
+
+01000000
+00100000
+00000000
+10100000
+10100000
+10100000
+01010000
+00000000
+
+ 152
+
+10010000
+00000000
+10010000
+10010000
+10110000
+01010000
+00010000
+11100000
+
+ 153
+
+01010000
+00000000
+01110000
+10001000
+10001000
+10001000
+01110000
+00000000
+
+ 154
+
+01010000
+00000000
+10001000
+10001000
+10001000
+10001000
+01110000
+00000000
+
+ 155
+
+00100000
+00100000
+01111000
+10000000
+10000000
+01111000
+00100000
+00100000
+
+ 156
+
+00011000
+00100100
+00100000
+11111000
+00100000
+11100010
+01011100
+00000000
+
+ 157
+
+10001000
+01010000
+00100000
+11111000
+00100000
+11111000
+00100000
+00000000
+
+ 158
+
+11000000
+10100000
+10100000
+11001000
+10011100
+10001000
+10001000
+10001100
+
+ 159
+
+00011000
+00100000
+00100000
+11111000
+00100000
+00100000
+00100000
+01000000
+
+ 160
+
+00010000
+00100000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 161
+
+00010000
+00100000
+00000000
+01100000
+00100000
+00100000
+01110000
+00000000
+
+ 162
+
+00100000
+01000000
+00000000
+01100000
+10010000
+10010000
+01100000
+00000000
+
+ 163
+
+00100000
+01000000
+00000000
+10010000
+10010000
+10010000
+01101000
+00000000
+
+ 164
+
+01010000
+10100000
+00000000
+10100000
+11010000
+10010000
+10010000
+00000000
+
+ 165
+
+00101000
+01010000
+00000000
+11001000
+10101000
+10011000
+10001000
+00000000
+
+ 166
+
+00000000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+11111000
+
+ 167
+
+00000000
+01100000
+10010000
+10010000
+10010000
+01100000
+00000000
+11110000
+
+ 168
+
+00100000
+00000000
+00100000
+01000000
+10000000
+10001000
+01110000
+00000000
+
+ 169
+
+00000000
+00000000
+00000000
+11111000
+10000000
+10000000
+00000000
+00000000
+
+ 170
+
+00000000
+00000000
+00000000
+11111000
+00001000
+00001000
+00000000
+00000000
+
+ 171
+
+10000100
+10001000
+10010000
+10101000
+01010100
+10000100
+00001000
+00011100
+
+ 172
+
+10000100
+10001000
+10010000
+10101000
+01011000
+10101000
+00111100
+00001000
+
+ 173
+
+00100000
+00000000
+00000000
+00100000
+00100000
+00100000
+00100000
+00000000
+
+ 174
+
+00000000
+00000000
+00100100
+01001000
+10010000
+01001000
+00100100
+00000000
+
+ 175
+
+00000000
+00000000
+10010000
+01001000
+00100100
+01001000
+10010000
+00000000
+
+ 176
+
+00101000
+01010000
+00100000
+01010000
+10001000
+11111000
+10001000
+00000000
+
+ 177
+
+00101000
+01010000
+01110000
+00001000
+01111000
+10001000
+01111000
+00000000
+
+ 178
+
+00101000
+01010000
+00000000
+01110000
+00100000
+00100000
+01110000
+00000000
+
+ 179
+
+00101000
+01010000
+00000000
+00100000
+00100000
+00100000
+01110000
+00000000
+
+ 180
+
+00101000
+01010000
+00000000
+01110000
+10001000
+10001000
+01110000
+00000000
+
+ 181
+
+01010000
+10100000
+00000000
+01100000
+10010000
+10010000
+01100000
+00000000
+
+ 182
+
+00101000
+01010000
+00000000
+10001000
+10001000
+10001000
+01110000
+00000000
+
+ 183
+
+01010000
+10100000
+00000000
+10100000
+10100000
+10100000
+01010000
+00000000
+
+ 184
+
+11111100
+01001000
+01001000
+01001000
+11101000
+00001000
+01010000
+00100000
+
+ 185
+
+00000000
+01010000
+00000000
+01010000
+01010000
+01010000
+00010000
+00100000
+
+ 186
+
+11000000
+01000100
+11001000
+01010100
+11101100
+01010100
+10011110
+00000100
+
+ 187
+
+00010000
+10101000
+01000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 188
+
+00000000
+00100000
+01010000
+10001000
+01010000
+00100000
+00000000
+00000000
+
+ 189
+
+10001000
+00010000
+00100000
+01000000
+10000000
+00101000
+00000000
+00000000
+
+ 190
+
+01111100
+10101000
+10101000
+01101000
+00101000
+00101000
+00101000
+00000000
+
+ 191
+
+00111000
+01000000
+00110000
+01001000
+01001000
+00110000
+00001000
+01110000
+
+ 192
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11111111
+11111111
+
+ 193
+
+11110000
+11110000
+11110000
+11110000
+00001111
+00001111
+00001111
+00001111
+
+ 194
+
+00000000
+00000000
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+
+ 195
+
+11111111
+11111111
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+ 196
+
+00000000
+00000000
+00000000
+00111100
+00111100
+00000000
+00000000
+00000000
+
+ 197
+
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+00000000
+00000000
+
+ 198
+
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+11000000
+
+ 199
+
+00001111
+00001111
+00001111
+00001111
+11110000
+11110000
+11110000
+11110000
+
+ 200
+
+11111100
+11111100
+11111100
+11111100
+11111100
+11111100
+11111100
+11111100
+
+ 201
+
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+00000011
+
+ 202
+
+00111111
+00111111
+00111111
+00111111
+00111111
+00111111
+00111111
+00111111
+
+ 203
+
+00010001
+00100010
+01000100
+10001000
+00010001
+00100010
+01000100
+10001000
+
+ 204
+
+10001000
+01000100
+00100010
+00010001
+10001000
+01000100
+00100010
+00010001
+
+ 205
+
+11111110
+01111100
+00111000
+00010000
+00000000
+00000000
+00000000
+00000000
+
+ 206
+
+00000000
+00000000
+00000000
+00000000
+00010000
+00111000
+01111100
+11111110
+
+ 207
+
+10000000
+11000000
+11100000
+11110000
+11100000
+11000000
+10000000
+00000000
+
+ 208
+
+00000001
+00000011
+00000111
+00001111
+00000111
+00000011
+00000001
+00000000
+
+ 209
+
+11111111
+01111110
+00111100
+00011000
+00011000
+00111100
+01111110
+11111111
+
+ 210
+
+10000001
+11000011
+11100111
+11111111
+11111111
+11100111
+11000011
+10000001
+
+ 211
+
+11110000
+11110000
+11110000
+11110000
+00000000
+00000000
+00000000
+00000000
+
+ 212
+
+00000000
+00000000
+00000000
+00000000
+00001111
+00001111
+00001111
+00001111
+
+ 213
+
+00001111
+00001111
+00001111
+00001111
+00000000
+00000000
+00000000
+00000000
+
+ 214
+
+00000000
+00000000
+00000000
+00000000
+11110000
+11110000
+11110000
+11110000
+
+ 215
+
+00110011
+00110011
+11001100
+11001100
+00110011
+00110011
+11001100
+11001100
+
+ 216
+
+00000000
+00100000
+00100000
+01010000
+01010000
+10001000
+11111000
+00000000
+
+ 217
+
+00100000
+00100000
+01110000
+00100000
+01110000
+00100000
+00100000
+00000000
+
+ 218
+
+00000000
+00000000
+00000000
+01010000
+10001000
+10101000
+01010000
+00000000
+
+ 219
+
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+
+ 220
+
+00000000
+00000000
+00000000
+00000000
+11111111
+11111111
+11111111
+11111111
+
+ 221
+
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+
+ 222
+
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+
+ 223
+
+11111111
+11111111
+11111111
+11111111
+00000000
+00000000
+00000000
+00000000
+
+ 224
+
+00000000
+00000000
+01101000
+10010000
+10010000
+10010000
+01101000
+00000000
+
+ 225
+
+00110000
+01001000
+01001000
+01110000
+01001000
+01001000
+01110000
+11000000
+
+ 226
+
+11111000
+10001000
+10000000
+10000000
+10000000
+10000000
+10000000
+00000000
+
+ 227
+
+11111000
+01010000
+01010000
+01010000
+01010000
+01010000
+10011000
+00000000
+
+ 228
+
+11111000
+10001000
+01000000
+00100000
+01000000
+10001000
+11111000
+00000000
+
+ 229
+
+00000000
+00000000
+01111000
+10010000
+10010000
+10010000
+01100000
+00000000
+
+ 230
+
+00000000
+01010000
+01010000
+01010000
+01010000
+01101000
+10000000
+10000000
+
+ 231
+
+00000000
+01010000
+10100000
+00100000
+00100000
+00100000
+00100000
+00000000
+
+ 232
+
+11111000
+00100000
+01110000
+10101000
+10101000
+01110000
+00100000
+11111000
+
+ 233
+
+00100000
+01010000
+10001000
+11111000
+10001000
+01010000
+00100000
+00000000
+
+ 234
+
+01110000
+10001000
+10001000
+10001000
+01010000
+01010000
+11011000
+00000000
+
+ 235
+
+00110000
+01000000
+01000000
+00100000
+01010000
+01010000
+01010000
+00100000
+
+ 236
+
+00000000
+00000000
+00000000
+01010000
+10101000
+10101000
+01010000
+00000000
+
+ 237
+
+00001000
+01110000
+10101000
+10101000
+10101000
+01110000
+10000000
+00000000
+
+ 238
+
+00111000
+01000000
+10000000
+11111000
+10000000
+01000000
+00111000
+00000000
+
+ 239
+
+01110000
+10001000
+10001000
+10001000
+10001000
+10001000
+10001000
+00000000
+
+ 240
+
+00000000
+11111000
+00000000
+11111000
+00000000
+11111000
+00000000
+00000000
+
+ 241
+
+00100000
+00100000
+11111000
+00100000
+00100000
+00000000
+11111000
+00000000
+
+ 242
+
+11000000
+00110000
+00001000
+00110000
+11000000
+00000000
+11111000
+00000000
+
+ 243
+
+00011000
+01100000
+10000000
+01100000
+00011000
+00000000
+11111000
+00000000
+
+ 244
+
+00010000
+00101000
+00100000
+00100000
+00100000
+00100000
+00100000
+00100000
+
+ 245
+
+00100000
+00100000
+00100000
+00100000
+00100000
+00100000
+10100000
+01000000
+
+ 246
+
+00000000
+00100000
+00000000
+11111000
+00000000
+00100000
+00000000
+00000000
+
+ 247
+
+00000000
+01010000
+10100000
+00000000
+01010000
+10100000
+00000000
+00000000
+
+ 248
+
+00000000
+00011000
+00100100
+00100100
+00011000
+00000000
+00000000
+00000000
+
+ 249
+
+00000000
+00110000
+01111000
+01111000
+00110000
+00000000
+00000000
+00000000
+
+ 250
+
+00000000
+00000000
+00000000
+00000000
+00110000
+00000000
+00000000
+00000000
+
+ 251
+
+00111110
+00100000
+00100000
+00100000
+10100000
+01100000
+00100000
+00000000
+
+ 252
+
+10100000
+01010000
+01010000
+01010000
+00000000
+00000000
+00000000
+00000000
+
+ 253
+
+01000000
+10100000
+00100000
+01000000
+11100000
+00000000
+00000000
+00000000
+
+ 254
+
+00000000
+00111000
+00111000
+00111000
+00111000
+00111000
+00111000
+00000000
+
+ 255
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
diff --git a/program.cpp b/program.cpp
new file mode 100644
index 0000000..2d24c29
--- /dev/null
+++ b/program.cpp
@@ -0,0 +1,1611 @@
+// program.cpp
+// Revision 24-apr-2009
+
+#include "program.h"
+
+#include "keyword.h"
+#include "error.h"
+#include "sysvar.h"
+#include "util.h"
+using util::to_string;
+#include "trace.h"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <algorithm>
+#include <cctype>
+#include <sstream>
+
+using std::string;
+// For debugging.
+using std::cerr;
+using std::endl;
+using std::flush;
+
+#include <cassert>
+#define ASSERT assert
+
+#include <string.h>
+
+#ifndef USE_HASH_MAP
+
+#include <map>
+#define MAP std::map
+
+#else
+
+#if __GNUC__ < 3
+#include <hash_map>
+#define N_MAP std
+#else
+#include <ext/hash_map>
+#define N_MAP __gnu_cxx
+#endif
+
+#define MAP N_MAP::hash_map
+
+namespace N_MAP {
+
+template <> struct hash <std::string>
+{
+ hash () : hashstr (hash <const char *> () ) { }
+ size_t operator () (const std::string & str) const
+ { return hashstr (str.c_str () ); }
+private:
+ hash <const char *> hashstr;
+};
+
+} // namespace N_MAP
+
+#endif
+
+#ifdef __BORLANDC__
+#pragma warn -inl
+#endif
+
+namespace sysvar= blassic::sysvar;
+using namespace blassic::file;
+
+//**********************************************************
+// Program
+//**********************************************************
+
+Program::Program ()
+{
+}
+
+Program::~Program ()
+{
+}
+
+//**********************************************************
+// Auxiliar
+//**********************************************************
+
+namespace {
+
+typedef size_t Position;
+
+inline BlLineNumber getLineNumber (const BlChar * p)
+{
+ return peek32 (p);
+}
+
+inline BlLineNumber getLineNumberAt (const BlChar * p)
+{
+ return peek32 (p);
+}
+
+inline void setLineNumber (BlChar * p, BlLineNumber n)
+{
+ poke32 (p, n);
+}
+
+inline BlLineLength getLineLength (BlChar * p)
+{
+ return peek32 (p);
+}
+
+inline BlLineLength getLineLengthAt (BlChar * p)
+{
+ return peek32 (p + sizeof (BlLineNumber) );
+}
+
+inline void setLineLength (BlChar * p, BlLineLength n)
+{
+ poke32 (p, n);
+}
+
+inline BlChar * getLineContentAt (BlChar * p)
+{
+ return p + sizeof (BlLineNumber) + sizeof (BlLineLength);
+}
+
+inline BlChar * getNextLineAt (BlChar * p)
+{
+ return p + getLineLengthAt (p) +
+ sizeof (BlLineNumber) + sizeof (BlLineLength);
+}
+
+inline void getLineAt (BlChar * p, CodeLine & codeline)
+{
+ codeline.assign (getLineContentAt (p),
+ getLineNumberAt (p),
+ getLineLengthAt (p) );
+}
+
+// Used in renum.
+typedef MAP <BlLineNumber, BlLineNumber> MapLine;
+
+} // namespace
+
+//**********************************************************
+// ProgramImpl
+//**********************************************************
+
+//#define OLD_LABEL_CACHE
+
+//#define CACHE_ALL_LINES
+
+class ProgramImpl : public Program {
+public:
+ ProgramImpl ();
+ ~ProgramImpl ();
+ BlChar * programptr () { return program; }
+
+ BlLineNumber getlabel (const std::string & str);
+ CodeLine getfirstline ();
+ void getnextline (CodeLine & codeline);
+ void getline (BlLineNumber num, CodeLine & codeline);
+ void getline (ProgramPos pos, CodeLine & codeline);
+ void do_insert (const CodeLine & codeline);
+ void insert (const CodeLine & codeline);
+ void deletelines (BlLineNumber iniline, BlLineNumber endline);
+ void listline (const CodeLine & codeline, BlFile & out) const;
+ void list (BlLineNumber iniline, BlLineNumber endline,
+ BlFile & out) const;
+ void save (const std::string & name) const;
+ void load (const std::string & name);
+ void load (std::istream & is);
+ void merge (const std::string & name,
+ BlLineNumber inidel, BlLineNumber enddel);
+ void renew ();
+ void renum (BlLineNumber blnNew, BlLineNumber blnOld,
+ BlLineNumber blnInc, BlLineNumber blnStop);
+private:
+ BlChar * program;
+ typedef size_t ProgSize;
+ ProgSize size;
+
+ static const size_t BLOCK= 16 * 1024;
+ static size_t blockrounded (size_t size);
+ void resize (ProgSize newsize);
+ void transfer_content (ProgramImpl & other);
+
+ //typedef MAP <BlLineNumber, Position> linecache_t;
+ typedef MAP <BlLineNumber, BlChar *> linecache_t;
+ linecache_t linecache;
+
+ typedef MAP <string, BlLineNumber> labelcache_t;
+ labelcache_t labelcache;
+
+public:
+ // Public to allow use for LabelCacheGuard.
+ void clear_label_cache ();
+private:
+ void clear_cache ();
+
+ #ifndef NDEBUG
+ size_t linecache_hits;
+ size_t linecache_fails;
+ size_t labelcache_hits;
+ size_t labelcache_fails;
+ #endif
+
+ #ifndef OLD_LABEL_CACHE
+ bool labelcache_inited;
+ void generate_label_cache ();
+ #endif
+
+ #ifdef CACHE_ALL_LINES
+ bool line_cache_inited;
+ void generate_line_cache ();
+ #endif
+
+ void changeline (Position pos, const MapLine & mapline);
+ void setlabel (const std::string & label, CodeLine & codeline);
+ void getlineinpos (Position pos, CodeLine & codeline) const;
+ CodeLine getlineinpos (Position pos) const;
+ Position nextline (Position pos) const;
+ BlLineLength sizeline (Position) const;
+ BlLineNumber numline (Position pos) const;
+ const BlChar * linecontent (Position pos) const;
+ BlChar * linecontent (Position pos);
+ void loadtext (std::istream & is);
+ void loadbinary (std::istream & is);
+};
+
+ProgramImpl::ProgramImpl () :
+ program (0),
+ size (0)
+
+ #ifndef NDEBUG
+ ,
+ linecache_hits (0),
+ linecache_fails (0),
+ labelcache_hits (0),
+ labelcache_fails (0)
+ #endif
+
+ #ifndef OLD_LABEL_CACHE
+ ,
+ labelcache_inited (false)
+ #endif
+
+ #ifdef CACHE_ALL_LINES
+ ,
+ line_cache_inited (false)
+ #endif
+{
+ TRACEFUNC (tr, "ProgramImpl::ProgramImpl");
+
+ resize (0);
+}
+
+ProgramImpl::~ProgramImpl ()
+{
+ TRACEFUNC (tr, "ProgramImpl::~ProgramImpl");
+
+ if (program)
+ free (program);
+
+ #ifndef NDEBUG
+ std::ostringstream oss;
+ oss << "Line cache: hits " << linecache_hits <<
+ ", fails " << linecache_fails <<
+ " Label cache: hits " << labelcache_hits <<
+ ", fails " << labelcache_fails;
+ TRMESSAGE (tr, oss.str () );
+ #endif
+}
+
+Program * newProgram ()
+{
+ return new ProgramImpl;
+}
+
+namespace {
+
+class ProgramTail {
+ BlLineNumber n;
+ BlLineLength l;
+ ProgramTail ()
+ {
+ setLineNumber (reinterpret_cast <BlChar *> (& n),
+ LineEndProgram);
+ setLineLength (reinterpret_cast <BlChar *> (& l), 0);
+ }
+public:
+ static const ProgramTail tail;
+};
+
+const ProgramTail ProgramTail::tail;
+
+} // namespace
+
+inline size_t ProgramImpl::blockrounded (size_t size)
+{
+ return ( (size + sizeof (ProgramTail) + BLOCK - 1) / BLOCK) * BLOCK;
+}
+
+void ProgramImpl::resize (ProgSize newsize)
+{
+ // No need to clear cache here, the callers
+ // must do it.
+
+ ProgSize newblock= blockrounded (newsize);
+ if (newblock != blockrounded (size) || ! program)
+ {
+ BlChar * newprog=
+ (BlChar *) realloc (program, newblock);
+ if (! newprog)
+ throw ErrOutMemory;
+ program= newprog;
+ }
+ size= newsize;
+ memcpy (program + size, & ProgramTail::tail, sizeof (ProgramTail) );
+}
+
+void ProgramImpl::transfer_content (ProgramImpl & other)
+{
+ // No need to clear cache here, the callers
+ // must do it.
+
+ if (this == & other)
+ {
+ ASSERT (0);
+ throw ErrBlassicInternal;
+ }
+ program= other.program;
+ size= other.size;
+ other.program= NULL;
+ other.size= 0;
+}
+
+void ProgramImpl::renew ()
+{
+ TRACEFUNC (tr, "ProgramImpl::renew");
+
+ clear_cache ();
+ resize (0);
+}
+
+inline BlLineLength ProgramImpl::sizeline (Position pos) const
+{
+ BlChar * aux= program + pos + sizeof (BlLineNumber);
+ return getLineLength (aux);
+}
+
+inline Position ProgramImpl::nextline (Position pos) const
+{
+ return pos + sizeline (pos) +
+ sizeof (BlLineNumber) + sizeof (BlLineLength);
+}
+
+inline BlLineNumber ProgramImpl::numline (Position pos) const
+{
+ return getLineNumber (program + pos);
+}
+
+inline const BlChar * ProgramImpl::linecontent (Position pos) const
+{
+ return program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength);
+}
+
+inline BlChar * ProgramImpl::linecontent (Position pos)
+{
+ return program + pos + sizeof (BlLineNumber) + sizeof (BlLineLength);
+}
+
+inline CodeLine ProgramImpl::getfirstline ()
+{
+ //if (size == 0)
+ // return CodeLine ();
+ return CodeLine (
+ //program + sizeof (BlLineNumber) + sizeof (BlLineLength),
+ linecontent (0),
+ numline (0), sizeline (0) );
+}
+
+inline void ProgramImpl::getnextline (CodeLine & codeline)
+{
+ //if (codeline.number () == 0)
+ if (codeline.number () == LineDirectCommand)
+ {
+ //codeline.assign (0, 0, 0);
+ codeline.assign (0, LineEndProgram, 0);
+ return;
+ }
+
+ #if 0
+
+ Position pos= codeline.content () - program;
+ pos+= codeline.length ();
+ if (pos >= size)
+ {
+ //codeline.assign (0, 0, 0);
+ codeline.assign (0, LineEndProgram, 0);
+ return;
+ }
+ codeline.assign (linecontent (pos), numline (pos), sizeline (pos) );
+
+ #else
+
+ // Testing a micro optimization.
+
+ BlChar * p= const_cast <BlChar *>
+ (codeline.content () + codeline.length () );
+ //codeline.assign (p + sizeof (BlLineNumber) + sizeof (BlLineLength),
+ // getLineNumber (p),
+ // getLineLength (p + sizeof (BlLineNumber) ) );
+
+ getLineAt (p, codeline);
+
+ #endif
+}
+
+void ProgramImpl::clear_label_cache ()
+{
+ TRACEFUNC (tr, "ProgramImpl::clear_label_cache");
+
+ labelcache.clear ();
+ #ifndef OLD_LABEL_CACHE
+ labelcache_inited= false;
+ #endif
+}
+
+void ProgramImpl::clear_cache ()
+{
+ TRACEFUNC (tr, "ProgramImpl::clear_cache");
+
+ clear_label_cache ();
+ linecache.clear ();
+
+ #ifdef CACHE_ALL_LINES
+ line_cache_inited= false;
+ #endif
+}
+
+void ProgramImpl::setlabel (const std::string & label,
+ CodeLine & codeline)
+{
+ BlLineNumber n (codeline.number () );
+
+ #if 0
+ labelcache [label]= n;
+ #else
+ std::pair <labelcache_t::iterator, bool> r =
+ labelcache.insert (std::make_pair (label, n) );
+ if (! r.second)
+ {
+ if (showdebuginfo () )
+ cerr << "Duplicate label '" << label <<
+ "' in lines " << r.first->second <<
+ " and " << n <<
+ endl;
+ throw ErrDuplicateLabel;
+ }
+ #endif
+
+ // Put it in the line number cache, to avoid one search.
+ #ifndef CACHE_ALL_LINES
+ //linecache [n]= codeline.content () - program
+ // - sizeof (BlLineNumber)
+ // - sizeof (BlLineLength);
+ linecache [n]= const_cast <BlChar *> (codeline.content () ) -
+ sizeof (BlLineNumber) - sizeof (BlLineLength);
+ #endif
+}
+
+#ifdef OLD_LABEL_CACHE
+
+inline BlLineNumber ProgramImpl::getlabel (const std::string & label)
+{
+ labelcache_t::iterator it= labelcache.find (label);
+ if (it != labelcache.end () )
+ {
+ #ifndef NDEBUG
+ ++labelcache_hits;
+ #endif
+ return it->second;
+ }
+ else
+ {
+ #ifndef NDEBUG
+ ++labelcache_fails;
+ #endif
+ }
+ CodeLine codeline= getfirstline ();
+ CodeLine::Token token;
+ //while (codeline.number () != 0)
+ while (codeline.number () != LineEndProgram)
+ {
+ codeline.gettoken (token);
+ if (token.code == keyLABEL)
+ {
+ codeline.gettoken (token);
+ if (label == token.str)
+ {
+ setlabel (label, codeline);
+ return codeline.number ();
+ }
+ }
+ getnextline (codeline);
+ }
+ //return 0;
+ return LineEndProgram;
+}
+
+#else
+
+// New label cache
+
+namespace {
+
+class LabelCacheGuard {
+public:
+ LabelCacheGuard (ProgramImpl & pin);
+ ~LabelCacheGuard ();
+ void release ();
+private:
+ ProgramImpl & pi;
+ bool released;
+};
+
+LabelCacheGuard::LabelCacheGuard (ProgramImpl & pin) :
+ pi (pin),
+ released (false)
+{ }
+
+LabelCacheGuard::~LabelCacheGuard ()
+{
+ if (! released)
+ pi.clear_label_cache ();
+}
+
+void LabelCacheGuard::release ()
+{
+ released= true;
+}
+
+} // namespace
+
+void ProgramImpl::generate_label_cache ()
+{
+ TRACEFUNC (tr, "ProgramImpl::generate_label_cache");
+
+ LabelCacheGuard guard (* this);
+
+ CodeLine codeline= getfirstline ();
+ CodeLine::Token token;
+ while (codeline.number () != LineEndProgram)
+ {
+ codeline.gettoken (token);
+ if (token.code == keyLABEL)
+ {
+ codeline.gettoken (token);
+ if (token.code != keyIDENTIFIER)
+ {
+ if (showdebuginfo () )
+ cerr << "Invalid LABEL "
+ "in line " <<
+ codeline.number () <<
+ endl;
+ throw ErrSyntax;
+ }
+ setlabel (token.str, codeline);
+ }
+ getnextline (codeline);
+ }
+
+ guard.release ();
+ labelcache_inited= true;
+}
+
+inline BlLineNumber ProgramImpl::getlabel (const std::string & label)
+{
+ if (! labelcache_inited)
+ {
+ #ifndef NDEBUG
+ ++labelcache_fails;
+ #endif
+ generate_label_cache ();
+ }
+
+ labelcache_t::iterator it= labelcache.find (label);
+ if (it != labelcache.end () )
+ {
+ #ifndef NDEBUG
+ ++labelcache_hits;
+ #endif
+ return it->second;
+ }
+ else
+ {
+ #ifndef NDEBUG
+ ++labelcache_fails;
+ #endif
+ //return 0;
+ return LineEndProgram;
+ }
+}
+
+#endif
+
+#if 0
+inline BlLineNumber ProgramImpl::getnextnum (CodeLine & line)
+{
+ if (line.number () == 0)
+ return 0;
+ Position pos= line.content () - program;
+ pos+= line.length ();
+ if (pos >= size)
+ return 0;
+ return numline (pos);
+}
+#endif
+
+inline void ProgramImpl::getlineinpos (Position pos, CodeLine & codeline)
+ const
+{
+ codeline.assign (linecontent (pos), numline (pos), sizeline (pos) );
+}
+
+CodeLine ProgramImpl::getlineinpos (Position pos) const
+{
+ return CodeLine
+ (linecontent (pos), numline (pos), sizeline (pos) );
+}
+
+
+#ifdef CACHE_ALL_LINES
+
+void ProgramImpl::generate_line_cache ()
+{
+ TRACEFUNC (tr, "ProgramImpl::generate_line_cache");
+
+ //for (Position pos= 0; pos < size; pos= nextline (pos) )
+ //{
+ // linecache [numline (pos) ]= pos;
+ //}
+ for (BlChar * p= program; ; p= getNextLineAt (p) )
+ {
+ BlLineNumber n= getLineNumberAt (p);
+ linecache [n]= p;
+ // The end mark is also included in the cache.
+ if (n > BlMaxLineNumber)
+ break;
+ }
+
+ line_cache_inited= true;
+}
+
+#endif
+
+inline void ProgramImpl::getline (BlLineNumber num, CodeLine & codeline)
+{
+ //TRACEFUNC (tr, "ProgramImpl::getline");
+
+ #ifdef CACHE_ALL_LINES
+ if (! line_cache_inited)
+ generate_line_cache ();
+ #endif
+
+ //Position pos= 0;
+ BlChar * p= program;
+
+ if (num != LineBeginProgram)
+ {
+ #ifndef CACHE_ALL_LINES
+
+ linecache_t::iterator it= linecache.find (num);
+ if (it != linecache.end () )
+ {
+ //pos= it->second;
+ p= it->second;
+ #ifndef NDEBUG
+ ++linecache_hits;
+ #endif
+ }
+ else
+ {
+ #ifndef NDEBUG
+ ++linecache_fails;
+ //TRMESSAGE (tr, "Line " + to_string (num) +
+ // " missing in cache");
+ #endif
+
+ //while (pos < size && numline (pos) < num)
+ // pos= nextline (pos);
+ //if (pos >= size)
+ //{
+ // codeline.assign (0, LineEndProgram, 0);
+ // return;
+ //}
+ while (getLineNumberAt (p) < num)
+ p= getNextLineAt (p);
+
+ //linecache [num]= pos;
+ linecache [num]= p;
+ }
+
+ #else
+
+ linecache_t::iterator it= linecache.lower_bound (num);
+// if (it == linecache.end () )
+// {
+// #ifndef NDEBUG
+// ++linecache_fails;
+// #endif
+// //codeline.assign (0, 0, 0);
+// codeline.assign (0, LineEndProgram, 0);
+// return;
+// }
+ #ifndef NDEBUG
+ ++linecache_hits;
+ #endif
+ //pos= it->second;
+ p= it->second;
+
+ #endif
+ }
+
+ //getlineinpos (pos, codeline);
+ getLineAt (p, codeline);
+}
+
+void ProgramImpl::getline (ProgramPos pos, CodeLine & codeline)
+{
+ BlLineNumber n= pos.getnum ();
+ getline (n, codeline);
+ if (codeline.number () == n)
+ {
+ BlChunk ch= pos.getchunk ();
+ if (ch != 0)
+ codeline.gotochunk (ch);
+ }
+}
+
+void ProgramImpl::do_insert (const CodeLine & codeline)
+{
+ Position pos= 0;
+ while (pos < size && numline (pos) < codeline.number () )
+ pos= nextline (pos);
+
+ const BlChar * strnew= codeline.content ();
+ BlLineLength linesize= codeline.length () +
+ sizeof (BlLineNumber) + sizeof (BlLineLength);
+
+ //#define USE_PADDING
+
+ #ifdef USE_PADDING
+ BlLineLength paddedsize= linesize;
+ unsigned int pad= linesize % 4;
+ if (pad > 0)
+ {
+ pad= 4 - pad;
+ paddedsize+= pad;
+ }
+ #endif
+
+ //unsigned long osize= size;
+ ProgSize newsize= size;
+
+ #ifndef USE_PADDING
+ Position destpos= pos + linesize;
+ #else
+ Position destpos= pos + paddedsize;
+ #endif
+
+ Position origpos;
+ if (pos < size && numline (pos) == codeline.number () )
+ {
+ origpos= nextline (pos);
+ //destpos= pos + sizenew;
+ newsize+= codeline.length () - sizeline (pos);
+ //size+= codeline.length () - sizeline (pos);
+ }
+ else
+ {
+ origpos= pos;
+ //destpos= pos + sizenew;
+
+ #ifndef USE_PADDING
+ newsize+= linesize;
+ //size+= linesize;
+ #else
+ newsize+= paddedsize;
+ //size+= paddedsize;
+ #endif
+ }
+
+ if (destpos > origpos)
+ {
+ ASSERT (newsize > size);
+ //ASSERT (size > osize);
+
+ #if 0
+ size_t newblock= blockrounded (size);
+ if (newblock != blockrounded (osize) )
+ {
+ unsigned char * newprog=
+ (unsigned char *) realloc (program, newblock);
+ if (! newprog)
+ throw ErrOutMemory;
+ program= newprog;
+ }
+ #else
+
+ ProgSize osize= size;
+ resize (newsize);
+
+ #endif
+
+ if (pos < osize)
+ {
+ memmove (program + destpos,
+ program + origpos,
+ osize - origpos);
+ }
+ }
+ else if (destpos < origpos)
+ {
+ ASSERT (newsize < size);
+ //ASSERT (size < osize);
+ memmove (program + destpos,
+ program + origpos,
+ size - origpos);
+ //osize - origpos);
+
+ #if 0
+ size_t newblock= blockrounded (size);
+ if (newblock != blockrounded (osize) )
+ {
+ unsigned char * newprog=
+ (unsigned char *) realloc (program, newblock);
+ if (! newprog)
+ throw ErrOutMemory;
+ program= newprog;
+ }
+ #else
+
+ resize (newsize);
+
+ #endif
+ }
+
+ setLineNumber (program + pos, codeline.number () );
+
+ #ifndef USE_PADDING
+ setLineLength (program + pos + sizeof (BlLineNumber),
+ codeline.length () );
+ #else
+ setLineLength (program + pos + sizeof (BlLineNumber),
+ codeline.length () + pad);
+ #endif
+
+ memcpy (linecontent (pos), strnew, codeline.length () );
+
+ #ifdef USE_PADDING
+ if (pad > 0)
+ memset (linecontent (pos) + codeline.length (), 0, pad);
+ #endif
+}
+
+void ProgramImpl::insert (const CodeLine & codeline)
+{
+ clear_cache ();
+ do_insert (codeline);
+}
+
+void ProgramImpl::deletelines
+ (BlLineNumber iniline, BlLineNumber endline)
+{
+ TRACEFUNC (tr, "ProgramImpl::deletelines");
+
+ if ( (iniline > BlMaxLineNumber && iniline != LineBeginProgram) ||
+ (endline > BlMaxLineNumber && endline != LineEndProgram) )
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ if (iniline == LineBeginProgram && endline == LineEndProgram)
+ {
+ renew ();
+ }
+ else
+ {
+ // Evaluate initial position.
+
+ Position pos= 0;
+ if (iniline != LineBeginProgram)
+ {
+ while (pos < size && numline (pos) < iniline)
+ pos= nextline (pos);
+ }
+ if (pos >= size)
+ return;
+
+ // Evaluate final position.
+
+ Position posend= pos;
+ while (posend < size && numline (posend) <= endline)
+ posend= nextline (posend);
+ if (posend == pos)
+ return;
+
+ #if 0
+ cout << "Deleting from " << numline (pos) << " to ";
+ if (posend < size)
+ cout << "(not including) " << numline (posend);
+ else
+ cout << "the end";
+ cout << endl;
+ #endif
+
+ if (posend < size)
+ memmove (program + pos,
+ program + posend,
+ size - posend);
+ //size_t osize= size;
+ //size-= posend - pos;
+ ProgSize newsize= size - posend + pos;
+
+ if (newsize > 0)
+ {
+ clear_cache ();
+ #if 0
+ size_t newblock= blockrounded (newsize);
+ if (newblock != blockrounded (size) )
+ realloc (program, newblock);
+ #else
+
+ resize (newsize);
+
+ #endif
+ }
+ else
+ {
+ renew ();
+ }
+ }
+}
+
+void ProgramImpl::listline (const CodeLine & codeline, BlFile & out)
+ const
+{
+ BlLineNumber number= codeline.number ();
+ BlLineLength linesize= codeline.length ();
+ out << /*std::setw (7) << */ number << ' ';
+ const BlChar * aux= codeline.content ();
+ std::string line;
+ for (unsigned long i= 0; i < linesize; ++i)
+ {
+ unsigned char c= aux [i];
+ if (c == '\0') // Skip garbage
+ break;
+ if (iskey (c) )
+ {
+ BlCode s= c;
+ s<<= 8;
+ s|= aux [++i];
+ line+= decodekeyword (s);
+ }
+ else if (c == INTEGER_PREFIX)
+ {
+ //BlInteger n;
+ //n= * (BlInteger *) (aux + i + 1);
+ BlInteger n= peek32 (aux + i + 1);
+ std::ostringstream oss;
+ oss << n;
+ line+= oss.str ();
+ i+= 4;
+ }
+ else if (c == '"')
+ {
+ line+= c;
+ while ( (c= aux [++i]) != 0)
+ if (c == '"')
+ line+= "\"\"";
+ else
+ line+= c;
+ line+= '"';
+ }
+ else if (c == '\t')
+ {
+ const size_t l= line.size ();
+ line.insert (l, 8 - l % 8, ' ');
+ }
+ else
+ line+= c;
+ }
+ out << line;
+ out.endline ();
+}
+
+void ProgramImpl::list
+ (BlLineNumber iniline, BlLineNumber endline, BlFile & out) const
+{
+ TRACEFUNC (tr, "ProgramImpl::list");
+
+ if ( (iniline > BlMaxLineNumber && iniline != LineBeginProgram) ||
+ (endline > BlMaxLineNumber && endline != LineEndProgram) )
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ Position pos= 0;
+ if (iniline != LineBeginProgram)
+ {
+ while (pos < size && numline (pos) < iniline)
+ pos= nextline (pos);
+ }
+ while (pos < size)
+ {
+ BlLineNumber number= numline (pos);
+ if (number > endline || number == LineEndProgram)
+ break;
+ listline (getlineinpos (pos), out);
+ pos= nextline (pos);
+ if (fInterrupted)
+ break;
+ }
+}
+
+namespace {
+
+bool hasblassicextension (const std::string & name)
+{
+ std::string::size_type l= name.size ();
+ if (l < 4)
+ return false;
+ std::string ext= name.substr (l - 4);
+ //#ifdef _Windows
+ std::transform (ext.begin (), ext.end (), ext.begin (), tolower);
+ //#endif
+ if (ext == ".blc" || ext == ".bas")
+ return true;
+ return false;
+}
+
+void openblassicprogram (std::ifstream & is, const std::string & name)
+{
+ const std::ios::openmode mode= std::ios::binary | std::ios::in;
+ is.open (name.c_str (), mode);
+ if (! is)
+ {
+ if (! hasblassicextension (name) )
+ {
+ std::string namex= name;
+ namex+= ".blc";
+ is.clear ();
+ is.open (namex.c_str (), mode);
+ if (! is.is_open () )
+ {
+ namex= name;
+ namex+= ".bas";
+ is.clear ();
+ is.open (namex.c_str (), mode);
+ if (! is.is_open () )
+ throw ErrFileNotFound;
+ }
+ }
+ else
+ throw ErrFileNotFound;
+ }
+}
+
+const char signature []=
+ { 'B', 'l', 'a', 's', 's', 'i', 'c', '\0' };
+const size_t lsig= sizeof (signature);
+
+bool isblassicbinary (std::istream & is)
+{
+ char magicstring [lsig];
+ is.read (magicstring, lsig);
+ if (! is || memcmp (magicstring, signature, lsig) != 0)
+ return false;
+ return true;
+}
+
+inline void checkread (std::istream & is, size_t readed)
+{
+ if (! is || size_t (is.gcount () ) != readed)
+ throw ErrFileRead;
+}
+
+typedef BlUint32 EndianType;
+const EndianType endian_mark= 0x12345678;
+
+class TextLoader {
+public:
+ TextLoader (ProgramImpl & program) :
+ program (program),
+ nextnumline (sysvar::get32 (sysvar::AutoInit) ),
+ incnumline (sysvar::get32 (sysvar::AutoInc) ),
+ maxnumline (BlMaxLineNumber - incnumline)
+ { }
+ bool directive (std::string str);
+ void load (std::istream & is);
+private:
+ ProgramImpl & program;
+ BlLineNumber nextnumline;
+ BlLineNumber incnumline;
+ BlLineNumber maxnumline;
+};
+
+bool TextLoader::directive (std::string str)
+{
+ TRACEFUNC (tr, "TextLoader::directive");
+
+ static std::string include ("include");
+ static const std::string::size_type linc= include.size ();
+ if (str.substr (1, linc) == include)
+ {
+ str.erase (0, linc + 1);
+ std::string::size_type l= str.find_first_not_of (" \t");
+ if (l > 0)
+ str.erase (0, l);
+ if (str.empty () )
+ return false;
+ if (str [0] == '"')
+ {
+ l= str.find ('"', 1);
+ str= str.substr (1, l - 1);
+ }
+ else if (str [0] == '<')
+ {
+ l= str.find ('>', 1);
+ str= str.substr (1, l - 1);
+ }
+ else
+ {
+ l= str.find_first_of (" \t");
+ if (l != std::string::npos)
+ str.erase (l);
+ }
+ TRMESSAGE (tr, str);
+ std::ifstream is;
+ openblassicprogram (is, str);
+ load (is);
+ return true;
+ }
+ return false;
+}
+
+void TextLoader::load (std::istream & is)
+{
+ TRACEFUNC (tr, "TextLoader::load");
+
+ bool blankcomment= sysvar::hasFlags2 (sysvar::BlankComment);
+
+ std::string str;
+ std::getline (is, str);
+ if (!str.empty () && str [0] == '#')
+ {
+ str.erase ();
+ std::getline (is, str);
+ }
+ CodeLine codeline;
+ bool fExhausted= false;
+ for ( ; is; std::getline (is, str) )
+ {
+ if (! str.empty () )
+ {
+ // EOF char on windows
+ if (str [0] == '\x1A')
+ break;
+
+ if (str [str.size () - 1] == '\r')
+ str.erase (str.size () - 1);
+ }
+
+ // Quick & dirty implemantation of #include
+ if (! str.empty () && str [0] == '#' && directive (str) )
+ continue;
+
+ if (str.empty () && blankcomment)
+ str= "'";
+
+ codeline.scan (str);
+ //if (codeline.number () == 0)
+ if (codeline.number () == LineDirectCommand)
+ {
+ if (fExhausted)
+ {
+ TRMESSAGE (tr, "Line exhausted");
+ throw ErrLineExhausted;
+ }
+ codeline.setnumber (nextnumline);
+ fExhausted= nextnumline > maxnumline;
+ nextnumline+= incnumline;
+ }
+ else
+ {
+ fExhausted= codeline.number () > maxnumline;
+ nextnumline= codeline.number () + incnumline;
+ }
+ if (codeline.length () > 0)
+ program.do_insert (codeline);
+ }
+}
+
+} // namespace
+
+void ProgramImpl::save (const std::string & name) const
+{
+ TRACEFUNC (tr, "ProgramImpl::save");
+
+ std::ofstream os (name.c_str (), std::ios::binary | std::ios::out);
+
+ // Blassic signature.
+ if (! os)
+ return;
+ os.write (signature, lsig);
+
+ // Endian mark.
+ ASSERT (sizeof (endian_mark) == 4);
+ os.write ( (char *) & endian_mark, 4);
+
+ // Size.
+ BlChar caux [4];
+ poke32 (caux, static_cast <BlUint32> (size) );
+ os.write ( (char *) caux, 4);
+
+ // Program body.
+ os.write ( (char *) program, size);
+ if (! os)
+ throw ErrFileWrite;
+}
+
+void ProgramImpl::loadtext (std::istream & is)
+{
+ TRACEFUNC (tr, "ProgramImpl::loadtext");
+
+ TextLoader loader (* this);
+ loader.load (is);
+}
+
+void ProgramImpl::loadbinary (std::istream & is)
+{
+ TRACEFUNC (tr, "ProgramImpl::loadbinary");
+
+ // This was intended to check endianess, but is
+ // currently unused.
+ EndianType endian_check;
+ ASSERT (sizeof endian_check == 4);
+
+ is.read ( (char *) & endian_check, 4);
+ checkread (is, 4);
+
+ #define SHOW_ENDIAN_CHECK
+ #ifdef SHOW_ENDIAN_CHECK
+ if (showdebuginfo () )
+ {
+ std::ostringstream oss;
+ oss << "Endian check: " << std::hex << endian_check;
+ cerr << oss.str () << endl;
+ }
+ #ifndef NDEBUG
+ {
+ std::ostringstream oss;
+ oss << "Endian check: " << std::hex << endian_check;
+ TRMESSAGE (tr, oss.str () );
+ }
+ #endif
+ #endif
+
+ // Get the program size.
+ BlChar caux [4];
+ is.read ( (char *) caux, 4);
+ checkread (is, 4);
+ unsigned long newsize= peek32 (caux);
+
+ // Get program body.
+ if (newsize > 0)
+ {
+ //size_t newblock= blockrounded (newsize);
+ //util::auto_alloc <BlChar> newprog (newblock);
+ //is.read (reinterpret_cast <char *> (newprog.data () ),
+ // newsize);
+
+ ProgramImpl other;
+ other.resize (newsize);
+ is.read (reinterpret_cast <char *> (other.program), newsize);
+
+ checkread (is, newsize);
+
+ //renew ();
+ //program= newprog;
+ //newprog.release ();
+ //size= newsize;
+
+ clear_cache ();
+ transfer_content (other);
+ }
+ else
+ renew ();
+}
+
+void ProgramImpl::load (const std::string & name)
+{
+ TRACEFUNC (tr, "ProgramImpl::load (const string &)");
+
+ std::ifstream (is);
+ openblassicprogram (is, name);
+
+ if (! isblassicbinary (is) )
+ {
+ renew ();
+ is.clear ();
+ is.seekg (0);
+ loadtext (is);
+ }
+ else
+ {
+ loadbinary (is);
+ }
+}
+
+void ProgramImpl::load (std::istream & is)
+{
+ TRACEFUNC (tr, "ProgramImpl::load (istream &)");
+
+ renew ();
+ loadtext (is);
+}
+
+void ProgramImpl::merge (const std::string & name,
+ BlLineNumber inidel,
+ BlLineNumber enddel)
+{
+ TRACEFUNC (tr, "ProgramImpl::merge");
+
+ bool dellines= true;
+ if (inidel == LineNoDelete)
+ {
+ if (enddel != LineNoDelete)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ dellines= false;
+ }
+ else
+ {
+ if (enddel == LineNoDelete)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ if ( (inidel > BlMaxLineNumber &&
+ inidel != LineBeginProgram) ||
+ (enddel > BlMaxLineNumber &&
+ enddel != LineEndProgram) )
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ }
+
+ clear_cache ();
+
+ #if 0
+ std::ifstream is;
+ openblassicprogram (is, name);
+
+ ProgramImpl inload;
+ if (! isblassicbinary (is) )
+ {
+ is.clear ();
+ is.seekg (0);
+ inload.loadtext (is);
+ }
+ else
+ {
+ inload.loadbinary (is);
+ }
+ is.close ();
+ #else
+
+ ProgramImpl inload;
+ inload.load (name);
+
+ #endif
+
+ if (dellines)
+ deletelines (inidel, enddel);
+
+ for (CodeLine codeline= inload.getfirstline ();
+ //codeline.number () != 0;
+ codeline.number () != LineEndProgram;
+ //codeline= inload.getnextline (codeline)
+ inload.getnextline (codeline)
+ )
+ {
+ do_insert (codeline);
+ }
+}
+
+namespace {
+
+bool iscodewithnumber (BlCode code)
+{
+ return (code == keyGOTO || code == keyGOSUB || code == keyRUN ||
+ code == keyRESTORE || code == keyRESUME ||
+ code == keyDELETE ||
+ code == keyLIST || code == keyLLIST ||
+ code == keyEDIT ||
+ code == keyTHEN || code == keyELSE);
+}
+
+void changenumber (BlChar * pos, const MapLine & mapline)
+{
+ BlLineNumber old= getLineNumber (pos);
+ //cerr << " Find " << old << flush;
+ MapLine::const_iterator it= mapline.find (old);
+ if (it != mapline.end () )
+ {
+ //cerr << " Changed " << it->second << flush;
+ setLineNumber (pos, it->second);
+ }
+}
+
+} // namespace
+
+void ProgramImpl::changeline (Position pos, const MapLine & mapline)
+{
+ const BlLineLength l= sizeline (pos);
+ BlChar * s= linecontent (pos);
+ BlLineLength p= 0;
+ BlChar c;
+ while (p < l)
+ {
+ c= s [p];
+ if (iskey (c) )
+ {
+ BlCode code= BlCode ( (BlCode (c) << 8 ) ) |
+ BlCode (s [p+1] );
+ p+= 2;
+ //cerr << "Key " << decodekeyword (code) << flush;
+ if (iscodewithnumber (code) )
+ {
+ //cerr << " analyzing" << flush;
+ for (;;)
+ {
+ while (p < l && isspace (s [p] ) )
+ ++p;
+ if (p >= l)
+ break;
+ c= s [p];
+ if (c == INTEGER_PREFIX)
+ {
+ BlChar * const pos= s + p + 1;
+ changenumber (pos, mapline);
+ p+= 1 + sizeof (BlInteger);
+ }
+ else if (c == ':')
+ {
+ ++p;
+ break;
+ }
+ else if (c == '"')
+ {
+ while (s [++p] != '\0')
+ continue;
+ ++p;
+ }
+ else if (iskey (c) )
+ p+= 2;
+ else if (c == '\'')
+ {
+ p= l;
+ break;
+ }
+ else ++p;
+ }
+ //cerr << endl;
+ }
+ //else cerr << endl;
+ }
+ else if (c == INTEGER_PREFIX)
+ p+= 1 + sizeof (BlInteger);
+ else if (c == '"')
+ {
+ while (s [++p] != '\0')
+ continue;
+ ++p;
+ }
+ else if (c == '\'')
+ break;
+ else ++p;
+ }
+}
+
+void ProgramImpl::renum (BlLineNumber blnNew, BlLineNumber blnOld,
+ BlLineNumber blnInc, BlLineNumber blnStop)
+{
+ TRACEFUNC (tr, "ProgramImpl::renum");
+ TRMESSAGE (tr, "args: " + to_string (blnNew) + ", " +
+ to_string (blnOld) + ", " +
+ to_string (blnInc) + ", " +
+ to_string (blnStop) );
+
+ if (blnNew > BlMaxLineNumber || blnInc > BlMaxLineNumber ||
+ (blnOld > BlMaxLineNumber && blnOld != LineBeginProgram) ||
+ (blnStop > BlMaxLineNumber && blnStop != LineEndProgram) )
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ bool showinfo= showdebuginfo ();
+
+ if (size == 0)
+ {
+ if (showinfo)
+ cerr << "Trying to renum but program is empty" <<
+ endl;
+ return;
+ }
+ if (blnInc == 0)
+ throw ErrImproperArgument;
+
+ // Find first line to renum.
+
+ Position pos= 0;
+ BlLineNumber previous= LineBeginProgram;
+ if (blnOld != LineBeginProgram)
+ {
+ TRMESSAGE (tr, "Searching for " + to_string (blnOld) );
+ while (pos < size && numline (pos) < blnOld)
+ {
+ previous= numline (pos);
+ //cerr << "Skipping line " << previous << endl;
+ pos= nextline (pos);
+ }
+ TRMESSAGE (tr, "Found " + to_string (numline (pos) ) );
+ }
+ if (previous != LineBeginProgram && previous >= blnNew)
+ throw ErrImproperArgument;
+
+ // Evaluate changes required.
+
+ MapLine mapline;
+ BlLineNumber actual;
+ BlLineNumber blnMax= BlMaxLineNumber - blnInc;
+ bool overflow= false;
+ for ( ; pos < size; pos= nextline (pos) )
+ {
+ actual= numline (pos);
+ if (actual >= blnStop)
+ {
+ TRMESSAGE (tr, "Stop line reached");
+ if (previous >= blnStop)
+ {
+ if (showinfo)
+ cerr << "Renumbered line " <<
+ previous <<
+ " is greater than " <<
+ blnStop <<
+ endl;
+ throw ErrImproperArgument;
+ }
+ break;
+ }
+ if (actual != blnNew)
+ {
+ if (overflow)
+ throw ErrLineExhausted;
+ TRMESSAGE (tr, "changing " + to_string (actual) +
+ " by " + to_string (blnNew) );
+ mapline [actual]= blnNew;
+ }
+ previous= blnNew;
+ if (blnNew > blnMax)
+ overflow= true;
+ else
+ blnNew+= blnInc;
+ }
+
+ if (mapline.empty () )
+ {
+ if (showinfo)
+ cerr << "renum: no changes needed" << endl;
+ return;
+ }
+
+ // Do the changes.
+
+ clear_cache ();
+
+ MapLine::iterator it, mapend= mapline.end ();
+ for (pos= 0; pos < size; pos= nextline (pos) )
+ {
+ actual= numline (pos);
+ it= mapline.find (actual);
+ if (it != mapend)
+ {
+ //cerr << "Changing line " << actual <<
+ // " by " << it->second << endl;
+ setLineNumber (program + pos, it->second);
+ }
+ changeline (pos, mapline);
+ }
+}
+
+// End of program.cpp
diff --git a/program.h b/program.h
new file mode 100644
index 0000000..2c04f02
--- /dev/null
+++ b/program.h
@@ -0,0 +1,47 @@
+#ifndef INCLUDE_BLASSIC_PROGRAM_H
+#define INCLUDE_BLASSIC_PROGRAM_H
+
+// program.h
+// Revision 31-jul-2004
+
+#include "blassic.h"
+#include "codeline.h"
+#include "file.h"
+
+class Program {
+public:
+ Program ();
+ virtual ~Program ();
+ virtual BlChar * programptr ()= 0;
+ virtual BlLineNumber getlabel (const std::string & str)= 0;
+ virtual CodeLine getfirstline ()= 0;
+ virtual void getnextline (CodeLine & codeline)= 0;
+ virtual void getline (BlLineNumber num, CodeLine & codeline)= 0;
+ virtual void getline (ProgramPos pos, CodeLine & codeline)= 0;
+ virtual void insert (const CodeLine & codeline)= 0;
+ virtual void deletelines
+ (BlLineNumber iniline, BlLineNumber endline)= 0;
+ virtual void listline (const CodeLine & codeline,
+ blassic::file::BlFile & out) const= 0;
+ virtual void list (BlLineNumber iniline, BlLineNumber endline,
+ blassic::file::BlFile & out) const= 0;
+ virtual void save (const std::string & name) const= 0;
+ virtual void load (const std::string & name)= 0;
+ virtual void load (std::istream & is)= 0;
+ virtual void merge (const std::string & name,
+ BlLineNumber inidel= LineNoDelete,
+ BlLineNumber enddel= LineNoDelete
+ )= 0;
+ virtual void renew ()= 0;
+ virtual void renum (BlLineNumber blnNew, BlLineNumber blnOld,
+ BlLineNumber blnInc, BlLineNumber blnStop)= 0;
+private:
+ Program (const Program &); // Prohibido
+ Program & operator= (const Program &); // Prohibido
+};
+
+Program * newProgram ();
+
+#endif
+
+// End of program.h
diff --git a/regexp.cpp b/regexp.cpp
new file mode 100644
index 0000000..b8f0d1d
--- /dev/null
+++ b/regexp.cpp
@@ -0,0 +1,302 @@
+// regexp.cpp
+// Revision 9-jan-2005
+
+#include "regexp.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "trace.h"
+#include "runner.h"
+#include "runnerline.h"
+
+#include "util.h"
+using util::touch;
+
+#ifndef BLASSIC_USE_WINDOWS
+
+#include <vector>
+
+#include <regex.h>
+
+#endif
+
+//***********************************************
+// Regexp::Internal
+//***********************************************
+
+
+class Regexp::Internal {
+public:
+ typedef Regexp::string string;
+ typedef Regexp::size_type size_type;
+
+ Internal (const string & exp, flag_t flags);
+ ~Internal ();
+ size_type find (const string & searched, size_type init);
+ string replace (const string & searched, size_type init,
+ const string & replaceby);
+ string replace (const string & searched, size_type init,
+ RunnerLine & runnerline, const string & fname);
+private:
+ flag_t flags;
+ #ifndef BLASSIC_USE_WINDOWS
+ regex_t reg;
+ #endif
+};
+
+Regexp::Internal::Internal (const string & exp, flag_t flags) :
+ flags (flags)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ touch (exp, flags);
+ throw ErrNotImplemented;
+
+ #else
+ int cflags= REG_EXTENDED;
+ if (flags & FLAG_NOCASE)
+ cflags|= REG_ICASE;
+ if (flags & FLAG_NEWLINE)
+ cflags|= REG_NEWLINE;
+ if (regcomp (& reg, exp.c_str (), cflags) != 0)
+ throw ErrRegexp;
+
+ #endif
+}
+
+Regexp::Internal::~Internal ()
+{
+ #ifndef BLASSIC_USE_WINDOWS
+
+ regfree (& reg);
+
+ #endif
+}
+
+Regexp::size_type Regexp::Internal::find (const string & searched,
+ size_type init)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ touch (searched, init);
+ throw ErrNotImplemented;
+
+ #else
+
+ regmatch_t match;
+ int eflags= 0;
+ if (flags & FLAG_NOBEG)
+ eflags|= REG_NOTBOL;
+ if (flags & FLAG_NOEND)
+ eflags|= REG_NOTEOL;
+ int r= regexec (& reg, searched.c_str () + init, 1, & match, eflags);
+ switch (r)
+ {
+ case 0:
+ return match.rm_so + init;
+ case REG_NOMATCH:
+ return std::string::npos;
+ default:
+ throw ErrRegexp;
+ }
+
+ return std::string::npos;
+
+ #endif
+}
+
+Regexp::string Regexp::Internal::replace
+ (const string & searched, size_type init, const string & replaceby)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ touch (searched, init, replaceby);
+ throw ErrNotImplemented;
+
+ #else
+
+ TRACEFUNC (tr, "Regexp::Internal::replace");
+
+ const size_t nmatch= reg.re_nsub + 1;
+ std::vector <regmatch_t> vmatch (nmatch);
+ int eflags= 0;
+ if (flags & FLAG_NOBEG)
+ eflags|= REG_NOTBOL;
+ if (flags & FLAG_NOEND)
+ eflags|= REG_NOTEOL;
+ int r= regexec (& reg, searched.c_str () + init,
+ nmatch, & vmatch [0], eflags);
+ switch (r)
+ {
+ case 0:
+ break;
+ case REG_NOMATCH:
+ return searched;
+ default:
+ throw ErrRegexp;
+ }
+
+ #if 0
+ TRMESSAGE (tr, "Coincidence list");
+ for (size_t i= 0; i < nmatch; ++i)
+ {
+ regoff_t ini= vmatch [i].rm_so;
+ if (ini == regoff_t (-1) )
+ TRMESSAGE (tr, "(empty)");
+ else
+ {
+ regoff_t len= vmatch [i].rm_eo - ini;
+ TRMESSAGE (tr, searched.substr (init + ini, len) );
+ }
+ }
+ TRMESSAGE (tr, "End of coincidence list");
+ #endif
+
+ string replace= replaceby;
+ size_type pos= replace.find ('$');
+ while (pos != std::string::npos)
+ {
+ //TRMESSAGE (tr, replace.substr (pos) );
+
+ if (pos == replace.size () - 1)
+ break;
+ char c= replace [pos + 1];
+ if (c == '$')
+ {
+ replace.erase (pos, 1);
+ ++pos;
+ }
+ else
+ {
+ if (isdigit (c) )
+ {
+ size_t n= c - '0';
+ if (n >= nmatch)
+ replace.erase (pos, 2);
+ else
+ {
+ regoff_t ini= vmatch [n].rm_so;
+ if (ini == regoff_t (-1) )
+ {
+ replace.erase (pos, 2);
+ }
+ else
+ {
+ regoff_t l= vmatch [n].rm_eo
+ - ini;
+ replace.replace (pos, 2,
+ searched, init + ini,
+ l);
+ pos-= 2;
+ pos+= l;
+ }
+ }
+ }
+ else
+ pos+= 2;
+ }
+ pos= replace.find ('$', pos);
+ }
+ return searched.substr (0, vmatch [0].rm_so + init) +
+ replace +
+ searched.substr (vmatch [0].rm_eo + init);
+
+ #endif
+}
+
+Regexp::string Regexp::Internal::replace
+ (const string & searched, size_type init,
+ RunnerLine & runnerline, const string & fname)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ touch (searched, init, runnerline, fname);
+ throw ErrNotImplemented;
+
+ #else
+
+ TRACEFUNC (tr, "Regexp::Internal::replace");
+
+ const size_t nmatch= reg.re_nsub + 1;
+ std::vector <regmatch_t> vmatch (nmatch);
+ int eflags= 0;
+ if (flags & FLAG_NOBEG)
+ eflags|= REG_NOTBOL;
+ if (flags & FLAG_NOEND)
+ eflags|= REG_NOTEOL;
+ int r= regexec (& reg, searched.c_str () + init,
+ nmatch, & vmatch [0], eflags);
+ switch (r)
+ {
+ case 0:
+ break;
+ case REG_NOMATCH:
+ return searched;
+ default:
+ throw ErrRegexp;
+ }
+
+ Function f= Function::get (fname);
+ LocalLevel ll;
+ const ParameterList & param= f.getparam ();
+ const size_t l= param.size ();
+ for (size_t i= 0; i < l; ++i)
+ {
+ std::string var= param [i];
+ TRMESSAGE (tr, "paramter: " + var);
+
+ std::string value;
+ if (i < nmatch)
+ {
+ regoff_t ini= vmatch [i].rm_so;
+ if (ini != regoff_t (-1) )
+ {
+ regoff_t l= vmatch [i].rm_eo - ini;
+ value= std::string (searched, ini + init, l);
+ }
+ }
+ assignvarstring (var, value);
+ }
+ blassic::result::BlResult result;
+ runnerline.callfn (f, fname, ll, result);
+
+ return searched.substr (0, vmatch [0].rm_so + init) +
+ result.str () +
+ searched.substr (vmatch [0].rm_eo + init);
+
+ #endif
+}
+
+//***********************************************
+// Regexp
+//***********************************************
+
+
+Regexp::Regexp (const string & exp, flag_t flags) :
+ pin (new Internal (exp, flags) )
+{
+}
+
+Regexp::~Regexp ()
+{
+ delete pin;
+}
+
+Regexp::size_type Regexp::find (const string & searched, size_type init)
+{
+ return pin->find (searched, init);
+}
+
+Regexp::string Regexp::replace
+ (const string & searched, size_type init, const string & replaceby)
+{
+ return pin->replace (searched, init, replaceby);
+}
+
+Regexp::string Regexp::replace (const string & searched, size_type init,
+ RunnerLine & runnerline, const string & fname)
+{
+ return pin->replace (searched, init, runnerline, fname);
+}
+
+// End of regexp.cpp
diff --git a/regexp.h b/regexp.h
new file mode 100644
index 0000000..fb64ddb
--- /dev/null
+++ b/regexp.h
@@ -0,0 +1,38 @@
+#ifndef INCLUDE_BLASSIC_REGEXP_H
+#define INCLUDE_BLASSIC_REGEXP_H
+
+// regexp.h
+// Revision 7-feb-2005
+
+
+#include <string>
+
+//#include "runnerline.h"
+class RunnerLine;
+
+
+class Regexp {
+public:
+ typedef std::string string;
+ typedef string::size_type size_type;
+ typedef unsigned int flag_t;
+ static const flag_t FLAG_NOCASE= 1;
+ static const flag_t FLAG_NOBEG= 2;
+ static const flag_t FLAG_NOEND= 4;
+ static const flag_t FLAG_NEWLINE= 8;
+
+ Regexp (const string & exp, flag_t flags);
+ ~Regexp ();
+ size_type find (const string & searched, size_type init);
+ string replace (const string & searched, size_type init,
+ const string & replaceby);
+ string replace (const string & searched, size_type init,
+ RunnerLine & runnerline, const string & fname);
+private:
+ class Internal;
+ Internal * pin;
+};
+
+#endif
+
+// End of regexp.h
diff --git a/result.h b/result.h
new file mode 100644
index 0000000..9bb071b
--- /dev/null
+++ b/result.h
@@ -0,0 +1,558 @@
+#ifndef INCLUDE_BLASSIC_RESULT_H
+#define INCLUDE_BLASSIC_RESULT_H
+
+// result.h
+// Revision 8-jan-2005
+
+#ifdef __BORLANDC__
+#pragma warn -inl
+#endif
+
+#include "blassic.h"
+
+#include "error.h"
+
+#include <math.h>
+
+// Now the aritmetic operations between integers are converted
+// to floating point, to avoid truncations on integer overflow.
+// Comment the next #define to get the old behaviour.
+
+#define CONVERTNUMBER
+
+namespace blassic {
+
+namespace result {
+
+inline double round (double n)
+{
+ double intpart;
+ double fracpart= modf (n, & intpart);
+ if (fracpart >= 0.5)
+ return intpart + 1;
+ else if (fracpart <= -0.5)
+ return intpart - 1;
+ else
+ return intpart;
+}
+
+inline BlInteger NumberToInteger (BlNumber n)
+{
+ n= round (n);
+ if (n > BlIntegerMax || n < BlIntegerMin)
+ throw ErrOverflow;
+ return static_cast <BlInteger> (n);
+}
+
+class BlResult {
+ VarType vartype;
+ std::string varstr;
+ union N {
+ BlNumber varnumber;
+ BlInteger varinteger;
+ N () { }
+ N (BlNumber num)
+ {
+ varnumber= num;
+ }
+ N (BlInteger inum)
+ {
+ varinteger= inum;
+ }
+ } n;
+ void integertonumber ()
+ {
+ vartype= VarNumber;
+ n.varnumber= n.varinteger;
+ }
+ void numbertointeger ()
+ {
+ vartype= VarInteger;
+ //n.varinteger= BlInteger (n.varnumber);
+ n.varinteger= NumberToInteger (n.varnumber);
+ }
+public:
+ BlResult () :
+ vartype (VarUndef)
+ { }
+ BlResult (BlNumber num) :
+ vartype (VarNumber),
+ n (num)
+ { }
+ BlResult (BlInteger inum) :
+ vartype (VarInteger),
+ n (inum)
+ { }
+ BlResult (const std::string & str) :
+ vartype (VarString),
+ varstr (str)
+ { }
+ BlResult (const BlResult & br) :
+ vartype (br.vartype)
+ {
+ switch (vartype)
+ {
+ case VarString:
+ varstr= br.varstr;
+ break;
+ case VarNumber:
+ n.varnumber= br.n.varnumber;
+ break;
+ case VarInteger:
+ n.varinteger= br.n.varinteger;
+ break;
+ default:
+ ;
+ }
+ }
+ void assign (BlNumber num)
+ {
+ vartype= VarNumber;
+ n.varnumber= num;
+ }
+ void assign (BlInteger inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ }
+ void assign (const std::string & str)
+ {
+ vartype= VarString;
+ varstr= str;
+ }
+ void operator = (const BlResult & br)
+ {
+ vartype= br.vartype;
+ switch (vartype)
+ {
+ case VarString:
+ varstr= br.varstr;
+ break;
+ case VarNumber:
+ n.varnumber= br.n.varnumber;
+ break;
+ case VarInteger:
+ n.varinteger= br.n.varinteger;
+ break;
+ default:
+ ;
+ }
+ }
+ VarType type () const { return vartype; }
+ bool is_numeric () const { return is_numeric_type (vartype); }
+ const std::string & str () const
+ {
+ if (vartype != VarString)
+ throw ErrMismatch;
+ return varstr;
+ }
+ std::string & str ()
+ {
+ if (vartype != VarString)
+ throw ErrMismatch;
+ return varstr;
+ }
+ BlNumber number () const
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ return n.varnumber;
+ case VarInteger:
+ return n.varinteger;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ BlInteger integer () const
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ //return BlInteger (n.varnumber);
+ return NumberToInteger (n.varnumber);
+ case VarInteger:
+ return n.varinteger;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ bool tobool () const
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ return n.varnumber != 0.0;
+ case VarInteger:
+ return n.varinteger != 0;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ BlNumber numberdenom () const
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ if (! n.varnumber)
+ throw ErrDivZero;
+ return n.varnumber;
+ case VarInteger:
+ if (! n.varinteger)
+ throw ErrDivZero;
+ return n.varinteger;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ BlInteger integerdenom () const
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ {
+ BlInteger inum= NumberToInteger (n.varnumber);
+ if (! inum)
+ throw ErrDivZero;
+ return inum;
+ }
+ case VarInteger:
+ if (! n.varinteger)
+ throw ErrDivZero;
+ return n.varinteger;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ /*BlResult & */ void operator = (const std::string & nstr)
+ {
+ vartype= VarString;
+ varstr= nstr;
+ //return * this;
+ }
+ /*BlResult & */ void operator = (BlNumber num)
+ {
+ vartype= VarNumber;
+ n.varnumber= num;
+ //varstr.erase ();
+ //return * this;
+ }
+ // Do not define operator = for BlInteger,
+ // it will be a redefinition for one of
+ // long, int or short.
+ /*BlResult & */ void operator = (long inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ //varstr.erase ();
+ //return * this;
+ }
+ void operator = (unsigned long inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ }
+ /*BlResult & */ void operator = (int inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ //varstr.erase ();
+ //return * this;
+ }
+ /*BlResult & */ void operator = (unsigned int inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ //varstr.erase ();
+ //return * this;
+ }
+ /*BlResult & */ void operator = (short inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ }
+ /*BlResult & */ void operator = (unsigned short inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ }
+ #if 0
+ /*BlResult & */ void operator = (size_t inum)
+ {
+ vartype= VarInteger;
+ n.varinteger= inum;
+ //varstr.erase ();
+ //return * this;
+ }
+ #endif
+ /*BlResult & */ void operator += (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarString:
+ varstr+= br.str ();
+ break;
+ case VarNumber:
+ n.varnumber+= br.number ();
+ break;
+ case VarInteger:
+ #ifndef CONVERTNUMBER
+ switch (br.vartype)
+ {
+ case VarInteger:
+ n.varinteger+= br.integer ();
+ break;
+ default:
+ integertonumber ();
+ n.varnumber+= br.number ();
+ }
+ #else
+ assign (n.varinteger + br.number () );
+ #endif
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ //return * this;
+ }
+ /*BlResult & */ void operator -= (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ n.varnumber-= br.number ();
+ break;
+ case VarInteger:
+ #ifndef CONVERTNUMBER
+ switch (br.vartype)
+ {
+ case VarInteger:
+ n.varinteger-= br.integer ();
+ break;
+ default:
+ vartype= VarNumber;
+ n.varnumber= n.varinteger;
+ n.varnumber-= br.number ();
+ }
+ #else
+ assign (n.varinteger - br.number () );
+ #endif
+ break;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ //return * this;
+ }
+ /*BlResult & */ void operator *= (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ n.varnumber*= br.number ();
+ break;
+ case VarInteger:
+ #ifndef CONVERTNUMBER
+ switch (br.vartype)
+ {
+ case VarInteger:
+ n.varinteger*= br.integer ();
+ break;
+ default:
+ integertonumber ();
+ n.varnumber*= br.number ();
+ }
+ #else
+ assign (n.varinteger * br.number () );
+ #endif
+ break;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ //return * this;
+ }
+ /*BlResult & */ void operator /= (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarInteger:
+ #ifndef CONVERTNUMBER
+ integertonumber ();
+ #else
+ assign (n.varinteger / br.numberdenom () );
+ break;
+ #endif
+ case VarNumber:
+ {
+ BlNumber num= br.number ();
+ if (num == 0)
+ throw ErrDivZero;
+ n.varnumber/= num;
+ }
+ break;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ //return * this;
+ }
+ /*BlResult & */ void operator %= (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarInteger:
+ n.varinteger= n.varinteger % br.integerdenom ();
+ break;
+ case VarNumber:
+ assign (NumberToInteger (n.varnumber) %
+ br.integerdenom () );
+ break;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ //return * this;
+ }
+ void integerdivideby (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarInteger:
+ n.varinteger/= br.integerdenom ();
+ break;
+ case VarNumber:
+ assign (NumberToInteger (n.varnumber) /
+ br.integerdenom () );
+ break;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ BlResult operator - ()
+ {
+ switch (vartype)
+ {
+ case VarNumber:
+ return BlResult (-n.varnumber);
+ case VarInteger:
+ #ifndef CONVERTNUMBER
+ return BlResult (-n.varinteger);
+ #else
+ return BlResult (-number () );
+ #endif
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ bool operator == (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarString:
+ return varstr == br.str ();
+ case VarNumber:
+ return n.varnumber == br.number ();
+ case VarInteger:
+ switch (br.vartype)
+ {
+ case VarInteger:
+ return n.varinteger == br.n.varinteger;
+ case VarNumber:
+ return n.varinteger == br.n.varnumber;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ bool operator != (const BlResult & br)
+ {
+ return ! operator == (br);
+ }
+ bool operator < (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarString:
+ return varstr < br.str ();
+ case VarNumber:
+ return n.varnumber < br.number ();
+ case VarInteger:
+ switch (br.vartype)
+ {
+ case VarInteger:
+ return n.varinteger < br.n.varinteger;
+ case VarNumber:
+ return n.varinteger < br.n.varnumber;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ bool operator <= (const BlResult & br)
+ {
+ switch (vartype)
+ {
+ case VarString:
+ return varstr <= br.str ();
+ case VarNumber:
+ return n.varnumber <= br.number ();
+ case VarInteger:
+ switch (br.vartype)
+ {
+ case VarInteger:
+ return n.varinteger <= br.n.varinteger;
+ case VarNumber:
+ return n.varinteger <= br.n.varnumber;
+ case VarString:
+ throw ErrMismatch;
+ default:
+ throw ErrBlassicInternal;
+ }
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ bool operator > (const BlResult & br)
+ {
+ return ! operator <= (br);
+ }
+ bool operator >= (const BlResult & br)
+ {
+ return ! operator < (br);
+ }
+};
+
+} // namespace result
+
+} // namespace blassic
+
+#endif
+
+// Fin de result.h
diff --git a/runner.cpp b/runner.cpp
new file mode 100644
index 0000000..546b660
--- /dev/null
+++ b/runner.cpp
@@ -0,0 +1,2190 @@
+// runner.cpp
+// Revision 24-apr-2009
+
+#include "runner.h"
+
+#include "result.h"
+
+// Testing
+#include "runnerline.h"
+//#include "runnerline_impl.h"
+
+#include "program.h"
+#include "keyword.h"
+#include "var.h"
+#include "codeline.h"
+#include "dim.h"
+#include "cursor.h"
+#include "graphics.h"
+#include "sysvar.h"
+
+#include "util.h"
+using util::to_string;
+using util::touch;
+
+#include "trace.h"
+#include "edit.h"
+#include "socket.h"
+#include "memory.h"
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+#include <ctime>
+#include <vector>
+#include <algorithm>
+#include <memory>
+#include <typeinfo>
+
+#include <math.h>
+
+#include <cassert>
+#define ASSERT assert
+
+#if __BORLANDC__ >= 0x0560
+#pragma warn -8091
+#endif
+
+using std::cerr;
+using std::endl;
+using std::for_each;
+using std::auto_ptr;
+
+namespace sysvar= blassic::sysvar;
+namespace onbreak= blassic::onbreak;
+
+using namespace blassic::file;
+
+//************************************************
+// Auxiliar
+//************************************************
+
+namespace {
+
+const std::string strbreak ("**+BREAK+**");
+
+void deletefile (GlobalRunner::ChanFile::value_type & chf)
+{
+ delete chf.second;
+}
+
+} // namespace
+
+//************************************************
+// GlobalRunner
+//************************************************
+
+GlobalRunner::GlobalRunner (Program & prog) :
+ program (prog),
+ fTron (false),
+ alreadypolled (false),
+ breakstate (onbreak::BreakStop),
+ fn_current_level (0)
+{
+ TRACEFUNC (tr, "GlobalRunner::GlobalRunner");
+
+ clearerrorgoto ();
+ clearreadline ();
+ resetfile0 ();
+ resetfileprinter ();
+ trigonometric_default ();
+}
+
+GlobalRunner::~GlobalRunner ()
+{
+ TRACEFUNC (tr, "GlobalRunner::~GlobalRunner");
+
+ for_each (chanfile.begin (), chanfile.end (), deletefile);
+ blassic::memory::dyn_freeall ();
+}
+
+void GlobalRunner::tron (bool fLine, BlChannel blc)
+{
+ fTron= true;
+ fTronLine= fLine;
+ BlChar flags= static_cast <BlChar> (fLine ? 3 : 1);
+ BlChar oldflags= sysvar::get (sysvar::TronFlags);
+ flags= flags | (oldflags & static_cast <BlChar> (~3) );
+ sysvar::set (sysvar::TronFlags, flags);
+ blcTron= blc;
+ sysvar::set16 (sysvar::TronChannel, blc);
+}
+
+void GlobalRunner::troff ()
+{
+ fTron= false;
+ fTronLine= false;
+ BlChar oldflags= sysvar::get (sysvar::TronFlags);
+ sysvar::set (sysvar::TronFlags, oldflags & static_cast <BlChar> (~3) );
+ sysvar::set16 (sysvar::TronChannel, 0);
+}
+
+void GlobalRunner::do_tronline (const CodeLine & codeline)
+{
+ if (codeline.number () == LineDirectCommand)
+ return;
+
+ BlFile & file= getfile (blcTron);
+ if (fTronLine)
+ program.listline (codeline, file);
+ else
+ {
+ //file << '[' << BlNumber (codeline.number () ) << ']';
+ file << '[' <<
+ static_cast <BlInteger> (codeline.number () ) <<
+ ']';
+ file.flush ();
+ }
+}
+
+void GlobalRunner::clearerrorgoto ()
+{
+ blnErrorGoto= LineEndProgram;
+ blnErrorGotoSource= LineEndProgram;
+}
+
+void GlobalRunner::seterrorgoto (BlLineNumber line, BlLineNumber source)
+{
+ // Line must be a valid program line except 0, because 0 mean
+ // deactivate, source can be a valid program line or a direct
+ // command.
+ if (line > BlMaxLineNumber ||
+ (source > BlMaxLineNumber && source != LineDirectCommand ) )
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ blnErrorGoto= line;
+ blnErrorGotoSource= source;
+}
+
+bool GlobalRunner::assign_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value, BlFile::Align align)
+{
+ bool r= false;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end ();
+ ++it)
+ // Changed behaviour: instead to assign to all possible
+ // fields with the same name in all files, assign only
+ // to the first.
+ // Retesting the initial behaviour.
+ #if 1
+ {
+ if (it->second->assign (var, dim, value, align) )
+ r= true;
+ }
+ return r;
+ #else
+ {
+ if (it->second->assign (var, dim, value, align) )
+ return true;
+ }
+ return false;
+ #endif
+}
+
+bool GlobalRunner::assign_mid_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len)
+{
+ bool r= false;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end ();
+ ++it)
+ {
+ if (it->second->assign_mid (var, dim, value, inipos, len) )
+ r= true;
+ }
+ return r;
+}
+
+BlChannel GlobalRunner::freefile () const
+{
+ for (BlChannel channel= 1; channel < PrinterChannel; ++channel)
+ if (chanfile.find (channel) == chanfile.end () )
+ return channel;
+ return 0;
+}
+
+BlFile & GlobalRunner::getfile (BlChannel channel) const
+{
+ ChanFile::const_iterator it= chanfile.find (channel);
+ if (it == chanfile.end () )
+ {
+ if (showdebuginfo () )
+ cerr << "Channel " << channel <<
+ " is not opened" << endl;
+ throw ErrFileNumber;
+ }
+ return * it->second;
+}
+
+void GlobalRunner::setfile (BlChannel channel, BlFile * npfile)
+{
+ TRACEFUNC (tr, "GlobalRunner::setfile");
+
+ std::pair <ChanFile::iterator, bool> r
+ (chanfile.insert (ChanFile::value_type (channel, npfile) ) );
+ if (! r.second)
+ {
+ TRMESSAGE (tr, "Exist, delete and substitute");
+ delete r.first->second;
+ r.first->second= npfile;
+ }
+ else
+ {
+ TRMESSAGE (tr, "Inserted new");
+ }
+}
+
+void GlobalRunner::resetfile0 ()
+{
+ TRACEFUNC (tr, "GlobalRunner::resetfile0");
+
+ auto_ptr <BlFile> pf (graphics::ingraphicsmode () ?
+ newBlFileWindow (DefaultChannel) :
+ newBlFileConsole () );
+ setfile (DefaultChannel, pf.get () );
+ pf.release ();
+}
+
+void GlobalRunner::resetfileprinter ()
+{
+ auto_ptr <BlFile> pf (newBlFilePrinter () );
+ setfile (PrinterChannel, pf.get () );
+ pf.release ();
+}
+
+void GlobalRunner::close_all ()
+{
+ std::vector <BlChannel> w;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end (); ++it)
+ {
+ BlFile * f= it->second;
+ if (f->isfile () )
+ {
+ delete f;
+ w.push_back (it->first);
+ }
+ }
+ for (size_t i= 0, l= w.size (); i < l; ++i)
+ {
+ size_t d= chanfile.erase (w [i] );
+ ASSERT (d == 1);
+ (void) d; // Avoid warning about unused.
+ }
+}
+
+void GlobalRunner::destroy_windows ()
+{
+ TRACEFUNC (tr, "GlobalRunner::destroy_windows");
+
+ std::vector <BlChannel> w;
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end (); ++it)
+ {
+ BlFile * f= it->second;
+ //if (typeid (* f) == typeid (BlFileWindow) )
+ if (f->istextwindow () )
+ {
+ delete f;
+ w.push_back (it->first);
+ }
+ }
+ for (size_t i= 0, l= w.size (); i < l; ++i)
+ {
+ TRMESSAGE (tr, "Destroying window " + to_string (w [i] ) );
+ size_t d= chanfile.erase (w [i] );
+ ASSERT (d == 1);
+ touch (d);
+ }
+}
+
+void GlobalRunner::closechannel (BlChannel channel)
+{
+ if (channel == PrinterChannel)
+ resetfileprinter ();
+ else
+ {
+ ChanFile::iterator it= chanfile.find (channel);
+ if (it != chanfile.end () )
+ {
+ delete it->second;
+ chanfile.erase (it);
+ }
+ }
+}
+
+void GlobalRunner::windowswap (BlChannel ch1, BlChannel ch2)
+{
+ bool showdebug= showdebuginfo ();
+ ChanFile::iterator it1= chanfile.find (ch1);
+ ChanFile::iterator it2= chanfile.find (ch2);
+ if (it1 == chanfile.end () || it2 == chanfile.end () )
+ {
+ if (showdebug)
+ {
+ if (it1 == chanfile.end () )
+ cerr << "Channel " << ch1 <<
+ " is not opened" << endl;
+ if (it2 == chanfile.end () )
+ cerr << "Channel " << ch2 <<
+ " is not opened" << endl;
+ }
+ throw ErrFileNumber;
+ }
+
+ //bool fail1= typeid (* it1->second) != typeid (BlFileWindow);
+ //bool fail2= typeid (* it2->second) != typeid (BlFileWindow);
+ bool fail1= ! it1->second->istextwindow ();
+ bool fail2= ! it2->second->istextwindow ();
+ if (fail1 || fail2)
+ {
+ if (showdebug)
+ {
+ if (fail1)
+ cerr << "Channel " << ch1 <<
+ " is not a window" << endl;
+ if (fail2)
+ cerr << "Channel " << ch2 <<
+ " is not a window" << endl;
+ }
+ throw ErrFileMode;
+ }
+
+ std::swap (it1->second, it2->second);
+}
+
+void GlobalRunner::pollchannel (BlChannel ch, BlLineNumber line)
+{
+ TRACEFUNC (tr, "GlobalRunner::pollchannel");
+
+ if (! isfileopen (ch) )
+ throw ErrFileNumber;
+ if (line == 0)
+ chanpolled.erase (ch);
+ else
+ chanpolled [ch]= line;
+}
+
+bool GlobalRunner::channelspolled ()
+{
+ // This is to let the program execute one instruction
+ // before doing other poll check.
+
+ if (chanpolled.empty () )
+ return false;
+ else
+ {
+ if (alreadypolled)
+ {
+ if (clearingpolled)
+ alreadypolled= false;
+ return false;
+ }
+ else
+ return true;
+ }
+}
+
+void GlobalRunner::setpolled ()
+{
+ alreadypolled= true;
+ clearingpolled= false;
+}
+
+void GlobalRunner::clearpolled ()
+{
+ clearingpolled= true;
+}
+
+namespace {
+
+class Polled {
+ GlobalRunner & gr;
+public:
+ Polled (GlobalRunner & gr) :
+ gr (gr)
+ { }
+ bool operator () (const GlobalRunner::ChanPolled::value_type & cp)
+ {
+ BlFile & f= gr.getfile (cp.first);
+ return f.poll ();
+ }
+};
+
+} // namespace
+
+BlLineNumber GlobalRunner::getpollnumber ()
+{
+ TRACEFUNC (tr, "GlobalRunner::getpollnumber");
+
+ ChanPolled::iterator it=
+ std::find_if (chanpolled.begin (), chanpolled.end (),
+ Polled (* this) );
+ if (it != chanpolled.end () )
+ return it->second;
+ else
+ return LineEndProgram;
+}
+
+void GlobalRunner::inc_fn_level ()
+{
+ const unsigned long maxlevel= sysvar::get32 (sysvar::MaxFnLevel);
+ if (fn_current_level >= maxlevel)
+ {
+ if (showdebuginfo () )
+ cerr << "Maximum level of FN recursion of " <<
+ maxlevel << " has been reached" << endl;
+ throw ErrFnRecursion;
+ }
+
+ ++fn_current_level;
+}
+
+void GlobalRunner::dec_fn_level ()
+{
+ if (fn_current_level == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "Internal problem handling FN exit" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ --fn_current_level;
+}
+
+//************************************************
+// LocalLevel
+//************************************************
+
+class LocalLevel::Internal {
+ typedef blassic::result::BlResult BlResult;
+ friend class LocalLevel; // Only to avoid a warning in gcc.
+public:
+ Internal () : nref (1) { }
+ void addref () { ++nref; }
+ void delref ()
+ {
+ if (--nref == 0)
+ delete this;
+ }
+ void addlocalvar (const std::string & name);
+ void freelocalvars ();
+private:
+ ~Internal () { }
+ size_t nref;
+ typedef std::map <std::string, BlResult> maploc_t;
+ maploc_t maploc;
+};
+
+void LocalLevel::Internal::addlocalvar (const std::string & name)
+{
+ TRACEFUNC (tr, "LocalLevel::Internal::addlocalvar");
+
+ // Changing this to make it exception safe.
+ #if 0
+ if (maploc.find (name) != maploc.end () )
+ return;
+ BlResult result;
+
+ switch (typeofvar (name) )
+ {
+ case VarNumber:
+ {
+ BlNumber n= 0;
+ std::swap (n, * addrvarnumber (name) );
+ result= n;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (n) );
+ }
+ break;
+ case VarInteger:
+ {
+ BlInteger n= 0;
+ std::swap (n, * addrvarinteger (name) );
+ result= n;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (n) );
+ }
+ break;
+ case VarString:
+ {
+ std::string str;
+ swap (str, * addrvarstring (name) );
+ result= str;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + str);
+ }
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Type of local variable '" <<
+ name << "'unknown" << endl;
+ throw ErrBlassicInternal;
+ }
+ maploc [name]= result;
+ #else
+
+ BlResult result;
+ VarType vtype= typeofvar (name);
+ VarPointer vp;
+ switch (vtype)
+ {
+ case VarInteger:
+ vp.pinteger= addrvarinteger (name);
+ result= * vp.pinteger;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (result.integer () ) );
+ break;
+ case VarNumber:
+ vp.pnumber= addrvarnumber (name);
+ result= * vp.pnumber;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + to_string (result.number () ) );
+ break;
+ case VarString:
+ vp.pstring= addrvarstring (name);
+ result= * vp.pstring;
+ TRMESSAGE (tr, std::string ("Saving ") + name +
+ " " + result.str () );
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Type of local variable '" <<
+ name << "'unknown" << endl;
+ throw ErrBlassicInternal;
+ }
+ std::pair <maploc_t::iterator, bool> r= maploc.insert
+ (maploc_t::value_type (name, result) );
+
+ // If already declared as local, does nothing.
+ if (! r.second)
+ {
+ TRMESSAGE (tr, name + " was already saved");
+ return;
+ }
+
+ switch (vtype)
+ {
+ case VarInteger:
+ * vp.pinteger= BlInteger ();
+ break;
+ case VarNumber:
+ * vp.pnumber= BlNumber ();
+ break;
+ case VarString:
+ vp.pstring->erase ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+
+ #endif
+}
+
+namespace {
+
+using blassic::result::BlResult;
+
+void freelocalvar (const std::pair <std::string, BlResult> & p)
+{
+ TRACEFUNC (tr, "freelocalvar");
+
+ switch (p.second.type () )
+ {
+ case VarNumber:
+ assignvarnumber (p.first, p.second.number () );
+ TRMESSAGE (tr, std::string ("Restoring ") + p.first +
+ " to " + to_string (p.second.number () ) );
+ break;
+ case VarInteger:
+ assignvarinteger (p.first, p.second.integer () );
+ TRMESSAGE (tr, std::string ("Restoring ") + p.first +
+ " to " + to_string (p.second.integer () ) );
+ break;
+ case VarString:
+ assignvarstring (p.first, p.second.str () );
+ TRMESSAGE (tr, std::string ("Restoring ") + p.first +
+ " to " + p.second.str () );
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Freeing local variable of unknown type" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+}
+
+} // namespace
+
+void LocalLevel::Internal::freelocalvars ()
+{
+ for_each (maploc.begin (), maploc.end (), freelocalvar);
+}
+
+LocalLevel::LocalLevel () :
+ pi (new Internal)
+{
+}
+
+LocalLevel::LocalLevel (const LocalLevel & ll) :
+ //Element (ge),
+ pi (ll.pi)
+{
+ pi->addref ();
+}
+
+LocalLevel::~LocalLevel ()
+{
+ pi->delref ();
+}
+
+LocalLevel & LocalLevel::operator = (const LocalLevel & ll)
+{
+ ll.pi->addref ();
+ pi->delref ();
+ pi= ll.pi;
+ return * this;
+}
+
+void LocalLevel::freelocalvars ()
+{
+ pi->freelocalvars ();
+}
+
+void LocalLevel::addlocalvar (const std::string & name)
+{
+ pi->addlocalvar (name);
+}
+
+//************************************************
+// class GosubStack
+//************************************************
+
+GosubStack::GosubStack (GlobalRunner & globalrunner) :
+ globalrunner (globalrunner)
+{
+}
+
+GosubStack::~GosubStack ()
+{
+ // This is to ensure that on exiting from a multiline
+ // DEF FN the local variables are correctly restored,
+ // even on exceptions.
+
+ TRACEFUNC (tr, "GosubStack::~GosubStack");
+
+ const bool inexcept= std::uncaught_exception ();
+
+ try
+ {
+ while (! st.empty () )
+ {
+ GosubElement & ge= st.top ();
+ ge.freelocalvars ();
+ if (ge.ispolled () )
+ globalrunner.clearpolled ();
+ st.pop ();
+ }
+ }
+ catch (...)
+ {
+ // Bad thing. Perhaps restoring a local variable
+ // has run out of memory?
+ // Try to inform the user without aborting.
+ if (! inexcept)
+ throw;
+ else
+ {
+ cerr << "**ERROR** "
+ "Failed to restore local variables" <<
+ endl;
+ }
+ }
+}
+
+void GosubStack::erase ()
+{
+ // Unnecessary restore local vars here, when is called
+ // vars will be cleared after.
+ while (! st.empty () )
+ st.pop ();
+}
+
+//************************************************
+// Auxiliar functions of Runner
+//************************************************
+
+namespace {
+
+const char * statusname (Runner::RunnerStatus status)
+{
+ const char * str= "unknown";
+ switch (status)
+ {
+ case Runner::Ended:
+ str= "Ended"; break;
+ case Runner::FnEnded:
+ str= "FnEnded"; break;
+ case Runner::ReadyToRun:
+ str= "ReadyToRun"; break;
+ case Runner::Running:
+ str= "Runnig"; break;
+ case Runner::Stopped:
+ str= "Stopped"; break;
+ case Runner::Jump:
+ str= "Jump"; break;
+ case Runner::Goto:
+ str= "Goto"; break;
+ //case Runner::InitingCommand:
+ // str= "InitingCommand"; break;
+ //case Runner::Command:
+ // str= "Command"; break;
+ case Runner::JumpResumeNext:
+ str= "JumpResumeNext"; break;
+ }
+ return str;
+}
+
+} // namespace
+
+std::ostream & operator << (std::ostream & os, Runner::RunnerStatus status)
+{
+ os << "RunnerStatus is: " << statusname (status) << std::endl;
+ return os;
+}
+
+//************************************************
+// class Runner
+//************************************************
+
+Runner::Runner (GlobalRunner & gr) :
+ globalrunner (gr),
+ program (gr.getprogram () ),
+ status (Ended),
+ fInElse (false),
+ fInWend (false),
+ gosubstack (globalrunner),
+ posbreak (LineEndProgram),
+ blnAuto (LineEndProgram)
+{
+ TRACEFUNC (tr, "Runner::Runner");
+
+ clearerror ();
+}
+
+Runner::Runner (const Runner & runner) :
+ globalrunner (runner.globalrunner),
+ program (runner.program),
+ status (Ended),
+ fInElse (false),
+ fInWend (false),
+ gosubstack (globalrunner),
+ posbreak (LineEndProgram),
+ blnAuto (LineEndProgram)
+{
+ TRACEFUNC (tr, "Runner::Runner (copy)");
+}
+
+Runner::~Runner ()
+{
+}
+
+void Runner::clear ()
+{
+ close_all ();
+
+ // Clear loops stacks.
+ while (! forstack.empty () )
+ for_pop ();
+ gosubstack.erase ();
+ while (! repeatstack.empty () )
+ repeatstack.pop ();
+ while (! whilestack.empty () )
+ whilestack.pop ();
+
+ // Do RESTORE
+ clearreadline ();
+
+ // Errors
+ clearerror ();
+ globalrunner.clearerrorgoto ();
+}
+
+// Runner ************ errors ***************
+
+BlErrNo Runner::geterr () const
+{
+ return berrLast.geterr ();
+}
+
+ProgramPos Runner::geterrpos () const
+{
+ return berrLast.getpos ();
+}
+
+BlLineNumber Runner::geterrline () const
+{
+ return berrLast.getpos ().getnum ();
+}
+
+void Runner::clearerror ()
+{
+ //berrLast= BlError (0, LineEndProgram);
+ berrLast.clear ();
+}
+
+BlError Runner::geterror () const
+{
+ return berrLast;
+}
+
+void Runner::seterror (const BlError & er)
+{
+ berrLast= er;
+}
+
+void Runner::spectrumwindows ()
+{
+ // Only can be called in graphics mode, default channel must
+ // be a window.
+ ASSERT (graphics::ingraphicsmode () );
+ ASSERT (getfile0 ().istextwindow () );
+
+ // Adjust main window to the normal print area.
+ getfile0 ().reset (1, 32, 1, 22);
+
+ // Set channel 1, if free or already a window, to the window
+ // of the INPUT area. Leave untouched if is not a window.
+ if (! isfileopen (1) )
+ {
+ auto_ptr <BlFile> pf (newBlFileWindow (1, 1, 32, 23, 24) );
+ setfile (1, pf.get () );
+ pf.release ();
+ }
+ else
+ {
+ BlFile & f1= getfile (1);
+ if (f1.istextwindow () )
+ f1.reset (1, 32, 23, 24);
+ }
+}
+
+void Runner::getline (std::string & line)
+{
+ clean_input ();
+ BlFile & file= getfile0 ();
+ file.getline (line);
+}
+
+void Runner::run ()
+{
+ // Una chapuza por ahora.
+ std::string str ("RUN");
+ CodeLine code;
+ code.scan (str);
+ runline (code);
+}
+
+bool Runner::next ()
+{
+ //TRACEFUNC (tr, "Runner::next ()");
+
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ ForElement * pfe= forstack.top ();
+ if (pfe->next () )
+ {
+ //TRMESSAGE (tr, "NEXT -> " +
+ // to_string (pfe->getpos ().getnum () ) + ":" +
+ // to_string (pfe->getpos ().getchunk () ) );
+ jump_to (pfe->getpos () );
+ return true;
+ }
+ else
+ {
+ //TRMESSAGE (tr, "End FOR");
+ forstack.pop ();
+ return false;
+ }
+}
+
+bool Runner::next (const std::string & varname)
+{
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ ForElement * pfe= forstack.top ();
+ if (! pfe->isvar (varname) )
+ {
+ if (sysvar::get (sysvar::TypeOfNextCheck) == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "Processing NEXT " <<
+ varname <<
+ " but current FOR is " <<
+ pfe->var () <<
+ " and mode is strict" <<
+ endl;
+ throw ErrNextWithoutFor;
+ }
+ else
+ {
+ // In ZX style NEXT can be omitted.
+ do
+ {
+ forstack.pop ();
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ pfe= forstack.top ();
+ } while (! pfe->isvar (varname) );
+ }
+ }
+ if (pfe->next () )
+ {
+ jump_to (pfe->getpos () );
+ return true;
+ }
+ else
+ {
+ forstack.pop ();
+ return false;
+ }
+}
+
+void Runner::tron (bool fLine, BlChannel blc)
+{
+ globalrunner.tron (fLine, blc);
+}
+
+void Runner::troff ()
+{
+ globalrunner.troff ();
+}
+
+namespace {
+
+inline bool goto_relaxed ()
+{
+ return sysvar::hasFlags1 (sysvar::RelaxedGoto);
+}
+
+} // namespace
+
+inline Runner::StatusRun Runner::checkstatusEnded
+ (CodeLine &, const CodeLine &)
+{
+ return StopNow;
+}
+
+inline Runner::StatusRun Runner::checkstatusFnEnded
+ (CodeLine &, const CodeLine &)
+{
+ TRACEFUNC (tr, "Runner::checkstatusFnEnded");
+
+ if (fn_level () == 0)
+ throw ErrUnexpectedFnEnd;
+ gosub_check_fn ();
+
+ return StopNow;
+}
+
+inline Runner::StatusRun Runner::checkstatusReadyToRun
+ (CodeLine & codeline, const CodeLine &)
+{
+ BlLineNumber gline= posgoto.getnum ();
+ if (gline == LineBeginProgram)
+ codeline= program.getfirstline ();
+
+ else
+ {
+ CodeLine aux;
+ program.getline (gline, aux);
+ if (aux.number () != gline)
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ //if (codeline.number () == 0)
+ if (codeline.number () == LineEndProgram)
+ {
+ //setstatus (Ended);
+ //throw blassic::ProgramPassedLastLine ();
+
+ setstatus (Ended);
+ return StopNow;
+ }
+ else
+ {
+ setstatus (Running);
+ return KeepRunning;
+ }
+}
+
+inline Runner::StatusRun Runner::checkstatusRunning
+ (CodeLine & codeline, const CodeLine &)
+{
+ if (codeline.number () == LineDirectCommand)
+ {
+ setstatus (Ended);
+ return StopNow;
+ }
+ else
+ {
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ #if 1
+
+ if (fn_level () > 0)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ throw ErrNoFnEnd;
+ }
+ setstatus (Ended);
+ return StopNow;
+
+ #else
+ throw blassic::ProgramPassedLastLine ();
+ #endif
+ }
+ else
+ return KeepRunning;
+ }
+}
+
+inline Runner::StatusRun Runner::checkstatusStopped
+ (CodeLine &, const CodeLine &)
+{
+ return StopNow;
+}
+
+inline Runner::StatusRun Runner::checkstatusJump
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ TRACEFUNC (tr, "Runner::checkstatusJump");
+
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (gotoline != LineDirectCommand)
+ {
+ if (codeline.number () != gotoline)
+ {
+ program.getline (posgoto, codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ if (fn_level () > 0)
+ throw ErrNoFnEnd;
+ setstatus (Ended);
+ return StopNow;
+ }
+ }
+ else
+ {
+ TRMESSAGE (tr, "Same line");
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ }
+ else
+ {
+ if (codeline.number () != LineDirectCommand)
+ codeline= codeline0;
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ setstatus (Running);
+ return KeepRunning;
+}
+
+inline Runner::StatusRun Runner::checkstatusGoto
+ (CodeLine & codeline, const CodeLine &)
+{
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (codeline.number () != gotoline)
+ {
+ CodeLine aux;
+ program.getline (gotoline, aux);
+ BlLineNumber l= aux.number ();
+ //if (l == 0 ||
+ // (l != gotoline && ! goto_relaxed () ) )
+ if (l != gotoline && ! goto_relaxed () )
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gotoline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ else
+ codeline.gotochunk (posgoto.getchunk () );
+ setstatus (Running);
+ return KeepRunning;
+}
+
+#if 0
+inline Runner::StatusRun Runner::checkstatusInitingCommand
+ (CodeLine &, const CodeLine &)
+{
+ setstatus (Command);
+ return KeepRunning;
+}
+
+inline Runner::StatusRun Runner::checkstatusCommand
+ (CodeLine &, const CodeLine &)
+{
+ return StopNow;
+ //return KeepRunning;
+}
+#endif
+
+inline Runner::StatusRun Runner::checkstatusJumpResumeNext
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (gotoline != LineDirectCommand)
+ {
+ if (codeline.number () != gotoline)
+ {
+ program.getline (posgoto, codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ if (fn_level () > 0)
+ throw ErrNoFnEnd;
+ setstatus (Ended);
+ return StopNow;
+ }
+ }
+ else
+ codeline.gotochunk
+ (posgoto.getchunk () );
+ }
+ else
+ {
+ if (codeline.number () != LineDirectCommand)
+ codeline= codeline0;
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+
+ BlLineNumber n= codeline.number ();
+ if (n == gotoline)
+ {
+ CodeLine::Token tok;
+ codeline.gettoken (tok);
+ if (tok.code == keyIF)
+ {
+ if (n == LineDirectCommand)
+ {
+ setstatus (Ended);
+ return StopNow;
+ }
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ {
+ //throw blassic::ProgramPassedLastLine ();
+ if (fn_level () > 0)
+ throw ErrNoFnEnd;
+ setstatus (Ended);
+ return StopNow;
+ }
+ }
+ else
+ {
+ while (! tok.isendsentence () )
+ codeline.gettoken (tok);
+ }
+ }
+ setstatus (Running);
+ return KeepRunning;
+}
+
+Runner::checkstatusfunc Runner::checkstatus [Runner::LastStatus + 1]=
+{
+ &Runner::checkstatusEnded,
+ &Runner::checkstatusFnEnded,
+ &Runner::checkstatusReadyToRun,
+ &Runner::checkstatusRunning,
+ &Runner::checkstatusStopped,
+ &Runner::checkstatusJump,
+ &Runner::checkstatusGoto,
+ //&Runner::checkstatusInitingCommand,
+ //&Runner::checkstatusCommand,
+ &Runner::checkstatusJumpResumeNext,
+};
+
+#if 0
+inline bool Runner::checkstatus
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ switch (status)
+ {
+ case ReadyToRun:
+ {
+ BlLineNumber gline= posgoto.getnum ();
+ if (gline == LineBeginProgram)
+ codeline= program.getfirstline ();
+
+ else
+ {
+ CodeLine aux;
+ program.getline (gline, aux);
+ if (aux.number () != gline)
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ //if (codeline.number () == 0)
+ if (codeline.number () == LineEndProgram)
+ //setstatus (Ended);
+ throw blassic::ProgramPassedLastLine ();
+ else
+ {
+ setstatus (Running);
+ return true;
+ }
+ }
+ //break;
+ case Jump:
+ {
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (gotoline != LineDirectCommand)
+ {
+ if (codeline.number () != gotoline)
+ {
+ program.getline (posgoto, codeline);
+ if (codeline.number () == LineEndProgram)
+ throw blassic::ProgramPassedLastLine ();
+ }
+ else
+ codeline.gotochunk
+ (posgoto.getchunk () );
+ }
+ else
+ {
+ if (codeline.number () != LineDirectCommand)
+ codeline= codeline0;
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ }
+ setstatus (Running);
+ return true;
+ case Goto:
+ {
+ const BlLineNumber gotoline= posgoto.getnum ();
+ if (codeline.number () != gotoline)
+ {
+ CodeLine aux;
+ program.getline (gotoline, aux);
+ BlLineNumber l= aux.number ();
+ //if (l == 0 ||
+ // (l != gotoline && ! goto_relaxed () ) )
+ if (l != gotoline && ! goto_relaxed () )
+ {
+ if (showdebuginfo () )
+ cerr << "Line " << gotoline <<
+ " not exist" << endl;
+ throw ErrLineNotExist;
+ }
+ codeline= aux;
+ }
+ else
+ codeline.gotochunk (posgoto.getchunk () );
+ }
+ setstatus (Running);
+ return true;
+ case Running:
+ //if (codeline.number () != 0)
+ // program.getnextline (codeline);
+ //if (codeline.number () == 0)
+ //{
+ // status= Ended;
+ // if (fn_level () > 0)
+ // throw blassic::ProgramPassedLastLine ();
+ //}
+ //else
+ // return true;
+ if (codeline.number () == LineDirectCommand)
+ {
+ setstatus (Ended);
+ return false;
+ }
+ else
+ {
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ #if 0
+ {
+ setstatus (Ended);
+ if (fn_level () > 0)
+ throw blassic::ProgramPassedLastLine
+ ();
+ return false;
+ }
+ #else
+ throw blassic::ProgramPassedLastLine ();
+ #endif
+ else
+ return true;
+ }
+ case InitingCommand:
+ setstatus (Command);
+ return true;
+ default:
+ ;
+ }
+ return false;
+}
+
+#else
+
+inline bool Runner::is_run_status
+ (CodeLine & codeline, const CodeLine & codeline0)
+{
+ return (this->*(checkstatus [status]) ) (codeline, codeline0)
+ == KeepRunning;
+}
+
+#endif
+
+void Runner::showfailerrorgoto () const
+{
+ if (! showdebuginfo () )
+ return;
+ BlLineNumber source= geterrorgotosource ();
+
+ cerr << "Line " << geterrorgoto () <<
+ " specified in ON ERROR GOTO on ";
+ if (source == LineDirectCommand)
+ cerr << "a direct command";
+ else
+ cerr << "line " << source;
+ cerr << " does not exist" <<
+ endl;
+}
+
+namespace {
+
+bool handle_error (Runner & runner, BlError & berr)
+{
+ BlLineNumber errorgoto= runner.geterrorgoto ();
+ if (errorgoto == LineEndProgram)
+ {
+ if (runner.fn_level () > 0)
+ {
+ // The position of the error
+ // will be defined by the
+ // first fn caller.
+ if (showdebuginfo () )
+ cerr << "Error " << berr.geterr () <<
+ " inside DEF FN on line " <<
+ berr.getpos ().getnum () <<
+ endl;
+ }
+ return true;
+ }
+ else
+ {
+ CodeLine aux;
+ runner.getprogram ().getline (errorgoto, aux);
+ if (aux.number () != errorgoto)
+ {
+ runner.showfailerrorgoto ();
+ berr.seterr (ErrLineNotExist);
+ return true;
+ }
+ runner.seterror (berr);
+ // Clear berr, or it will be still active
+ // next time something is throwed.
+ berr.clear ();
+ runner.jump_to (errorgoto);
+ return false;
+ }
+}
+
+} // namespace
+
+#if 0
+void Runner::runline_catch (const CodeLine & codeline, ProgramPos pos,
+ BlError & berr, bool & endloop, bool & dobreak)
+{
+ TRACEFUNC (tr, "Runner::runline_catch");
+
+ //bool fnend= false;
+
+ try
+ {
+ throw; // Relaunch pending exception to catch it.
+ }
+ catch (std::bad_alloc &)
+ {
+ berr= BlError (ErrOutMemory,
+ //runnerline.getposactual () );
+ pos);
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (SocketError & se)
+ {
+ if (showdebuginfo () )
+ cerr << se.what () << endl;
+ berr= BlError (ErrSocket,
+ //runnerline.getposactual () );
+ pos);
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlErrNo e)
+ {
+ berr= BlError (e,
+ //runnerline.getposactual () );
+ pos);
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlError & newberr)
+ {
+ berr= newberr;
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlBreak &)
+ {
+ fInterrupted= false;
+ //ProgramPos actual= runnerline.getposactual ();
+ ProgramPos actual= pos;
+ switch (getbreakstate () )
+ {
+ case onbreak::BreakStop:
+ if (fn_level () > 0)
+ throw;
+ endloop= true;
+ dobreak= true;
+ break;
+ case onbreak::BreakCont:
+ throw BlError (ErrBlassicInternal, actual);
+ case onbreak::BreakGosub:
+ gosub_line (getbreakgosub (), actual);
+ break;
+ }
+ //if (endloop)
+ // break;
+ }
+ #if 0
+ catch (blassic::ProgramEnd &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "END inside DEF FN in line " <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ close_all ();
+ setstatus (Ended);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramPassedLastLine &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "End of program reached "
+ "inside DEF FN" <<
+ endl;
+ throw;
+ }
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramStop &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "STOP inside DEF FN "
+ "in line "
+ <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ BlFile & f= getfile0 ();
+ f << "**Stopped**";
+ if (codeline.number () != LineDirectCommand)
+ f << " in " << codeline.number ();
+ f.endline ();
+ //ProgramPos posbreak (runnerline.getposactual () );
+ ProgramPos posbreak (pos);
+ posbreak.nextchunk ();
+ set_break (posbreak);
+ setstatus (Stopped);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramFnEnd &)
+ {
+ #if 0
+ TRMESSAGE (tr, "FnEnd");
+ if (fn_level () == 0)
+ {
+ berr= BlError (ErrUnexpectedFnEnd, pos);
+ endloop= handle_error (* this, berr);
+ }
+ try
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ endloop= true;
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, pos);
+ endloop= handle_error (* this, berr);
+ }
+ #else
+
+ fnend= true;
+
+ #endif
+ }
+ if (fnend)
+ {
+ TRMESSAGE (tr, "FnEnd");
+ if (fn_level () == 0)
+ {
+ berr.set (ErrUnexpectedFnEnd, pos);
+ endloop= handle_error (* this, berr);
+ }
+ try
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ endloop= true;
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, pos);
+ endloop= handle_error (* this, berr);
+ }
+ }
+ #endif
+}
+#endif
+
+#if 0
+
+void Runner::runline (const CodeLine & codeline0)
+{
+ TRACEFUNC (tr, "Runner::runline");
+
+ if (codeline0.number () != LineDirectCommand)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ auto_ptr <RunnerLine> prunnerline
+ (newRunnerLine (* this, codeline0) );
+ RunnerLine & runnerline= * prunnerline.get ();
+
+ CodeLine & codeline= runnerline.getcodeline ();
+ bool endloop= false;
+ bool dobreak= false;
+ BlError berr;
+
+ setstatus (InitingCommand);
+
+ // Test:
+ otra:
+
+ //for (;;)
+ //{
+ try
+ {
+ TRMESSAGE (tr, statusname (status) );
+ if (! is_run_status (codeline, codeline0) )
+ //if ( (this->*(checkstatus [status]) )
+ // (codeline, codeline0) == StopNow)
+ {
+ // Test:
+ //break;
+ goto atloopend;
+ }
+
+ //do {
+ //TRMESSAGE (tr, statusname (status) );
+
+ //runnerline.setline (codeline);
+
+ // Do tron if active.
+ tronline (codeline);
+
+ //runnerline.execute ();
+ prunnerline->execute ();
+ //} while (checkstatus (codeline, codeline0) );
+ }
+ catch (std::bad_alloc &)
+ {
+ berr.set (ErrOutMemory, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (SocketError & se)
+ {
+ if (showdebuginfo () )
+ cerr << se.what () << endl;
+ berr.set (ErrSocket, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlError & newberr)
+ {
+ berr= newberr;
+ endloop= handle_error (* this, berr);
+ //if (endloop)
+ // break;
+ }
+ catch (BlBreak &)
+ {
+ fInterrupted= false;
+ ProgramPos actual= runnerline.getposactual ();
+ //ProgramPos actual= pos;
+ switch (getbreakstate () )
+ {
+ case onbreak::BreakStop:
+ if (fn_level () > 0)
+ throw;
+ endloop= true;
+ dobreak= true;
+ break;
+ case onbreak::BreakCont:
+ throw BlError (ErrBlassicInternal, actual);
+ case onbreak::BreakGosub:
+ gosub_line (getbreakgosub (), actual);
+ break;
+ }
+ //if (endloop)
+ // break;
+ }
+ #if 0
+ catch (blassic::ProgramEnd &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "END inside DEF FN in line " <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ close_all ();
+ setstatus (Ended);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramPassedLastLine &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "End of program reached "
+ "inside DEF FN" <<
+ endl;
+ throw;
+ }
+ setstatus (Ended);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramStop &)
+ {
+ if (fn_level () > 0)
+ {
+ if (showdebuginfo () )
+ cerr << "STOP inside DEF FN "
+ "in line "
+ <<
+ codeline.number () <<
+ endl;
+ throw;
+ }
+ BlFile & f= getfile0 ();
+ std::ostringstream oss;
+ oss << "**Stopped**";
+ if (codeline.number () != LineDirectCommand)
+ oss << " in " << codeline.number ();
+ f << oss.str ();
+ f.endline ();
+ ProgramPos posbreak (runnerline.getposactual () );
+ //ProgramPos posbreak (pos);
+ posbreak.nextchunk ();
+ set_break (posbreak);
+ setstatus (Stopped);
+ //break;
+ endloop= true; // New
+ }
+ catch (blassic::ProgramFnEnd &)
+ {
+ #if 0
+ TRMESSAGE (tr, "FnEnd");
+ if (fn_level () == 0)
+ {
+ berr= BlError (ErrUnexpectedFnEnd, pos);
+ endloop= handle_error
+ (* this, berr);
+ }
+ try
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ endloop= true;
+ }
+ catch (BlErrNo e)
+ {
+ berr= BlError (e, pos);
+ endloop= handle_error
+ (* this, berr);
+ }
+ #else
+
+ if (fn_level () == 0)
+ {
+ berr= BlError (ErrUnexpectedFnEnd,
+ //pos);
+ runnerline.getposactual () );
+ }
+ else
+ {
+ gosub_check_fn ();
+ setstatus (Ended);
+ }
+ endloop= true;
+
+ #endif
+ }
+ #endif
+ catch (...)
+ {
+ TRMESSAGE (tr, "catched ...");
+ throw;
+ }
+
+ #if 0
+ catch (...)
+ {
+ runline_catch (codeline, runnerline.getposactual (),
+ berr, endloop, dobreak);
+ }
+ #endif
+
+ // Test
+ #if 0
+
+ if (endloop)
+ break;
+ #else
+
+ if (! endloop)
+ goto otra;
+ #endif
+
+ #if 0
+ check_again:
+ try
+ {
+ if (! checkstatus (codeline, codeline0) )
+ //break;
+ endloop= true;
+ }
+ catch (...)
+ {
+ runline_catch (codeline, runnerline.getposactual (),
+ berr, endloop, dobreak);
+ if (endloop)
+ {
+ //break;
+ }
+ else
+ goto check_again;
+ }
+ if (endloop)
+ break;
+ #endif
+
+ // Test:
+ //} // for (;;)
+ atloopend:
+
+ if (endloop)
+ {
+ if (dobreak)
+ throw BlBreakInPos (runnerline.getposactual () );
+ else if (berr.geterr () != 0)
+ {
+ seterror (berr);
+ throw berr;
+ }
+ }
+}
+
+#else
+
+void Runner::runline (const CodeLine & codeline0)
+{
+ TRACEFUNC (tr, "Runner::runline");
+
+ if (codeline0.number () != LineDirectCommand)
+ {
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+
+ #if 1
+
+ auto_ptr <RunnerLine> prunnerline
+ (newRunnerLine (* this, codeline0) );
+ RunnerLine & runnerline= * prunnerline.get ();
+
+ #else
+
+ RunnerLineImpl runnerline (* this, codeline0);
+
+ #endif
+
+ CodeLine & codeline= runnerline.getcodeline ();
+ bool endloop= false;
+ bool dobreak= false;
+ BlError berr;
+
+ //setstatus (InitingCommand);
+ setstatus (Running);
+
+ // {
+ // TRACEFUNC (traux, "runline auxiliar block");
+
+ while (! endloop)
+ {
+ try
+ {
+ do {
+ //TRMESSAGE (tr, statusname (status) );
+
+ // Do tron if active.
+ tronline (codeline);
+
+ //prunnerline->execute ();
+ runnerline.execute ();
+
+ TRMESSAGE (tr, "Line finished");
+ } while (is_run_status (codeline, codeline0) );
+ endloop= true;
+ }
+ catch (std::bad_alloc &)
+ {
+ berr.set (ErrOutMemory, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ }
+ catch (SocketError & se)
+ {
+ if (showdebuginfo () )
+ cerr << se.what () << endl;
+ berr.set (ErrSocket, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ }
+ catch (BlErrNo e)
+ {
+ berr.set (e, runnerline.getposactual () );
+ endloop= handle_error (* this, berr);
+ }
+ catch (BlError & newberr)
+ {
+ berr= newberr;
+ endloop= handle_error (* this, berr);
+ }
+ catch (BlBreak &)
+ {
+ fInterrupted= false;
+ ProgramPos actual= runnerline.getposactual ();
+ switch (getbreakstate () )
+ {
+ case onbreak::BreakStop:
+ if (fn_level () > 0)
+ throw;
+ endloop= true;
+ dobreak= true;
+ break;
+ case onbreak::BreakCont:
+ throw BlError (ErrBlassicInternal, actual);
+ case onbreak::BreakGosub:
+ gosub_line (getbreakgosub (), actual);
+ break;
+ }
+ }
+ //catch (Exit & e)
+ //{
+ // //TRMESSAGE (traux, "Exitting");
+ // throw (Exit (e.code () ) );
+ //}
+
+ } // while
+
+ // } // Auxiliar block
+
+ //if (endloop)
+ //{
+ if (dobreak)
+ throw BlBreakInPos (runnerline.getposactual () );
+ else if (berr.geterr () != 0)
+ {
+ seterror (berr);
+ throw berr;
+ }
+ //}
+}
+
+#endif
+
+bool Runner::processline (const std::string & line)
+{
+ TRACEFUNC (tr, "Runner::processline");
+
+ CodeLine codeline;
+ codeline.scan (line);
+ BlLineNumber nline= codeline.number ();
+ //if (nline == 0)
+ if (nline == LineDirectCommand)
+ {
+ if (blnAuto != LineEndProgram)
+ {
+ // This probably must be changed.
+ if (codeline.empty () )
+ program.deletelines (blnAuto, blnAuto);
+ else
+ {
+ codeline.setnumber (blnAuto);
+ program.insert (codeline);
+ }
+ if (blnAuto > BlMaxLineNumber - blnAutoInc)
+ {
+ blnAuto= LineEndProgram;
+ throw BlError (ErrLineExhausted,
+ LineDirectCommand);
+ }
+ else
+ blnAuto+= blnAutoInc;
+ }
+ else
+ {
+ if (codeline.empty () )
+ return false;
+ runline (codeline);
+ return true;
+ }
+ }
+ else
+ {
+ if (nline > BlMaxLineNumber)
+ throw BlError (ErrLineExhausted);
+ if (codeline.empty () )
+ program.deletelines (nline, nline);
+ else
+ program.insert (codeline);
+ if (blnAuto != LineEndProgram)
+ {
+ blnAuto= codeline.number ();
+ if (blnAuto > BlMaxLineNumber - blnAutoInc)
+ {
+ blnAuto= LineEndProgram;
+ throw BlError (ErrLineExhausted,
+ LineDirectCommand);
+ }
+ else
+ blnAuto+= blnAutoInc;
+ }
+ }
+ return false;
+}
+
+namespace {
+
+void welcome (BlFile & f)
+{
+ f.endline ();
+ f << "Blassic " << version::Major << '.' <<
+ version::Minor << '.' <<
+ version::Release;
+ f.endline ();
+ f << "(C) 2001-2009 Julian Albo";
+ f.endline ();
+ f.endline ();
+}
+
+} // namespace
+
+bool Runner::editline (BlLineNumber bln, std::string & str)
+{
+ TRACEFUNC (tr, "editline - line number->string");
+
+ std::string buffer;
+ {
+ BlFileOutString bfos;
+ program.list (bln, bln, bfos);
+ buffer= bfos.str ();
+ if (buffer.empty () )
+ {
+ bfos << bln << ' ';
+ bfos.endline ();
+ buffer= bfos.str ();
+ }
+ }
+ buffer.erase (buffer.size () - 1);
+ TRMESSAGE (tr, std::string (1, '\'') + buffer + '\'');
+
+ static const std::string number ("01234567890");
+ size_t inipos= buffer.find_first_of (number);
+ ASSERT (inipos != std::string::npos);
+ inipos= buffer.find_first_not_of (number, inipos);
+ ASSERT (inipos != std::string::npos);
+ ++inipos;
+
+ BlFile & bf= getfile0 ();
+ bool r;
+ if ( (r= blassic::edit::editline (bf, buffer, inipos) ) == true)
+ str= buffer;
+ return r;
+}
+
+void Runner::interactive ()
+{
+ TRACEFUNC (tr, "Runner::interactive");
+
+ // Now the title is stablished in blassic.cpp
+ //set_title ("blassic");
+
+ welcome (getfile0 () );
+
+ bool showprompt= true;
+ for (;;)
+ {
+ std::string line;
+ if (blnAuto != LineEndProgram)
+ {
+ if (! editline (blnAuto, line) )
+ fInterrupted= true;
+ }
+ else
+ {
+ if (showprompt)
+ {
+ BlFile & f= getfile0 ();
+ f << strPrompt;
+ f.endline ();
+ }
+ //cout << "] " << flush;
+
+ getfile0 ().getline (line, true);
+ }
+
+ if (fInterrupted)
+ {
+ fInterrupted= false;
+ BlFile & bf= getfile0 ();
+ bf << strbreak;
+ bf.endline ();
+ std::cin.clear ();
+ blnAuto= LineEndProgram;
+ continue;
+ }
+ if (! std::cin)
+ break;
+
+ #ifndef _Windows
+
+ if (! line.empty () && line [line.size () - 1] == '\r')
+ line= line.substr (0, line.size () - 1);
+
+ #endif
+
+ try
+ {
+ showprompt= processline (line);
+ }
+ catch (BlErrNo ben)
+ {
+ BlFile & f= getfile0 ();
+ f << ErrStr (ben);
+ f.endline ();
+ setstatus (Stopped);
+ }
+ catch (BlError & be)
+ {
+ BlFile & f= getfile0 ();
+ f << to_string (be);
+ f.endline ();
+ setstatus (Stopped);
+ }
+ catch (BlBreakInPos & bbip)
+ {
+ BlFile & f= getfile0 ();
+ f << to_string (bbip);
+ f.endline ();
+ set_break (bbip.getpos () );
+ setstatus (Stopped);
+ }
+ } // for (;;)
+}
+
+void Runner::clean_input ()
+{
+ if (graphics::ingraphicsmode () )
+ graphics::clean_input ();
+ else
+ cursor::clean_input ();
+}
+
+void Runner::ring ()
+{
+ if (graphics::ingraphicsmode () )
+ graphics::ring ();
+ else
+ cursor::ring ();
+}
+
+void Runner::set_title (const std::string & str)
+{
+ if (graphics::ingraphicsmode () )
+ graphics::set_title (str);
+ else
+ cursor::set_title (str);
+}
+
+// End of runner.cpp
diff --git a/runner.h b/runner.h
new file mode 100644
index 0000000..e1faeda
--- /dev/null
+++ b/runner.h
@@ -0,0 +1,658 @@
+#ifndef INCLUDE_BLASSIC_RUNNER_H
+#define INCLUDE_BLASSIC_RUNNER_H
+
+// runner.h
+// Revision 6-feb-2005
+
+//#include "program.h"
+
+class Program;
+
+#include "blassic.h"
+
+#include "error.h"
+#include "file.h"
+#include "codeline.h"
+#include "var.h"
+#include "element.h"
+
+//#include "runnerline.h"
+
+#include <iostream>
+#include <stack>
+#include <vector>
+#include <map>
+
+
+// ********************* GlobalRunner **********************
+
+
+namespace blassic {
+
+
+namespace onbreak {
+
+enum BreakState { BreakStop, BreakCont, BreakGosub };
+
+} // namespace onbreak
+
+
+} // namespace blassic
+
+
+enum TrigonometricMode { TrigonometricRad, TrigonometricDeg };
+
+// We encapsulate the random generator in a class to have all code
+// related to it in a place, and to be able to change it easily.
+
+// random in some systems may not use the RAND_MAX value,
+// then we use it only in linux.
+
+class RandomGenerator {
+public:
+ BlNumber operator () ()
+ {
+ #if defined __linux__
+ return BlNumber (random () ) / (RAND_MAX + 1.0);
+ #else
+ return BlNumber (rand () ) / (RAND_MAX + 1.0);
+ #endif
+ }
+ void seed (unsigned int value)
+ {
+ #if defined __linux__
+ srandom (value);
+ #else
+ srand (value);
+ #endif
+ }
+};
+
+class GlobalRunner {
+public:
+ GlobalRunner (Program & prog);
+ ~GlobalRunner ();
+
+ // Program
+private:
+ Program & program;
+public:
+ Program & getprogram () { return program; }
+
+ // TRON stuff
+private:
+ bool fTron, fTronLine;
+ BlChannel blcTron;
+ void do_tronline (const CodeLine & line);
+public:
+ void tron (bool fLine, BlChannel blc);
+ void troff ();
+ void tronline (const CodeLine & codeline)
+ {
+ if (fTron)
+ do_tronline (codeline);
+ }
+
+ // GlobalRunner Channel stuff
+public:
+ typedef std::map <BlChannel, blassic::file::BlFile *> ChanFile;
+ typedef std::map <BlChannel, BlLineNumber> ChanPolled;
+private:
+ ChanFile chanfile;
+ ChanPolled chanpolled;
+ bool alreadypolled;
+ bool clearingpolled;
+public:
+ bool assign_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value,
+ blassic::file::BlFile::Align align);
+ bool assign_mid_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len);
+ bool isfileopen (BlChannel channel) const
+ { return chanfile.find (channel) != chanfile.end (); }
+ BlChannel freefile () const;
+ blassic::file::BlFile & getfile (BlChannel channel) const;
+ void setfile (BlChannel channel, blassic::file::BlFile * npfile);
+ void resetfile0 ();
+ void resetfileprinter ();
+ void close_all ();
+ void destroy_windows ();
+ void closechannel (BlChannel channel);
+ void windowswap (BlChannel ch1, BlChannel ch2);
+
+ void pollchannel (BlChannel ch, BlLineNumber line);
+ bool channelspolled ();
+ BlLineNumber getpollnumber ();
+ void setpolled ();
+ void clearpolled ();
+
+ // GlobalRunner DATA / READ / RESTORE stuff
+private:
+ BlLineNumber datanumline;
+ BlChunk datachunk;
+ unsigned short dataelem;
+public:
+ BlLineNumber & getdatanumline () { return datanumline; }
+ BlChunk & getdatachunk () { return datachunk; }
+ unsigned short & getdataelem () { return dataelem; }
+ void setreadline (BlLineNumber bln)
+ {
+ datanumline= bln;
+ datachunk= 0;
+ dataelem= 0;
+ }
+ void clearreadline ()
+ {
+ datanumline= LineBeginProgram;
+ datachunk= 0;
+ dataelem= 0;
+ }
+
+ // GlobalRunner ON ERROR GOTO stuff.
+private:
+ BlLineNumber blnErrorGoto;
+ BlLineNumber blnErrorGotoSource;
+public:
+ void clearerrorgoto ();
+ void seterrorgoto (BlLineNumber line, BlLineNumber source);
+ BlLineNumber geterrorgoto () const
+ { return blnErrorGoto; }
+ BlLineNumber geterrorgotosource () const
+ { return blnErrorGotoSource; }
+
+ // GlobalRunner ON BREAK
+private:
+ blassic::onbreak::BreakState breakstate;
+ BlLineNumber breakgosubline;
+public:
+ void setbreakstate (blassic::onbreak::BreakState newstate)
+ {
+ breakstate= newstate;
+ }
+ blassic::onbreak::BreakState getbreakstate () const
+ { return breakstate; }
+ void setbreakgosub (BlLineNumber bln)
+ {
+ breakstate= blassic::onbreak::BreakGosub;
+ breakgosubline= bln;
+ }
+ BlLineNumber getbreakgosub () { return breakgosubline; }
+
+ // Control of depth of fn calls.
+private:
+ size_t fn_current_level;
+public:
+ size_t fn_level () const { return fn_current_level; }
+ void inc_fn_level ();
+ void dec_fn_level ();
+
+ // Trigonometric mode.
+private:
+ TrigonometricMode trigmode;
+public:
+ TrigonometricMode trigonometric_mode () const { return trigmode; }
+ void trigonometric_default () { trigmode= TrigonometricRad; }
+ void trigonometric_mode (TrigonometricMode trigmode_n)
+ { trigmode= trigmode_n; }
+
+ // Random number generator.
+private:
+ RandomGenerator randgen;
+public:
+ BlNumber getrandom () { return randgen (); }
+ void seedrandom (unsigned int value) { randgen.seed (value); }
+};
+
+
+// ********************* Runner **********************
+
+
+class GosubStack {
+private:
+ GlobalRunner & globalrunner;
+ typedef std::stack <GosubElement> st_t;
+ st_t st;
+public:
+ typedef st_t::size_type size_type;
+public:
+ GosubStack (GlobalRunner & globalrunner);
+ ~GosubStack ();
+ bool empty () const
+ {
+ return st.empty ();
+ }
+ size_type size () const
+ {
+ return st.size ();
+ }
+ void check_fn () const
+ {
+ if (st.empty () )
+ throw ErrUnexpectedFnEnd;
+ if (st.top ().isgosub () )
+ throw ErrGosubWithoutReturn;
+ }
+ void erase ();
+ void push (ProgramPos pos, bool is_polled)
+ {
+ st.push (GosubElement (pos, is_polled) );
+ if (is_polled)
+ globalrunner.setpolled ();
+ }
+ void push (LocalLevel & ll)
+ {
+ st.push (GosubElement (ll) );
+ }
+ void pop (ProgramPos & ppos)
+ {
+ if (st.empty () )
+ throw ErrReturnWithoutGosub;
+ GosubElement & go= st.top ();
+ if (! go.isgosub () )
+ throw ErrReturnWithoutGosub;
+ ppos= go.getpos ();
+ go.freelocalvars ();
+ if (go.ispolled () )
+ globalrunner.clearpolled ();
+ st.pop ();
+ }
+ void popfn ()
+ {
+ if (st.empty () )
+ throw ErrReturnWithoutGosub;
+ GosubElement & go= st.top ();
+ if (go.isgosub () )
+ throw ErrGosubWithoutReturn;
+ go.freelocalvars ();
+ st.pop ();
+ }
+ void addlocalvar (const std::string & name)
+ {
+ if (st.empty () )
+ throw ErrMisplacedLocal;
+ GosubElement go= st.top ();
+ go.addlocalvar (name);
+ }
+};
+
+class Runner {
+public:
+ enum RunnerStatus {
+ Ended,
+ FnEnded,
+ ReadyToRun,
+ Running,
+ Stopped,
+ Jump,
+ Goto,
+ //InitingCommand,
+ //Command,
+ JumpResumeNext,
+ LastStatus= JumpResumeNext,
+ };
+private:
+ enum StatusRun { KeepRunning, StopNow };
+
+ typedef StatusRun (Runner::* checkstatusfunc)
+ (CodeLine &, const CodeLine &);
+ static checkstatusfunc checkstatus [LastStatus + 1];
+
+ StatusRun checkstatusEnded
+ (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusFnEnded
+ (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusReadyToRun
+ (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusRunning
+ (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusStopped
+ (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusJump
+ (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusGoto
+ (CodeLine & line, const CodeLine & line0);
+ //StatusRun checkstatusInitingCommand
+ // (CodeLine & line, const CodeLine & line0);
+ //StatusRun checkstatusCommand
+ // (CodeLine & line, const CodeLine & line0);
+ StatusRun checkstatusJumpResumeNext
+ (CodeLine & line, const CodeLine & line0);
+ bool is_run_status (CodeLine & line, const CodeLine & line0);
+
+
+ GlobalRunner & globalrunner;
+ Program & program;
+ RunnerStatus status;
+ bool fInElse;
+ bool fInWend;
+public:
+ //Runner (Program & prog);
+ Runner (GlobalRunner & gr);
+ Runner (const Runner & runner);
+ ~Runner ();
+
+ Program & getprogram () { return program; }
+ void clear ();
+ void getline (std::string & line);
+ void runline_catch (const CodeLine & codeline, ProgramPos pos,
+ BlError & berr, bool & endloop, bool & dobreak);
+ void runline (const CodeLine & codeline0);
+ void run ();
+ bool editline (BlLineNumber bln, std::string & str);
+ void interactive ();
+
+ // Runner *********** Errors **************
+private:
+ BlCode codprev;
+ BlError berrLast;
+public:
+ BlErrNo geterr () const;
+ ProgramPos geterrpos () const;
+ BlLineNumber geterrline () const;
+ void clearerror ();
+ BlError geterror () const;
+ void seterror (const BlError & er);
+
+ // Runner *********** Flow control **************
+private:
+ ProgramPos posgoto;
+public:
+ void setstatus (RunnerStatus stat) { status= stat; }
+ void run_to (BlLineNumber line)
+ {
+ posgoto= line;
+ status= ReadyToRun;
+ }
+ void run_to (ProgramPos pos)
+ {
+ posgoto= pos;
+ status= ReadyToRun;
+ }
+ void jump_to (BlLineNumber line)
+ {
+ posgoto= line;
+ status= Jump;
+ }
+ void jump_to (ProgramPos pos)
+ {
+ posgoto= pos;
+ status= Jump;
+ }
+ void goto_to (BlLineNumber line)
+ {
+ posgoto= line;
+ status= Goto;
+ }
+ void goto_to (ProgramPos pos)
+ {
+ posgoto= pos;
+ status= Goto;
+ }
+ void resume_next (ProgramPos pos)
+ {
+ posgoto= pos;
+ status= JumpResumeNext;
+ }
+
+ // Runner *********** FOR / NEXT **************
+private:
+ std::stack <ForElement *, std::vector <ForElement *> > forstack;
+public:
+ void push_for (ForElement * pfe)
+ {
+ forstack.push (pfe);
+ }
+ //bool for_empty () const { return forstack.empty (); }
+ ForElement & for_top ()
+ {
+ if (forstack.empty () )
+ throw ErrNextWithoutFor;
+ return * forstack.top ();
+ }
+ void for_pop () { delete forstack.top (); forstack.pop (); }
+ // New version, supposed faster.
+ bool next ();
+ bool next (const std::string & varname);
+
+ // Runner *********** GOSUB / RETURN / FN **************
+private:
+ GosubStack gosubstack;
+public:
+ bool gosub_empty () const
+ { return gosubstack.empty (); }
+ size_t gosub_size () const
+ { return gosubstack.size (); }
+ void gosub_check_fn () const
+ { gosubstack.check_fn (); }
+ void gosub_pop (ProgramPos & pos)
+ { gosubstack.pop (pos); }
+ void fn_pop () { gosubstack.popfn (); }
+ void gosub_addlocalvar (const std::string & str)
+ {
+ gosubstack.addlocalvar (str);
+ }
+ void gosub_push (LocalLevel & ll)
+ {
+ gosubstack.push (ll);
+ }
+ void gosub_line (BlLineNumber dest, ProgramPos posgosub,
+ bool is_polled= false)
+ {
+ gosubstack.push (posgosub, is_polled);
+ goto_to (dest);
+ }
+ size_t fn_level () const { return globalrunner.fn_level (); }
+ void inc_fn_level ()
+ { globalrunner.inc_fn_level (); }
+ void dec_fn_level ()
+ { globalrunner.dec_fn_level (); }
+
+ // Runner *********** REPEAT / UNTIL **************
+private:
+ std::stack <RepeatElement> repeatstack;
+public:
+ bool repeat_empty () const { return repeatstack.empty (); }
+ void repeat_pop () { repeatstack.pop (); }
+ RepeatElement & repeat_top () { return repeatstack.top (); }
+ void repeat_push (const RepeatElement & re) { repeatstack.push (re); }
+
+ // Runner *********** WHILE / WEND **************
+private:
+ std::stack <WhileElement> whilestack;
+public:
+ bool in_wend () { return fInWend; }
+ void in_wend (bool f) { fInWend= f; }
+ bool while_empty () { return whilestack.empty (); }
+ void while_pop () { whilestack.pop (); }
+ WhileElement & while_top () { return whilestack.top (); }
+ void while_push (const WhileElement & we) { whilestack.push (we); }
+
+ // Runner *********** TRON **************
+
+ void tron (bool fLine, BlChannel blc);
+ void troff ();
+ void tronline (const CodeLine & line)
+ { globalrunner.tronline (line); }
+
+ // Runner *********** BREAK / CONT **************
+private:
+ ProgramPos posbreak;
+public:
+ void jump_break ()
+ {
+ //if (! posbreak)
+ if (posbreak.getnum () == LineEndProgram ||
+ posbreak.getnum () == LineDirectCommand)
+ throw ErrNoContinue;
+ posgoto= posbreak;
+ //posbreak= 0;
+ posbreak= LineEndProgram;
+ status= Jump;
+ }
+ void set_break (ProgramPos pos) { posbreak= pos; }
+
+ #if 0
+ void setbreakstate (BreakState newstate)
+ {
+ breakstate= newstate;
+ }
+ BreakState getbreakstate () { return breakstate; }
+ void setbreakgosub (BlLineNumber bln)
+ {
+ breakstate= BreakGosub;
+ breakgosubline= bln;
+ }
+ BlLineNumber getbreakgosub () { return breakgosubline; }
+ #else
+
+ void setbreakstate (blassic::onbreak::BreakState newstate)
+ {
+ globalrunner.setbreakstate (newstate);
+ }
+ blassic::onbreak::BreakState getbreakstate () const
+ {
+ return globalrunner.getbreakstate ();
+ }
+ void setbreakgosub (BlLineNumber bln)
+ {
+ globalrunner.setbreakgosub (bln);
+ }
+ BlLineNumber getbreakgosub ()
+ {
+ return globalrunner.getbreakgosub ();
+ }
+
+ #endif
+
+
+ // Runner *********** DATA / READ / RESTORE **************
+
+ BlLineNumber & getdatanumline ()
+ { return globalrunner.getdatanumline (); }
+ BlChunk & getdatachunk ()
+ { return globalrunner.getdatachunk (); }
+ unsigned short & getdataelem ()
+ { return globalrunner.getdataelem (); }
+
+ // Runner *********** ON ERROR GOTO **************
+
+ void showfailerrorgoto () const;
+ void clearerrorgoto ()
+ { globalrunner.clearerrorgoto (); }
+ void seterrorgoto (BlLineNumber line, BlLineNumber source)
+ { globalrunner.seterrorgoto (line, source); }
+ BlLineNumber geterrorgoto () const
+ { return globalrunner.geterrorgoto (); }
+ BlLineNumber geterrorgotosource () const
+ { return globalrunner.geterrorgotosource (); }
+
+ // Runner *********** Channels **************
+
+ #if 0
+ void assign_channel_var
+ (const std::string & var, const std::string & value,
+ blassic::file::BlFile::Align align)
+ {
+ for (ChanFile::iterator it= chanfile.begin ();
+ it != chanfile.end ();
+ ++it)
+ {
+ it->second->assign (var, value, align);
+ }
+ }
+ #else
+ bool assign_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value,
+ blassic::file::BlFile::Align align)
+ { return globalrunner.assign_channel_var (var, dim, value, align); }
+ #endif
+ bool assign_mid_channel_var
+ (const std::string & var, const Dimension & dim,
+ const std::string & value,
+ size_t inipos, std::string::size_type len)
+ {
+ return globalrunner.assign_mid_channel_var
+ (var, dim, value, inipos, len);
+ }
+ //bool isfileopen (BlChannel channel) const
+ //{ return chanfile.find (channel) != chanfile.end (); }
+ bool isfileopen (BlChannel channel) const
+ { return globalrunner.isfileopen (channel); }
+ BlChannel freefile () const
+ { return globalrunner.freefile (); }
+ blassic::file::BlFile & getfile (BlChannel channel) const
+ { return globalrunner.getfile (channel); }
+ blassic::file::BlFile & getfile0 () const
+ { return globalrunner.getfile (DefaultChannel); }
+ void setfile (BlChannel channel, blassic::file::BlFile * npfile)
+ { globalrunner.setfile (channel, npfile); }
+ void resetfile0 ()
+ { globalrunner.resetfile0 (); }
+ void close_all ()
+ { globalrunner.close_all (); }
+ void destroy_windows ()
+ { globalrunner.destroy_windows (); }
+ void closechannel (BlChannel channel)
+ { globalrunner.closechannel (channel); }
+ void windowswap (BlChannel ch1, BlChannel ch2)
+ { globalrunner.windowswap (ch1, ch2); }
+
+ void pollchannel (BlChannel ch, BlLineNumber line)
+ { globalrunner.pollchannel (ch, line); }
+ bool channelspolled ()
+ { return globalrunner.channelspolled (); }
+ BlLineNumber getpollnumber ()
+ { return globalrunner.getpollnumber (); }
+
+ void spectrumwindows ();
+
+ // Runner *********** DATA / READ / RESTORE **************
+
+ void setreadline (BlLineNumber bln)
+ { globalrunner.setreadline (bln); }
+ void clearreadline ()
+ { globalrunner.clearreadline (); }
+
+ // Runner *********** AUTO **************
+private:
+ BlLineNumber blnAuto, blnAutoInc;
+public:
+ void setauto (BlLineNumber line, BlLineNumber inc)
+ { blnAuto= line; blnAutoInc= inc; }
+
+ // Runner *********** Trigonometric mode **************
+ TrigonometricMode trigonometric_mode ()
+ { return globalrunner.trigonometric_mode (); }
+ void trigonometric_default ()
+ { globalrunner.trigonometric_default (); }
+ void trigonometric_mode (TrigonometricMode trigmode_n)
+ { globalrunner.trigonometric_mode (trigmode_n); }
+
+private:
+
+ bool processline (const std::string & line);
+
+public:
+ // Runner *********** Random number generator **************
+
+ BlNumber getrandom ()
+ { return globalrunner.getrandom (); }
+ void seedrandom (unsigned int value)
+ { globalrunner.seedrandom (value); }
+
+ // Runner *********** Auxiliars **************
+
+ void clean_input ();
+ void ring ();
+ void set_title (const std::string & str);
+};
+
+std::ostream & operator << (std::ostream & os, Runner::RunnerStatus status);
+
+#endif
+
+// Fin de runner.h
diff --git a/runnerline.cpp b/runnerline.cpp
new file mode 100644
index 0000000..13dfe63
--- /dev/null
+++ b/runnerline.cpp
@@ -0,0 +1,26 @@
+// runnerline.cpp
+// Revision 31-jul-2004
+
+#include "runnerline.h"
+
+#include "trace.h"
+
+RunnerLine::RunnerLine (Runner & runner, const CodeLine & newcodeline) :
+ runner (runner),
+ codeline (newcodeline)
+{
+ TRACEFUNC (tr, "RunnerLine::RunnerLine");
+}
+
+RunnerLine::RunnerLine (Runner & runner) :
+ runner (runner)
+{
+ TRACEFUNC (tr, "RunnerLine::RunnerLine");
+}
+
+RunnerLine::~RunnerLine ()
+{
+ TRACEFUNC (tr, "RunnerLine::~RunnerLine");
+}
+
+// End of runnerline.cpp
diff --git a/runnerline.h b/runnerline.h
new file mode 100644
index 0000000..b738f58
--- /dev/null
+++ b/runnerline.h
@@ -0,0 +1,34 @@
+#ifndef INCLUDE_BLASSIC_RUNNERLINE_H
+#define INCLUDE_BLASSIC_RUNNERLINE_H
+
+// runnerline.h
+// Revision 18-jul-2004
+
+#include "codeline.h"
+#include "function.h"
+#include "result.h"
+
+class Runner;
+class LocalLevel;
+
+class RunnerLine {
+public:
+ RunnerLine (Runner & runner);
+ RunnerLine (Runner & runner, const CodeLine & newcodeline);
+ virtual ~RunnerLine ();
+
+ CodeLine & getcodeline () { return codeline; }
+ virtual void execute ()= 0;
+ virtual ProgramPos getposactual () const= 0;
+ virtual void callfn (Function & f, const std::string & fname,
+ LocalLevel & ll, blassic::result::BlResult & result)= 0;
+protected:
+ Runner & runner;
+ CodeLine codeline;
+};
+
+RunnerLine * newRunnerLine (Runner & runner, const CodeLine & newcodeline);
+
+#endif
+
+// End of runnerline.h
diff --git a/runnerline_impl.cpp b/runnerline_impl.cpp
new file mode 100644
index 0000000..1656988
--- /dev/null
+++ b/runnerline_impl.cpp
@@ -0,0 +1,4347 @@
+// runnerline_impl.cpp
+// Revision 9-feb-2005
+
+#include "runnerline_impl.h"
+
+#include "error.h"
+#include "dynamic.h"
+#include "runner.h"
+#include "program.h"
+#include "directory.h"
+#include "sysvar.h"
+#include "graphics.h"
+#include "util.h"
+#include "using.h"
+#include "mbf.h"
+#include "regexp.h"
+#include "memory.h"
+#include "trace.h"
+
+#include <sstream>
+#include <iomanip>
+#include <algorithm>
+#include <functional>
+#include <memory>
+#include <cstdio>
+#include <cerrno>
+#include <ctime>
+#include <cctype>
+#include <iostream>
+
+// cmath is not used because in some platforms asinh and others
+// are declared only in math.h
+#include <math.h>
+
+#if defined __unix__ || defined __linux__
+// Using uname on unix, linux and cygwin.
+#include <sys/utsname.h>
+#endif
+
+#include <cassert>
+#define ASSERT assert
+
+using std::cerr;
+using std::endl;
+using std::auto_ptr;
+using std::isalpha;
+
+namespace sysvar= blassic::sysvar;
+namespace onbreak= blassic::onbreak;
+
+using namespace blassic::file;
+
+using util::dim_array;
+using util::touch;
+
+
+namespace {
+
+#if defined __unix__ || defined __linux__
+// Even in windows with cygwin.
+const char * os_family= "unix";
+
+#else
+
+const char * os_family= "windows";
+
+#endif
+
+// Workaround for a problem in some versions of gcc.
+// Do not define zero as const, that does not solve the problem.
+// But do not modify it! You have been warned!
+double zero= 0.0;
+
+#if 0
+inline bool iscomp (BlCode code)
+{
+ return code == '=' || code == keyDISTINCT ||
+ code == '<' || code == keyMINOREQUAL ||
+ code == '>' || code == keyGREATEREQUAL;
+}
+
+inline bool islogical2 (BlCode code)
+{
+ return code == keyOR || code == keyAND || code == keyXOR;
+}
+
+#else
+
+// Testing as macro for speed.
+
+#define iscomp(code) \
+ ((code) == '=' || (code) == keyDISTINCT || \
+ (code) == '<' || (code) == keyMINOREQUAL || \
+ (code) == '>' || (code) == keyGREATEREQUAL)
+
+#define islogical2(code) ((code) == keyOR || (code) == keyAND || \
+ (code) == keyXOR)
+
+#endif
+
+#ifdef M_PIl
+const BlNumber value_pi= M_PIl;
+#else
+const BlNumber value_pi= 4.0 * atan (1);
+#endif
+
+const BlNumber value_pi_div_180= value_pi / 180.0;
+const BlNumber value_180_div_pi= 180.0 / value_pi;
+
+// ********** Hyperbolic trigonometric arc functions **********
+
+
+namespace auxmath {
+
+#if HAVE_DECL_ASINH
+using ::asinh;
+#else
+double asinh (double x)
+{
+ return log (x + sqrt (x * x + 1) );
+}
+#endif
+
+#if HAVE_DECL_ACOSH
+using ::acosh;
+#else
+double acosh (double x)
+{
+ errno= 0;
+ double r= sqrt (x * x - 1);
+ if (errno != 0)
+ return 0;
+ return log (x + r );
+}
+#endif
+
+#if HAVE_DECL_ATANH
+using ::atanh;
+#else
+double atanh (double x)
+{
+ return log ( (1 + x) / (1 - x) ) / 2;
+}
+#endif
+
+} // namespace auxmath
+
+
+// ***************** Auxiliary math functions *************
+
+double auxFIX (double n)
+{
+ double r;
+ modf (n, & r);
+ return r;
+}
+
+} // namespace
+
+
+RunnerLineImpl::RunnerLineImpl
+ (Runner & runner, const CodeLine & newcodeline) :
+ RunnerLine (runner, newcodeline),
+ program (runner.getprogram () ),
+ pdirectory (0),
+ fInElse (false)
+{
+ TRACEFUNC (tr, "RunnerLineImpl::RunnerLineImpl");
+}
+
+RunnerLineImpl::RunnerLineImpl (Runner & runner) :
+ RunnerLine (runner),
+ program (runner.getprogram () ),
+ fInElse (false)
+{
+ TRACEFUNC (tr, "RunnerLineImpl::RunnerLineImpl");
+}
+
+RunnerLineImpl::~RunnerLineImpl ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::~RunnerLineImpl");
+}
+
+RunnerLine * newRunnerLine (Runner & runner, const CodeLine & newcodeline)
+{
+ return new RunnerLineImpl (runner, newcodeline);
+}
+
+#ifdef ONE_TABLE
+
+#define insfunc_element(elem) \
+ {key##elem, \
+ { & RunnerLineImpl::do_##elem, \
+ & RunnerLineImpl::valsyntax_error} }
+
+#define insfunc_alias(elem,alias) \
+ {key##elem, \
+ { & RunnerLineImpl::do_##alias, \
+ & RunnerLineImpl::valsyntax_error} }
+
+#define valfunc_element(elem) \
+ {key##elem, \
+ { & RunnerLineImpl::syntax_error, \
+ & RunnerLineImpl::val_##elem} }
+
+#define valfunc_alias(elem,alias) \
+ {key##elem, \
+ { & RunnerLineImpl::syntax_error, \
+ & RunnerLineImpl::val_##alias} }
+
+#define mixfunc_element(elem) \
+ {key##elem, \
+ { & RunnerLineImpl::do_##elem, \
+ & RunnerLineImpl::val_##elem} }
+
+
+const RunnerLineImpl::tfunctions_t RunnerLineImpl::tfunctions []=
+{
+ valfunc_element (OpenPar),
+ insfunc_element (Colon),
+
+ insfunc_element (END),
+ insfunc_element (LIST),
+ insfunc_element (REM),
+ insfunc_element (LOAD),
+ insfunc_element (SAVE),
+ insfunc_element (NEW),
+ insfunc_element (EXIT),
+ insfunc_element (RUN),
+ insfunc_element (PRINT),
+ insfunc_element (FOR),
+ insfunc_element (NEXT),
+ insfunc_element (IF),
+ insfunc_element (ELSE),
+ insfunc_element (TRON),
+ insfunc_element (TROFF),
+ mixfunc_element (LET),
+ insfunc_element (GOTO),
+ insfunc_element (STOP),
+ insfunc_element (CONT),
+ insfunc_element (CLEAR),
+ insfunc_element (GOSUB),
+ insfunc_element (RETURN),
+ insfunc_element (POKE),
+ insfunc_element (DATA),
+ insfunc_element (READ),
+ insfunc_element (RESTORE),
+ insfunc_element (INPUT),
+ insfunc_element (LINE),
+ insfunc_element (RANDOMIZE),
+ insfunc_element (PLEASE),
+ insfunc_element (AUTO),
+ insfunc_element (DIM),
+ insfunc_element (SYSTEM),
+ insfunc_element (ON),
+ insfunc_element (ERROR),
+ insfunc_element (OPEN),
+ insfunc_element (CLOSE),
+ insfunc_element (LOCATE),
+ insfunc_element (CLS),
+ insfunc_element (WRITE),
+ insfunc_element (MODE),
+ insfunc_element (MOVE),
+ insfunc_element (COLOR),
+ insfunc_element (GET),
+ mixfunc_element (LABEL),
+ insfunc_element (DELIMITER),
+ insfunc_element (REPEAT),
+ insfunc_element (UNTIL),
+ insfunc_element (WHILE),
+ insfunc_element (WEND),
+ insfunc_element (PLOT),
+ insfunc_element (POPEN),
+ insfunc_element (RESUME),
+ insfunc_element (DELETE),
+ insfunc_element (LOCAL),
+ insfunc_element (PUT),
+ insfunc_element (FIELD),
+ insfunc_element (LSET),
+
+ // Lset and rset use same function.
+ insfunc_alias (RSET, LSET),
+
+ insfunc_element (SOCKET),
+ insfunc_element (DRAW),
+ insfunc_element (DEF),
+ mixfunc_element (FN),
+ insfunc_element (ERASE),
+ insfunc_element (SWAP),
+ insfunc_element (SYMBOL),
+ insfunc_element (ZONE),
+ insfunc_element (POP),
+ insfunc_element (NAME),
+ insfunc_element (KILL),
+ insfunc_element (FILES),
+ insfunc_element (PAPER),
+ insfunc_element (PEN),
+ insfunc_element (SHELL),
+ insfunc_element (MERGE),
+ insfunc_element (CHDIR),
+ insfunc_element (MKDIR),
+ insfunc_element (RMDIR),
+ insfunc_element (SYNCHRONIZE),
+ insfunc_element (PAUSE),
+ insfunc_element (CHAIN),
+ insfunc_element (ENVIRON),
+ insfunc_element (EDIT),
+ insfunc_element (DRAWR),
+ insfunc_element (PLOTR),
+ insfunc_element (MOVER),
+ insfunc_element (POKE16),
+ insfunc_element (POKE32),
+ insfunc_element (RENUM),
+ insfunc_element (CIRCLE),
+ insfunc_element (MASK),
+ insfunc_element (WINDOW),
+ insfunc_element (GRAPHICS),
+ insfunc_element (BEEP),
+ insfunc_element (DEFINT),
+
+ // DEFINT, DEFSTR, DEFREAL, DEFSNG and DEFDBL use same function.
+ insfunc_alias (DEFSTR, DEFINT),
+ insfunc_alias (DEFREAL, DEFINT),
+ insfunc_alias (DEFSNG, DEFINT),
+ insfunc_alias (DEFDBL, DEFINT),
+
+ insfunc_element (INK),
+ insfunc_element (SET_TITLE),
+ insfunc_element (TAG),
+
+ // TAG and TAGOFF use same function.
+ insfunc_alias (TAGOFF, TAG),
+
+ insfunc_element (ORIGIN),
+ insfunc_element (DEG),
+
+ // DEG and RAD use same function.
+ insfunc_alias (RAD, DEG),
+
+ insfunc_element (INVERSE),
+ insfunc_element (IF_DEBUG),
+
+ // LPRINT and PRINT use same function.
+ insfunc_alias (LPRINT, PRINT),
+
+ insfunc_element (LLIST),
+ insfunc_element (WIDTH),
+ insfunc_element (BRIGHT),
+ insfunc_element (DRAWARC),
+ insfunc_element (PULL),
+ insfunc_element (PAINT),
+ insfunc_element (FREE_MEMORY),
+ insfunc_element (SCROLL),
+ insfunc_element (ZX_PLOT),
+ insfunc_element (ZX_UNPLOT),
+
+ mixfunc_element (MID_S),
+ valfunc_element (LEFT_S),
+ valfunc_element (RIGHT_S),
+ valfunc_element (CHR_S),
+ valfunc_element (ENVIRON_S),
+ valfunc_element (STRING_S),
+ valfunc_element (OSFAMILY_S),
+ valfunc_element (HEX_S),
+ valfunc_element (SPACE_S),
+ valfunc_element (UPPER_S),
+ valfunc_element (LOWER_S),
+ valfunc_element (STR_S),
+ valfunc_element (OCT_S),
+ valfunc_element (BIN_S),
+ valfunc_element (INKEY_S),
+ mixfunc_element (PROGRAMARG_S),
+ valfunc_element (DATE_S),
+ valfunc_element (TIME_S),
+ valfunc_element (INPUT_S),
+ valfunc_element (MKI_S),
+ valfunc_element (MKS_S),
+ valfunc_element (MKD_S),
+ valfunc_element (MKL_S),
+ valfunc_element (TRIM_S),
+ valfunc_element (LTRIM_S),
+ valfunc_element (RTRIM_S),
+ valfunc_element (OSNAME_S),
+ valfunc_element (FINDFIRST_S),
+ valfunc_element (FINDNEXT_S),
+ valfunc_element (COPYCHR_S),
+ valfunc_element (STRERR_S),
+ valfunc_element (DEC_S),
+ valfunc_element (VAL_S),
+ valfunc_element (SCREEN_S),
+ valfunc_element (MKSMBF_S),
+ valfunc_element (MKDMBF_S),
+ valfunc_element (REGEXP_REPLACE_S),
+ // UCASE$ and LCASE$ are alias for UPPER$ and LOWER$
+ valfunc_alias (UCASE_S, UPPER_S),
+ valfunc_alias (LCASE_S, LOWER_S),
+
+ valfunc_element (ASC),
+ valfunc_element (LEN),
+ valfunc_element (PEEK),
+ valfunc_element (PROGRAMPTR),
+ valfunc_element (RND),
+ valfunc_element (INT),
+ valfunc_element (SIN),
+ valfunc_element (COS),
+ valfunc_element (PI),
+ valfunc_element (TAN),
+ valfunc_element (SQR),
+ valfunc_element (ASIN),
+ valfunc_element (ACOS),
+ valfunc_element (INSTR),
+ valfunc_element (ATAN),
+ valfunc_element (ABS),
+ valfunc_element (USR),
+ valfunc_element (VAL),
+ valfunc_element (EOF),
+ valfunc_element (VARPTR),
+ valfunc_element (SYSVARPTR),
+ valfunc_element (SGN),
+ valfunc_element (LOG),
+ valfunc_element (LOG10),
+ valfunc_element (EXP),
+ valfunc_element (TIME),
+ valfunc_element (ERR),
+ valfunc_element (ERL),
+ valfunc_element (CVI),
+ valfunc_element (CVS),
+ valfunc_element (CVD),
+ valfunc_element (CVL),
+ valfunc_element (MIN),
+ valfunc_element (MAX),
+ valfunc_element (CINT),
+ valfunc_element (FIX),
+ valfunc_element (XMOUSE),
+ valfunc_element (YMOUSE),
+ valfunc_element (XPOS),
+ valfunc_element (YPOS),
+ valfunc_element (PEEK16),
+ valfunc_element (PEEK32),
+ valfunc_element (RINSTR),
+ valfunc_element (FIND_FIRST_OF),
+ valfunc_element (FIND_LAST_OF),
+ valfunc_element (FIND_FIRST_NOT_OF),
+ valfunc_element (FIND_LAST_NOT_OF),
+ valfunc_element (SINH),
+ valfunc_element (COSH),
+ valfunc_element (TANH),
+ valfunc_element (ASINH),
+ valfunc_element (ACOSH),
+ valfunc_element (ATANH),
+ valfunc_element (ATAN2),
+ valfunc_element (TEST),
+ valfunc_element (TESTR),
+ valfunc_element (POS),
+ valfunc_element (VPOS),
+ valfunc_element (LOF),
+ valfunc_element (FREEFILE),
+ valfunc_element (INKEY),
+ valfunc_element (ROUND),
+ valfunc_element (CVSMBF),
+ valfunc_element (CVDMBF),
+ valfunc_element (REGEXP_INSTR),
+ valfunc_element (ALLOC_MEMORY),
+ valfunc_element (LOC),
+
+ mixfunc_element (IDENTIFIER),
+ mixfunc_element (NUMBER),
+ valfunc_element (STRING),
+ mixfunc_element (INTEGER),
+ insfunc_element (ENDLINE),
+
+ // Table used ends here.
+ // Serch returning end to indicate fail point
+ // to the next entry.
+
+ {0, { & RunnerLineImpl::syntax_error,
+ & RunnerLineImpl::valsyntax_error } },
+};
+
+const RunnerLineImpl::tfunctions_t * RunnerLineImpl::tfunctionsend=
+ tfunctions + dim_array (tfunctions) - 1;
+
+#else
+// No ONE_TABLE
+
+#ifndef INSTRUCTION_SWITCH
+
+#define tfunc_t_element(elem) {key##elem, & RunnerLineImpl::do_##elem}
+
+const RunnerLineImpl::tfunc_t RunnerLineImpl::tfunc []=
+{
+ tfunc_t_element (Colon),
+ tfunc_t_element (END),
+ tfunc_t_element (LIST),
+ tfunc_t_element (REM),
+ tfunc_t_element (LOAD),
+ tfunc_t_element (SAVE),
+ tfunc_t_element (NEW),
+ tfunc_t_element (EXIT),
+ tfunc_t_element (RUN),
+ tfunc_t_element (PRINT),
+ tfunc_t_element (FOR),
+ tfunc_t_element (NEXT),
+ tfunc_t_element (IF),
+ tfunc_t_element (ELSE),
+ tfunc_t_element (TRON),
+ tfunc_t_element (TROFF),
+ tfunc_t_element (LET),
+ tfunc_t_element (GOTO),
+ tfunc_t_element (STOP),
+ tfunc_t_element (CONT),
+ tfunc_t_element (CLEAR),
+ tfunc_t_element (GOSUB),
+ tfunc_t_element (RETURN),
+ tfunc_t_element (POKE),
+ tfunc_t_element (DATA),
+ tfunc_t_element (READ),
+ tfunc_t_element (RESTORE),
+ tfunc_t_element (INPUT),
+ tfunc_t_element (LINE),
+ tfunc_t_element (RANDOMIZE),
+ tfunc_t_element (PLEASE),
+ tfunc_t_element (AUTO),
+ tfunc_t_element (DIM),
+ tfunc_t_element (SYSTEM),
+ tfunc_t_element (ON),
+ tfunc_t_element (ERROR),
+ tfunc_t_element (OPEN),
+ tfunc_t_element (CLOSE),
+ tfunc_t_element (LOCATE),
+ tfunc_t_element (CLS),
+ tfunc_t_element (WRITE),
+ tfunc_t_element (MODE),
+ tfunc_t_element (MOVE),
+ tfunc_t_element (COLOR),
+ tfunc_t_element (GET),
+ tfunc_t_element (LABEL),
+ tfunc_t_element (DELIMITER),
+ tfunc_t_element (REPEAT),
+ tfunc_t_element (UNTIL),
+ tfunc_t_element (WHILE),
+ tfunc_t_element (WEND),
+ tfunc_t_element (PLOT),
+ tfunc_t_element (POPEN),
+ tfunc_t_element (RESUME),
+ tfunc_t_element (DELETE),
+ tfunc_t_element (LOCAL),
+ tfunc_t_element (PUT),
+ tfunc_t_element (FIELD),
+ tfunc_t_element (LSET),
+
+ // Lset and rset use same function.
+ {keyRSET, & RunnerLineImpl::do_LSET},
+
+ tfunc_t_element (SOCKET),
+ tfunc_t_element (DRAW),
+ tfunc_t_element (DEF),
+ tfunc_t_element (FN),
+ tfunc_t_element (ERASE),
+ tfunc_t_element (SWAP),
+ tfunc_t_element (SYMBOL),
+ tfunc_t_element (ZONE),
+ tfunc_t_element (POP),
+ tfunc_t_element (NAME),
+ tfunc_t_element (KILL),
+ tfunc_t_element (FILES),
+ tfunc_t_element (PAPER),
+ tfunc_t_element (PEN),
+ tfunc_t_element (SHELL),
+ tfunc_t_element (MERGE),
+ tfunc_t_element (CHDIR),
+ tfunc_t_element (MKDIR),
+ tfunc_t_element (RMDIR),
+ tfunc_t_element (SYNCHRONIZE),
+ tfunc_t_element (PAUSE),
+ tfunc_t_element (CHAIN),
+ tfunc_t_element (ENVIRON),
+ tfunc_t_element (EDIT),
+ tfunc_t_element (DRAWR),
+ tfunc_t_element (PLOTR),
+ tfunc_t_element (MOVER),
+ tfunc_t_element (POKE16),
+ tfunc_t_element (POKE32),
+ tfunc_t_element (RENUM),
+ tfunc_t_element (CIRCLE),
+ tfunc_t_element (MASK),
+ tfunc_t_element (WINDOW),
+ tfunc_t_element (GRAPHICS),
+ tfunc_t_element (BEEP),
+ tfunc_t_element (DEFINT),
+
+ // DEFINT, DEFSTR, DEFREAL, DEFSNG and DEFDBL use same function.
+ {keyDEFSTR, & RunnerLineImpl::do_DEFINT},
+ {keyDEFREAL, & RunnerLineImpl::do_DEFINT},
+ {keyDEFSNG, & RunnerLineImpl::do_DEFINT},
+ {keyDEFDBL, & RunnerLineImpl::do_DEFINT},
+
+ tfunc_t_element (INK),
+ tfunc_t_element (SET_TITLE),
+ tfunc_t_element (TAG),
+
+ // TAG and TAGOFF use same function.
+ {keyTAGOFF, & RunnerLineImpl::do_TAG},
+
+ tfunc_t_element (ORIGIN),
+ tfunc_t_element (DEG),
+
+ // DEG and RAD use same function.
+ {keyRAD, & RunnerLineImpl::do_DEG},
+
+ tfunc_t_element (INVERSE),
+ tfunc_t_element (IF_DEBUG),
+
+ // LPRINT and PRINT use same function.
+ {keyLPRINT, & RunnerLineImpl::do_PRINT},
+
+ tfunc_t_element (LLIST),
+ tfunc_t_element (WIDTH),
+ tfunc_t_element (BRIGHT),
+ tfunc_t_element (DRAWARC),
+ tfunc_t_element (PULL),
+ tfunc_t_element (PAINT),
+ tfunc_t_element (FREE_MEMORY),
+ tfunc_t_element (SCROLL),
+ tfunc_t_element (ZX_PLOT),
+ tfunc_t_element (ZX_UNPLOT),
+
+ tfunc_t_element (MID_S),
+ tfunc_t_element (PROGRAMARG_S),
+
+ {keyIDENTIFIER, & RunnerLineImpl::do_IDENTIFIER},
+ tfunc_t_element (NUMBER),
+ {keyINTEGER, & RunnerLineImpl::do_NUMBER},
+ tfunc_t_element (ENDLINE),
+
+ // Table used ends here.
+ // Serch returning end to indicate fail point
+ // to the next entry.
+
+ {0, & RunnerLineImpl::syntax_error },
+};
+
+const RunnerLineImpl::tfunc_t * RunnerLineImpl::tfuncend=
+ tfunc + dim_array (tfunc) - 1;
+
+#endif
+// INSTRUCTION_SWITCH
+
+
+#ifndef OPERATION_SWITCH
+
+#define valfunction_t_element(elem) {key##elem, & RunnerLineImpl::val_##elem}
+
+const RunnerLineImpl::valfunction_t RunnerLineImpl::valfunction []=
+{
+ valfunction_t_element (OpenPar),
+
+ valfunction_t_element (LET),
+ valfunction_t_element (LABEL),
+ valfunction_t_element (FN),
+
+ valfunction_t_element (MID_S),
+ valfunction_t_element (LEFT_S),
+ valfunction_t_element (RIGHT_S),
+ valfunction_t_element (CHR_S),
+ valfunction_t_element (ENVIRON_S),
+ valfunction_t_element (STRING_S),
+ valfunction_t_element (OSFAMILY_S),
+ valfunction_t_element (HEX_S),
+ valfunction_t_element (SPACE_S),
+ valfunction_t_element (UPPER_S),
+ valfunction_t_element (LOWER_S),
+ valfunction_t_element (STR_S),
+ valfunction_t_element (OCT_S),
+ valfunction_t_element (BIN_S),
+ valfunction_t_element (INKEY_S),
+ valfunction_t_element (PROGRAMARG_S),
+ valfunction_t_element (DATE_S),
+ valfunction_t_element (TIME_S),
+ valfunction_t_element (INPUT_S),
+ valfunction_t_element (MKI_S),
+ valfunction_t_element (MKS_S),
+ valfunction_t_element (MKD_S),
+ valfunction_t_element (MKL_S),
+ valfunction_t_element (TRIM_S),
+ valfunction_t_element (LTRIM_S),
+ valfunction_t_element (RTRIM_S),
+ valfunction_t_element (OSNAME_S),
+ valfunction_t_element (FINDFIRST_S),
+ valfunction_t_element (FINDNEXT_S),
+ valfunction_t_element (COPYCHR_S),
+ valfunction_t_element (STRERR_S),
+ valfunction_t_element (DEC_S),
+ valfunction_t_element (VAL_S),
+ valfunction_t_element (SCREEN_S),
+ valfunction_t_element (MKSMBF_S),
+ valfunction_t_element (MKDMBF_S),
+ valfunction_t_element (REGEXP_REPLACE_S),
+ // UCASE$ and LCASE$ are alias for UPPER$ and LOWER$
+ { keyUCASE_S, & RunnerLineImpl::val_UPPER_S},
+ { keyLCASE_S, & RunnerLineImpl::val_LOWER_S},
+
+ valfunction_t_element (ASC),
+ valfunction_t_element (LEN),
+ valfunction_t_element (PEEK),
+ valfunction_t_element (PROGRAMPTR),
+ valfunction_t_element (RND),
+ valfunction_t_element (INT),
+ valfunction_t_element (SIN),
+ valfunction_t_element (COS),
+ valfunction_t_element (PI),
+ valfunction_t_element (TAN),
+ valfunction_t_element (SQR),
+ valfunction_t_element (ASIN),
+ valfunction_t_element (ACOS),
+ valfunction_t_element (INSTR),
+ valfunction_t_element (ATAN),
+ valfunction_t_element (ABS),
+ valfunction_t_element (USR),
+ valfunction_t_element (VAL),
+ valfunction_t_element (EOF),
+ valfunction_t_element (VARPTR),
+ valfunction_t_element (SYSVARPTR),
+ valfunction_t_element (SGN),
+ valfunction_t_element (LOG),
+ valfunction_t_element (LOG10),
+ valfunction_t_element (EXP),
+ valfunction_t_element (TIME),
+ valfunction_t_element (ERR),
+ valfunction_t_element (ERL),
+ valfunction_t_element (CVI),
+ valfunction_t_element (CVS),
+ valfunction_t_element (CVD),
+ valfunction_t_element (CVL),
+ valfunction_t_element (MIN),
+ valfunction_t_element (MAX),
+ valfunction_t_element (CINT),
+ valfunction_t_element (FIX),
+ valfunction_t_element (XMOUSE),
+ valfunction_t_element (YMOUSE),
+ valfunction_t_element (XPOS),
+ valfunction_t_element (YPOS),
+ valfunction_t_element (PEEK16),
+ valfunction_t_element (PEEK32),
+ valfunction_t_element (RINSTR),
+ valfunction_t_element (FIND_FIRST_OF),
+ valfunction_t_element (FIND_LAST_OF),
+ valfunction_t_element (FIND_FIRST_NOT_OF),
+ valfunction_t_element (FIND_LAST_NOT_OF),
+ valfunction_t_element (SINH),
+ valfunction_t_element (COSH),
+ valfunction_t_element (TANH),
+ valfunction_t_element (ASINH),
+ valfunction_t_element (ACOSH),
+ valfunction_t_element (ATANH),
+ valfunction_t_element (ATAN2),
+ valfunction_t_element (TEST),
+ valfunction_t_element (TESTR),
+ valfunction_t_element (POS),
+ valfunction_t_element (VPOS),
+ valfunction_t_element (LOF),
+ valfunction_t_element (FREEFILE),
+ valfunction_t_element (INKEY),
+ valfunction_t_element (ROUND),
+ valfunction_t_element (CVSMBF),
+ valfunction_t_element (CVDMBF),
+ valfunction_t_element (REGEXP_INSTR),
+ valfunction_t_element (ALLOC_MEMORY),
+ valfunction_t_element (LOC),
+
+ valfunction_t_element (IDENTIFIER),
+ valfunction_t_element (NUMBER),
+ valfunction_t_element (STRING),
+ valfunction_t_element (INTEGER),
+
+ // Table used ends here.
+ // Serch returning end to indicate fail point
+ // to the next entry.
+
+ {0, & RunnerLineImpl::valsyntax_error },
+};
+
+const RunnerLineImpl::valfunction_t * RunnerLineImpl::valfunctionend=
+ valfunction + dim_array (valfunction) - 1;
+
+#endif
+// OPERATION_SWITCH
+
+
+#endif
+// ONE_TABLE
+
+
+#ifndef NDEBUG
+
+bool RunnerLineImpl::checktfunc ()
+{
+ #ifdef ONE_TABLE
+
+ for (size_t i= 1; i < dim_array (tfunctions) - 1; ++i)
+ {
+ if (tfunctions [i - 1].code >= tfunctions [i].code)
+ {
+ cerr << "Failed check of tfunctions in " <<
+ i << endl;
+ abort ();
+ }
+ }
+
+ #else
+ // No ONE_TABLE
+
+ #ifndef INSTRUCTION_SWITCH
+
+ for (size_t i= 1; i < dim_array (tfunc) - 1; ++i)
+ {
+ if (tfunc [i - 1].code >= tfunc [i].code)
+ {
+ cerr << "Failed check of tfunc in " <<
+ i << endl;
+ abort ();
+ }
+ }
+
+ #endif
+ // INSTRUCTION_SWITCH
+
+ #ifndef OPERATION_SWITCH
+
+ for (size_t i= 1; i < dim_array (valfunction) - 1; ++i)
+ {
+ if (valfunction [i - 1].code >= valfunction [i].code)
+ {
+ cerr << "Failed check on valfunction in " <<
+ i << endl;
+ abort ();
+ }
+ }
+
+ #endif
+ // OPERATION_SWITCH
+
+ #endif
+ // ONE_TABLE
+
+ return true;
+}
+
+const bool RunnerLineImpl::tfuncchecked= checktfunc ();
+
+#endif
+
+#ifdef BRUTAL_MODE
+
+#ifdef ONE_TABLE
+
+RunnerLineImpl::functions_t
+ RunnerLineImpl::array_functions [keyMAX_CODE_USED + 1];
+
+#else
+
+RunnerLineImpl::do_func RunnerLineImpl::array_func [keyMAX_CODE_USED + 1];
+
+RunnerLineImpl::do_valfunction
+ RunnerLineImpl::array_valfunction [keyMAX_CODE_USED + 1];
+
+#endif
+
+bool RunnerLineImpl::init_array_func ()
+{
+ #ifdef ONE_TABLE
+
+ // This intializer generates an internal error in some
+ // old versions of gcc.
+ //functions_t emptyfunc= { & RunnerLineImpl::syntax_error,
+ // & RunnerLineImpl::valsyntax_error };
+ functions_t emptyfunc;
+ emptyfunc.inst_func= & RunnerLineImpl::syntax_error;
+ emptyfunc.val_func= & RunnerLineImpl::valsyntax_error;
+
+ std::fill (array_functions,
+ array_functions + dim_array (array_functions),
+ emptyfunc);
+ for (const tfunctions_t * p= tfunctions; p != tfunctionsend; ++p)
+ array_functions [p->code]= p->f;
+
+ #else
+
+ std::fill (array_func, array_func + dim_array (array_func),
+ & RunnerLineImpl::syntax_error);
+ for (const tfunc_t * p= tfunc; p != tfuncend; ++p)
+ array_func [p->code]= p->f;
+
+ std::fill (array_valfunction,
+ array_valfunction + dim_array (array_valfunction),
+ & RunnerLineImpl::valsyntax_error);
+ for (const valfunction_t * p= valfunction; p != valfunctionend; ++p)
+ array_valfunction [p->code]= p->f;
+
+ #endif
+
+ return true;
+}
+
+bool RunnerLineImpl::array_func_inited= init_array_func ();
+
+#endif
+
+
+#ifdef BRUTAL_MODE
+
+#ifdef ONE_TABLE
+
+RunnerLineImpl::do_func RunnerLineImpl::findfunc (BlCode code)
+{
+ return array_functions [code].inst_func;
+}
+
+RunnerLineImpl::do_valfunction RunnerLineImpl::findvalfunc (BlCode code)
+{
+ return array_functions [code].val_func;
+}
+
+#else
+// No ONE_TABLE
+
+RunnerLineImpl::do_func RunnerLineImpl::findfunc (BlCode code)
+{
+ return array_func [code];
+}
+
+RunnerLineImpl::do_valfunction RunnerLineImpl::findvalfunc (BlCode code)
+{
+ return array_valfunction [code];
+}
+
+#endif
+
+#else
+// No BRUTAL_MODE
+
+
+#ifdef ONE_TABLE
+
+RunnerLineImpl::do_func RunnerLineImpl::findfunc (BlCode code)
+{
+ using std::lower_bound;
+ const tfunctions_t tfs= {code, {NULL, NULL} };
+ const tfunctions_t * ptf=
+ lower_bound <const RunnerLineImpl::tfunctions_t *,
+ const RunnerLineImpl::tfunctions_t>
+ (tfunctions, tfunctionsend, tfs);
+ if (ptf->code != code)
+ return & RunnerLineImpl::syntax_error;
+ else
+ return ptf->f.inst_func;
+}
+
+RunnerLineImpl::do_valfunction RunnerLineImpl::findvalfunc (BlCode code)
+{
+ using std::lower_bound;
+ const tfunctions_t tfs= {code, {NULL, NULL} };
+ const tfunctions_t * ptf=
+ lower_bound <const RunnerLineImpl::tfunctions_t *,
+ const RunnerLineImpl::tfunctions_t>
+ (tfunctions, tfunctionsend, tfs);
+ if (ptf->code != code)
+ return & RunnerLineImpl::valsyntax_error;
+ else
+ return ptf->f.val_func;
+}
+
+#else
+// No ONE_TABLE
+
+#ifndef INSTRUCTION_SWITCH
+
+RunnerLineImpl::do_func RunnerLineImpl::findfunc (BlCode code)
+{
+ using std::lower_bound;
+ const tfunc_t tfs= {code, NULL};
+ // C++ Builder can't deduce the lower_bound template argments,
+ // I don't know why.
+ const tfunc_t * ptf=
+ lower_bound <const RunnerLineImpl::tfunc_t *,
+ const RunnerLineImpl::tfunc_t>
+ (tfunc, tfuncend, tfs);
+ if (ptf->code != code)
+ return & RunnerLineImpl::syntax_error;
+ else
+ return ptf->f;
+}
+
+#endif
+// INSTRUCTION_SWITCH
+
+#ifndef OPERATION_SWITCH
+
+RunnerLineImpl::do_valfunction RunnerLineImpl::findvalfunc (BlCode code)
+{
+ using std::lower_bound;
+ const valfunction_t vfs= { code, NULL};
+ const valfunction_t * pvf=
+ lower_bound <const RunnerLineImpl::valfunction_t *,
+ const RunnerLineImpl::valfunction_t>
+ (valfunction, valfunctionend, vfs);
+ if (pvf->code != code)
+ return & RunnerLineImpl::valsyntax_error;
+ else
+ return pvf->f;
+}
+
+#endif
+// OPERATION_SWITCH
+
+#endif
+// ONE_TABLE
+
+#endif
+// BRUTAL_MODE
+
+
+#if 0
+// Use macros instead to avoid strange errors on hp-ux.
+
+void RunnerLineImpl::requiretoken (BlCode code) const throw (BlErrNo)
+{
+ if (token.code != code)
+ throw ErrSyntax;
+}
+
+void RunnerLineImpl::expecttoken (BlCode code) throw (BlErrNo)
+{
+ gettoken ();
+ requiretoken (code);
+}
+
+#else
+
+#define requiretoken(c) if (token.code == c) ; else throw ErrSyntax
+
+#define expecttoken(c) \
+ do { \
+ gettoken (); \
+ if (token.code != c) throw ErrSyntax; \
+ } while (0)
+
+#endif
+
+
+void RunnerLineImpl::getnextchunk ()
+{
+ while (! endsentence () )
+ gettoken ();
+ if (token.code != keyENDLINE)
+ gettoken ();
+}
+
+BlFile & RunnerLineImpl::getfile (BlChannel channel) const
+{
+ return runner.getfile (channel);
+}
+
+BlFile & RunnerLineImpl::getfile0 () const
+{
+ return runner.getfile0 ();
+}
+
+BlNumber RunnerLineImpl::evalnum ()
+{
+ BlResult result;
+ eval (result);
+ return result.number ();
+}
+
+BlNumber RunnerLineImpl::expectnum ()
+{
+ gettoken ();
+ return evalnum ();
+}
+
+BlInteger RunnerLineImpl::evalinteger ()
+{
+ BlResult result;
+ eval (result);
+ return result.integer ();
+}
+
+BlInteger RunnerLineImpl::expectinteger ()
+{
+ gettoken ();
+ return evalinteger ();
+}
+
+std::string RunnerLineImpl::evalstring ()
+{
+ BlResult result;
+ eval (result);
+ return result.str ();
+}
+
+std::string RunnerLineImpl::expectstring ()
+{
+ gettoken ();
+ return evalstring ();
+}
+
+BlChannel RunnerLineImpl::evalchannel ()
+{
+ BlResult result;
+ eval (result);
+ return util::checked_cast <BlChannel> (result.integer (), ErrMismatch);
+}
+
+BlChannel RunnerLineImpl::expectchannel ()
+{
+ gettoken ();
+ return evalchannel ();
+}
+
+BlChannel RunnerLineImpl::evaloptionalchannel (BlChannel defchan)
+{
+ if (token.code == keySharp)
+ {
+ gettoken ();
+ BlInteger n= evalinteger ();
+ return util::checked_cast <BlChannel> (n, ErrMismatch);
+ }
+ else
+ return defchan;
+}
+
+BlChannel RunnerLineImpl::expectoptionalchannel (BlChannel defchan)
+{
+ gettoken ();
+ return evaloptionalchannel (defchan);
+}
+
+BlChannel RunnerLineImpl::evalrequiredchannel ()
+{
+ if (token.code == keySharp)
+ gettoken ();
+ BlInteger n= evalinteger ();
+ return util::checked_cast <BlChannel> (n, ErrMismatch);
+}
+
+BlChannel RunnerLineImpl::expectrequiredchannel ()
+{
+ gettoken ();
+ return evalrequiredchannel ();
+}
+
+std::string::size_type RunnerLineImpl::evalstringindex ()
+{
+ BlInteger n= evalinteger ();
+ if (n < 1)
+ throw ErrBadSubscript;
+ return static_cast <std::string::size_type> (n);
+}
+
+void RunnerLineImpl::evalstringslice (const std::string & str,
+ std::string::size_type & from, std::string::size_type & to)
+{
+ const std::string::size_type limit= str.size ();
+ from= 0;
+ to= limit;
+ gettoken ();
+ if (token.code != ']')
+ {
+ if (token.code != keyTO)
+ {
+ from= evalstringindex () - 1;
+ if (token.code == keyTO)
+ {
+ gettoken ();
+ if (token.code != ']')
+ to= evalstringindex ();
+ }
+ else
+ to= from + 1;
+ }
+ else
+ {
+ gettoken ();
+ if (token.code != ']')
+ to= evalstringindex ();
+ }
+ requiretoken (']');
+ }
+ gettoken ();
+ if (from < to)
+ {
+ if (from >= limit || to > limit)
+ throw ErrBadSubscript;
+ }
+}
+
+void RunnerLineImpl::assignslice (VarPointer & vp, const BlResult & result)
+{
+ ASSERT (vp.type == VarStringSlice);
+
+ using std::string;
+
+ string & str= * vp.pstring;
+ string value= result.str ();
+ if (vp.from >= vp.to)
+ return;
+ const string::size_type l= vp.to - vp.from;
+ const string::size_type vsize= value.size ();
+ if (l < vsize)
+ value.erase (l);
+ else if (l > vsize)
+ value+= string (l - vsize, ' ');
+ str.replace (vp.from, l, value);
+}
+
+VarPointer RunnerLineImpl::evalvarpointer ()
+{
+ requiretoken (keyIDENTIFIER);
+ std::string varname= token.str;
+ gettoken ();
+ Dimension d;
+ bool isarray= false;
+ bool isslice= false;
+ VarPointer vp;
+ switch (token.code)
+ {
+ case '(':
+ d= getdims ();
+ isarray= true;
+ break;
+ case '[':
+ {
+ if (typeofvar (varname) != VarString)
+ throw ErrMismatch;
+ vp.type= VarStringSlice;
+ vp.pstring= addrvarstring (varname);
+ evalstringslice (* vp.pstring, vp.from, vp.to);
+ }
+ isslice= true;
+ break;
+ default:
+ break;
+ }
+
+ if (! isslice)
+ vp.type= typeofvar (varname);
+
+ switch (vp.type)
+ {
+ case VarNumber:
+ vp.pnumber= isarray ?
+ addrdimnumber (varname, d) :
+ addrvarnumber (varname);
+ break;
+ case VarInteger:
+ vp.pinteger= isarray ?
+ addrdiminteger (varname, d) :
+ addrvarinteger (varname);
+ break;
+ case VarString:
+ vp.pstring= isarray ?
+ addrdimstring (varname, d) :
+ addrvarstring (varname);
+ break;
+ case VarStringSlice:
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ return vp;
+}
+
+void RunnerLineImpl::evalmultivarpointer (ListVarPointer & lvp)
+{
+ for (;;)
+ {
+ VarPointer vp= evalvarpointer ();
+ lvp.push_back (vp);
+ if (token.code != ',')
+ break;
+ gettoken ();
+ }
+}
+
+VarPointer RunnerLineImpl::eval_let ()
+{
+ VarPointer vp= evalvarpointer ();
+ requiretoken ('=');
+ BlResult result;
+ expect (result);
+ switch (vp.type)
+ {
+ case VarNumber:
+ * vp.pnumber= result.number ();
+ break;
+ case VarInteger:
+ * vp.pinteger= result.integer ();
+ break;
+ case VarString:
+ * vp.pstring= result.str ();
+ break;
+ case VarStringSlice:
+ assignslice (vp, result);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ return vp;
+}
+
+void RunnerLineImpl::parenarg (BlResult & result)
+{
+ expect (result);
+ requiretoken (')');
+ gettoken ();
+}
+
+void RunnerLineImpl::getparenarg (BlResult & result)
+{
+ expecttoken ('(');
+ expect (result);
+ requiretoken (')');
+ gettoken ();
+}
+
+void RunnerLineImpl::getparenarg (BlResult & result, BlResult & result2)
+{
+ expecttoken ('(');
+ expect (result);
+ requiretoken (',');
+ expect (result2);
+ requiretoken (')');
+ gettoken ();
+}
+
+BlFile & RunnerLineImpl::getparenfile ()
+{
+ expecttoken ('(');
+ //expecttoken ('#');
+ //BlChannel c= expectchannel ();
+ BlChannel c= expectrequiredchannel ();
+ requiretoken (')');
+ gettoken ();
+ return getfile (c);
+}
+
+namespace {
+
+inline void checkfinite (double n)
+{
+ // Some errors do not set errno, this check can
+ // detect some.
+ #if (defined __unix__ && ! defined __hpux__) \
+ || defined __linux__
+ if (! finite (n) )
+ throw ErrDomain;
+ #else
+ touch (n);
+ #endif
+}
+
+inline double callnumericfunc (double (* f) (double), double n)
+{
+ errno= 0;
+ n= f (n);
+ switch (errno)
+ {
+ case 0:
+ checkfinite (n);
+ break;
+ case EDOM:
+ throw ErrDomain;
+ case ERANGE:
+ throw ErrRange;
+ default:
+ if (showdebuginfo () )
+ cerr << "Math error, errno= " << errno << endl;
+ throw ErrBlassicInternal;
+ }
+ return n;
+}
+
+inline double callnumericfunc (double (* f) (double, double),
+ double n, double n2)
+{
+ errno= 0;
+ n= f (n, n2);
+ switch (errno)
+ {
+ case 0:
+ checkfinite (n);
+ break;
+ case EDOM:
+ throw ErrDomain;
+ case ERANGE:
+ throw ErrRange;
+ default:
+ if (showdebuginfo () )
+ cerr << "Math error, errno= " << errno << endl;
+ throw ErrBlassicInternal;
+ }
+ return n;
+}
+
+} // namespace
+
+void RunnerLineImpl::valnumericfunc (double (* f) (double), BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ BlNumber n= result.number ();
+ result= callnumericfunc (f, n);
+}
+
+void RunnerLineImpl::valnumericfunc2 (double (* f) (double, double),
+ BlResult & result)
+{
+ BlResult result2;
+ getparenarg (result, result2);
+ BlNumber n= result.number ();
+ BlNumber n2= result2.number ();
+ result= callnumericfunc (f, n, n2);
+}
+
+void RunnerLineImpl::valtrigonometricfunc
+ (double (* f) (double), BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ BlNumber n= result.number ();
+ switch (runner.trigonometric_mode () )
+ {
+ case TrigonometricDeg:
+ n*= value_pi_div_180;
+ break;
+ case TrigonometricRad:
+ break;
+ }
+ result= callnumericfunc (f, n);
+}
+
+void RunnerLineImpl::valtrigonometricinvfunc
+ (double (* f) (double), BlResult & result)
+{
+ getparenarg (result);
+ BlNumber n= result.number ();
+ n= callnumericfunc (f, n);
+ // Provisional
+ switch (runner.trigonometric_mode () )
+ {
+ case TrigonometricDeg:
+ n*= value_180_div_pi;
+ break;
+ case TrigonometricRad:
+ break;
+ }
+ result= n;
+}
+
+void RunnerLineImpl::val_ASC (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ const std::string & str= result.str ();
+ if (str.empty () ) result= 0L;
+ else result= BlInteger ( (unsigned char) str [0] );
+}
+
+void RunnerLineImpl::val_LEN (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ result= result.str ().size ();
+}
+
+void RunnerLineImpl::val_PEEK (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ BlChar * addr= (BlChar *) size_t (result.number () );
+ //result= BlNumber (size_t (* addr) );
+ result= BlInteger (size_t (* addr) );
+}
+
+void RunnerLineImpl::val_PEEK16 (BlResult & result)
+{
+ getparenarg (result);
+ BlChar * addr= (BlChar *) size_t (result.number () );
+ result= peek16 (addr);
+}
+
+void RunnerLineImpl::val_PEEK32 (BlResult & result)
+{
+ getparenarg (result);
+ BlChar * addr= (BlChar *) size_t (result.number () );
+ //result= BlNumber (static_cast <unsigned long> (peek32 (addr) ) );
+ result= peek32 (addr);
+}
+
+void RunnerLineImpl::val_PROGRAMPTR (BlResult & result)
+{
+ gettoken ();
+ //result= BlNumber (size_t (program.programptr () ) );
+ result= static_cast <BlInteger> (size_t (program.programptr () ) );
+}
+
+void RunnerLineImpl::val_SYSVARPTR (BlResult & result)
+{
+ gettoken ();
+ result= sysvar::address ();
+}
+
+void RunnerLineImpl::val_RND (BlResult & result)
+{
+ BlNumber n;
+ gettoken ();
+ if (token.code == '(')
+ {
+ parenarg (result);
+ n= result.number ();
+ }
+ else n= 1;
+
+ static BlNumber previous= 0;
+
+ if (n == 0)
+ {
+ result= previous;
+ return;
+ }
+
+ if (n < 0)
+ //srand (time (0) );
+ runner.seedrandom (time (0) );
+
+ BlNumber r= runner.getrandom ();
+ result= r;
+ previous= r;
+}
+
+void RunnerLineImpl::val_INT (BlResult & result)
+{
+ valnumericfunc (floor, result);
+}
+
+void RunnerLineImpl::val_SIN (BlResult & result)
+{
+ valtrigonometricfunc (sin, result);
+}
+
+void RunnerLineImpl::val_COS (BlResult & result)
+{
+ valtrigonometricfunc (cos, result);
+}
+
+void RunnerLineImpl::val_PI (BlResult & result)
+{
+ result= value_pi;
+ gettoken ();
+}
+
+void RunnerLineImpl::val_TAN (BlResult & result)
+{
+ valtrigonometricfunc (tan, result);
+}
+
+void RunnerLineImpl::val_SQR (BlResult & result)
+{
+ valnumericfunc (sqrt, result);
+}
+
+void RunnerLineImpl::val_ASIN (BlResult & result)
+{
+ valtrigonometricinvfunc (asin, result);
+}
+
+void RunnerLineImpl::val_ACOS (BlResult & result)
+{
+ valtrigonometricinvfunc (acos, result);
+}
+
+void RunnerLineImpl::val_ATAN (BlResult & result)
+{
+ valtrigonometricinvfunc (atan, result);
+}
+
+void RunnerLineImpl::val_ABS (BlResult & result)
+{
+ valnumericfunc (fabs, result);
+}
+
+void RunnerLineImpl::val_LOG (BlResult & result)
+{
+ valnumericfunc (log, result);
+}
+
+void RunnerLineImpl::val_LOG10 (BlResult & result)
+{
+ valnumericfunc (log10, result);
+}
+
+void RunnerLineImpl::val_EXP (BlResult & result)
+{
+ valnumericfunc (exp, result);
+}
+
+void RunnerLineImpl::val_TIME (BlResult & result)
+{
+ result= BlInteger (time (NULL) );
+ gettoken ();
+}
+
+void RunnerLineImpl::val_ERR (BlResult & result)
+{
+ result= static_cast <BlInteger> (runner.geterr () );
+ gettoken ();
+}
+
+void RunnerLineImpl::val_ERL (BlResult & result)
+{
+ result= static_cast <BlInteger> (runner.geterrline () );
+ gettoken ();
+}
+
+void RunnerLineImpl::val_FIX (BlResult & result)
+{
+ valnumericfunc (auxFIX, result);
+}
+
+void RunnerLineImpl::val_XMOUSE (BlResult & result)
+{
+ result= static_cast <BlInteger> (graphics::xmouse () );
+ gettoken ();
+}
+
+void RunnerLineImpl::val_YMOUSE (BlResult & result)
+{
+ result= static_cast <BlInteger> (graphics::ymouse () );
+ gettoken ();
+}
+
+void RunnerLineImpl::val_XPOS (BlResult & result)
+{
+ result= graphics::xpos ();
+ gettoken ();
+}
+
+void RunnerLineImpl::val_YPOS (BlResult & result)
+{
+ result= graphics::ypos ();
+ gettoken ();
+}
+
+void RunnerLineImpl::val_SINH (BlResult & result)
+{
+ valnumericfunc (sinh, result);
+}
+
+void RunnerLineImpl::val_COSH (BlResult & result)
+{
+ valnumericfunc (cosh, result);
+}
+
+void RunnerLineImpl::val_TANH (BlResult & result)
+{
+ valnumericfunc (tanh, result);
+}
+
+void RunnerLineImpl::val_ASINH (BlResult & result)
+{
+ valnumericfunc (auxmath::asinh, result);
+}
+
+void RunnerLineImpl::val_ACOSH (BlResult & result)
+{
+ valnumericfunc (auxmath::acosh, result);
+}
+
+void RunnerLineImpl::val_ATANH (BlResult & result)
+{
+ valnumericfunc (auxmath::atanh, result);
+}
+
+void RunnerLineImpl::val_ATAN2 (BlResult & result)
+{
+ valnumericfunc2 (atan2, result);
+}
+
+namespace {
+
+// Flags to valinstr calls.
+
+const bool instr_direct= false;
+const bool instr_reverse= true;
+
+} // namespace
+
+void RunnerLineImpl::valinstrbase (BlResult & result, bool reverse)
+{
+ expecttoken ('(');
+ std::string str;
+ std::string::size_type init= reverse ? std::string::npos : 0;
+
+ expect (result);
+ switch (result.type () )
+ {
+ case VarString:
+ str= result.str ();
+ break;
+ case VarNumber:
+ #if 0
+ init= std::string::size_type (result.number () );
+ if (init > 0)
+ --init;
+ requiretoken (',');
+ str= expectstring ();
+ break;
+ #endif
+ case VarInteger:
+ init= result.integer ();
+ //if (init > 0)
+ // --init;
+ if (init < 1)
+ throw ErrFunctionCall;
+ --init;
+ requiretoken (',');
+ str= expectstring ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ requiretoken (',');
+ std::string tofind= expectstring ();
+ requiretoken (')');
+ gettoken ();
+ std::string::size_type pos;
+ if (tofind.empty () )
+ {
+ if (str.empty () )
+ pos= 0;
+ else
+ if (init < str.size () )
+ pos= init + 1;
+ else
+ pos= 0;
+ }
+ else
+ {
+ pos= reverse ?
+ str.rfind (tofind, init) :
+ str.find (tofind, init);
+ if (pos == std::string::npos)
+ pos= 0;
+ else ++pos;
+ }
+ result= BlInteger (pos);
+}
+
+void RunnerLineImpl::val_INSTR (BlResult & result)
+{
+ valinstrbase (result, instr_direct);
+}
+
+void RunnerLineImpl::val_RINSTR (BlResult & result)
+{
+ valinstrbase (result, instr_reverse);
+}
+
+namespace {
+
+// Flags to valfindfirstlast calls.
+
+const bool find_first= true;
+const bool find_last= false;
+const bool find_yes= true;
+const bool find_not= false;
+
+} // namespace
+
+void RunnerLineImpl::valfindfirstlast (BlResult & result, bool first, bool yesno)
+{
+ expecttoken ('(');
+ std::string str;
+ std::string::size_type init= first ? 0 : std::string::npos;
+
+ expect (result);
+ switch (result.type () )
+ {
+ case VarString:
+ str= result.str ();
+ break;
+ case VarNumber:
+ init= std::string::size_type (result.number () );
+ if (init > 0)
+ --init;
+ requiretoken (',');
+ str= expectstring ();
+ break;
+ case VarInteger:
+ init= result.integer ();
+ if (init > 0)
+ --init;
+ requiretoken (',');
+ str= expectstring ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ requiretoken (',');
+ std::string tofind= expectstring ();
+ requiretoken (')');
+ gettoken ();
+ std::string::size_type pos;
+ if (tofind.empty () )
+ {
+ if (str.empty () )
+ pos= 0;
+ else
+ if (init < str.size () )
+ pos= init + 1;
+ else
+ pos= 0;
+ }
+ else
+ {
+ pos= first ?
+ ( yesno ? str.find_first_of (tofind, init) :
+ str.find_first_not_of (tofind, init) )
+ :
+ (yesno ? str.find_last_of (tofind, init) :
+ str.find_last_not_of (tofind, init) );
+ if (pos == std::string::npos)
+ pos= 0;
+ else ++pos;
+ }
+ result= BlInteger (pos);
+}
+
+void RunnerLineImpl::val_FIND_FIRST_OF (BlResult & result)
+{
+ valfindfirstlast (result, find_first, find_yes);
+}
+
+void RunnerLineImpl::val_FIND_LAST_OF (BlResult & result)
+{
+ valfindfirstlast (result, find_last, find_yes);
+}
+
+void RunnerLineImpl::val_FIND_FIRST_NOT_OF (BlResult & result)
+{
+ valfindfirstlast (result, find_first, find_not);
+}
+
+void RunnerLineImpl::val_FIND_LAST_NOT_OF (BlResult & result)
+{
+ valfindfirstlast (result, find_last, find_not);
+}
+
+namespace {
+
+
+unsigned long spectrumUDGcode (const std::string & str)
+{
+ if (str.size () != 1)
+ throw ErrImproperArgument;
+ unsigned char c= str [0];
+ const unsigned char base= 144;
+
+ // Changed this. Now instead of the Spectrum limit of 'u'
+ // a to z are allowed.
+
+ if (c >= 'a' && c <= 'z')
+ c= static_cast <unsigned char>
+ (c - 'a' + base);
+ else if (c >= 'A' && c <= 'Z')
+ c= static_cast <unsigned char>
+ (c - 'A' + base);
+ else if (c < 144 || c > 169)
+ throw ErrImproperArgument;
+
+ return sysvar::get32 (sysvar::CharGen) + c * 8;
+}
+
+} // namespace
+
+void RunnerLineImpl::val_USR (BlResult & result)
+{
+ gettoken ();
+ if (token.code != '(')
+ {
+ // Without parenthesis only Spectrum style
+ // USR char is allowed.
+ //valparen (result);
+ valbase (result);
+ result= spectrumUDGcode (result.str() );
+ return;
+ }
+ DynamicUsrFunc symaddr;
+ DynamicHandle libhandle;
+
+ // These are now defined here to avoid an error
+ // in C++ Builder.
+ std::vector <int> vparam;
+ util::auto_buffer <int> param;
+
+ expect (result);
+ switch (result.type () )
+ {
+ case VarNumber:
+ case VarInteger:
+ symaddr= (DynamicUsrFunc) result.integer ();
+ break;
+ case VarString:
+ {
+ std::string libname= result.str ();
+ switch (token.code)
+ {
+ case ',':
+ break;
+ case ')':
+ // Spectrum USR character.
+ result= spectrumUDGcode (libname);
+ gettoken ();
+ return;
+ default:
+ throw ErrSyntax;
+ }
+ std::string funcname= expectstring ();
+ libhandle.assign (libname);
+ symaddr= libhandle.addr (funcname);
+ }
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+
+ int nparams= 0;
+ //std::vector <int> vparam;
+ while (token.code == ',')
+ {
+ expect (result);
+ vparam.push_back (result.integer () );
+ ++nparams;
+ }
+ requiretoken (')');
+ gettoken ();
+ //util::auto_buffer <int> param;
+ if (nparams)
+ {
+ param.alloc (nparams);
+ std::copy (vparam.begin (), vparam.end (), param.begin () );
+ }
+
+ result= (* symaddr) (nparams, param);
+}
+
+void RunnerLineImpl::val_VAL (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ std::string str= result.str ();
+ switch (sysvar::get (sysvar::TypeOfVal) )
+ {
+ case 0:
+ // VAL simple.
+ {
+ #if 0
+ size_t i= 0, l= str.size ();
+ while (i < l && str [i] == ' ')
+ ++i;
+ #else
+ std::string::size_type i=
+ str.find_first_not_of (" \t");
+ if (i > 0)
+ if (i == std::string::npos)
+ str.erase ();
+ else
+ str= str.substr (i);
+ #endif
+ }
+ result= CodeLine::Token::number (str);
+ break;
+ case 1:
+ // VAL with expression evaluation (Sinclair ZX)
+ if (str.find_first_not_of (" \t")
+ == std::string::npos)
+ {
+ result= 0L;
+ break;
+ }
+ str= std::string ("0 ") + str;
+ {
+ #if 1
+
+ CodeLine valcodeline;
+ valcodeline.scan (str);
+ RunnerLineImpl valrunnerline (runner, valcodeline);
+
+ #else
+
+ RunnerLineImpl valrunnerline (runner);
+ CodeLine & valcodeline= valrunnerline.getcodeline ();
+ valcodeline.scan (str);
+
+ #endif
+
+ valrunnerline.expect (result);
+ if (valrunnerline.token.code != keyENDLINE)
+ throw ErrSyntax;
+ }
+ if (! result.is_numeric () )
+ throw ErrMismatch;
+ break;
+ default:
+ throw ErrNotImplemented;
+ }
+}
+
+void RunnerLineImpl::val_EOF (BlResult & result)
+{
+ // Change to accept the form: EOF (#file)
+ //getparenarg (result);
+
+ expecttoken (keyOpenPar);
+ gettoken ();
+ if (token.code == keySharp)
+ gettoken ();
+ eval (result);
+ requiretoken (')');
+ gettoken ();
+
+ BlChannel channel= BlChannel (result.integer () );
+ BlFile & file= getfile (channel);
+ result= BlInteger (file.eof () ? -1 : 0);
+}
+
+void RunnerLineImpl::val_VARPTR (BlResult & result)
+{
+ expecttoken ('(');
+ expecttoken (keyIDENTIFIER);
+ std::string varname (token.str);
+ VarType type= typeofvar (varname);
+ size_t addr= 0;
+ gettoken ();
+ switch (token.code)
+ {
+ case ')':
+ // Simple
+ switch (type)
+ {
+ case VarNumber:
+ addr= reinterpret_cast <size_t>
+ (addrvarnumber (varname) );
+ break;
+ case VarInteger:
+ addr= reinterpret_cast <size_t>
+ (addrvarinteger (varname) );
+ break;
+ case VarString:
+ addr= reinterpret_cast <size_t>
+ (addrvarstring (varname) );
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ result= 0L;
+ gettoken ();
+ break;
+ case '(':
+ // Array
+ {
+ Dimension dims= getdims ();
+ result= 0L;
+ requiretoken (')');
+ switch (type)
+ {
+ case VarNumber:
+ addr= reinterpret_cast <size_t>
+ (addrdimnumber (varname, dims) );
+ break;
+ case VarInteger:
+ addr= reinterpret_cast <size_t>
+ (addrdiminteger (varname, dims) );
+ break;
+ case VarString:
+ addr= reinterpret_cast <size_t>
+ (addrdimstring (varname, dims) );
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ gettoken ();
+ }
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ //result= BlNumber (addr);
+ result= static_cast <BlInteger> (addr);
+}
+
+void RunnerLineImpl::val_SGN (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ BlNumber d= result.number ();
+ // Do not use 0.0 instead of zero, is a workaround
+ // for an error on some versions of gcc.
+ result= d < zero ? -1L : d > zero ? 1L : 0L;
+}
+
+void RunnerLineImpl::val_CVI (BlResult & result)
+{
+ getparenarg (result);
+ std::string str (result.str () );
+ if (str.size () < 2)
+ throw ErrFunctionCall;
+ result= BlInteger (short ( (unsigned char) str [0] ) |
+ short ( ( (unsigned char) str [1] ) << 8) );
+}
+
+void RunnerLineImpl::val_CVS (BlResult & result)
+{
+ #define SIZE_S 4
+ ASSERT (sizeof (float) == 4);
+
+ getparenarg (result);
+ const std::string & str (result.str () );
+ if (str.size () < SIZE_S)
+ throw ErrFunctionCall;
+ BlNumber bn= BlNumber
+ (* reinterpret_cast <const float *> (str.data () ) );
+ result= bn;
+
+ #undef SIZE_S
+}
+
+void RunnerLineImpl::val_CVD (BlResult & result)
+{
+ #define SIZE_D 8
+ ASSERT (sizeof (double) == 8);
+
+ getparenarg (result);
+ const std::string & str (result.str () );
+ if (str.size () < SIZE_D)
+ throw ErrFunctionCall;
+ BlNumber bn= static_cast <BlNumber>
+ ( (* reinterpret_cast <const double *> (str.data () ) ) );
+ result= bn;
+ #undef SIZE_D
+}
+
+void RunnerLineImpl::val_CVL (BlResult & result)
+{
+ getparenarg (result);
+ std::string str (result.str () );
+ if (str.size () < 4)
+ throw ErrFunctionCall;
+ result=
+ long ( (unsigned char) str [0] ) |
+ long ( ( (unsigned char) str [1] ) << 8) |
+ long ( ( (unsigned char) str [2] ) << 16) |
+ long ( ( (unsigned char) str [3] ) << 24);
+}
+
+void RunnerLineImpl::val_MIN (BlResult & result)
+{
+ expecttoken ('(');
+ BlNumber bnMin= expectnum ();
+ while (token.code == ',')
+ bnMin= std::min (bnMin, expectnum () );
+ requiretoken (')');
+ gettoken ();
+ result= bnMin;
+}
+
+void RunnerLineImpl::val_MAX (BlResult & result)
+{
+ expecttoken ('(');
+ BlNumber bnMax= expectnum ();
+ while (token.code == ',')
+ bnMax= std::max (bnMax, expectnum () );
+ requiretoken (')');
+ gettoken ();
+ result= bnMax;
+}
+
+void RunnerLineImpl::val_CINT (BlResult & result)
+{
+ gettoken ();
+ #if 0
+ if (token.code == '(')
+ {
+ expect (result);
+ requiretoken (')');
+ gettoken ();
+ }
+ else
+ eval (result);
+ #else
+ //valparen (result);
+ valbase (result);
+ #endif
+ result= result.integer ();
+}
+
+void RunnerLineImpl::val_TEST (BlResult & result)
+{
+ expecttoken ('(');
+ int x= expectinteger ();
+ requiretoken (',');
+ int y= expectinteger ();
+ requiretoken (')');
+ gettoken ();
+ result= static_cast <BlInteger> (graphics::test (x, y, false) );
+}
+
+void RunnerLineImpl::val_TESTR (BlResult & result)
+{
+ expecttoken ('(');
+ int x= expectinteger ();
+ requiretoken (',');
+ int y= expectinteger ();
+ requiretoken (')');
+ gettoken ();
+ result= static_cast <BlInteger> (graphics::test (x, y, true) );
+}
+
+void RunnerLineImpl::val_POS (BlResult & result)
+{
+ result= static_cast <BlInteger> (getparenfile ().pos () + 1);
+}
+
+void RunnerLineImpl::val_VPOS (BlResult & result)
+{
+ result= getparenfile ().vpos () + 1;
+}
+
+void RunnerLineImpl::val_LOF (BlResult & result)
+{
+ //expecttoken ('(');
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //BlChannel ch= evalchannel ();
+ //requiretoken (')');
+ //gettoken ();
+ //result= getfile (ch).lof ();
+ result= getparenfile ().lof ();
+}
+
+void RunnerLineImpl::val_FREEFILE (BlResult & result)
+{
+ gettoken ();
+ result= runner.freefile ();
+}
+
+void RunnerLineImpl::val_INKEY (BlResult & result)
+{
+ getparenarg (result);
+ result= graphics::keypressed (result.integer () );
+}
+
+void RunnerLineImpl::val_ROUND (BlResult & result)
+{
+ using blassic::result::round;
+ expecttoken ('(');
+ BlNumber n= expectnum ();
+ BlInteger d= 0;
+ if (token.code == ',')
+ d= expectinteger ();
+ requiretoken (')');
+ gettoken ();
+ if (d == 0)
+ result= round (n);
+ else if (d > 0)
+ {
+ for (BlInteger i= 0; i < d; ++i)
+ n*= 10;
+ n= round (n);
+ for (BlInteger i= 0; i < d; ++i)
+ n/= 10;
+ result= n;
+ }
+ else
+ {
+ for (BlInteger i= 0; i > d; --i)
+ n/= 10;
+ n= round (n);
+ for (BlInteger i= 0; i > d; --i)
+ n*= 10;
+ result= n;
+ }
+}
+
+void RunnerLineImpl::val_CVSMBF (BlResult & result)
+{
+ getparenarg (result);
+ const std::string & str (result.str () );
+ result= mbf::mbf_s (str);
+}
+
+void RunnerLineImpl::val_CVDMBF (BlResult & result)
+{
+ getparenarg (result);
+ const std::string & str (result.str () );
+ result= mbf::mbf_d (str);
+}
+
+void RunnerLineImpl::val_REGEXP_INSTR (BlResult & result)
+{
+ expecttoken ('(');
+ std::string searched;
+ std::string::size_type init= 0;
+
+ expect (result);
+ switch (result.type () )
+ {
+ case VarString:
+ searched= result.str ();
+ break;
+ case VarNumber:
+ case VarInteger:
+ init= result.integer ();
+ if (init < 1)
+ throw ErrFunctionCall;
+ --init;
+ requiretoken (',');
+ searched= expectstring ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ requiretoken (',');
+ std::string expr= expectstring ();
+ BlInteger flags= 0;
+ if (token.code == ',')
+ {
+ flags= expectinteger ();
+ }
+ else
+ {
+ // Default flags value depending on the initial position.
+ if (init > 0)
+ flags= Regexp::FLAG_NOBEG;
+ }
+ requiretoken (')');
+ gettoken ();
+
+ Regexp regexp (expr, flags);
+ Regexp::size_type r= regexp.find (searched, init);
+ if (r == std::string::npos)
+ result= 0;
+ else
+ result= r + 1;
+}
+
+void RunnerLineImpl::val_ALLOC_MEMORY (BlResult & result)
+{
+ getparenarg (result);
+ result= blassic::memory::dyn_alloc (result.integer () );
+}
+
+void RunnerLineImpl::val_LOC (BlResult & result)
+{
+ expecttoken (keyOpenPar);
+ gettoken ();
+ if (token.code == keySharp)
+ gettoken ();
+ eval (result);
+ requiretoken (')');
+ gettoken ();
+
+ BlChannel channel= BlChannel (result.integer () );
+ BlFile & file= getfile (channel);
+ result= BlInteger (file.loc () );
+}
+
+void RunnerLineImpl::val_MID_S (BlResult & result)
+{
+ expecttoken ('(');
+ std::string str= expectstring ();
+ requiretoken (',');
+ BlNumber blfrom= expectnum ();
+ size_t from= size_t (blfrom) - 1;
+ size_t len;
+ if (token.code == ',')
+ {
+ BlNumber bllen= expectnum ();
+ len= size_t (bllen);
+ }
+ else
+ len= std::string::npos;
+ requiretoken (')');
+ if (from >= str.size () )
+ result= std::string ();
+ else
+ result= str.substr (from, len);
+ gettoken ();
+}
+
+void RunnerLineImpl::val_LEFT_S (BlResult & result)
+{
+ expecttoken ('(');
+ std::string str= expectstring ();
+ requiretoken (',');
+ BlNumber blfrom= expectnum ();
+ requiretoken (')');
+ size_t from= size_t (blfrom);
+ result= str.substr (0, from);
+ gettoken ();
+}
+
+void RunnerLineImpl::val_RIGHT_S (BlResult & result)
+{
+ expecttoken ('(');
+ std::string str= expectstring ();
+ requiretoken (',');
+ BlNumber blfrom= expectnum ();
+ requiretoken (')');
+ size_t from= size_t (blfrom);
+ size_t l= str.size ();
+ if (from < l)
+ result= str.substr (str.size () - from);
+ else
+ result= str;
+ gettoken ();
+}
+
+void RunnerLineImpl::val_CHR_S (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ result= std::string (1, (unsigned char) result.number () );
+}
+
+void RunnerLineImpl::val_ENVIRON_S (BlResult & result)
+{
+ getparenarg (result);
+ char * str= getenv (result.str ().c_str () );
+ if (str)
+ result= std::string (str);
+ else
+ result= std::string ();
+}
+
+void RunnerLineImpl::val_STRING_S (BlResult & result)
+{
+ expecttoken ('(');
+ expect (result);
+ size_t rep= result.integer ();
+ requiretoken (',');
+ expect (result);
+ requiretoken (')');
+ gettoken ();
+ BlChar charrep= '\0';
+ switch (result.type () )
+ {
+ case VarNumber:
+ charrep= BlChar ( (unsigned int) result.number () );
+ break;
+ case VarInteger:
+ charrep= BlChar (result.integer () );
+ break;
+ case VarString:
+ {
+ const std::string & aux= result.str ();
+ if (aux.empty () )
+ charrep= '\0';
+ else
+ charrep= aux [0];
+ }
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ result= std::string (rep, charrep);
+}
+
+void RunnerLineImpl::val_OSFAMILY_S (BlResult & result)
+{
+ gettoken ();
+ result= std::string (os_family);
+}
+
+void RunnerLineImpl::val_OSNAME_S (BlResult & result)
+{
+ gettoken ();
+
+ #if defined __unix__ || defined __linux__
+ // Even in cygwin
+
+ struct utsname buf;
+ if (uname (&buf) != 0)
+ result= "unknown";
+ else
+ result= buf.sysname;
+
+ #elif defined BLASSIC_USE_WINDOWS
+
+ result= "Windows";
+
+ #else
+
+ result= "unknown";
+
+ #endif
+}
+
+void RunnerLineImpl::val_HEX_S (BlResult & result)
+{
+ expecttoken ('(');
+ expect (result);
+ if (result.type () == VarNumber)
+ {
+ BlNumber m= blassic::result::round (result.number () );
+ if (m <= BlUint32Max && m > BlInt32Max)
+ result= m - BlUint32Max - 1;
+ }
+ BlInteger n= result.integer ();
+ size_t w= 0;
+ if (token.code == ',')
+ {
+ expect (result);
+ w= result.integer ();
+ }
+ requiretoken (')');
+ gettoken ();
+ std::ostringstream oss;
+ oss.setf (std::ios::uppercase);
+ oss << std::hex <<
+ std::setw (w) << std::setfill ('0') <<
+ n;
+ result= oss.str ();
+}
+
+void RunnerLineImpl::val_SPACE_S (BlResult & result)
+{
+ getparenarg (result);
+ result= std::string (size_t (result.number () ), ' ');
+}
+
+void RunnerLineImpl::val_UPPER_S (BlResult & result)
+{
+ getparenarg (result);
+ std::string & str= result.str ();
+ std::transform (str.begin (), str.end (), str.begin (), toupper);
+}
+
+void RunnerLineImpl::val_LOWER_S (BlResult & result)
+{
+ getparenarg (result);
+ std::string & str= result.str ();
+ std::transform (str.begin (), str.end (), str.begin (), tolower);
+}
+
+void RunnerLineImpl::val_STR_S (BlResult & result)
+{
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ std::ostringstream oss;
+ BlNumber n= result.number ();
+ if (sysvar::hasFlags1 (sysvar::SpaceStr_s) &&
+ n >= zero)
+ oss << ' ';
+ oss << std::setprecision (10) << n;
+ result= oss.str ();
+}
+
+void RunnerLineImpl::val_OCT_S (BlResult & result)
+{
+ expecttoken ('(');
+ BlNumber n= expectnum ();
+ size_t w= 0;
+ if (token.code == ',')
+ {
+ BlNumber blw= expectnum ();
+ w= size_t (blw);
+ }
+ requiretoken (')');
+ gettoken ();
+ std::ostringstream oss;
+ oss.setf (std::ios::uppercase);
+ oss << std::oct <<
+ std::setw (w) << std::setfill ('0') <<
+ (unsigned long) n;
+ result= oss.str ();
+}
+
+void RunnerLineImpl::val_BIN_S (BlResult & result)
+{
+ expecttoken ('(');
+ BlNumber bn= expectnum ();
+ size_t w= 0;
+ if (token.code == ',')
+ {
+ BlNumber blw= expectnum ();
+ w= size_t (blw);
+ }
+ requiretoken (')');
+ gettoken ();
+ unsigned long n= (unsigned long) bn;
+ std::string str;
+ while (n)
+ {
+ str= ( (n & 1) ? '1' : '0') + str;
+ n/= 2;
+ }
+ if (str.empty () )
+ str= std::string (1, '0');
+ if (w > 0 && str.size () < w)
+ str= std::string (w - str.size (), '0') + str;
+ result= str;
+}
+
+void RunnerLineImpl::val_INKEY_S (BlResult & result)
+{
+ gettoken ();
+ //result= inkey ();
+ // Now we can specify channel used for input.
+ BlChannel ch= DefaultChannel;
+ if (token.code == '(')
+ {
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //ch= evalchannel ();
+ ch= expectrequiredchannel ();
+ requiretoken (')');
+ gettoken ();
+ }
+ std::string r= getfile (ch).inkey ();
+ if (r == "\n" && sysvar::hasFlags1 (sysvar::ConvertLFCR) )
+ r= "\r";
+ result= r;
+}
+
+void RunnerLineImpl::val_PROGRAMARG_S (BlResult & result)
+{
+ getparenarg (result);
+ result= getprogramarg (size_t (result.number () - 1) );
+}
+
+void RunnerLineImpl::val_DATE_S (BlResult & result)
+{
+ using std::setw;
+ using std::setfill;
+
+ gettoken ();
+ std::time_t t= time (NULL);
+ struct std::tm * ptm= std::localtime (& t);
+ std::ostringstream oss;
+ oss << setw (2) << setfill ('0') << (ptm->tm_mon + 1) << '-' <<
+ setw (2) << setfill ('0') << ptm->tm_mday << '-' <<
+ (ptm->tm_year + 1900);
+ result= oss.str ();
+}
+
+void RunnerLineImpl::val_TIME_S (BlResult & result)
+{
+ using std::setw;
+ using std::setfill;
+
+ gettoken ();
+ std::time_t t= time (NULL);
+ struct std::tm * ptm= std::localtime (& t);
+ std::ostringstream oss;
+ oss << setw (2) << setfill ('0') << ptm->tm_hour << ':' <<
+ setw (2) << setfill ('0') << ptm->tm_min << ':' <<
+ setw (2) << setfill ('0') << ptm->tm_sec;
+ result= oss.str ();
+}
+
+void RunnerLineImpl::val_INPUT_S (BlResult & result)
+{
+ expecttoken ('(');
+ BlNumber bn= expectnum ();
+ BlChannel channel= DefaultChannel;
+ switch (token.code)
+ {
+ case ')':
+ break;
+ case ',':
+ gettoken ();
+ //if (token.code == '#')
+ // channel= expectchannel ();
+ channel= evaloptionalchannel (channel);
+ requiretoken (')');
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ gettoken ();
+ BlFile & in= getfile (channel);
+ result= in.read (size_t (bn) );
+}
+
+void RunnerLineImpl::val_MKI_S (BlResult & result)
+{
+ getparenarg (result);
+ BlNumber bn= result.number ();
+ unsigned short s= (unsigned short) short (bn);
+ std::string str;
+ str= char (s & 255);
+ str+= char (s >> 8);
+ result= str;
+}
+
+void RunnerLineImpl::val_MKS_S (BlResult & result)
+{
+ getparenarg (result);
+ float f= result.number ();
+ std::string str (reinterpret_cast <char *> (& f), sizeof (float) );
+ result= str;
+}
+
+void RunnerLineImpl::val_MKD_S (BlResult & result)
+{
+ getparenarg (result);
+ double f= result.number ();
+ std::string str (reinterpret_cast <char *> (& f), sizeof (double) );
+ result= str;
+}
+
+void RunnerLineImpl::val_MKL_S (BlResult & result)
+{
+ getparenarg (result);
+ BlNumber bn= result.number ();
+ unsigned int s= (unsigned int) int (bn);
+ std::string str;
+ str= char (s & 255);
+ str+= char ( (s >> 8) & 255);
+ str+= char ( (s >> 16) & 255);
+ str+= char ( (s >> 24) & 255);
+ result= str;
+}
+
+#if 0
+void RunnerLineImpl::val_TRIM (BlResult & result)
+{
+ using std::string;
+
+ bool tleft= false, tright= false;
+ switch (token.code)
+ {
+ case keyTRIM_S:
+ tleft= true; tright= true;
+ break;
+ case keyLTRIM_S:
+ tleft= true;
+ break;
+ case keyRTRIM_S:
+ tright= true;
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Erroneous call to valtrim" << endl;
+ throw ErrBlassicInternal;
+ }
+ getparenarg (result);
+ string str= result.str ();
+ if (tleft)
+ {
+ string::size_type
+ inipos= str.find_first_not_of (' ');
+ if (inipos > 0)
+ if (inipos == string::npos)
+ str= string ();
+ else
+ //str= str.substr (inipos);
+ str.erase (0, inipos);
+ }
+ if (tright)
+ {
+ string::size_type
+ endpos= str.find_last_not_of (' ');
+ if (endpos != string::npos)
+ //str= str.substr (0, endpos + 1);
+ str.erase (endpos + 1);
+ else str= string ();
+ }
+ result= str;
+}
+#endif
+
+void RunnerLineImpl::valtrimbase (BlResult & result,
+ bool tleft, bool tright)
+{
+ using std::string;
+
+ if (! tleft && ! tright)
+ {
+ if (showdebuginfo () )
+ cerr << "Erroneous call to valtrim" << endl;
+ throw ErrBlassicInternal;
+ }
+
+ getparenarg (result);
+ string str= result.str ();
+ if (tleft)
+ {
+ string::size_type
+ inipos= str.find_first_not_of (' ');
+ if (inipos > 0)
+ if (inipos == string::npos)
+ str= string ();
+ else
+ //str= str.substr (inipos);
+ str.erase (0, inipos);
+ }
+ if (tright)
+ {
+ string::size_type
+ endpos= str.find_last_not_of (' ');
+ if (endpos != string::npos)
+ //str= str.substr (0, endpos + 1);
+ str.erase (endpos + 1);
+ else str= string ();
+ }
+ result= str;
+}
+
+void RunnerLineImpl::val_TRIM_S (BlResult & result)
+{
+ valtrimbase (result, true, true);
+}
+
+void RunnerLineImpl::val_LTRIM_S (BlResult & result)
+{
+ valtrimbase (result, true, false);
+}
+
+void RunnerLineImpl::val_RTRIM_S (BlResult & result)
+{
+ valtrimbase (result, false, true);
+}
+
+void RunnerLineImpl::val_FINDFIRST_S (BlResult & result)
+{
+ getparenarg (result);
+ if (! pdirectory)
+ pdirectory= new Directory ();
+ result= pdirectory->findfirst (result.str () );
+}
+
+void RunnerLineImpl::val_FINDNEXT_S (BlResult & result)
+{
+ if (! pdirectory)
+ result= std::string ();
+ else
+ result= pdirectory->findnext ();
+ gettoken ();
+}
+
+void RunnerLineImpl::val_COPYCHR_S (BlResult & result)
+{
+ expecttoken ('(');
+ expecttoken ('#');
+ BlChannel c= expectchannel ();
+
+ BlChar from= BlChar (0), to= BlChar (255);
+ if (token.code == ',')
+ {
+ from= static_cast <BlChar> (expectnum () );
+ if (token.code == ',')
+ {
+ to= static_cast <BlChar> (expectnum () );
+ }
+ }
+ requiretoken (')');
+ gettoken ();
+
+ BlFile & window= getfile (c);
+ result= window.copychr (from, to);
+}
+
+void RunnerLineImpl::val_STRERR_S (BlResult & result)
+{
+ getparenarg (result);
+ result= ErrStr (static_cast <BlErrNo> (result.integer () ) );
+}
+
+void RunnerLineImpl::val_DEC_S (BlResult & result)
+{
+ expecttoken ('(');
+ BlNumber n= expectnum ();
+ requiretoken (',');
+ std::string format= expectstring ();
+ VectorUsing usingf;
+ parseusing (format, usingf);
+ if (usingf.size () != 1)
+ throw ErrFunctionCall;
+ UsingNumeric * pun= dynamic_cast <UsingNumeric *> (usingf [0] );
+ if (pun == NULL)
+ throw ErrFunctionCall;
+ BlFileOutString fos;
+ pun->putnumeric (fos, n);
+ result= fos.str ();
+ requiretoken (')');
+ gettoken ();
+}
+
+void RunnerLineImpl::val_VAL_S (BlResult & result)
+{
+ //getparenarg (result);
+ gettoken ();
+ //valparen (result);
+ valbase (result);
+ std::string str= result.str ();
+ if (str.find_first_not_of (" \t")
+ == std::string::npos)
+ {
+ result= std::string ();
+ }
+ else
+ {
+ str= std::string ("0 ") + str;
+
+ #if 1
+
+ CodeLine valcodeline;
+ valcodeline.scan (str);
+ RunnerLineImpl valrunnerline (runner, valcodeline);
+
+ #else
+
+ RunnerLineImpl valrunnerline (runner);
+ CodeLine & valcodeline= valrunnerline.getcodeline ();
+ valcodeline.scan (str);
+
+ #endif
+
+ valrunnerline.expect (result);
+ if (valrunnerline.token.code != keyENDLINE)
+ throw ErrSyntax;
+ if (result.type () != VarString)
+ throw ErrMismatch;
+ }
+}
+
+void RunnerLineImpl::val_SCREEN_S (BlResult & result)
+{
+ expecttoken ('(');
+ BlInteger y= expectinteger ();
+ requiretoken (',');
+ BlInteger x= expectinteger ();
+ requiretoken (')');
+ gettoken ();
+ result= graphics::screenchr (x, y);
+}
+
+void RunnerLineImpl::val_MKSMBF_S (BlResult & result)
+{
+ getparenarg (result);
+ result= mbf::to_mbf_s (result.number () );
+}
+
+void RunnerLineImpl::val_MKDMBF_S (BlResult & result)
+{
+ getparenarg (result);
+ result= mbf::to_mbf_d (result.number () );
+}
+
+void RunnerLineImpl::val_REGEXP_REPLACE_S (BlResult & result)
+{
+ expecttoken ('(');
+ std::string searched;
+ std::string::size_type init= 0;
+
+ expect (result);
+ switch (result.type () )
+ {
+ case VarString:
+ searched= result.str ();
+ break;
+ case VarNumber:
+ case VarInteger:
+ init= result.integer ();
+ if (init < 1)
+ throw ErrFunctionCall;
+ --init;
+ requiretoken (',');
+ searched= expectstring ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ requiretoken (',');
+ std::string expr= expectstring ();
+ requiretoken (',');
+ gettoken ();
+ std::string replaceby;
+ bool isfunction= false;
+ if (token.code == keyFN)
+ {
+ isfunction= true;
+ gettoken ();
+ if (token.code != keyIDENTIFIER)
+ throw ErrSyntax;
+ replaceby= token.str;
+ gettoken ();
+ }
+ else
+ replaceby= evalstring ();
+ BlInteger flags= 0;
+ if (token.code == ',')
+ {
+ flags= expectinteger ();
+ }
+ else
+ {
+ // Default flags value depending on the initial position.
+ if (init > 0)
+ flags= Regexp::FLAG_NOBEG;
+ }
+ requiretoken (')');
+ gettoken ();
+
+ Regexp regexp (expr, flags);
+ if (isfunction)
+ result= regexp.replace (searched, init, * this, replaceby);
+ else
+ result= regexp.replace (searched, init, replaceby);
+}
+
+namespace {
+
+class FnErrorShower {
+public:
+ FnErrorShower (const std::string & fname) :
+ finished (false),
+ name (fname)
+ { }
+ ~FnErrorShower ()
+ {
+ if (! finished && showdebuginfo () )
+ cerr << "Error processing FN " << name << endl;
+ }
+ void finish ()
+ {
+ finished= true;
+ }
+private:
+ bool finished;
+ const std::string & name;
+};
+
+class FnLevelIncrementer {
+public:
+ FnLevelIncrementer (Runner & r) :
+ r (r)
+ {
+ r.inc_fn_level ();
+ }
+ ~FnLevelIncrementer ()
+ {
+ r.dec_fn_level ();
+ }
+private:
+ Runner & r;
+};
+
+} // namespace
+
+void RunnerLineImpl::callfn (Function & f, const std::string & fname,
+ LocalLevel & ll, BlResult & result)
+{
+ switch (f.getdeftype () )
+ {
+ case Function::DefSingle:
+ {
+ // Prevents lock on recursive calls.
+ if (fInterrupted)
+ {
+ if (runner.getbreakstate () !=
+ onbreak::BreakCont)
+ throw BlBreak ();
+ else
+ fInterrupted= false;
+ }
+
+ FnErrorShower check (fname);
+
+ //CodeLine & code= f.getcode ();
+ //code.gotochunk (0);
+ //RunnerLineImpl fnrunnerline (runner, code);
+
+ //RunnerLineImpl fnrunnerline (runner);
+ //CodeLine & fncodeline= fnrunnerline.getcodeline ();
+
+ // Use the heap to decrease the use
+ // of the stack in recursive fn calls.
+ //auto_ptr <RunnerLineImpl> pfnrunnerline
+ // (new RunnerLineImpl (runner) );
+ //CodeLine & fncodeline= pfnrunnerline->getcodeline ();
+ //fncodeline= f.getcode ();
+
+ CodeLine fncodeline (f.getcode () );
+ auto_ptr <RunnerLineImpl> pfnrunnerline
+ (new RunnerLineImpl (runner, fncodeline) );
+
+ FnLevelIncrementer fli (runner);
+ //fnrunnerline.expect (result);
+ pfnrunnerline->expect (result);
+ ll.freelocalvars ();
+
+ check.finish ();
+ }
+ break;
+ case Function::DefMulti:
+ {
+ ll.addlocalvar (fname);
+ //Runner fnrun (program);
+ Runner fnrun (runner);
+ // We reuse the break position
+ // to jump to the fn definition.
+ fnrun.set_break (f.getpos () );
+ fnrun.gosub_push (ll);
+ CodeLine jumpline;
+ jumpline.scan ("CONT");
+ {
+ FnLevelIncrementer fli (runner);
+ FnErrorShower check (fname);
+ fnrun.runline (jumpline);
+ check.finish ();
+ }
+
+ size_t stacksize= fnrun.gosub_size ();
+ if (stacksize > 1)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "FN END with GOSUB "
+ "pending of RETURN" <<
+ endl;
+ }
+ throw ErrGosubWithoutReturn;
+ }
+ if (stacksize == 0)
+ {
+ if (showdebuginfo () )
+ {
+ cerr << "FN control missing" << endl;
+ }
+ throw ErrBlassicInternal;
+ }
+
+ switch (typeofvar (fname) )
+ {
+ case VarNumber:
+ result= evaluatevarnumber (fname);
+ break;
+ case VarInteger:
+ result= evaluatevarinteger (fname);
+ break;
+ case VarString:
+ result= evaluatevarstring (fname);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ fnrun.fn_pop ();
+ }
+ break;
+ }
+}
+
+void RunnerLineImpl::val_FN (BlResult & result)
+{
+ // Get FN name.
+ expecttoken (keyIDENTIFIER);
+ std::string fname= token.str;
+ Function f= Function::get (fname);
+
+ // Get parameters.
+ gettoken ();
+ LocalLevel ll;
+ const ParameterList & param= f.getparam ();
+ size_t l= param.size ();
+ if (l != 0)
+ {
+ requiretoken ('(');
+ for (size_t i= 0; i < l; ++i)
+ {
+ BlResult aux;
+ expect (result);
+ //const std::string & var= param [i];
+ std::string var= param [i];
+ ll.addlocalvar (var);
+ VarType type= typeofvar (var);
+ switch (type)
+ {
+ case VarNumber:
+ assignvarnumber (var, result.number () );
+ break;
+ case VarInteger:
+ assignvarinteger (var, result.integer () );
+ break;
+ case VarString:
+ assignvarstring (var, result.str () );
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ if (i < l - 1)
+ requiretoken (',');
+ }
+ requiretoken (')');
+ gettoken ();
+ }
+
+ // Execute the function.
+ callfn (f, fname, ll, result);
+}
+
+void RunnerLineImpl::valsubindex (const std::string & varname,
+ BlResult & result)
+{
+ Dimension dims= getdims ();
+ switch (typeofvar (varname) )
+ {
+ case VarNumber:
+ result= valuedimnumber (varname, dims);
+ break;
+ case VarInteger:
+ result= valuediminteger (varname, dims);
+ break;
+ case VarString:
+ result= valuedimstring (varname, dims);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+}
+
+void RunnerLineImpl::val_LET (BlResult & result)
+{
+ gettoken ();
+ VarPointer vp= eval_let ();
+ switch (vp.type)
+ {
+ case VarNumber:
+ result= * vp.pnumber;
+ break;
+ case VarInteger:
+ result= * vp.pinteger;
+ break;
+ case VarString:
+ result= * vp.pstring;
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+}
+
+void RunnerLineImpl::val_LABEL (BlResult & result)
+{
+ gettoken ();
+ if (token.code != keyIDENTIFIER)
+ throw ErrSyntax;
+ result= static_cast <BlNumber> (program.getlabel (token.str) );
+ gettoken ();
+}
+
+void RunnerLineImpl::val_IDENTIFIER (BlResult & result)
+{
+ std::string varname (token.str);
+ gettoken ();
+ if (token.code == '(')
+ valsubindex (varname, result);
+ else
+ switch (typeofvar (varname) )
+ {
+ case VarNumber:
+ result= evaluatevarnumber (varname);
+ break;
+ case VarInteger:
+ result= evaluatevarinteger (varname);
+ break;
+ case VarString:
+ result= evaluatevarstring (varname);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+}
+
+void RunnerLineImpl::val_STRING (BlResult & result)
+{
+ result= token.str;
+ gettoken ();
+}
+
+void RunnerLineImpl::val_NUMBER (BlResult & result)
+{
+ result= token.number ();
+ gettoken ();
+}
+
+void RunnerLineImpl::val_INTEGER (BlResult & result)
+{
+ result= token.integer ();
+ gettoken ();
+}
+
+void RunnerLineImpl::val_OpenPar (BlResult & result)
+{
+ gettoken ();
+ eval (result);
+ if (token.code != keyClosePar)
+ throw ErrSyntax;
+ gettoken ();
+}
+
+void RunnerLineImpl::valbase (BlResult & result)
+{
+ #ifdef OPERATION_SWITCH
+
+# define HANDLE_OPER(elem) \
+ case key##elem: \
+ val_##elem (result); \
+ break
+
+# define HANDLE_OPER2(elem1, elem2) \
+ case key##elem1: \
+ val_##elem2 (result); \
+ break
+
+ switch (token.code)
+ {
+ HANDLE_OPER (OpenPar);
+
+ HANDLE_OPER (LET);
+ HANDLE_OPER (LABEL);
+ HANDLE_OPER (FN);
+
+ HANDLE_OPER (MID_S);
+ HANDLE_OPER (LEFT_S);
+ HANDLE_OPER (RIGHT_S);
+ HANDLE_OPER (CHR_S);
+ HANDLE_OPER (ENVIRON_S);
+ HANDLE_OPER (STRING_S);
+ HANDLE_OPER (OSFAMILY_S);
+ HANDLE_OPER (HEX_S);
+ HANDLE_OPER (SPACE_S);
+ HANDLE_OPER (UPPER_S);
+ HANDLE_OPER (LOWER_S);
+ HANDLE_OPER (STR_S);
+ HANDLE_OPER (OCT_S);
+ HANDLE_OPER (BIN_S);
+ HANDLE_OPER (INKEY_S);
+ HANDLE_OPER (PROGRAMARG_S);
+ HANDLE_OPER (DATE_S);
+ HANDLE_OPER (TIME_S);
+ HANDLE_OPER (INPUT_S);
+ HANDLE_OPER (MKI_S);
+ HANDLE_OPER (MKS_S);
+ HANDLE_OPER (MKD_S);
+ HANDLE_OPER (MKL_S);
+ HANDLE_OPER (TRIM_S);
+ HANDLE_OPER (LTRIM_S);
+ HANDLE_OPER (RTRIM_S);
+ HANDLE_OPER (OSNAME_S);
+ HANDLE_OPER (FINDFIRST_S);
+ HANDLE_OPER (FINDNEXT_S);
+ HANDLE_OPER (COPYCHR_S);
+ HANDLE_OPER (STRERR_S);
+ HANDLE_OPER (DEC_S);
+ HANDLE_OPER (VAL_S);
+ HANDLE_OPER (SCREEN_S);
+ HANDLE_OPER (MKSMBF_S);
+ HANDLE_OPER (MKDMBF_S);
+ HANDLE_OPER (REGEXP_REPLACE_S);
+ // UCASE$ and LCASE$ are alias for UPPER$ and LOWER$
+ HANDLE_OPER2 (UCASE_S, UPPER_S);
+ HANDLE_OPER2 (LCASE_S, LOWER_S);
+
+ HANDLE_OPER (ASC);
+ HANDLE_OPER (LEN);
+ HANDLE_OPER (PEEK);
+ HANDLE_OPER (PROGRAMPTR);
+ HANDLE_OPER (RND);
+ HANDLE_OPER (INT);
+ HANDLE_OPER (SIN);
+ HANDLE_OPER (COS);
+ HANDLE_OPER (PI);
+ HANDLE_OPER (TAN);
+ HANDLE_OPER (SQR);
+ HANDLE_OPER (ASIN);
+ HANDLE_OPER (ACOS);
+ HANDLE_OPER (INSTR);
+ HANDLE_OPER (ATAN);
+ HANDLE_OPER (ABS);
+ HANDLE_OPER (USR);
+ HANDLE_OPER (VAL);
+ HANDLE_OPER (EOF);
+ HANDLE_OPER (VARPTR);
+ HANDLE_OPER (SYSVARPTR);
+ HANDLE_OPER (SGN);
+ HANDLE_OPER (LOG);
+ HANDLE_OPER (LOG10);
+ HANDLE_OPER (EXP);
+ HANDLE_OPER (TIME);
+ HANDLE_OPER (ERR);
+ HANDLE_OPER (ERL);
+ HANDLE_OPER (CVI);
+ HANDLE_OPER (CVS);
+ HANDLE_OPER (CVD);
+ HANDLE_OPER (CVL);
+ HANDLE_OPER (MIN);
+ HANDLE_OPER (MAX);
+ HANDLE_OPER (CINT);
+ HANDLE_OPER (FIX);
+ HANDLE_OPER (XMOUSE);
+ HANDLE_OPER (YMOUSE);
+ HANDLE_OPER (XPOS);
+ HANDLE_OPER (YPOS);
+ HANDLE_OPER (PEEK16);
+ HANDLE_OPER (PEEK32);
+ HANDLE_OPER (RINSTR);
+ HANDLE_OPER (FIND_FIRST_OF);
+ HANDLE_OPER (FIND_LAST_OF);
+ HANDLE_OPER (FIND_FIRST_NOT_OF);
+ HANDLE_OPER (FIND_LAST_NOT_OF);
+ HANDLE_OPER (SINH);
+ HANDLE_OPER (COSH);
+ HANDLE_OPER (TANH);
+ HANDLE_OPER (ASINH);
+ HANDLE_OPER (ACOSH);
+ HANDLE_OPER (ATANH);
+ HANDLE_OPER (ATAN2);
+ HANDLE_OPER (TEST);
+ HANDLE_OPER (TESTR);
+ HANDLE_OPER (POS);
+ HANDLE_OPER (VPOS);
+ HANDLE_OPER (LOF);
+ HANDLE_OPER (FREEFILE);
+ HANDLE_OPER (INKEY);
+ HANDLE_OPER (ROUND);
+ HANDLE_OPER (CVSMBF);
+ HANDLE_OPER (CVDMBF);
+ HANDLE_OPER (REGEXP_INSTR);
+ HANDLE_OPER (ALLOC_MEMORY);
+ HANDLE_OPER (LOC);
+
+ HANDLE_OPER (IDENTIFIER);
+ HANDLE_OPER (NUMBER);
+ HANDLE_OPER (STRING);
+ HANDLE_OPER (INTEGER);
+ default:
+ throw ErrSyntax;
+ }
+
+ if (result.type () == VarString)
+ {
+ if (token.code == '[')
+ slice (result);
+ }
+
+ #else
+ // No OPERATION_SWITCH
+
+ //(this->* array_valfunction [token.code] ) (result);
+
+ (this->* findvalfunc (token.code) ) (result);
+
+ if (result.type () == VarString)
+ {
+ if (token.code == '[')
+ slice (result);
+ }
+
+ #endif
+ // OPERATION_SWITCH
+}
+
+#if 0
+void RunnerLineImpl::valparen (BlResult & result)
+{
+ #if 0
+ if (token.code == '(')
+ {
+ gettoken ();
+ eval (result);
+ if (token.code != ')')
+ throw ErrSyntax;
+ gettoken ();
+ }
+ else
+ #endif
+ valbase (result);
+}
+#endif
+
+void RunnerLineImpl::slice (BlResult & result)
+{
+ using std::string;
+
+ string str= result.str ();
+ do
+ {
+ #if 0
+ gettoken ();
+ string::size_type from= 0;
+ string::size_type to= str.size ();
+ if (token.code != ']')
+ {
+ if (token.code != keyTO)
+ {
+ from= evalstringindex ();
+ if (token.code == keyTO)
+ {
+ gettoken ();
+ to= evalstringindex ();
+ }
+ else
+ to= from;
+ }
+ else
+ {
+ gettoken ();
+ if (token.code != ']')
+ to= evalstringindex ();
+ }
+ requiretoken (']');
+ }
+ gettoken ();
+
+ if (from > to)
+ str.erase ();
+ else
+ {
+ std::string::size_type limit= str.size ();
+ if (from >= limit || to >= limit)
+ throw ErrBadSubscript;
+ str= str.substr (from, to - from + 1);
+ }
+ #else
+
+ string::size_type from, to;
+ evalstringslice (str, from, to);
+ if (from + 1 > to)
+ str.erase ();
+ else
+ str= str.substr (from, to - from);
+
+ #endif
+ } while (token.code == '[');
+ result= str;
+}
+
+void RunnerLineImpl::valexponent (BlResult & result)
+{
+ //valparen (result);
+ valbase (result);
+ #if 0
+ if (result.type () == VarString)
+ {
+ if (token.code == '[')
+ slice (result);
+ }
+ else
+ {
+ #endif
+ while (token.code == '^')
+ {
+ gettoken ();
+ BlResult guard;
+ valunary (guard);
+ result= callnumericfunc (pow,
+ result.number (), guard.number () );
+ }
+ //}
+}
+
+void RunnerLineImpl::valmod (BlResult & result)
+{
+ valexponent (result);
+ while (token.code == keyMOD)
+ {
+ gettoken ();
+ BlResult guard;
+ valexponent (guard);
+ result%= guard;
+ }
+}
+
+void RunnerLineImpl::valunary (BlResult & result)
+{
+ BlCode op= 0;
+ if (token.code == '+' || token.code == '-' || token.code == keyNOT)
+ {
+ op= token.code;
+ gettoken ();
+ valunary (result);
+ }
+ else valmod (result);
+
+ switch (op)
+ {
+ case 0:
+ break;
+ case '+':
+ if (! result.is_numeric () )
+ throw ErrMismatch;
+ break;
+ case '-':
+ result= -result;
+ break;
+ case keyNOT:
+ //result= BlNumber (~ long (result.number () ) );
+ {
+ sysvar::Flags2Bit f2 (sysvar::getFlags2 () );
+ if (f2.has (sysvar::BoolMode) )
+ {
+ bool r;
+ switch (result.type () )
+ {
+ case VarInteger:
+ r= ! result.integer (); break;
+ case VarNumber:
+ r= ! result.number (); break;
+ default:
+ throw ErrMismatch;
+ }
+ result= r ?
+ (f2.has (sysvar::TruePositive) ?
+ 1 :
+ -1) :
+ 0;
+ }
+ else
+ result= ~ result.integer ();
+ }
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+}
+
+void RunnerLineImpl::valdivint (BlResult & result)
+{
+ valunary (result);
+ BlCode op= token.code;
+ while (op == '\\')
+ {
+ BlResult guard;
+ gettoken ();
+ valunary (guard);
+ //BlInteger g= guard.integer ();
+ //if (g == 0)
+ // throw ErrDivZero;
+ //result= result.integer () / g;
+ result.integerdivideby (guard);
+ op= token.code;
+ }
+}
+
+void RunnerLineImpl::valmuldiv (BlResult & result)
+{
+ //valunary (result);
+ valdivint (result);
+ BlCode op= token.code;
+ while (op == '*' || op == '/')
+ {
+ BlResult guard;
+ gettoken ();
+ //valunary (guard);
+ valdivint (guard);
+ switch (op)
+ {
+ case '*':
+ result*= guard;
+ break;
+ case '/':
+ result/= guard;
+ break;
+ default:
+ ;
+ }
+ op= token.code;
+ }
+}
+
+void RunnerLineImpl::valplusmin (BlResult & result)
+{
+ valmuldiv (result);
+ BlCode op= token.code;
+ while (op == '+' || op == '-')
+ {
+ BlResult guard;
+ gettoken ();
+ valmuldiv (guard);
+ switch (op)
+ {
+ case '+':
+ result+= guard;
+ break;
+ case '-':
+ result-= guard;
+ break;
+ }
+ op= token.code;
+ }
+}
+
+void RunnerLineImpl::valcomp (BlResult & result)
+{
+ valplusmin (result);
+ BlCode op= token.code;
+ if (iscomp (op) )
+ {
+ bool true_positive= sysvar::hasFlags2 (sysvar::TruePositive);
+ BlResult guard;
+ bool r;
+ do
+ {
+ gettoken ();
+ valplusmin (guard);
+ switch (op)
+ {
+ case '=':
+ r= (result == guard);
+ break;
+ case keyDISTINCT:
+ r= (result != guard);
+ break;
+ case '<':
+ r= (result < guard);
+ break;
+ case keyMINOREQUAL:
+ r= (result <= guard);
+ break;
+ case '>':
+ r= (result > guard);
+ break;
+ case keyGREATEREQUAL:
+ r= (result >= guard);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ result= r ? (true_positive ? 1 : -1) : 0;
+ op= token.code;
+ } while (iscomp (op) );
+ }
+}
+
+void RunnerLineImpl::valorand (BlResult & result)
+{
+ valcomp (result);
+ BlCode op= token.code;
+ if (islogical2 (op) )
+ {
+ bool boolean_mode= sysvar::hasFlags2 (sysvar::BoolMode);
+ bool true_positive= sysvar::hasFlags2 (sysvar::TruePositive);
+ BlResult guard;
+ do
+ {
+ gettoken ();
+ valcomp (guard);
+ if (boolean_mode)
+ {
+ bool r;
+ bool r1= result.tobool ();
+ bool r2= guard.tobool ();
+ switch (op)
+ {
+ case keyOR:
+ r= r1 || r2;
+ break;
+ case keyAND:
+ r= r1 && r2;
+ break;
+ case keyXOR:
+ r= r1 != r2;
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ result= r ? (true_positive ? 1 : -1) : 0;
+ }
+ else
+ {
+ BlInteger n1= result.integer ();
+ BlInteger n2= guard.integer ();
+ switch (op)
+ {
+ case keyOR:
+ //result= BlNumber (n1 | n2);
+ result= n1 | n2;
+ break;
+ case keyAND:
+ //result= BlNumber (n1 & n2);
+ result= n1 & n2;
+ break;
+ case keyXOR:
+ //result= BlNumber (n1 ^ n2);
+ result= n1 ^ n2;
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ op= token.code;
+ } while (islogical2 (op) );
+ }
+}
+
+void RunnerLineImpl::eval (BlResult & result)
+{
+ valorand (result);
+}
+
+void RunnerLineImpl::expect (BlResult & result)
+{
+ gettoken ();
+ eval (result);
+}
+
+BlLineNumber RunnerLineImpl::evallinenumber ()
+{
+ BlLineNumber bln;
+ switch (token.code)
+ {
+ case keyNUMBER:
+ bln= blassic::result::NumberToInteger (token.number () );
+ break;
+ case keyINTEGER:
+ bln= BlLineNumber (token.integer () );
+ break;
+ case keyIDENTIFIER:
+ bln= program.getlabel (token.str);
+ if (bln == LineEndProgram)
+ throw ErrNoLabel;
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ if (bln > BlMaxLineNumber)
+ {
+ if (showdebuginfo () )
+ cerr << "Invalid line number";
+ throw ErrSyntax;
+ }
+ gettoken ();
+ return bln;
+}
+
+void RunnerLineImpl::evallinerange (BlLineNumber & blnBeg,
+ BlLineNumber & blnEnd)
+{
+ blnBeg= LineBeginProgram;
+ blnEnd= LineEndProgram;
+ if (! endsentence () && token.code != ',')
+ {
+ if (token.code != '-')
+ {
+ blnBeg= evallinenumber ();
+ if (token.code == '-')
+ {
+ gettoken ();
+ if (! endsentence () && token.code != ',')
+ blnEnd= evallinenumber ();
+ }
+ else
+ blnEnd= blnBeg;
+ }
+ else
+ {
+ gettoken ();
+ blnEnd= evallinenumber ();
+ }
+ }
+}
+
+Dimension RunnerLineImpl::getdims ()
+{
+ //TRACEFUNC (tr, "RunnerLineImpl::getdims");
+ ASSERT (token.code == '(');
+
+ Dimension dims;
+ do
+ {
+ dims.add (expectinteger () );
+ } while (token.code == ',');
+ requiretoken (')');
+ gettoken ();
+ return dims;
+}
+
+Dimension RunnerLineImpl::evaldims ()
+{
+ requiretoken ('(');
+ return getdims ();
+}
+
+Dimension RunnerLineImpl::expectdims ()
+{
+ expecttoken ('(');
+ return getdims ();
+}
+
+void RunnerLineImpl::errorifparam ()
+{
+ gettoken ();
+ require_endsentence ();
+}
+
+void RunnerLineImpl::gosub_line (BlLineNumber dest)
+{
+ //ProgramPos posgosub= runner.getposactual ();
+ ProgramPos posgosub (getposactual () );
+ posgosub.nextchunk ();
+ #if 1
+ //if (token.code == keyENDLINE && posgosub.getnum () != 0)
+ if (token.code == keyENDLINE &&
+ posgosub.getnum () != LineDirectCommand)
+ {
+ #if 1
+ posgosub.nextline ();
+ #else
+ BlLineNumber num= program.getnextnum (line);
+ if (num != 0)
+ posgosub= num;
+ #endif
+ }
+ #endif
+ runner.gosub_line (dest, posgosub);
+}
+
+void RunnerLineImpl::getinkparams ()
+{
+ if (endsentence () )
+ return;
+ requiretoken (',');
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger ink= evalinteger ();
+ graphics::setcolor (ink);
+ if (token.code != ',')
+ {
+ require_endsentence ();
+ return;
+ }
+ }
+ gettoken ();
+ BlInteger inkmode= evalinteger ();
+ require_endsentence ();
+ graphics::setdrawmode (inkmode);
+}
+
+void RunnerLineImpl::getdrawargs (BlInteger & y)
+{
+ requiretoken (',');
+ y= expectinteger ();
+ getinkparams ();
+}
+
+void RunnerLineImpl::getdrawargs (BlInteger & x, BlInteger & y)
+{
+ x= expectinteger ();
+ getdrawargs (y);
+}
+
+void RunnerLineImpl::make_clear ()
+{
+ runner.clear ();
+ runner.clearerrorgoto ();
+ clearvars ();
+ Function::clear ();
+ graphics::clear_images ();
+ definevar (VarNumber, 'A', 'Z');
+ runner.trigonometric_default ();
+}
+
+bool RunnerLineImpl::syntax_error ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::syntax_error");
+
+ throw ErrSyntax;
+}
+
+void RunnerLineImpl::valsyntax_error (BlResult &)
+{
+ TRACEFUNC (tr, "RunnerLineImpl::valsyntax_error");
+
+ throw ErrSyntax;
+}
+
+bool RunnerLineImpl::execute_instruction ()
+{
+ //TRACEFUNC (tr, "RunnerLineImpl::execute_instruction");
+
+ #ifndef INSTRUCTION_SWITCH
+
+ if ( (this->*findfunc (token.code) ) () )
+ {
+ //TRMESSAGE (tr, "Instruction returned true");
+ return true;
+ }
+ else
+ return false;
+
+ #else
+
+# define HANDLE_ELEM(elem) \
+ case key##elem: \
+ return do_##elem ()
+
+# define HANDLE_ELEM2(elem1, elem2) \
+ case key##elem1: \
+ return do_##elem2 ()
+
+ switch (token.code)
+ {
+ HANDLE_ELEM (Colon);
+ HANDLE_ELEM (END);
+ HANDLE_ELEM (LIST);
+ HANDLE_ELEM (REM);
+ HANDLE_ELEM (LOAD);
+ HANDLE_ELEM (SAVE);
+ HANDLE_ELEM (NEW);
+ HANDLE_ELEM (EXIT);
+ HANDLE_ELEM (RUN);
+ HANDLE_ELEM (PRINT);
+ HANDLE_ELEM (FOR);
+ HANDLE_ELEM (NEXT);
+ HANDLE_ELEM (IF);
+ HANDLE_ELEM (ELSE);
+ HANDLE_ELEM (TRON);
+ HANDLE_ELEM (TROFF);
+ HANDLE_ELEM (LET);
+ HANDLE_ELEM (GOTO);
+ HANDLE_ELEM (STOP);
+ HANDLE_ELEM (CONT);
+ HANDLE_ELEM (CLEAR);
+ HANDLE_ELEM (GOSUB);
+ HANDLE_ELEM (RETURN);
+ HANDLE_ELEM (POKE);
+ HANDLE_ELEM (DATA);
+ HANDLE_ELEM (READ);
+ HANDLE_ELEM (RESTORE);
+ HANDLE_ELEM (INPUT);
+ HANDLE_ELEM (LINE);
+ HANDLE_ELEM (RANDOMIZE);
+ HANDLE_ELEM (PLEASE);
+ HANDLE_ELEM (AUTO);
+ HANDLE_ELEM (DIM);
+ HANDLE_ELEM (SYSTEM);
+ HANDLE_ELEM (ON);
+ HANDLE_ELEM (ERROR);
+ HANDLE_ELEM (OPEN);
+ HANDLE_ELEM (CLOSE);
+ HANDLE_ELEM (LOCATE);
+ HANDLE_ELEM (CLS);
+ HANDLE_ELEM (WRITE);
+ HANDLE_ELEM (MODE);
+ HANDLE_ELEM (MOVE);
+ HANDLE_ELEM (COLOR);
+ HANDLE_ELEM (GET);
+ HANDLE_ELEM (LABEL);
+ HANDLE_ELEM (DELIMITER);
+ HANDLE_ELEM (REPEAT);
+ HANDLE_ELEM (UNTIL);
+ HANDLE_ELEM (WHILE);
+ HANDLE_ELEM (WEND);
+ HANDLE_ELEM (PLOT);
+ HANDLE_ELEM (POPEN);
+ HANDLE_ELEM (RESUME);
+ HANDLE_ELEM (DELETE);
+ HANDLE_ELEM (LOCAL);
+ HANDLE_ELEM (PUT);
+ HANDLE_ELEM (FIELD);
+ HANDLE_ELEM (LSET);
+
+ // Lset and rset use same function.
+ HANDLE_ELEM2 (RSET, LSET);
+
+ HANDLE_ELEM (SOCKET);
+ HANDLE_ELEM (DRAW);
+ HANDLE_ELEM (DEF);
+ HANDLE_ELEM (FN);
+ HANDLE_ELEM (ERASE);
+ HANDLE_ELEM (SWAP);
+ HANDLE_ELEM (SYMBOL);
+ HANDLE_ELEM (ZONE);
+ HANDLE_ELEM (POP);
+ HANDLE_ELEM (NAME);
+ HANDLE_ELEM (KILL);
+ HANDLE_ELEM (FILES);
+ HANDLE_ELEM (PAPER);
+ HANDLE_ELEM (PEN);
+ HANDLE_ELEM (SHELL);
+ HANDLE_ELEM (MERGE);
+ HANDLE_ELEM (CHDIR);
+ HANDLE_ELEM (MKDIR);
+ HANDLE_ELEM (RMDIR);
+ HANDLE_ELEM (SYNCHRONIZE);
+ HANDLE_ELEM (PAUSE);
+ HANDLE_ELEM (CHAIN);
+ HANDLE_ELEM (ENVIRON);
+ HANDLE_ELEM (EDIT);
+ HANDLE_ELEM (DRAWR);
+ HANDLE_ELEM (PLOTR);
+ HANDLE_ELEM (MOVER);
+ HANDLE_ELEM (POKE16);
+ HANDLE_ELEM (POKE32);
+ HANDLE_ELEM (RENUM);
+ HANDLE_ELEM (CIRCLE);
+ HANDLE_ELEM (MASK);
+ HANDLE_ELEM (WINDOW);
+ HANDLE_ELEM (GRAPHICS);
+ HANDLE_ELEM (BEEP);
+ HANDLE_ELEM (DEFINT);
+
+ // DEFINT, DEFSTR, DEFREAL, DEFSNG and DEFDBL use same function.
+ HANDLE_ELEM2 (DEFSTR, DEFINT);
+ HANDLE_ELEM2 (DEFREAL, DEFINT);
+ HANDLE_ELEM2 (DEFSNG, DEFINT);
+ HANDLE_ELEM2 (DEFDBL, DEFINT);
+
+ HANDLE_ELEM (INK);
+ HANDLE_ELEM (SET_TITLE);
+ HANDLE_ELEM (TAG);
+
+ // TAG and TAGOFF use same function.
+ HANDLE_ELEM2 (TAGOFF, TAG);
+
+ HANDLE_ELEM (ORIGIN);
+ HANDLE_ELEM (DEG);
+
+ // DEG and RAD use same function.
+ HANDLE_ELEM2 (RAD, DEG);
+
+ HANDLE_ELEM (INVERSE);
+ HANDLE_ELEM (IF_DEBUG);
+
+ // LPRINT and PRINT use same function.
+ HANDLE_ELEM2 (LPRINT, PRINT);
+
+ HANDLE_ELEM (LLIST);
+ HANDLE_ELEM (WIDTH);
+ HANDLE_ELEM (BRIGHT);
+ HANDLE_ELEM (DRAWARC);
+ HANDLE_ELEM (PULL);
+ HANDLE_ELEM (PAINT);
+ HANDLE_ELEM (FREE_MEMORY);
+ HANDLE_ELEM (SCROLL);
+ HANDLE_ELEM (ZX_PLOT);
+ HANDLE_ELEM (ZX_UNPLOT);
+
+ HANDLE_ELEM (MID_S);
+ HANDLE_ELEM (PROGRAMARG_S);
+
+ HANDLE_ELEM (IDENTIFIER);
+ HANDLE_ELEM (NUMBER);
+ HANDLE_ELEM2 (INTEGER, NUMBER);
+ HANDLE_ELEM (ENDLINE);
+
+ default:
+ throw ErrSyntax;
+ }
+
+ #endif
+}
+
+void RunnerLineImpl::execute ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::execute");
+
+ // Cleaned and clarified the code of this function.
+
+ fInElse= false;
+ //codprev= 0;
+ codprev= codeline.actualcode ();
+
+ for (;;)
+ {
+ //next_instruction:
+
+ #ifndef BLASSIC_NO_GRAPHICS
+ // Allows refreshing of the graphics window.
+
+ #ifndef BLASSIC_USE_WINDOWS
+ // In windows a thread takes care of graphics,
+ // in others frequent calls to graphics::idle
+ // are needed to handle events in the graphics
+ // window.
+
+ // Avoid calling idle too many times.
+ // Someone wants to tune this?
+ if (graphics::ingraphicsmode () )
+ {
+ static size_t counter= 0;
+ if (counter ++ == 100)
+ {
+ graphics::idle ();
+ counter= 0;
+ }
+ }
+ #endif
+
+ #endif
+
+
+ // Testing little change: control this after executing
+ // the instruction.
+
+ #if 0
+
+ // ELSE control. Does not allow a precise syntax
+ // checking, but actually works.
+ // ELSE can be found in four ways:
+ // - When IF look for it.
+ // - As the end of a instruction.
+ // - After :
+ // - As the firsts instruction of one line.
+ // Here are treated the two first cases, the
+ // others are processed as a normal instruction.
+
+ codprev= codeline.actualcode ();
+ if (codprev == keyELSE)
+ {
+ if (fInElse)
+ {
+ // Was found by IF, process the rest
+ // of the line.
+ fInElse= false;
+ }
+ else
+ {
+ // Not found by if. Exit the line.
+ //break;
+ return;
+ }
+ }
+
+ #endif
+
+ gettoken ();
+ actualchunk= codeline.chunk ();
+
+ if (fInterrupted)
+ {
+ if (runner.getbreakstate () != onbreak::BreakCont)
+ throw BlBreak ();
+ fInterrupted= false;
+ }
+
+ if (runner.channelspolled () )
+ {
+ BlLineNumber line= runner.getpollnumber ();
+ if (line != LineEndProgram)
+ {
+ runner.gosub_line (line, getposactual (),
+ true);
+ //break;
+ return;
+ }
+ }
+
+ #if 1
+
+ bool finishline= execute_instruction ();
+ if (finishline)
+ //break;
+ return;
+
+ #else
+
+ #ifndef INSTRUCTION_SWITCH
+
+ if ( (this->*findfunc (token.code) ) () )
+ {
+ //TRMESSAGE (tr, "Instruction returned true");
+ break;
+ }
+
+ #endif
+
+ #endif
+
+ // Test.
+ //do_func f= findfunc (token.code);
+ //bool r= (this->* f) ();
+ //if (r)
+ // break;
+
+ // This makes a tiny speed improvement with my test
+ // programs, perhaps in other programs can be the
+ // contrary? Anyway, the difference is not important,
+ // can be supressed and all works.
+ if (token.code == keyENDLINE)
+ {
+ //TRMESSAGE (tr, "End of line");
+ //break;
+ return;
+ }
+
+ #if 1
+
+ codprev= token.code;
+ if (codprev == keyELSE)
+ {
+ //TRMESSAGE (tr, "ELSE after instruction");
+ if (fInElse)
+ {
+ // Was found by IF, process the rest
+ // of the line.
+ fInElse= false;
+ }
+ else
+ {
+ // Not found by if. Exit the line.
+ //break;
+ return;
+ }
+ }
+
+ #endif
+
+ //goto next_instruction;
+
+ } // for (;;)
+}
+
+// End of runnerline_impl.cpp
diff --git a/runnerline_impl.h b/runnerline_impl.h
new file mode 100644
index 0000000..ab9e9e5
--- /dev/null
+++ b/runnerline_impl.h
@@ -0,0 +1,531 @@
+#ifndef INCLUDE_BLASSIC_RUNNERLINE_IMPL_H
+#define INCLUDE_BLASSIC_RUNNERLINE_IMPL_H
+
+// runnerline_impl.h
+// Revision 23-jan-2005
+
+#include "runnerline.h"
+
+#include "blassic.h"
+#include "error.h"
+#include "result.h"
+#include "codeline.h"
+#include "file.h"
+#include "function.h"
+#include "var.h"
+
+#include <list>
+#include <algorithm>
+
+class Runner;
+class Program;
+class LocalLevel;
+class Directory;
+
+//#define INSTRUCTION_SWITCH
+//#define OPERATION_SWITCH
+
+#define BRUTAL_MODE
+#define ONE_TABLE
+
+class RunnerLineImpl : public RunnerLine {
+public:
+ typedef blassic::result::BlResult BlResult;
+
+ RunnerLineImpl (Runner & runner);
+ RunnerLineImpl (Runner & runner, const CodeLine & newcodeline);
+ ~RunnerLineImpl ();
+
+ void setcodeline (const CodeLine & newcodeline)
+ {
+ codeline= newcodeline;
+ }
+ CodeLine & getcodeline () { return codeline; }
+
+ bool execute_instruction ();
+ void execute ();
+
+ BlLineNumber number () const { return codeline.number (); }
+
+ ProgramPos getposactual () const
+ {
+ //return ProgramPos (pline->number (), actualchunk);
+ return ProgramPos (codeline.number (), actualchunk);
+ }
+private:
+ Program & program;
+ CodeLine::Token token;
+ BlCode codprev;
+
+ BlChunk actualchunk;
+ Directory * pdirectory;
+
+ // Instrucion execution.
+
+ bool fInElse;
+
+ // ************ Dispatch functions ****************
+
+ #ifndef INSTRUCTION_SWITCH
+ typedef bool (RunnerLineImpl::* do_func) ();
+ #endif
+
+ #ifndef OPERATION_SWITCH
+ typedef void (RunnerLineImpl::* do_valfunction) (BlResult &);
+ #endif
+
+ #ifdef ONE_TABLE
+
+ #ifdef INSTRUCTION_SWITCH
+ #error Incompatible options
+ #endif
+
+ struct functions_t {
+ do_func inst_func;
+ do_valfunction val_func;
+ };
+ struct tfunctions_t {
+ BlCode code;
+ functions_t f;
+ bool operator < (const tfunctions_t & t) const
+ {
+ return code < t.code;
+ }
+ };
+ static const tfunctions_t tfunctions [];
+ static const tfunctions_t * tfunctionsend;
+
+ #ifdef BRUTAL_MODE
+
+ static functions_t array_functions [];
+
+ #endif
+
+ #else
+ // No ONE_TABLE
+
+ // ************ Instruction functions *************
+
+ #ifndef INSTRUCTION_SWITCH
+
+ struct tfunc_t {
+ BlCode code;
+ do_func f;
+ bool operator < (const tfunc_t & t) const
+ {
+ return code < t.code;
+ }
+ };
+
+ static const tfunc_t tfunc [];
+ static const tfunc_t * tfuncend;
+
+ #endif
+
+ // ************ Val functions *****************
+
+ #ifndef OPERATION_SWITCH
+
+ struct valfunction_t {
+ BlCode code;
+ do_valfunction f;
+ bool operator < (const valfunction_t & t) const
+ {
+ return code < t.code;
+ }
+ };
+
+ static const valfunction_t valfunction [];
+ static const valfunction_t * valfunctionend;
+
+ #endif
+
+ #ifdef BRUTAL_MODE
+
+ static do_valfunction array_valfunction [];
+
+ static do_func array_func [];
+
+ #endif
+
+ #endif
+ // ONE_TABLE
+
+ #ifdef BRUTAL_MODE
+
+ static bool init_array_func ();
+ static bool array_func_inited;
+
+ #endif
+
+ #ifndef NDEBUG
+ static bool checktfunc ();
+ static const bool tfuncchecked;
+ #endif
+
+ #ifndef INSTRUCTION_SWITCH
+ do_func findfunc (BlCode code);
+ #endif
+
+ #ifndef OPERATION_SWITCH
+ do_valfunction findvalfunc (BlCode code);
+ #endif
+
+
+ //*****************************************************
+
+
+ bool syntax_error ();
+ void valsyntax_error (BlResult &);
+
+ void getnextchunk ();
+
+ blassic::file::BlFile & getfile (BlChannel channel) const;
+ blassic::file::BlFile & getfile0 () const;
+
+ void gettoken () { codeline.gettoken (token); }
+
+ bool endsentence () { return token.isendsentence (); }
+ void require_endsentence () const // throw (BlErrNo)
+ {
+ if (! token.isendsentence () )
+ throw ErrSyntax;
+ }
+
+ #if 0
+ // Use macros instead to avoid strange errors on hp-ux.
+ void requiretoken (BlCode code) const throw (BlErrNo);
+ void expecttoken (BlCode code) throw (BlErrNo);
+ #endif
+
+ BlNumber evalnum ();
+ BlNumber expectnum ();
+ BlInteger evalinteger ();
+ BlInteger expectinteger ();
+ std::string evalstring ();
+ std::string expectstring ();
+
+ BlChannel evalchannel ();
+ BlChannel expectchannel ();
+ BlChannel evaloptionalchannel (BlChannel defchan= DefaultChannel);
+ BlChannel expectoptionalchannel (BlChannel defchan= DefaultChannel);
+ BlChannel evalrequiredchannel ();
+ BlChannel expectrequiredchannel ();
+
+ void parenarg (BlResult & result);
+ void getparenarg (BlResult & result);
+ void getparenarg (BlResult & result, BlResult & result2);
+ blassic::file::BlFile & getparenfile ();
+
+ void valnumericfunc (double (* f) (double), BlResult & result);
+ void valnumericfunc2 (double (* f) (double, double),
+ BlResult & result);
+ void valtrigonometricfunc
+ (double (* f) (double), BlResult & result);
+ void valtrigonometricinvfunc
+ (double (* f) (double), BlResult & result);
+
+ void val_ASC (BlResult & result);
+ void val_LEN (BlResult & result);
+ void val_PEEK (BlResult & result);
+ void val_PEEK16 (BlResult & result);
+ void val_PEEK32 (BlResult & result);
+ void val_PROGRAMPTR (BlResult & result);
+ void val_SYSVARPTR (BlResult & result);
+ void val_RND (BlResult & result);
+ void val_INT (BlResult & result);
+ void val_SIN (BlResult & result);
+ void val_COS (BlResult & result);
+ void val_PI (BlResult & result);
+ void val_TAN (BlResult & result);
+ void val_SQR (BlResult & result);
+ void val_ASIN (BlResult & result);
+ void val_ACOS (BlResult & result);
+ void val_ATAN (BlResult & result);
+ void val_ABS (BlResult & result);
+ void val_LOG (BlResult & result);
+ void val_LOG10 (BlResult & result);
+ void val_EXP (BlResult & result);
+ void val_TIME (BlResult & result);
+ void val_ERR (BlResult & result);
+ void val_ERL (BlResult & result);
+ void val_FIX (BlResult & result);
+ void val_XMOUSE (BlResult & result);
+ void val_YMOUSE (BlResult & result);
+ void val_XPOS (BlResult & result);
+ void val_YPOS (BlResult & result);
+ void val_SINH (BlResult & result);
+ void val_COSH (BlResult & result);
+ void val_TANH (BlResult & result);
+ void val_ASINH (BlResult & result);
+ void val_ACOSH (BlResult & result);
+ void val_ATANH (BlResult & result);
+ void val_ATAN2 (BlResult & result);
+
+ void valinstrbase (BlResult & result, bool reverse);
+ void val_INSTR (BlResult & result);
+ void val_RINSTR (BlResult & result);
+
+ void valfindfirstlast (BlResult & result, bool first, bool yesno);
+ void val_FIND_FIRST_OF (BlResult & result);
+ void val_FIND_LAST_OF (BlResult & result);
+ void val_FIND_FIRST_NOT_OF (BlResult & result);
+ void val_FIND_LAST_NOT_OF (BlResult & result);
+
+ void val_USR (BlResult & result);
+ void val_VAL (BlResult & result);
+ void val_EOF (BlResult & result);
+ void val_VARPTR (BlResult & result);
+ void val_SGN (BlResult & result);
+ void val_CVI (BlResult & result);
+ void val_CVS (BlResult & result);
+ void val_CVD (BlResult & result);
+ void val_CVL (BlResult & result);
+ void val_MIN (BlResult & result);
+ void val_MAX (BlResult & result);
+ void val_CINT (BlResult & result);
+ void val_TEST (BlResult & result);
+ void val_TESTR (BlResult & result);
+ void val_POS (BlResult & result);
+ void val_VPOS (BlResult & result);
+ void val_LOF (BlResult & result);
+ void val_FREEFILE (BlResult & result);
+ void val_INKEY (BlResult & result);
+ void val_ROUND (BlResult & result);
+ void val_CVSMBF (BlResult & result);
+ void val_CVDMBF (BlResult & result);
+ void val_REGEXP_INSTR (BlResult & result);
+ void val_ALLOC_MEMORY (BlResult & result);
+ void val_LOC (BlResult & result);
+
+ void val_MID_S (BlResult & result);
+ void val_LEFT_S (BlResult & result);
+ void val_RIGHT_S (BlResult & result);
+ void val_CHR_S (BlResult & result);
+ void val_ENVIRON_S (BlResult & result);
+ void val_STRING_S (BlResult & result);
+ void val_OSFAMILY_S (BlResult & result);
+ void val_OSNAME_S (BlResult & result);
+ void val_HEX_S (BlResult & result);
+ void val_SPACE_S (BlResult & result);
+ void val_UPPER_S (BlResult & result);
+ void val_LOWER_S (BlResult & result);
+ void val_STR_S (BlResult & result);
+ void val_OCT_S (BlResult & result);
+ void val_BIN_S (BlResult & result);
+ void val_INKEY_S (BlResult & result);
+ void val_PROGRAMARG_S (BlResult & result);
+ void val_DATE_S (BlResult & result);
+ void val_TIME_S (BlResult & result);
+ void val_INPUT_S (BlResult & result);
+ void val_MKI_S (BlResult & result);
+ void val_MKS_S (BlResult & result);
+ void val_MKD_S (BlResult & result);
+ void val_MKL_S (BlResult & result);
+ void valtrimbase (BlResult & result, bool tleft, bool trigth);
+ void val_TRIM_S (BlResult & result);
+ void val_LTRIM_S (BlResult & result);
+ void val_RTRIM_S (BlResult & result);
+ void val_FINDFIRST_S (BlResult & result);
+ void val_FINDNEXT_S (BlResult & result);
+ void val_COPYCHR_S (BlResult & result);
+ void val_STRERR_S (BlResult & result);
+ void val_DEC_S (BlResult & result);
+ void val_VAL_S (BlResult & result);
+ void val_SCREEN_S (BlResult & result);
+ void val_MKSMBF_S (BlResult & result);
+ void val_MKDMBF_S (BlResult & result);
+ void val_REGEXP_REPLACE_S (BlResult & result);
+
+ void val_LET (BlResult & result);
+ void val_LABEL (BlResult & result);
+ void val_IDENTIFIER (BlResult & result);
+ void val_NUMBER (BlResult & result);
+ void val_STRING (BlResult & result);
+ void val_INTEGER (BlResult & result);
+ void val_OpenPar (BlResult & result);
+
+public:
+ void callfn (Function & f, const std::string & fname,
+ LocalLevel & ll, BlResult & result);
+private:
+ void val_FN (BlResult & result);
+
+ void valsubindex (const std::string & varname, BlResult & result);
+ void valbase (BlResult & result);
+ //void valparen (BlResult & result);
+
+ void slice (BlResult & result);
+
+ void valexponent (BlResult & result);
+ void valmod (BlResult & result);
+ void valunary (BlResult & result);
+ void valdivint (BlResult & result);
+ void valmuldiv (BlResult & result);
+ void valplusmin (BlResult & result);
+ void valcomp (BlResult & result);
+ void valorand (BlResult & result);
+
+ void eval (BlResult & result);
+ void expect (BlResult & result);
+
+ std::string::size_type evalstringindex ();
+ void evalstringslice (const std::string & str,
+ std::string::size_type & from, std::string::size_type & to);
+ void assignslice (VarPointer & vp, const BlResult & result);
+
+ VarPointer evalvarpointer ();
+ typedef std::list <VarPointer> ListVarPointer;
+ void evalmultivarpointer (ListVarPointer & lvp);
+ VarPointer eval_let ();
+
+ BlLineNumber evallinenumber ();
+ void evallinerange (BlLineNumber & blnBeg, BlLineNumber & blnEnd);
+ Dimension getdims ();
+ Dimension evaldims ();
+ Dimension expectdims ();
+
+ void errorifparam ();
+ void gosub_line (BlLineNumber dest);
+
+ void getinkparams ();
+ void getdrawargs (BlInteger & y);
+ void getdrawargs (BlInteger & x, BlInteger & y);
+
+ void make_clear ();
+
+ void print_using (blassic::file::BlFile & out);
+ void letsubindex (const std::string &varname);
+ void do_line_input ();
+ void do_get_image ();
+ void do_put_image ();
+ void definevars (VarType type);
+ void do_graphics_pen ();
+ void do_graphics_paper ();
+ void do_graphics_cls ();
+ bool do_def_fn ();
+ void do_list (BlChannel nfile);
+
+ bool do_Colon ();
+ bool do_ENDLINE ();
+ bool do_INTEGER ();
+ bool do_NUMBER ();
+ bool do_END ();
+ bool do_LIST ();
+ bool do_LLIST ();
+ bool do_REM ();
+ bool do_LOAD ();
+ bool do_SAVE ();
+ bool do_NEW ();
+ bool do_EXIT ();
+ bool do_RUN ();
+ bool do_PRINT ();
+ bool do_FOR ();
+ bool do_NEXT ();
+ bool do_IF ();
+ bool do_TRON ();
+ bool do_TROFF ();
+ bool do_IDENTIFIER ();
+ bool do_LET ();
+ bool do_GOTO ();
+ bool do_GOSUB ();
+ bool do_STOP ();
+ bool do_CONT ();
+ bool do_CLEAR ();
+ bool do_RETURN ();
+ bool do_POKE ();
+ bool do_READ ();
+ bool do_DATA ();
+ bool do_RESTORE ();
+ bool do_INPUT ();
+ bool do_LINE ();
+ bool do_RANDOMIZE ();
+ bool do_AUTO ();
+ bool do_DIM ();
+ bool do_SYSTEM ();
+ bool do_ON ();
+ bool do_ERROR ();
+ bool do_OPEN ();
+ bool do_POPEN ();
+ bool do_CLOSE ();
+ bool do_LOCATE ();
+ bool do_CLS ();
+ bool do_WRITE ();
+ bool do_MODE ();
+ bool do_MOVE ();
+ bool do_COLOR ();
+ bool do_GET ();
+ bool do_LABEL ();
+ bool do_DELIMITER ();
+ bool do_REPEAT ();
+ bool do_UNTIL ();
+ bool do_WHILE ();
+ bool do_WEND ();
+ bool do_PLOT ();
+ bool do_RESUME ();
+ bool do_DELETE ();
+ bool do_LOCAL ();
+ bool do_PUT ();
+ bool do_FIELD ();
+ bool do_LSET ();
+ bool do_SOCKET ();
+ bool do_MID_S ();
+ bool do_DRAW ();
+ bool do_DEF ();
+ bool do_FN ();
+ bool do_PROGRAMARG_S ();
+ bool do_ERASE ();
+ bool do_SWAP ();
+ bool do_SYMBOL ();
+ bool do_ZONE ();
+ bool do_POP ();
+ bool do_NAME ();
+ bool do_KILL ();
+ bool do_FILES ();
+ bool do_PAPER ();
+ bool do_PEN ();
+ bool do_SHELL ();
+ bool do_MERGE ();
+ bool do_CHDIR ();
+ bool do_MKDIR ();
+ bool do_RMDIR ();
+ bool do_SYNCHRONIZE ();
+ bool do_PAUSE ();
+ bool do_CHAIN ();
+ bool do_ENVIRON ();
+ bool do_EDIT ();
+ bool do_DRAWR ();
+ bool do_PLOTR ();
+ bool do_MOVER ();
+ bool do_POKE16 ();
+ bool do_POKE32 ();
+ bool do_RENUM ();
+ bool do_CIRCLE ();
+ bool do_MASK ();
+ bool do_WINDOW ();
+ bool do_GRAPHICS ();
+ bool do_BEEP ();
+ bool do_DEFINT ();
+ bool do_INK ();
+ bool do_SET_TITLE ();
+ bool do_TAG ();
+ bool do_ORIGIN ();
+ bool do_DEG ();
+ bool do_INVERSE ();
+ bool do_IF_DEBUG ();
+ bool do_WIDTH ();
+ bool do_BRIGHT ();
+ bool do_PLEASE ();
+ bool do_DRAWARC ();
+ bool do_PULL ();
+ bool do_PAINT ();
+ bool do_FREE_MEMORY ();
+ bool do_SCROLL ();
+ bool do_ZX_PLOT ();
+ bool do_ZX_UNPLOT ();
+ bool do_ELSE ();
+};
+
+#endif
+
+// End of runnerline_impl.h
diff --git a/runnerline_instructions.cpp b/runnerline_instructions.cpp
new file mode 100644
index 0000000..08d2fc4
--- /dev/null
+++ b/runnerline_instructions.cpp
@@ -0,0 +1,4277 @@
+// runnerline_instructions.cpp
+// Revision 24-apr-2009
+
+#include "runnerline_impl.h"
+
+#include "error.h"
+#include "runner.h"
+#include "program.h"
+#include "sysvar.h"
+#include "graphics.h"
+#include "util.h"
+using util::to_string;
+#include "memory.h"
+#include "directory.h"
+#include "charset.h"
+
+#include "trace.h"
+
+#include <memory>
+using std::auto_ptr;
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+using std::flush;
+
+#include <string.h>
+#include <time.h>
+
+#include <cassert>
+#define ASSERT assert
+
+namespace sysvar= blassic::sysvar;
+namespace onbreak= blassic::onbreak;
+
+using namespace blassic::file;
+
+#define requiretoken(c) if (token.code == c) ; else throw ErrSyntax
+
+#define expecttoken(c) \
+ do { \
+ gettoken (); \
+ if (token.code != c) throw ErrSyntax; \
+ } while (false)
+
+
+bool RunnerLineImpl::do_Colon ()
+{
+ return false;
+}
+
+bool RunnerLineImpl::do_ENDLINE ()
+{
+ return true;
+}
+
+bool RunnerLineImpl::do_INTEGER ()
+{
+ // goto omitido
+
+ if (codprev != keyELSE && codprev != keyTHEN)
+ {
+ if (codprev != keyGOTO && codprev != keyGOSUB)
+ throw ErrSyntax;
+ if (! sysvar::hasFlags1 (sysvar::ThenOmitted) )
+ throw ErrBlassicInternal;
+ // Not ErrSyntax, this is not supposed to happen.
+ }
+
+ BlLineNumber bln= evallinenumber ();
+ require_endsentence ();
+
+ if (codprev != keyGOSUB)
+ runner.goto_to (bln);
+ else
+ gosub_line (bln);
+
+ return true;
+}
+
+bool RunnerLineImpl::do_NUMBER ()
+{
+ return do_INTEGER ();
+}
+
+bool RunnerLineImpl::do_END ()
+{
+ errorifparam ();
+
+ #if 1
+
+ runner.close_all ();
+ runner.setstatus (Runner::Ended);
+ return true;
+
+ #else
+
+ throw blassic::ProgramEnd ();
+
+ #endif
+}
+
+void RunnerLineImpl::do_list (BlChannel nfile)
+{
+ // Same function used for LIST and LLIST, differing only
+ // in the default channel.
+
+ //BlChannel nfile= (token.code == keyLLIST) ?
+ // PrinterChannel : DefaultChannel;
+ gettoken ();
+ if (token.code == '#')
+ {
+ nfile= expectchannel ();
+ if (!endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ }
+ }
+
+ BlLineNumber iniline, endline;
+ evallinerange (iniline, endline);
+
+ require_endsentence ();
+
+ program.list (iniline, endline, getfile (nfile) );
+}
+
+bool RunnerLineImpl::do_LIST ()
+{
+ do_list (DefaultChannel);
+ return false;
+}
+
+bool RunnerLineImpl::do_LLIST ()
+{
+ do_list (PrinterChannel);
+ return false;
+}
+
+bool RunnerLineImpl::do_REM ()
+{
+ return true;
+}
+
+bool RunnerLineImpl::do_LOAD ()
+{
+ using std::ifstream;
+ using std::ios;
+
+ std::string progname= expectstring ();
+ if (endsentence () )
+ {
+ program.load (progname);
+ runner.setstatus (Runner::Ended);
+ return true;
+ }
+ requiretoken (',');
+ gettoken ();
+ if (token.code == keyIDENTIFIER &&
+ typeofvar (token.str) == VarString)
+ {
+ std::string varname= token.str;
+ gettoken ();
+ require_endsentence ();
+
+ ifstream is (progname.c_str (), ios::binary | ios::in);
+ // Without explicit in read doesn't work on hp-ux,
+ // I don't know why.
+
+ if (! is.is_open () )
+ throw ErrFileNotFound;
+ is.seekg (0, std::ios::end);
+ size_t size= is.tellg ();
+ is.seekg (0, std::ios::beg);
+ std::string result;
+ // Opening a block to avoid an error on Borland C++ that
+ // calls ~auto_buffer when throwing ErrFileNotFound
+ {
+ util::auto_buffer <char> aux (size);
+ is.read (aux, size);
+ result.assign (aux, size);
+ }
+ assignvarstring (varname, result);
+ }
+ else
+ {
+ char * init;
+ {
+ BlNumber bn= evalnum ();
+ init= reinterpret_cast <char *> (size_t (bn) );
+ }
+ size_t len= 0;
+ if (token.code == ',')
+ {
+ BlNumber bn= expectnum ();
+ len= size_t (bn);
+ }
+ require_endsentence ();
+
+ ifstream is (progname.c_str (), std::ios::binary);
+ if (! is.is_open () )
+ throw ErrFileNotFound;
+ if (len == 0)
+ {
+ is.seekg (0, std::ios::end);
+ len= is.tellg ();
+ is.seekg (0, std::ios::beg);
+ }
+ is.read (init, len);
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_SAVE ()
+{
+ using std::ofstream;
+
+ std::string progname= expectstring ();
+ if (endsentence () )
+ program.save (progname);
+ else
+ {
+ requiretoken (',');
+ expecttoken (keyIDENTIFIER);
+ if (token.str.size () != 1)
+ throw ErrSyntax;
+ char c= char (toupper (token.str [0] ) );
+ switch (c)
+ {
+ case 'A':
+ gettoken ();
+ require_endsentence ();
+ {
+ //BlFileRegular fout (progname, BlFile::Output);
+ //program.list (LineBeginProgram,
+ // LineEndProgram, fout);
+ auto_ptr <BlFile> pfout
+ (newBlFileRegular (progname, Output) );
+ program.list (LineBeginProgram,
+ LineEndProgram, * pfout);
+ }
+ break;
+ case 'B':
+ gettoken ();
+ if (token.code != ',')
+ throw ErrSyntax;
+ gettoken ();
+ {
+ const char * init;
+ size_t len;
+ if (token.code == keyIDENTIFIER &&
+ typeofvar (token.str) == VarString)
+ {
+ std::string * pstr= addrvarstring (token.str);
+ init= pstr->data ();
+ len= pstr->size ();
+ gettoken ();
+ }
+ else
+ {
+ BlNumber bn= evalnum ();
+ init= reinterpret_cast <const char *>
+ (size_t (bn) );
+ if (token.code != ',')
+ throw ErrSyntax;
+ bn= expectnum ();
+ len= size_t (bn);
+ }
+ require_endsentence ();
+ ofstream os (progname.c_str (), std::ios::binary);
+ if (! os.is_open () )
+ throw ErrFileNotFound;
+ os.write (init, len);
+ }
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_NEW ()
+{
+ errorifparam ();
+ program.renew ();
+ make_clear ();
+ return true;
+}
+
+bool RunnerLineImpl::do_EXIT ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_EXIT");
+
+ gettoken ();
+ int r= 0;
+ if (! endsentence () )
+ {
+ BlNumber n= evalnum ();
+ if (! endsentence () )
+ throw ErrSyntax;
+ r= int (n);
+ }
+ throw Exit (r);
+}
+
+bool RunnerLineImpl::do_RUN ()
+{
+ gettoken ();
+ BlLineNumber dest= LineBeginProgram;
+ if (token.code == keyNUMBER || token.code == keyINTEGER)
+ {
+ dest= evallinenumber ();
+ require_endsentence ();
+ }
+ else if (! endsentence () )
+ {
+ std::string progname= evalstring ();
+ require_endsentence ();
+ program.renew ();
+ program.load (progname);
+ }
+ make_clear ();
+ runner.clearreadline ();
+ runner.run_to (dest);
+ return true;
+}
+
+bool RunnerLineImpl::do_FOR ()
+{
+ const BlInteger one= 1;
+ ProgramPos posfor (getposactual () );
+ expecttoken (keyIDENTIFIER);
+ std::string varname= token.str;
+ expecttoken ('=');
+
+ std::auto_ptr <ForElement> pelement;
+ switch (typeofvar (varname) )
+ {
+ case VarNumber:
+ {
+ BlNumber initial= expectnum ();
+ requiretoken (keyTO);
+ BlNumber final= expectnum ();
+ BlNumber step= (token.code == keySTEP) ?
+ expectnum () : 1.0;
+ pelement.reset (newForElementNumber (varname, posfor,
+ initial, final, step) );
+ }
+ break;
+ case VarInteger:
+ {
+ BlInteger initial= expectinteger ();
+ requiretoken (keyTO);
+ BlInteger final= expectinteger ();
+ BlInteger step= (token.code == keySTEP) ?
+ expectinteger () : one;
+ pelement.reset (newForElementInteger (varname, posfor,
+ initial, final, step) );
+ }
+ break;
+ default:
+ throw ErrMismatch;
+ }
+
+ switch (token.code)
+ {
+ case ':':
+ pelement->nextchunk ();
+ break;
+ case keyENDLINE:
+ if (posfor.getnum () != LineDirectCommand)
+ pelement->nextline ();
+ else
+ pelement->nextchunk ();
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ runner.push_for (pelement.get () );
+ pelement.release ();
+ return false;
+}
+
+bool RunnerLineImpl::do_NEXT ()
+{
+ gettoken ();
+ //std::string varname;
+ if (endsentence () )
+ {
+ #if 0
+ //if (runner.for_empty () )
+ // throw ErrNextWithoutFor;
+ ForElement & fe= runner.for_top ();
+ if (fe.next () )
+ {
+ runner.jump_to (fe.getpos () );
+ return true;
+ }
+ runner.for_pop ();
+ return false;
+ #else
+
+ return runner.next ();
+
+ #endif
+ }
+
+ for (;;)
+ {
+ requiretoken (keyIDENTIFIER);
+ //varname= token.str;
+ //gettoken ();
+
+ #if 0
+ //if (runner.for_empty () )
+ // throw ErrNextWithoutFor;
+ ForElement * pfe= & runner.for_top ();
+ //if (! varname.empty () && ! fe.isvar (varname) )
+ if (! pfe->isvar (token.str) )
+ {
+ if (sysvar::get (sysvar::TypeOfNextCheck) == 0)
+ {
+ if (showdebuginfo () )
+ cerr << "Processing NEXT " <<
+ token.str <<
+ " but current FOR is " <<
+ pfe->var () <<
+ endl;
+ throw ErrNextWithoutFor;
+ }
+ else
+ {
+ // In ZX style NEXT can be omitted.
+ do {
+ runner.for_pop ();
+ pfe= & runner.for_top ();
+ } while (! pfe->isvar (token.str) );
+ }
+ }
+ if (pfe->next () )
+ {
+ runner.jump_to (pfe->getpos () );
+ return true;
+ }
+ runner.for_pop ();
+ #else
+
+ if (runner.next (token.str) )
+ return true;
+
+ #endif
+
+ gettoken ();
+ if (endsentence () )
+ break;
+ requiretoken (',');
+ //expecttoken (keyIDENTIFIER);
+ //varname= token.str;
+ gettoken ();
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_IF ()
+{
+ BlNumber result= expectnum ();
+
+ if (token.code != keyTHEN)
+ {
+ // First check if THEN can be omitted.
+ if (! sysvar::hasFlags1 (sysvar::ThenOmitted) )
+ throw ErrSyntax;
+ // If that case, check the valid instructions.
+ if (token.code != keyGOTO && token.code != keyGOSUB)
+ throw ErrSyntax;
+ }
+
+ if (result != 0)
+ return false;
+ else
+ {
+ // Search ELSE, with possible nested IFs.
+ unsigned int iflevel= 1;
+ do
+ {
+ gettoken ();
+ switch (token.code)
+ {
+ case keyIF:
+ ++iflevel; break;
+ case keyELSE:
+ --iflevel; break;
+ default:
+ break;
+ }
+ } while (iflevel > 0 && token.code != keyENDLINE);
+ if (token.code == keyELSE)
+ {
+ // Continue processing the line in the position
+ // after the ELSE. The flag marks the ELSE must
+ // be entered, otherwise is supposed that has
+ // encountered as the end of other instruction.
+ fInElse= true;
+ return false;
+ }
+ else
+ {
+ // Only can be ENDLINE.
+ return true;
+ }
+ }
+}
+
+bool RunnerLineImpl::do_TRON ()
+{
+ gettoken ();
+ bool fLine= false;
+ if (token.code == keyLINE)
+ {
+ fLine= true;
+ gettoken ();
+ }
+ //BlChannel channel= DefaultChannel;
+ //if (token.code == '#')
+ // channel= expectchannel ();
+ BlChannel channel= evaloptionalchannel ();
+
+ require_endsentence ();
+ runner.tron (fLine, channel);
+ return false;
+}
+
+bool RunnerLineImpl::do_TROFF ()
+{
+ errorifparam ();
+ runner.troff ();
+ return false;
+}
+
+#if 0
+void RunnerLineImpl::letsubindex (const std::string & varname)
+{
+ Dimension dims= expectdims ();
+ requiretoken ('=');
+ BlResult result;
+ expect (result);
+ require_endsentence ();
+ switch (typeofvar (varname) )
+ {
+ case VarNumber:
+ assigndimnumber (varname, dims, result.number () );
+ break;
+ case VarInteger:
+ assigndiminteger (varname, dims, result.integer () );
+ break;
+ case VarString:
+ assigndimstring (varname, dims, result.str () );
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+}
+#endif
+
+bool RunnerLineImpl::do_IDENTIFIER ()
+{
+ #if 0
+
+ requiretoken (keyIDENTIFIER);
+ std::string varname= token.str;
+ gettoken ();
+ if (token.code == '(')
+ {
+ letsubindex (varname);
+ return false;
+ }
+ //requiretoken ('=');
+ // Crash on hp-ux when failed. Compiler fault?
+ // Workaround:
+ if (token.code != '=')
+ throw ErrSyntax;
+
+ BlResult result;
+ expect (result);
+ require_endsentence ();
+ switch (typeofvar (varname) )
+ {
+ case VarNumber:
+ assignvarnumber (varname, result.number () );
+ break;
+ case VarInteger:
+ assignvarinteger (varname, result.integer () );
+ break;
+ case VarString:
+ assignvarstring (varname, result.str () );
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+
+ #else
+
+ eval_let ();
+ require_endsentence ();
+
+ #endif
+
+ return false;
+}
+
+bool RunnerLineImpl::do_LET ()
+{
+ gettoken ();
+ return do_IDENTIFIER ();
+}
+
+bool RunnerLineImpl::do_GOTO ()
+{
+ gettoken ();
+ BlLineNumber dest= evallinenumber ();
+ require_endsentence ();
+ runner.goto_to (dest);
+ return true;
+}
+
+bool RunnerLineImpl::do_GOSUB ()
+{
+ gettoken ();
+ BlLineNumber dest= evallinenumber ();
+ require_endsentence ();
+
+ gosub_line (dest);
+ return true;
+}
+
+bool RunnerLineImpl::do_STOP ()
+{
+ errorifparam ();
+
+ #if 1
+
+ BlFile & f= getfile0 ();
+ f << "**Stopped**";
+
+ //if (line.number () != 0)
+ // f << " in " << line.number ();
+ //if (pline->number () != 0)
+ // f << " in " << pline->number ();
+ if (codeline.number () != LineDirectCommand)
+ f << " in " << codeline.number ();
+
+ //f << '\n';
+ f.endline ();
+ //ProgramPos posbreak (runner.getposactual () );
+ ProgramPos posbreak (getposactual () );
+ posbreak.nextchunk ();
+ runner.set_break (posbreak);
+ runner.setstatus (Runner::Stopped);
+ return true;
+
+ #else
+
+ throw blassic::ProgramStop ();
+
+ #endif
+}
+
+bool RunnerLineImpl::do_CONT ()
+{
+ errorifparam ();
+ runner.jump_break ();
+ return true;
+}
+
+bool RunnerLineImpl::do_CLEAR ()
+{
+ gettoken ();
+ switch (token.code)
+ {
+ case keyINK:
+ gettoken ();
+ require_endsentence ();
+ graphics::clearink ();
+ break;
+ case keyINPUT:
+ gettoken ();
+ require_endsentence ();
+ runner.clean_input ();
+ break;
+ default:
+ if (! endsentence () )
+ throw ErrSyntax;
+ make_clear ();
+ break;
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_RETURN ()
+{
+ gettoken ();
+ BlLineNumber line= LineEndProgram;
+ if (! endsentence () )
+ {
+ line= evallinenumber ();
+ require_endsentence ();
+ }
+ ProgramPos pos;
+ runner.gosub_pop (pos);
+ if (line != LineEndProgram)
+ runner.goto_to (line);
+ else
+ runner.jump_to (pos);
+ return true;
+}
+
+bool RunnerLineImpl::do_POKE ()
+{
+ BlNumber bnAddr= expectnum ();
+ requiretoken (',');
+ //BlChar * addr= (BlChar *) (unsigned int) bnAddr;
+ BlChar * addr= (BlChar *) (size_t) bnAddr;
+ BlNumber bnValue= expectnum ();
+ require_endsentence ();
+ BlChar value= (BlChar) (unsigned int) bnValue;
+ * addr= value;
+ return false;
+}
+
+bool RunnerLineImpl::do_READ ()
+{
+ // Yes, I know this function has many gotos and is poorly
+ // structured. Maybe someday I rewrite it. In the
+ // meantime, if someone write a good replacement and send
+ // it to me, I will put his/her name here in upper case ;)
+
+ //TRACEFUNC (tr, "RunnerLineImpl::do_READ");
+
+ ListVarPointer lvp;
+ gettoken ();
+ evalmultivarpointer (lvp);
+ require_endsentence ();
+ if (lvp.empty () )
+ {
+ if (showdebuginfo () )
+ cerr << "Empty READ var list" << endl;
+ throw ErrSyntax;
+ }
+ ListVarPointer::iterator itvp= lvp.begin ();
+ const ListVarPointer::iterator itvpend= lvp.end ();
+
+ BlLineNumber & datanumline= runner.getdatanumline ();
+ BlChunk & datachunk= runner.getdatachunk ();
+ unsigned short & dataelem= runner.getdataelem ();
+
+ //CodeLine dataline= program.getline (datanumline);
+ CodeLine dataline;
+
+ program.getline (datanumline, dataline);
+
+ CodeLine::Token datatok;
+otra:
+ if (dataline.number () == LineEndProgram)
+ throw ErrDataExhausted;
+ if (dataline.number () > datanumline)
+ {
+ datachunk= 0;
+ dataelem= 0;
+ }
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ if (dataline.chunk () < datachunk)
+ {
+ while (dataline.chunk () < datachunk)
+ {
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ if (datatok.code == keyENDLINE)
+ break;
+ }
+ if (datatok.code != keyENDLINE)
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ }
+ if (datatok.code == keyENDLINE)
+ {
+ //cerr << "Read searching next line" << endl;
+ //dataline= program.getnextline (dataline);
+ program.getnextline (dataline);
+ goto otra;
+ }
+otra2:
+ while (datatok.code != keyDATA)
+ {
+ dataelem= 0;
+ datachunk= dataline.chunk ();
+ do {
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ } while (datatok.code != keyENDLINE &&
+ dataline.chunk () == datachunk);
+ if (datatok.code == keyENDLINE)
+ {
+ //cerr << "Read searching next line" << endl;
+ //dataline= program.getnextline (dataline);
+ program.getnextline (dataline);
+ if (dataline.number () == LineEndProgram)
+ throw ErrDataExhausted;
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ }
+ else
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ }
+ datatok= dataline.getdata ();
+ unsigned short elem= 0;
+otra3:
+ while (elem < dataelem)
+ {
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ if (datatok.code == ':')
+ {
+ //datatok= dataline.gettoken ();
+ dataline.gettoken (datatok);
+ dataelem= 0;
+ goto otra2;
+ }
+ if (datatok.code == keyENDLINE)
+ {
+ //cerr << "Read searching next line" << endl;
+ //dataline= program.getnextline (dataline);
+ program.getnextline (dataline);
+ goto otra;
+ }
+ if (datatok.code != ',')
+ {
+ if (showdebuginfo () )
+ cerr << "DATA invalid on line " <<
+ dataline.number () << endl;
+ throw ErrSyntax;
+ }
+ datatok= dataline.getdata ();
+
+ // Supressed this check to allow a comma at end of data.
+ //if (datatok.isendsentence () )
+ // throw ErrSyntax;
+
+ ++elem;
+ }
+
+ //cerr << "(Data en linea " << dataline.number () <<
+ // " '" << datatok.str << "' " <<
+ // datatok.integer () << ')' << flush;
+
+ datanumline= dataline.number ();
+ datachunk= dataline.chunk ();
+ dataelem= (unsigned short) (elem + 1);
+
+ switch (itvp->type)
+ {
+ case VarNumber:
+ * itvp->pnumber= datatok.number ();
+ break;
+ case VarInteger:
+ switch (datatok.code)
+ {
+ case keyINTEGER:
+ * itvp->pinteger= datatok.valueint;
+ break;
+ case keyENDLINE:
+ * itvp->pinteger= 0;
+ break;
+ case keySTRING:
+ {
+
+ BlResult r= datatok.number ();
+ * itvp->pinteger= r.integer ();
+ }
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "DATA mismatch on line " <<
+ dataline.number () << endl;
+ throw ErrMismatch;
+ }
+ break;
+ #if 0
+ case VarString:
+ switch (datatok.code)
+ {
+ case keySTRING:
+ * itvp->pstring= datatok.str;
+ break;
+ case keyINTEGER:
+ * itvp->pstring= to_string (datatok.valueint);
+ break;
+ case keyENDLINE:
+ * itvp->pstring= std::string ();
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Unexpected token in DATA in line" <<
+ datanumline << endl;
+ throw ErrBlassicInternal;
+ }
+ break;
+ #endif
+ case VarString:
+ case VarStringSlice:
+ {
+ std::string value;
+ switch (datatok.code)
+ {
+ case keySTRING:
+ value= datatok.str;
+ break;
+ case keyINTEGER:
+ value= to_string (datatok.valueint);
+ break;
+ case keyENDLINE:
+ value= std::string ();
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Unexpected token in DATA "
+ "in line" <<
+ datanumline << endl;
+ throw ErrBlassicInternal;
+ }
+ if (itvp->type == VarString)
+ * itvp->pstring= value;
+ else
+ assignslice (* itvp, BlResult (value) );
+ }
+ break;
+ default:
+ if (showdebuginfo () )
+ cerr << "Unexpected var type in READ "
+ "of DATA in line" << datanumline << endl;
+ throw ErrBlassicInternal;
+ }
+ if (++itvp != itvpend)
+ goto otra3;
+
+ return false;
+}
+
+bool RunnerLineImpl::do_DATA ()
+{
+ do
+ {
+ gettoken ();
+ } while (! endsentence () );
+ return false;
+}
+
+bool RunnerLineImpl::do_RESTORE ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_restore");
+
+ gettoken ();
+ if (! endsentence () )
+ {
+ BlLineNumber bln= evallinenumber ();
+ require_endsentence ();
+ TRMESSAGE (tr,
+ std::string ("Restoring to ") + to_string (bln) );
+ runner.setreadline (bln);
+ }
+ else
+ {
+ TRMESSAGE (tr, "Restoring to begin");
+ runner.clearreadline ();
+ }
+ return false;
+}
+
+namespace {
+
+struct clearvar {
+ void operator () (VarPointer & vt) const
+ {
+ switch (vt.type)
+ {
+ case VarNumber:
+ * vt.pnumber= 0;
+ break;
+ case VarInteger:
+ * vt.pinteger= 0;
+ break;
+ case VarString:
+ vt.pstring->erase ();
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+};
+
+bool isdelimdiscardingwhite (std::istream & is, char delim)
+{
+ char c;
+ while (is.get (c) )
+ {
+ if (c == delim)
+ {
+ is.putback (c);
+ return true;
+ }
+ if (! isspace (c) )
+ {
+ is.putback (c);
+ return false;
+ }
+ }
+ return true; // We count eof as delimiter
+}
+
+void parsestring (std::string & result, std::istringstream & iss,
+ char quote, char delimiter)
+{
+ std::string str;
+ char c;
+ bool atend= isdelimdiscardingwhite
+ (iss, delimiter);
+ if (! atend)
+ {
+ iss >> c;
+ if (! iss)
+ atend= true;
+ }
+ if (! atend)
+ {
+ if (c == quote)
+ {
+ #if 0
+ while (iss >> c && c != quote)
+ {
+ str+= c;
+ }
+ #else
+ while (iss >> c)
+ {
+ if (c != quote)
+ str+= c;
+ else
+ {
+ iss >> c;
+ if (! iss)
+ break;
+ if (c == quote)
+ str+= c;
+ else
+ {
+ iss.unget ();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+ else
+ {
+ while (iss && c != delimiter)
+ {
+ str+= c;
+ iss >> c;
+ }
+ if (iss)
+ iss.unget ();
+ }
+ }
+ //* vp.pstring= str;
+ result= str;
+}
+
+void parsenumber (BlNumber & result, std::istringstream & iss,
+ char /* quote*/, char delimiter)
+{
+ BlNumber n;
+ if (isdelimdiscardingwhite (iss, delimiter) )
+ n= 0;
+ else
+ {
+ iss >> n;
+ if (! iss)
+ throw ErrMismatch;
+ }
+ //* vp.pnumber= n;
+ result= n;
+}
+
+void parseinteger (BlInteger & result, std::istringstream & iss,
+ char /* quote*/, char delimiter)
+{
+ BlInteger n;
+ if (isdelimdiscardingwhite (iss, delimiter) )
+ n= 0;
+ else
+ {
+ iss >> n;
+ if (! iss)
+ throw ErrMismatch;
+ }
+ //* vp.pinteger= n;
+ result= n;
+}
+
+} // namespace
+
+bool RunnerLineImpl::do_INPUT ()
+{
+ gettoken ();
+ BlChannel channel= DefaultChannel;
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ std::string prompt;
+ bool lineend= true;
+ if (token.code == ';')
+ {
+ lineend= false;
+ gettoken ();
+ }
+ switch (token.code)
+ {
+ case keySTRING:
+ prompt= token.str;
+ gettoken ();
+ switch (token.code)
+ {
+ // This was reversed, corected on 3-jun-2003
+ case ';':
+ prompt+= "? ";
+ break;
+ case ',':
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ std::cout << flush;
+ gettoken ();
+ break;
+ default:
+ prompt= "? ";
+ }
+
+ // Parse the list of variables.
+
+ ListVarPointer inputvars;
+ evalmultivarpointer (inputvars);
+ require_endsentence ();
+ if (inputvars.empty () )
+ throw ErrSyntax;
+
+ // Prepare input channel
+
+ std::string input;
+ BlFile & in= getfile (channel);
+ char quote= in.quote ();
+ char delimiter= in.delimiter ();
+
+ // Accept line from input
+
+ for (;;)
+ {
+ if (channel == DefaultChannel)
+ {
+ runner.clean_input ();
+ //cursorvisible ();
+ }
+ if (! prompt.empty () )
+ {
+ if (channel == DefaultChannel || in.istextwindow () )
+ {
+ in << prompt;
+ in.flush ();
+ }
+ }
+ in.getline (input, lineend);
+
+ if (fInterrupted)
+ {
+ std::cin.clear ();
+ if (runner.getbreakstate () != onbreak::BreakCont)
+ // This throw causes an error in windows,
+ // we return and let the caller catch
+ // the interrupted condition instead.
+ //throw BlBreak ();
+ return false;
+ else
+ {
+ fInterrupted= false;
+ //in << '\n';
+ in.endline ();
+ continue;
+ }
+ }
+ break;
+ }
+
+ // Process the line entered
+
+ // We must take into account that an whitespace can be a delimiter
+ // (tipically a tab).
+
+ std::istringstream iss (input);
+ iss.unsetf (std::ios::skipws);
+
+ ListVarPointer::iterator itvp= inputvars.begin ();
+ const ListVarPointer::iterator itvpend= inputvars.end ();
+
+ for ( ; itvp != itvpend; ++itvp)
+ {
+ VarPointer & vp= * itvp;
+ switch (vp.type)
+ {
+ case VarNumber:
+ parsenumber (* vp.pnumber, iss, quote, delimiter);
+ break;
+ case VarInteger:
+ parseinteger (* vp.pinteger, iss, quote, delimiter);
+ break;
+ case VarString:
+ parsestring (* vp.pstring, iss, quote, delimiter);
+ break;
+ case VarStringSlice:
+ {
+ std::string str;
+ parsestring (str, iss, quote, delimiter);
+ assignslice (vp, BlResult (str) );
+ }
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ if (isdelimdiscardingwhite (iss, delimiter) )
+ {
+ if (iss.eof () )
+ {
+ //++i;
+ ++itvp;
+ break;
+ }
+ else
+ iss.get ();
+ }
+ else
+ throw ErrMismatch;
+ }
+
+ // If not enough data entered, clear remaining vars.
+
+ std::for_each (itvp, itvpend, clearvar () );
+
+ return false;
+}
+
+void RunnerLineImpl::do_line_input ()
+{
+ #if 0
+
+ gettoken ();
+ BlChannel channel= DefaultChannel;
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+
+ #else
+
+ gettoken ();
+ BlChannel channel= DefaultChannel;
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ std::string prompt;
+ bool lineend= true;
+ if (token.code == ';')
+ {
+ lineend= false;
+ gettoken ();
+ }
+ switch (token.code)
+ {
+ case keySTRING:
+ prompt= token.str;
+ gettoken ();
+ switch (token.code)
+ {
+ // This was reversed, corected on 3-jun-2003
+ case ';':
+ prompt+= "? ";
+ break;
+ case ',':
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ std::cout << flush;
+ gettoken ();
+ break;
+ default:
+ prompt= "? ";
+ }
+
+ #endif
+
+ requiretoken (keyIDENTIFIER);
+ std::string varname= token.str;
+ gettoken ();
+ require_endsentence ();
+ if (typeofvar (varname) != VarString)
+ throw ErrMismatch;
+
+ std::string value;
+ BlFile & in= getfile (channel);
+ if (channel == DefaultChannel)
+ {
+ runner.clean_input ();
+ //cursorvisible ();
+ }
+
+ for (;;)
+ {
+ if (! prompt.empty () )
+ {
+ if (channel == DefaultChannel || in.istextwindow () )
+ {
+ in << prompt;
+ in.flush ();
+ }
+ }
+ in.getline (value, lineend);
+ if (fInterrupted)
+ {
+ std::cin.clear ();
+ if (runner.getbreakstate () != onbreak::BreakCont)
+ return;
+ else
+ {
+ fInterrupted= false;
+ //in << '\n';
+ in.endline ();
+ continue;
+ }
+ }
+ break;
+ }
+
+ assignvarstring (varname, value);
+}
+
+bool RunnerLineImpl::do_LINE ()
+{
+ gettoken ();
+ if (token.code == keyINPUT)
+ {
+ do_line_input ();
+ return false;
+ }
+ graphics::Point from;
+ if (token.code == '-')
+ from= graphics::getlast ();
+ else
+ {
+ requiretoken ('(');
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ requiretoken (')');
+ expecttoken ('-');
+ from= graphics::Point (x, y);
+ }
+ expecttoken ('(');
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ requiretoken (')');
+ gettoken ();
+ enum Type { TypeLine, TypeRect, TypeFillRect };
+ Type type= TypeLine;
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger color= evalinteger ();
+ graphics::setcolor (color);
+ }
+ if (token.code == ',')
+ {
+ gettoken ();
+ requiretoken (keyIDENTIFIER);
+ if (token.str == "B")
+ type= TypeRect;
+ else if (token.str == "BF")
+ type= TypeFillRect;
+ else throw ErrSyntax;
+ gettoken ();
+ }
+ require_endsentence ();
+ }
+
+ switch (type)
+ {
+ case TypeLine:
+ graphics::move (from.x, from.y);
+ graphics::line (x, y);
+ break;
+ case TypeRect:
+ graphics::rectangle (from, graphics::Point (x, y) );
+ break;
+ case TypeFillRect:
+ graphics::rectanglefilled (from, graphics::Point (x, y) );
+ break;
+ }
+
+ return false;
+}
+
+bool RunnerLineImpl::do_RANDOMIZE ()
+{
+ gettoken ();
+ unsigned int seedvalue;
+ if (endsentence () )
+ seedvalue= time (NULL);
+ else
+ {
+ BlNumber result= evalnum ();
+ //errorifparam ();
+ require_endsentence ();
+ //seedvalue= static_cast <unsigned int> (result);
+ seedvalue= util::checked_cast <unsigned int>
+ (result, ErrBadSubscript);
+ }
+
+ #if 0
+ randgen.seed (seedvalue);
+ #else
+ runner.seedrandom (seedvalue);
+ #endif
+
+ return false;
+}
+
+bool RunnerLineImpl::do_AUTO ()
+{
+ if (codeline.number () != LineDirectCommand)
+ throw ErrInvalidCommand;
+ BlLineNumber
+ auto_ini= sysvar::get32 (sysvar::AutoInit),
+ auto_inc= sysvar::get32 (sysvar::AutoInc);
+ gettoken ();
+ if (! endsentence () )
+ {
+ if (token.code != ',')
+ {
+ switch (token.code)
+ {
+ case keyNUMBER:
+ auto_ini= (BlLineNumber) token.number ();
+ break;
+ case keyINTEGER:
+ auto_ini= token.integer ();
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ gettoken ();
+ }
+ if (token.code == ',')
+ {
+ gettoken ();
+ switch (token.code)
+ {
+ case keyNUMBER:
+ auto_inc= (BlLineNumber) token.number ();
+ break;
+ case keyINTEGER:
+ auto_inc= token.integer ();
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ gettoken ();
+ }
+ require_endsentence ();
+ }
+ #if 0
+ blnAuto= auto_ini;
+ blnAutoInc= auto_inc;
+ #else
+ runner.setauto (auto_ini, auto_inc);
+ #endif
+ return false;
+}
+
+bool RunnerLineImpl::do_DIM ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_DIM");
+
+ do {
+ expecttoken (keyIDENTIFIER);
+ std::string varname= token.str;
+ Dimension dims= expectdims ();
+ switch (typeofvar (varname) )
+ {
+ case VarNumber:
+ dimvarnumber (varname, dims);
+ break;
+ case VarInteger:
+ dimvarinteger (varname, dims);
+ break;
+ case VarString:
+ dimvarstring (varname, dims);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ } while (token.code == ',');
+ require_endsentence ();
+ return false;
+}
+
+bool RunnerLineImpl::do_SYSTEM ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_SYSTEM");
+
+ errorifparam ();
+ throw Exit ();
+}
+
+bool RunnerLineImpl::do_ON ()
+{
+ enum TypeOn { OnNoValid, OnGoto, OnGosub };
+ gettoken ();
+ switch (token.code)
+ {
+ case keyERROR:
+ {
+ expecttoken (keyGOTO);
+ gettoken ();
+ // Allow use line 0 if using a label.
+ bool islabel= token.code == keyIDENTIFIER;
+ BlLineNumber bln= evallinenumber ();
+ require_endsentence ();
+ if (bln != 0 || islabel)
+ runner.seterrorgoto (bln, codeline.number () );
+ else
+ runner.clearerrorgoto ();
+ }
+ return false;
+ case keyBREAK:
+ gettoken ();
+ switch (token.code)
+ {
+ case keySTOP:
+ runner.setbreakstate (onbreak::BreakStop);
+ break;
+ case keyCONT:
+ runner.setbreakstate (onbreak::BreakCont);
+ break;
+ case keyGOSUB:
+ {
+ gettoken ();
+ BlLineNumber bln= evallinenumber ();
+ errorifparam ();
+ runner.setbreakgosub (bln);
+ }
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ return false;
+ case keySharp:
+ {
+ BlChannel ch= expectchannel ();
+ requiretoken (keyGOSUB);
+ gettoken ();
+ BlLineNumber line= evallinenumber ();
+ require_endsentence ();
+ runner.pollchannel (ch, line);
+ }
+ return false;
+ default:
+ break;
+ }
+ BlNumber bn= evalnum ();
+ size_t n= (size_t) bn;
+
+ TypeOn type= OnNoValid;
+ switch (token.code)
+ {
+ case keyGOTO:
+ type= OnGoto;
+ break;
+ case keyGOSUB:
+ type= OnGosub;
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ BlLineNumber bln;
+ std::vector <BlLineNumber> line;
+ do
+ {
+ gettoken ();
+ bln= evallinenumber ();
+ line.push_back (bln);
+ } while (token.code == ',');
+ require_endsentence ();
+ size_t l= line.size ();
+ if (n > 0 && n <= l)
+ {
+ switch (type)
+ {
+ case OnGoto:
+ runner.goto_to (line [n - 1] );
+ break;
+ case OnGosub:
+ gosub_line (line [n - 1] );
+ break;
+ default:
+ ; // Avoid a warning
+ }
+ return true;
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_ERROR ()
+{
+ BlNumber blCod= expectnum ();
+ require_endsentence ();
+ throw BlErrNo (blCod);
+}
+
+bool RunnerLineImpl::do_OPEN ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_OPEN");
+
+ BlCode op= token.code;
+ BlChannel channel= DefaultChannel;
+ std::string filename;
+ OpenMode mode= Input;
+ size_t record_len= 128;
+ bool binary= false;
+ // Defined here to avoid an error in C++ Builder
+ auto_ptr <BlFile> pbf;
+
+ gettoken ();
+ if (token.code == keyERROR)
+ {
+ if (op != keyOPEN)
+ throw ErrSyntax;
+ op= keyERROR;
+ expecttoken (keyAS);
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //channel= evalchannel ();
+ channel= expectrequiredchannel ();
+ }
+ else
+ {
+ BlResult result;
+ eval (result);
+ std::string firstarg= result.str ();
+ switch (token.code)
+ {
+ case keyFOR:
+ // Newer syntax.
+ filename= firstarg;
+ gettoken ();
+ if (token.code == keyBINARY)
+ {
+ binary= true;
+ gettoken ();
+ }
+ switch (token.code)
+ {
+ case keyINPUT:
+ mode= Input;
+ break;
+ case keyOUTPUT:
+ mode= Output;
+ break;
+ case keyAPPEND:
+ mode= Append;
+ break;
+ case keyRANDOM:
+ mode= Random;
+ break;
+ case keyLPRINT:
+ if (op != keyOPEN)
+ throw ErrSyntax;
+ mode= Append;
+ channel= PrinterChannel;
+ gettoken ();
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ if (channel == DefaultChannel)
+ {
+ expecttoken (keyAS);
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //channel= evalchannel ();
+ channel= expectrequiredchannel ();
+
+ if (token.code == keyLEN)
+ {
+ expecttoken ('=');
+ gettoken ();
+ BlNumber bn= evalnum ();
+ record_len= size_t (bn);
+ if (mode != Random)
+ throw ErrFileMode;
+ }
+ }
+ break;
+ case keyAS:
+ filename= firstarg;
+ if (op == keyPOPEN)
+ mode= InOut;
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //channel= evalchannel ();
+ channel= expectrequiredchannel ();
+ break;
+ case ',':
+ // Older syntax.
+ if (firstarg == "I" || firstarg == "i")
+ mode= Input;
+ else if (firstarg == "O" || firstarg == "o")
+ mode= Output;
+ else if (firstarg == "A" || firstarg == "a")
+ mode= Append;
+ else if (firstarg == "R" || firstarg == "r")
+ mode= Random;
+ else
+ throw ErrFileMode;
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //channel= evalchannel ();
+ channel= expectrequiredchannel ();
+ requiretoken (',');
+ filename= expectstring ();
+ if (token.code == ',')
+ {
+ if (mode != Random)
+ throw ErrFileMode;
+ BlNumber bn= expectnum ();
+ record_len= size_t (bn);
+ }
+ break;
+ default:
+ throw ErrSyntax;
+ } // switch
+ } // if
+
+ require_endsentence ();
+ if (channel == DefaultChannel)
+ throw ErrFileNumber;
+
+ // BINARY is ignored except with regular file.
+ //auto_ptr <BlFile> pbf;
+ switch (op)
+ {
+ case keyOPEN:
+ if (mode == Random)
+ pbf. reset (newBlFileRandom (filename, record_len) );
+ else
+ {
+ if (binary)
+ mode= OpenMode (mode | Binary);
+ pbf.reset (newBlFileRegular (filename, mode) );
+ }
+ break;
+ case keyPOPEN:
+ if (mode != Input && mode != Output && mode != InOut)
+ throw ErrFileMode;
+ pbf.reset (newBlFilePopen (filename, mode) );
+ break;
+ case keyERROR:
+ pbf.reset (newBlFileOutput (cerr) );
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+
+ runner.setfile (channel, pbf.get () );
+ pbf.release ();
+ return false;
+}
+
+bool RunnerLineImpl::do_POPEN ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_POPEN");
+
+ OpenMode mode= InOut;
+
+ std::string filename= expectstring ();
+ bool witherror= false;
+ if (token.code == keyERROR)
+ {
+ witherror= true;
+ gettoken ();
+ }
+ if (token.code == keyFOR)
+ {
+ gettoken ();
+ switch (token.code)
+ {
+ case keyINPUT:
+ mode= Input;
+ break;
+ case keyOUTPUT:
+ mode= Output;
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ gettoken ();
+ }
+ requiretoken (keyAS);
+ BlChannel channel= expectrequiredchannel ();
+ require_endsentence ();
+
+ if (witherror)
+ mode= OpenMode (mode | WithErr);
+ auto_ptr <BlFile> pbf (newBlFilePopen (filename, mode) );
+ runner.setfile (channel, pbf.get () );
+ pbf.release ();
+
+ return false;
+}
+
+bool RunnerLineImpl::do_CLOSE ()
+{
+ gettoken ();
+ if (endsentence () )
+ {
+ runner.close_all ();
+ return false;
+ }
+ if (token.code == keyINPUT || token.code == keyOUTPUT)
+ {
+ bool isinput= token.code == keyINPUT;
+ for (;;)
+ {
+ BlChannel channel= expectrequiredchannel ();
+ BlFile & f= getfile (channel);
+ if (isinput)
+ f.closein ();
+ else
+ f.closeout ();
+ if (token.code != ',')
+ break;
+
+ }
+ require_endsentence ();
+ return false;
+ }
+ for (;;)
+ {
+ BlChannel channel;
+ if (token.code == keyLPRINT)
+ {
+ channel= PrinterChannel;
+ gettoken ();
+ }
+ else
+ {
+ if (token.code == '#')
+ gettoken ();
+ channel= evalchannel ();
+ }
+ if (channel == DefaultChannel)
+ throw ErrFileNumber;
+ runner.closechannel (channel);
+ if (token.code != ',')
+ {
+ if (endsentence () )
+ break;
+ throw ErrSyntax;
+ }
+ gettoken ();
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_LOCATE ()
+{
+ gettoken ();
+ BlChannel ch= DefaultChannel;
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlInteger row= evalinteger ();
+ requiretoken (',');
+ BlInteger col= expectinteger ();
+ require_endsentence ();
+ BlFile & out= getfile (ch);
+ if (sysvar::hasFlags1 (sysvar::LocateStyle) )
+ {
+ // LOCATE style Amstrad CPC: col, row
+ std::swap (row, col);
+ }
+ out.gotoxy (col - 1, row - 1);
+ return false;
+}
+
+bool RunnerLineImpl::do_CLS ()
+{
+ //gettoken ();
+ //BlChannel ch= DefaultChannel;
+ //if (token.code == '#')
+ //{
+ // ch= expectchannel ();
+ //}
+ BlChannel ch= expectoptionalchannel ();
+ require_endsentence ();
+ BlFile & out= getfile (ch);
+ out.cls ();
+ return false;
+}
+
+bool RunnerLineImpl::do_WRITE ()
+{
+ gettoken ();
+ BlChannel channel= DefaultChannel;
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlFile & out= getfile (channel);
+ BlResult result;
+ char quote= out.quote ();
+ for (;;)
+ {
+ if (token.code != ',')
+ {
+ eval (result);
+ switch (result.type () )
+ {
+ case VarNumber:
+ out << result.number ();
+ break;
+ case VarInteger:
+ out<< result.integer ();
+ break;
+ case VarString:
+ if (quote) out << quote;
+ out << result.str ();
+ if (quote) out << quote;
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ }
+ if (token.code == ',')
+ {
+ out << out.delimiter ();
+ gettoken ();
+ }
+ else break;
+ }
+ require_endsentence ();
+ //out << '\n';
+ out.endline ();
+ return false;
+}
+
+bool RunnerLineImpl::do_MODE ()
+{
+ //BlNumber mode= expectnum ();
+ BlResult result;
+ expect (result);
+
+ bool spectrummode= false;
+ //BlInteger mode;
+ if (result.type () == VarString)
+ {
+ require_endsentence ();
+ const std::string & strmode= result.str ();
+ graphics::setmode (strmode);
+ //mode= 1;
+ if (strmode == "spectrum")
+ spectrummode= true;
+ }
+ else
+ {
+ BlInteger mode= result.integer ();
+ if (endsentence () )
+ graphics::setmode (mode);
+ else
+ {
+ requiretoken (',');
+ BlInteger height= expectinteger ();
+ bool inverty= false;
+ BlInteger zoomx= 1, zoomy= 1;
+ if (token.code == ',')
+ {
+ gettoken ();
+ if (token.code != ',')
+ inverty= evalinteger ();
+ if (token.code == ',')
+ {
+ gettoken ();
+ if (token.code != ',')
+ zoomx= evalinteger ();
+ if (token.code == ',')
+ zoomy= expectinteger ();
+ }
+ }
+ require_endsentence ();
+ graphics::setmode (mode, height, inverty,
+ zoomx, zoomy);
+ }
+ }
+ runner.destroy_windows ();
+ runner.resetfile0 ();
+ if (spectrummode)
+ runner.spectrumwindows ();
+ return false;
+}
+
+bool RunnerLineImpl::do_MOVE ()
+{
+ #if 0
+ BlNumber x= expectnum ();
+ requiretoken (',');
+ BlNumber y= expectnum ();
+ require_endsentence ();
+ graphics::move (int (x), int (y) );
+ #else
+ BlInteger x, y;
+ getdrawargs (x, y);
+ graphics::move (x, y);
+ #endif
+ return false;
+}
+
+bool RunnerLineImpl::do_COLOR ()
+{
+ gettoken ();
+ BlFile & out= getfile0 ();
+ if (token.code != ',')
+ {
+ BlInteger color= evalinteger ();
+ out.setcolor (color);
+ if (graphics::ingraphicsmode () )
+ graphics::setcolor (color);
+ if (endsentence () )
+ return false;
+ requiretoken (',');
+ }
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger back= evalinteger ();
+ out.setbackground (back);
+ if (graphics::ingraphicsmode () )
+ graphics::setbackground (back);
+ if (endsentence () )
+ return false;
+ requiretoken (',');
+ }
+ gettoken ();
+ // Border color in Gwbasic. Ignored.
+ evalinteger ();
+ require_endsentence ();
+ return false;
+}
+
+void RunnerLineImpl::do_get_image ()
+{
+ BlInteger x1= expectinteger ();
+ requiretoken (',');
+ BlInteger y1= expectinteger ();
+ requiretoken (')');
+ expecttoken ('-');
+ expecttoken ('(');
+ BlInteger x2= expectinteger ();
+ requiretoken (',');
+ BlInteger y2= expectinteger ();
+ requiretoken (')');
+ expecttoken (',');
+ gettoken ();
+ requiretoken (keyIDENTIFIER);
+ std::string name= token.str;
+ gettoken ();
+ require_endsentence ();
+ graphics::get_image (x1, y1, x2, y2, name);
+}
+
+bool RunnerLineImpl::do_GET ()
+{
+ gettoken ();
+ if (token.code == '(')
+ {
+ do_get_image ();
+ return false;
+ }
+
+ if (token.code != keyIDENTIFIER ||
+ typeofvar (token.str) != VarString)
+ {
+ // GET #
+ if (token.code == '#')
+ gettoken ();
+ BlChannel channel= evalchannel ();
+ size_t pos= 0;
+ if (token.code == ',')
+ {
+ BlNumber bnPos= expectnum ();
+ pos= size_t (bnPos);
+ if (pos == 0)
+ throw ErrBadRecord;
+ }
+ require_endsentence ();
+ BlFile & out= getfile (channel);
+ out.get (pos);
+ return false;
+ }
+ // GET var$
+ std::string varname= token.str;
+ gettoken ();
+ require_endsentence ();
+
+ #if 0
+ std::string r= graphics::ingraphicsmode () ?
+ graphics::getkey () :
+ cursor::getkey ();
+ #else
+ std::string r= getfile0 ().getkey ();
+ #endif
+
+ if (r == "\n" && sysvar::hasFlags1 (sysvar::ConvertLFCR) )
+ r= "\r";
+ assignvarstring (varname, r);
+ return false;
+}
+
+bool RunnerLineImpl::do_LABEL ()
+{
+ expecttoken (keyIDENTIFIER);
+ //std::string label= token.str;
+ gettoken ();
+ require_endsentence ();
+ return false;
+}
+
+bool RunnerLineImpl::do_DELIMITER ()
+{
+ gettoken ();
+ BlChannel channel= DefaultChannel;
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlFile & in= getfile (channel);
+ std::string str= evalstring ();
+ char delim= 0, quote= 0, escape= 0;
+ if (! str.empty () )
+ delim= str [0];
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ str= expectstring ();
+ if (! str.empty () )
+ quote= str [0];
+ if (! endsentence () )
+ {
+ requiretoken(',');
+ str= expectstring ();
+ if (! str.empty () )
+ escape= str [0];
+ require_endsentence ();
+ }
+ }
+ in.delimiter (delim);
+ in.quote (quote);
+ in.escape (escape);
+ return false;
+}
+
+bool RunnerLineImpl::do_REPEAT ()
+{
+ errorifparam ();
+ ProgramPos posrepeat (getposactual () );
+ if (token.code == keyENDLINE)
+ {
+ if (posrepeat.getnum () != LineDirectCommand)
+ posrepeat.nextline ();
+ else
+ throw ErrRepeatWithoutUntil;
+ }
+ else
+ posrepeat.nextchunk ();
+ runner.repeat_push (RepeatElement (posrepeat) );
+ return false;
+}
+
+bool RunnerLineImpl::do_UNTIL ()
+{
+ if (runner.repeat_empty () )
+ throw ErrUntilWithoutRepeat;
+ BlResult br;
+ expect (br);
+ bool cond= br.tobool ();
+ require_endsentence ();
+ if (cond)
+ {
+ runner.repeat_pop ();
+ return false;
+ }
+ RepeatElement re= runner.repeat_top ();
+ runner.jump_to (re.getpos () );
+ return true;
+}
+
+bool RunnerLineImpl::do_WHILE ()
+{
+ //ProgramPos poswhile (runner.getposactual () );
+ ProgramPos poswhile (getposactual () );
+ BlResult br;
+ expect (br);
+ bool cond= br.tobool ();
+ require_endsentence ();
+
+ if (cond)
+ {
+ if (! runner.in_wend () )
+ runner.while_push (WhileElement (poswhile) );
+ else
+ runner.in_wend (false);
+ return false;
+ }
+ if (runner.in_wend () )
+ {
+ runner.while_pop ();
+ runner.in_wend (false);
+ }
+ bool sameline= true;
+
+ // Find the WEND.
+ for (size_t level= 1; level > 0; )
+ {
+ getnextchunk ();
+ if (token.code == keyENDLINE)
+ {
+ if (codeline.number () == LineDirectCommand)
+ throw BlError (ErrWhileWithoutWend, poswhile);
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ throw BlError (ErrWhileWithoutWend, poswhile);
+ sameline= false;
+ gettoken ();
+ }
+ switch (token.code)
+ {
+ case keyWHILE: ++level; break;
+ case keyWEND: --level; break;
+ default: ;
+ }
+ }
+ // At the WEND, check the syntax.
+ gettoken ();
+ require_endsentence ();
+
+ if (sameline)
+ return false;
+
+ ProgramPos pos (codeline.number (), codeline.chunk () );
+ if (token.code == keyENDLINE)
+ {
+ // If direct command, is sameline.
+ pos.nextline ();
+ }
+ runner.jump_to (pos);
+ return true;
+}
+
+bool RunnerLineImpl::do_WEND ()
+{
+ errorifparam ();
+ if (runner.while_empty () )
+ throw ErrWendWithoutWhile;
+ WhileElement w= runner.while_top ();
+ runner.jump_to (w.getpos () );
+ runner.in_wend (true);
+ return true;
+}
+
+bool RunnerLineImpl::do_PLOT ()
+{
+ BlInteger x, y;
+ std::vector <graphics::Point> points;
+ gettoken ();
+ if (token.code == keyTO)
+ {
+ points.push_back (graphics::getlast () );
+ }
+ else
+ {
+ x= evalinteger ();
+ requiretoken (',');
+ y= expectinteger ();
+ if (token.code != keyTO)
+ {
+ getinkparams ();
+ graphics::plot (x, y);
+ return false;
+ }
+ points.push_back (graphics::Point (int (x), int (y) ) );
+ }
+ for (;;)
+ {
+ x= expectinteger ();
+ requiretoken (',');
+ y= expectinteger ();
+ points.push_back (graphics::Point (x, y) );
+ if (endsentence () )
+ break;
+ requiretoken (keyTO);
+ }
+ graphics::plot (points);
+ return false;
+}
+
+bool RunnerLineImpl::do_RESUME ()
+{
+ ProgramPos posresume= runner.geterrpos ();
+ BlLineNumber errline= posresume.getnum ();
+ if (errline == LineDirectCommand || errline == LineEndProgram)
+ throw ErrCannotResume;
+
+ gettoken ();
+ if (token.code == keyNEXT)
+ {
+ gettoken ();
+ require_endsentence ();
+ runner.resume_next (posresume);
+ }
+ else if (endsentence () )
+ {
+ runner.jump_to (posresume);
+ }
+ else
+ {
+ BlLineNumber line= evallinenumber ();
+ require_endsentence ();
+ runner.goto_to (line);
+ }
+ runner.clearerror ();
+ return true;
+}
+
+bool RunnerLineImpl::do_DELETE ()
+{
+ gettoken ();
+ BlLineNumber iniline, endline;
+ evallinerange (iniline, endline);
+ require_endsentence ();
+ program.deletelines (iniline, endline);
+ runner.setstatus (Runner::Ended);
+ return true;
+}
+
+bool RunnerLineImpl::do_LOCAL ()
+{
+ do
+ {
+ expecttoken (keyIDENTIFIER);
+ runner.gosub_addlocalvar (token.str);
+ gettoken ();
+ } while (token.code == ',');
+ require_endsentence ();
+ return false;
+}
+
+void RunnerLineImpl::do_put_image ()
+{
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ requiretoken (')');
+ expecttoken (',');
+ gettoken ();
+ requiretoken (keyIDENTIFIER);
+ std::string name= token.str;
+ gettoken ();
+
+ // Mode used.
+ int mode= 0;
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ switch (token.code)
+ {
+ case keyXOR:
+ mode= 1; break;
+ case keyAND:
+ mode= 2; break;
+ case keyOR:
+ mode= 3; break;
+ case keyNOT:
+ mode= 4; break;
+ default:
+ throw ErrSyntax;
+ }
+ gettoken ();
+ require_endsentence ();
+ }
+ graphics::put_image (x, y, name, mode);
+}
+
+bool RunnerLineImpl::do_PUT ()
+{
+ gettoken ();
+ if (token.code == '(')
+ {
+ do_put_image ();
+ return false;
+ }
+
+ if (token.code == '#')
+ gettoken ();
+ BlChannel channel= evalchannel ();
+ size_t pos= 0;
+ if (token.code == ',')
+ {
+ BlNumber bnPos= expectnum ();
+ pos= size_t (bnPos);
+ }
+ require_endsentence ();
+
+ BlFile & out= getfile (channel);
+ out.put (pos);
+
+ return false;
+}
+
+bool RunnerLineImpl::do_FIELD ()
+{
+ gettoken ();
+ enum FieldType { FieldSimple, FieldClear, FieldAppend };
+ FieldType type= FieldSimple;
+ switch (token.code)
+ {
+ case keyCLEAR:
+ type= FieldClear;
+ gettoken ();
+ break;
+ case keyAPPEND:
+ type= FieldAppend;
+ gettoken ();
+ break;
+ default:
+ // Nothing to do.
+ ;
+ }
+ if (token.code == '#')
+ gettoken ();
+ BlChannel channel= evalchannel ();
+ BlFile & out= getfile (channel);
+ if (type == FieldClear)
+ {
+ require_endsentence ();
+ out.field_clear ();
+ return false;
+ }
+ std::vector <BlFile::field_element> fe;
+ do
+ {
+ requiretoken (',');
+ BlNumber bnSize= expectnum ();
+ size_t size= size_t (bnSize);
+ requiretoken (keyAS);
+ expecttoken (keyIDENTIFIER);
+ #if 1
+ // Now matrix elements are accepted as field vars.
+ gettoken ();
+ Dimension dim;
+ if (token.code == '(')
+ dim= getdims ();
+ fe.push_back (BlFile::field_element (size, token.str, dim) );
+ #else
+ fe.push_back ( BlFile::field_element (size, token.str) );
+ gettoken ();
+ #endif
+ } while (! endsentence () );
+ switch (type)
+ {
+ case FieldSimple:
+ out.field (fe);
+ break;
+ case FieldAppend:
+ out.field_append (fe);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_LSET ()
+{
+ BlFile::Align align;
+ switch (token.code)
+ {
+ case keyLSET: align= BlFile::AlignLeft; break;
+ case keyRSET: align= BlFile::AlignRight; break;
+ default: throw ErrBlassicInternal;
+ }
+
+ // Get the variable to L/RSET.
+ gettoken ();
+ if (token.code != keyIDENTIFIER)
+ throw ErrSyntax;
+ std::string var= token.str;
+ if (typeofvar (var) != VarString)
+ throw ErrMismatch;
+ //expecttoken ('=');
+ //bool hasindex= false;
+ Dimension dim;
+ //std::string * pstr;
+ gettoken ();
+ if (token.code == '(')
+ {
+ // It's a matrix element.
+ //hasindex= true;
+ dim= getdims ();
+ //pstr= addrdimstring (var, dim);
+ }
+ //else
+ // pstr= addrvarstring (var);
+
+ requiretoken ('=');
+ const std::string value= expectstring ();
+ require_endsentence ();
+
+ // First try to assign to a field var.
+
+ #if 0
+ // Blassic does not accept a matrix element as field.
+ if (! hasindex)
+ if (runner.assign_channel_var (var, value, align) )
+ return false;
+ #else
+ // Now accepts.
+ if (runner.assign_channel_var (var, dim, value, align) )
+ return false;
+ #endif
+
+ // If a field with that name exists, the variable already
+ // has been assigned, then we can return.
+
+ // If there is not file field with such name, do the work
+ // here with the previous string length.
+ std::string * pstr= dim.empty () ?
+ addrvarstring (var) :
+ addrdimstring (var, dim);
+ const std::string::size_type l= pstr->size ();
+ if (l == 0)
+ return false;
+ #if 0
+ const std::string::size_type lvalue= value.size ();
+ if (lvalue < l)
+ {
+ if (align == BlFile::AlignLeft)
+ {
+ * pstr= value + std::string (l - lvalue, ' ');
+ }
+ else
+ {
+ * pstr= std::string (l - lvalue, ' ') + value;
+ }
+ }
+ else if (lvalue > l)
+ {
+ * pstr= value.substr (0, l);
+ }
+ else
+ * pstr= value;
+ #else
+ if (align == BlFile::AlignLeft)
+ * pstr= util::stringlset (value, l);
+ else
+ * pstr= util::stringrset (value, l);
+ #endif
+ ASSERT (pstr->size () == l);
+ return false;
+}
+
+bool RunnerLineImpl::do_SOCKET ()
+{
+ std::string host= expectstring ();
+ requiretoken (',');
+ BlNumber bn= expectnum ();
+ requiretoken (keyAS);
+ //gettoken ();
+ //if (token.code == '#')
+ // gettoken ();
+ //BlChannel channel= evalchannel ();
+ BlChannel channel= expectrequiredchannel ();
+ require_endsentence ();
+
+ auto_ptr <BlFile> pbf (newBlFileSocket (host, short (bn) ) );
+ runner.setfile (channel, pbf.get () );
+ pbf.release ();
+
+ return false;
+}
+
+bool RunnerLineImpl::do_MID_S ()
+{
+ expecttoken ('(');
+ expecttoken (keyIDENTIFIER);
+ std::string varname= token.str;
+ if (typeofvar (varname) != VarString)
+ throw ErrMismatch;
+
+ Dimension dim;
+ //std::string * presult;
+ //expecttoken (',');
+ gettoken ();
+ if (token.code == '(')
+ {
+ dim= getdims ();
+ //presult= addrdimstring (varname, dim);
+ }
+ //else
+ //{
+ // presult= addrvarstring (varname);
+ //}
+ requiretoken (',');
+
+ size_t inipos;
+ {
+ BlNumber bnInipos= expectnum ();
+ inipos= util::checked_cast <size_t> (bnInipos, ErrMismatch);
+ }
+ if (inipos == 0)
+ throw ErrMismatch;
+ --inipos;
+ //size_t len= 0; // Initialized to avoid warning.
+ std::string::size_type len= 0; // Initialized to avoid warning.
+ bool fLen= false;
+ if (token.code == ',')
+ {
+ BlNumber bnLen= expectnum ();
+ len= util::checked_cast <std::string::size_type>
+ (bnLen, ErrMismatch);
+ fLen= true;
+ }
+ requiretoken (')');
+ expecttoken ('=');
+ std::string value= expectstring ();
+ require_endsentence ();
+
+ if (! fLen)
+ len= std::string::npos;
+
+ // First try to assign to a field var.
+
+ if (runner.assign_mid_channel_var (varname, dim, value, inipos, len) )
+ return false;
+
+ // If there is no file field, do the work here.
+
+ std::string * pstr= dim.empty () ?
+ addrvarstring (varname) :
+ addrdimstring (varname, dim);
+ size_t l= value.size ();
+ if (! fLen || len > l)
+ len= l;
+
+ l= pstr->size ();
+ if (inipos >= l)
+ return false;
+ if (inipos + len > l)
+ len= l - inipos;
+ std::copy (value.begin (), value.begin () + len,
+ pstr->begin () + inipos);
+ return false;
+}
+
+bool RunnerLineImpl::do_DRAW ()
+{
+ //BlNumber x= expectnum ();
+ BlResult r;
+ expect (r);
+ if (r.type () == VarString)
+ graphics::draw (r.str () );
+ else
+ {
+ BlInteger x= r.integer ();
+ #if 0
+ requiretoken (',');
+ //BlNumber y= expectnum ();
+ expect (r);
+ BlInteger y= r.integer ();
+
+ require_endsentence ();
+ #else
+ BlInteger y;
+ getdrawargs (y);
+ #endif
+ //graphics::line (int (x), int (y) );
+ graphics::line (x, y);
+ }
+ return false;
+}
+
+namespace {
+
+std::string quoteescape (const std::string & str)
+{
+ std::string result;
+ for (std::string::size_type i= 0, l= str.size (); i < l; ++i)
+ {
+ char c= str [i];
+ if (c == '"')
+ result+= "\"\"";
+ else
+ result+= c;
+ }
+ return result;
+}
+
+} // namespace
+
+bool RunnerLineImpl::do_def_fn ()
+{
+ // Get function name.
+
+ expecttoken (keyIDENTIFIER);
+ std::string fnname= token.str;
+ gettoken ();
+
+ // Get parameters.
+
+ ParameterList param;
+ switch (token.code)
+ {
+ case '=':
+ // Single sentence function without parameters
+ break;
+ case '(':
+ // Function with parameters
+ do {
+ expecttoken (keyIDENTIFIER);
+ param.push_back (token.str);
+ gettoken ();
+ } while (token.code == ',');
+ requiretoken (')');
+ gettoken ();
+ if (token.code != '=' && ! endsentence () )
+ throw ErrSyntax;
+ break;
+ default:
+ if (endsentence () )
+ break; // Multi sentence function without parameters
+ throw ErrSyntax;
+ }
+
+ // Get function body.
+
+ bool retval= false;
+ auto_ptr <Function> pf;
+ if (endsentence () )
+ {
+ // Multi sentence function. Search for FN END.
+
+ ProgramPos posfn (codeline.number (), codeline.chunk () );
+ if (token.code == keyENDLINE)
+ posfn.nextline ();
+ bool sameline= true;
+ for (bool finding= true; finding;)
+ {
+ getnextchunk ();
+ if (token.code == keyENDLINE)
+ {
+ if (codeline.number () == LineDirectCommand)
+ throw ErrInvalidDirect;
+ program.getnextline (codeline);
+ if (codeline.number () == LineEndProgram)
+ throw ErrIncompleteDef;
+ sameline= false;
+ gettoken ();
+ }
+ switch (token.code)
+ {
+ case keyFN:
+ gettoken ();
+ if (token.code == keyEND)
+ finding= false;
+ //else
+ // throw ErrSyntax;
+ break;
+ }
+ }
+ gettoken ();
+ require_endsentence ();
+
+ // Prepare to skip function body.
+
+ if (! sameline)
+ {
+ ProgramPos pos (codeline.number (),
+ codeline.chunk () );
+ if (token.code == keyENDLINE)
+ {
+ // Can't be direct command.
+ pos.nextline ();
+ }
+ runner.jump_to (pos);
+ retval= true;
+ }
+ pf.reset (new Function (posfn, param) );
+ }
+ else
+ {
+ // Single sentence funcion
+
+ gettoken ();
+ std::string fndef ("0 ");
+ // The "0 " is the fake line number.
+ for ( ; ! endsentence (); gettoken () )
+ {
+ if (token.code < 256)
+ fndef+= token.code;
+ else
+ switch (token.code)
+ {
+ case keyIDENTIFIER:
+ case keyNUMBER:
+ fndef+= token.str;
+ break;
+ case keyINTEGER:
+ fndef+= to_string
+ (token.integer () );
+ break;
+ case keySTRING:
+ fndef+= '"';
+ fndef+= quoteescape (token.str);
+ fndef+= '"';
+ break;
+ default:
+ fndef+= decodekeyword (token.code);
+ }
+ fndef+= ' ';
+ }
+ pf.reset (new Function (fndef, param) );
+ }
+
+ // Put in table of functions.
+
+ pf->insert (fnname);
+ // No need to release pf, insert does a copy.
+
+ return retval;
+}
+
+namespace {
+
+inline char get_letter (const std::string & str)
+{
+ if (str.size () != 1)
+ throw ErrSyntax;
+ char c= str [0];
+ if (! isalpha (c) )
+ throw ErrSyntax;
+ return c;
+}
+
+} // namespace
+
+void RunnerLineImpl::definevars (VarType type)
+{
+ do
+ {
+ expecttoken (keyIDENTIFIER);
+ char c= get_letter (token.str);
+ gettoken ();
+ if (token.code == '-')
+ {
+ expecttoken (keyIDENTIFIER);
+ char c2= get_letter (token.str);
+ definevar (type, c, c2);
+ gettoken ();
+ }
+ else
+ definevar (type, c);
+ } while (token.code == ',');
+ require_endsentence ();
+}
+
+bool RunnerLineImpl::do_DEF ()
+{
+ gettoken ();
+ VarType type;
+ switch (token.code)
+ {
+ case keyFN:
+ return do_def_fn ();
+ case keySTR:
+ case keyINT:
+ case keyREAL:
+ type= token.code == keySTR ? VarString :
+ token.code == keyINT ? VarInteger : VarNumber;
+ #if 0
+ do {
+ expecttoken (keyIDENTIFIER);
+ char c= get_letter (token.str);
+ gettoken ();
+ if (token.code == '-')
+ {
+ expecttoken (keyIDENTIFIER);
+ char c2= get_letter (token.str);
+ definevar (type, c, c2);
+ gettoken ();
+ }
+ else
+ definevar (type, c);
+ } while (token.code == ',');
+ require_endsentence ();
+ #else
+ definevars (type);
+ #endif
+ return false;
+ default:
+ throw ErrSyntax;
+ }
+}
+
+bool RunnerLineImpl::do_FN ()
+{
+ gettoken ();
+ bool isend= true;
+ switch (token.code)
+ {
+ case keyEND:
+ break;
+ case keyRETURN:
+ isend= false;
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ errorifparam ();
+
+ //runner.setstatus (Runner::Ended);
+ //return true;
+
+ if (! isend)
+ {
+ if (runner.fn_level () == 0)
+ throw ErrUnexpectedFnEnd;
+ while (runner.gosub_size () > 1)
+ {
+ ProgramPos unused;
+ runner.gosub_pop (unused);
+ }
+ }
+
+ //throw blassic::ProgramFnEnd ();
+
+ runner.setstatus (Runner::FnEnded);
+ return true;
+}
+
+bool RunnerLineImpl::do_PROGRAMARG_S ()
+{
+ std::vector <std::string> args;
+ gettoken ();
+ if (! endsentence () )
+ {
+ for (;;)
+ {
+ std::string par= evalstring ();
+ args.push_back (par);
+ if (endsentence () )
+ break;
+ requiretoken (',');
+ gettoken ();
+ }
+ }
+ setprogramargs (args);
+ return false;
+}
+
+bool RunnerLineImpl::do_ERASE ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_ERASE");
+
+ do
+ {
+ expecttoken (keyIDENTIFIER);
+ std::string str (token.str);
+ switch (typeofvar (str) )
+ {
+ case VarNumber:
+ erasevarnumber (str);
+ break;
+ case VarInteger:
+ erasevarinteger (str);
+ break;
+ case VarString:
+ erasevarstring (str);
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ gettoken ();
+ } while (token.code == ',');
+ require_endsentence ();
+ return false;
+}
+
+bool RunnerLineImpl::do_SWAP ()
+{
+ expecttoken (keyIDENTIFIER);
+ std::string strvar1= token.str;
+ gettoken ();
+ Dimension dim1;
+ bool isarray1= false;
+ if (token.code == '(')
+ {
+ dim1= getdims ();
+ isarray1= true;
+ }
+ requiretoken (',');
+ gettoken ();
+ requiretoken (keyIDENTIFIER);
+ std::string strvar2= token.str;
+ gettoken ();
+ Dimension dim2;
+ bool isarray2= false;
+ if (token.code == '(')
+ {
+ dim2= getdims ();
+ isarray2= true;
+ }
+ require_endsentence ();
+ VarType type= typeofvar (strvar1);
+ if (type != typeofvar (strvar2) )
+ throw ErrMismatch;
+ switch (type)
+ {
+ case VarNumber:
+ {
+ BlNumber * pbn1= isarray1 ?
+ addrdimnumber (strvar1, dim1) :
+ addrvarnumber (strvar1);
+ BlNumber * pbn2= isarray2 ?
+ addrdimnumber (strvar2, dim2) :
+ addrvarnumber (strvar2);
+ std::swap (* pbn1, * pbn2);
+ }
+ break;
+ case VarInteger:
+ {
+ BlInteger * pbi1= isarray1 ?
+ addrdiminteger (strvar1, dim1) :
+ addrvarinteger (strvar1);
+ BlInteger * pbi2= isarray2 ?
+ addrdiminteger (strvar2, dim2) :
+ addrvarinteger (strvar2);
+ std::swap ( * pbi1, * pbi2);
+ }
+ break;
+ case VarString:
+ {
+ std::string * pstr1= isarray1 ?
+ addrdimstring (strvar1, dim1) :
+ addrvarstring (strvar1);
+ std::string * pstr2= isarray2 ?
+ addrdimstring (strvar2, dim2) :
+ addrvarstring (strvar2);
+ std::swap (* pstr1, * pstr2);
+ }
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_SYMBOL ()
+{
+ gettoken ();
+ if (token.code == keyAFTER)
+ {
+ BlInteger n= expectinteger ();
+
+ // Support for change of character set.
+
+ if (token.code == keyAS)
+ {
+ using namespace charset;
+ std::string model= expectstring ();
+ if (model == "default")
+ default_charset= & default_data;
+ else if (model == "cpc")
+ default_charset= & cpc_data;
+ else if (model == "spectrum")
+ default_charset= & spectrum_data;
+ else
+ throw ErrImproperArgument;
+ }
+
+ require_endsentence ();
+ graphics::symbolafter (static_cast <int> (n) );
+ return false;
+ }
+ BlNumber bnSymbol= evalnum ();
+
+ unsigned char byte [8];
+ for (int i= 0; i < 8; ++i)
+ byte [i]= 0;
+
+ for (int i= 0; i < 8; ++i)
+ {
+ if (token.code != ',')
+ {
+ // Parameters can be omitted
+ break;
+ }
+ BlNumber bnByte= expectnum ();
+ byte [i]= static_cast <unsigned char> (bnByte);
+ }
+ require_endsentence ();
+ graphics::definesymbol ( int (bnSymbol), byte);
+ return false;
+}
+
+bool RunnerLineImpl::do_ZONE ()
+{
+ BlInteger z= expectinteger ();
+ require_endsentence ();
+ sysvar::set16 (sysvar::Zone, static_cast <short> (z) );
+ return false;
+}
+
+bool RunnerLineImpl::do_POP ()
+{
+ errorifparam ();
+ ProgramPos notused;
+ runner.gosub_pop (notused);
+ return false;
+}
+
+bool RunnerLineImpl::do_NAME ()
+{
+ std::string strOrig= expectstring ();
+ requiretoken (keyAS);
+ std::string strDest= expectstring ();
+ require_endsentence ();
+ rename_file (strOrig, strDest);
+ return false;
+}
+
+bool RunnerLineImpl::do_KILL ()
+{
+ std::string strFile= expectstring ();
+ require_endsentence ();
+ remove_file (strFile);
+ return false;
+}
+
+bool RunnerLineImpl::do_FILES ()
+{
+ std::string param;
+ gettoken ();
+ BlChannel ch= DefaultChannel;
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ param= expectstring ();
+ }
+ }
+ else
+ {
+ if (! endsentence () )
+ param= evalstring ();
+ }
+ require_endsentence ();
+ if (param.empty () )
+ param= "*";
+
+ std::vector <std::string> file;
+
+ // Populate the vector with the files searched.
+ Directory d;
+ for (std::string r= d.findfirst (param.c_str () ); ! r.empty ();
+ r= d.findnext () )
+ file.push_back (r);
+
+ const size_t l= file.size ();
+
+ // GwBasic do this, I mimic it.
+ if (l == 0)
+ throw ErrFileNotFound;
+
+ size_t maxlength= 0;
+ for (size_t i= 0; i < l; ++i)
+ maxlength= std::max (maxlength, file [i].size () );
+ ++maxlength;
+ BlFile & bf= getfile (ch);
+ size_t width= 0;
+ try
+ {
+ width= bf.getwidth ();
+ }
+ catch (...)
+ {
+ }
+ size_t cols= width / maxlength;
+ if (cols <= 1)
+ {
+ for (size_t i= 0; i < l; ++i)
+ {
+ //bf << file [i] << '\n';
+ bf << file [i];
+ bf.endline ();
+ }
+ }
+ else
+ {
+ const size_t widthcol= width / cols;
+ for (size_t i= 0; i < l; ++i)
+ {
+ const std::string & str= file [i];
+ bf << file [i];
+ if (i % cols == cols - 1)
+ //bf << '\n';
+ bf.endline ();
+ else
+ bf << std::string
+ (widthcol - str.size (), ' ');
+ }
+ if ( l > 0 && l % cols != 0)
+ //bf << '\n';
+ bf.endline ();
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_PAPER ()
+{
+ gettoken ();
+ BlChannel ch= DefaultChannel;
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlInteger color= evalinteger ();
+ require_endsentence ();
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::setbackground (color);
+ else
+ textbackground (color);
+ #else
+ BlFile & out= getfile (ch);
+ out.setbackground (color);
+ #endif
+ return false;
+}
+
+bool RunnerLineImpl::do_PEN ()
+{
+ gettoken ();
+ BlChannel ch= DefaultChannel;
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlFile & out= getfile (ch);
+ if (token.code != ',')
+ {
+ // All parameters can't be omitted
+ BlInteger color= evalinteger ();
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::setcolor (int (color) );
+ else
+ textcolor (int (color) );
+ #else
+ out.setcolor (color);
+ #endif
+ if (token.code != ',')
+ {
+ require_endsentence ();
+ return false;
+ }
+ }
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger bgmode= evalinteger ();
+ graphics::settransparent (bgmode);
+ if (token.code != ',')
+ {
+ require_endsentence ();
+ return false;
+ }
+ }
+ BlInteger mode= expectinteger ();
+ graphics::setdrawmode (mode);
+ require_endsentence ();
+ return false;
+}
+
+bool RunnerLineImpl::do_SHELL ()
+{
+ gettoken ();
+ if (endsentence () )
+ throw ErrNotImplemented;
+ std::string command= evalstring ();
+ require_endsentence ();
+ int r= system (command.c_str () );
+ //std::cerr << "Result: " << r << endl;
+ if (r == -1)
+ throw ErrOperatingSystem;
+ sysvar::set (sysvar::ShellResult, char (r >> 8) );
+ return false;
+}
+
+bool RunnerLineImpl::do_MERGE ()
+{
+ std::string progname= expectstring ();
+ require_endsentence ();
+ program.merge (progname);
+ runner.setstatus (Runner::Ended);
+ return true;
+}
+
+bool RunnerLineImpl::do_CHDIR ()
+{
+ std::string dirname= expectstring ();
+ require_endsentence ();
+ change_dir (dirname);
+ return false;
+}
+
+bool RunnerLineImpl::do_MKDIR ()
+{
+ std::string dirname= expectstring ();
+ require_endsentence ();
+ make_dir (dirname);
+ return false;
+}
+
+bool RunnerLineImpl::do_RMDIR ()
+{
+ std::string dirname= expectstring ();
+ require_endsentence ();
+ remove_dir (dirname);
+ return false;
+}
+
+bool RunnerLineImpl::do_SYNCHRONIZE ()
+{
+ gettoken ();
+ if (endsentence () )
+ graphics::synchronize ();
+ else
+ {
+ BlNumber n= evalnum ();
+ graphics::synchronize (n != 0);
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_PAUSE ()
+{
+ TRACEFUNC (tr, "do_pause");
+
+ BlNumber bln= expectnum ();
+ require_endsentence ();
+ unsigned long n= static_cast <unsigned long> (bln);
+
+ // Allow pending writes in graphic window before the pause.
+ graphics::idle ();
+
+ sleep_milisec (n);
+
+ return false;
+}
+
+bool RunnerLineImpl::do_CHAIN ()
+{
+ bool merging= false;
+ BlLineNumber inidel= LineNoDelete;
+ BlLineNumber enddel= LineNoDelete;
+
+ gettoken ();
+ if (token.code == keyMERGE)
+ {
+ merging= true;
+ gettoken ();
+ }
+ std::string progname= evalstring ();
+ BlLineNumber iniline= LineBeginProgram;
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ if (token.code != keyDELETE)
+ {
+ iniline= evallinenumber ();
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ expecttoken (keyDELETE);
+ }
+ }
+ if (token.code == keyDELETE)
+ {
+ if (! merging)
+ throw ErrSyntax;
+ gettoken ();
+ evallinerange (inidel, enddel);
+ }
+ require_endsentence ();
+ }
+
+ if (merging)
+ program.merge (progname, inidel, enddel);
+ else
+ program.load (progname);
+
+ runner.run_to (iniline);
+ return true;
+}
+
+bool RunnerLineImpl::do_ENVIRON ()
+{
+ BlResult result;
+ expect (result);
+ const std::string & str= result.str ();
+ size_t l= str.size ();
+ // We use an auto alloc, then in case of error the memory is freed.
+ util::auto_alloc <char> envstr (l + 1);
+ memcpy (envstr, str.data (), l);
+ envstr [l]= 0;
+ if (putenv (envstr) != 0)
+ throw ErrFunctionCall;
+ // Do not free the string now, is part of the environment.
+ envstr.release ();
+ return false;
+}
+
+bool RunnerLineImpl::do_EDIT ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_edit");
+
+ gettoken ();
+ if (token.code != keyNUMBER && token.code != keyINTEGER)
+ throw ErrSyntax;
+ BlLineNumber dest= evallinenumber ();
+ require_endsentence ();
+
+ #if 0
+
+ std::string buffer;
+ {
+ BlFileOutString bfos;
+ program.list (dest, dest, bfos);
+ buffer= bfos.str ();
+ if (buffer.empty () )
+ {
+ //bfos << dest << " \n";
+ bfos << dest;
+ bfos.endline ();
+ buffer= bfos.str ();
+ }
+ }
+ buffer.erase (buffer.size () - 1);
+ static const std::string number ("01234567890");
+ size_t inipos= buffer.find_first_of (number);
+ ASSERT (inipos != std::string::npos);
+ inipos= buffer.find_first_not_of (number, inipos);
+ ASSERT (inipos != std::string::npos);
+ ++inipos;
+
+ if (editline (getfile0 (), buffer, inipos) )
+ {
+ CodeLine code;
+ code.scan (buffer);
+ BlLineNumber nline= code.number ();
+ if (nline == 0)
+ throw ErrBlassicInternal;
+ else
+ {
+ if (code.empty () )
+ program.deletelines (nline, nline);
+ else
+ program.insert (code);
+ }
+ }
+
+ #else
+
+ //editline (getfile0 (), program, dest);
+ std::string line;
+ if (runner.editline (dest, line) )
+ {
+ CodeLine codeline;
+ codeline.scan (line);
+ BlLineNumber nline= codeline.number ();
+ if (nline == LineDirectCommand)
+ {
+ // Need revision.
+ runner.runline (codeline);
+ }
+ else
+ {
+ program.insert (codeline);
+ }
+ }
+
+ #endif
+
+ return false;
+}
+
+bool RunnerLineImpl::do_DRAWR ()
+{
+ #if 0
+ BlNumber x= expectnum ();
+ requiretoken (',');
+ BlNumber y= expectnum ();
+ require_endsentence ();
+ graphics::liner (int (x), int (y) );
+ #else
+ BlInteger x, y;
+ getdrawargs (x, y);
+ graphics::liner (x, y);
+ #endif
+ return false;
+}
+
+bool RunnerLineImpl::do_PLOTR ()
+{
+ #if 0
+ BlNumber x= expectnum ();
+ requiretoken (',');
+ BlNumber y= expectnum ();
+ require_endsentence ();
+ graphics::plotr (int (x), int (y) );
+ #else
+ BlInteger x, y;
+ getdrawargs (x, y);
+ graphics::plotr (x, y);
+ #endif
+ return false;
+}
+
+bool RunnerLineImpl::do_MOVER ()
+{
+ #if 0
+ BlNumber x= expectnum ();
+ requiretoken (',');
+ BlNumber y= expectnum ();
+ require_endsentence ();
+ graphics::mover (int (x), int (y) );
+ #else
+ BlInteger x, y;
+ getdrawargs (x, y);
+ graphics::mover (x, y);
+ #endif
+ return false;
+}
+
+bool RunnerLineImpl::do_POKE16 ()
+{
+ BlNumber bnAddr= expectnum ();
+ requiretoken (',');
+ BlChar * addr= (BlChar *) (size_t) bnAddr;
+ BlNumber bnValue= expectnum ();
+ require_endsentence ();
+ unsigned short value= (unsigned short) bnValue;
+ poke16 (addr, value);
+ return false;
+}
+
+bool RunnerLineImpl::do_POKE32 ()
+{
+ BlNumber bnAddr= expectnum ();
+ requiretoken (',');
+ BlChar * addr= (BlChar *) (size_t) bnAddr;
+ BlNumber bnValue= expectnum ();
+ require_endsentence ();
+ BlInteger value= BlInteger (bnValue);
+ poke32 (addr, value);
+ return false;
+}
+
+bool RunnerLineImpl::do_RENUM ()
+{
+ gettoken ();
+ BlLineNumber newnumber= 10;
+ BlLineNumber oldnumber= LineBeginProgram;
+ BlLineNumber increment= 10;
+ BlLineNumber stop= LineEndProgram;
+ if (! endsentence () )
+ {
+ if (token.code != ',')
+ newnumber= evallinenumber ();
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ if (token.code != ',')
+ oldnumber= evallinenumber ();
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ if (token.code != ',')
+ increment= evallinenumber ();
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ gettoken ();
+ stop= evallinenumber ();
+ require_endsentence ();
+ }
+ }
+ }
+ }
+ program.renum (newnumber, oldnumber, increment, stop);
+ runner.setstatus (Runner::Ended);
+ return true;
+}
+
+bool RunnerLineImpl::do_CIRCLE ()
+{
+ gettoken ();
+ //requiretoken ('(');
+ if (token.code != '(')
+ {
+ // Spectrum syntax.
+ BlInteger x= evalinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ requiretoken (',');
+ BlInteger radius= expectinteger ();
+ require_endsentence ();
+ graphics::circle (x, y, radius);
+ return false;
+ }
+ BlResult r;
+ expect (r);
+ BlInteger x= r.integer ();
+ requiretoken (',');
+ expect (r);
+ BlInteger y= r.integer ();
+ requiretoken (')');
+ expecttoken (',');
+ expect (r);
+ BlInteger radius= r.integer ();
+ BlNumber arcbeg= 0, arcend= 0;
+ bool fArc= false;
+ bool fElliptic= false;
+ BlNumber elliptic= 0; // initialized to avoid a warning.
+ if (endsentence () )
+ goto do_it;
+ requiretoken (',');
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger color= evalinteger ();
+ graphics::setcolor (color);
+ if (endsentence () )
+ goto do_it;
+ requiretoken (',');
+ }
+ gettoken ();
+ if (token.code != ',')
+ {
+ arcbeg= evalnum ();
+ fArc= true;
+ if (endsentence () )
+ goto do_it;
+ requiretoken (',');
+ }
+ gettoken ();
+ if (token.code != ',')
+ {
+ arcend= evalnum ();
+ fArc= true;
+ if (endsentence () )
+ goto do_it;
+ requiretoken (',');
+ }
+ gettoken ();
+ elliptic= evalnum ();
+ fElliptic= true;
+ require_endsentence ();
+do_it:
+ if (! fElliptic)
+ {
+ if (! fArc)
+ graphics::circle (x, y, radius);
+ else
+ graphics::arccircle (x, y, radius, arcbeg, arcend);
+ }
+ else
+ {
+ int rx, ry;
+ if (elliptic > 1)
+ {
+ rx= static_cast <int> (radius / elliptic);
+ ry= radius;
+ }
+ else
+ {
+ rx= radius;
+ ry= static_cast <int> (radius * elliptic);
+ }
+ if (! fArc)
+ graphics::ellipse (x, y, rx, ry);
+ else
+ graphics::arcellipse (x, y, rx, ry, arcbeg, arcend);
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_MASK ()
+{
+ BlResult r;
+ gettoken ();
+ if (token.code != ',')
+ {
+ eval (r);
+ graphics::mask (r.integer () );
+ }
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ expect (r);
+ graphics::maskdrawfirstpoint (r.integer () );
+ }
+ require_endsentence ();
+ return false;
+}
+
+bool RunnerLineImpl::do_WINDOW ()
+{
+ gettoken ();
+ if (token.code == keySWAP)
+ {
+ BlChannel ch1= expectchannel ();
+ requiretoken (',');
+ BlChannel ch2= expectchannel ();
+ require_endsentence ();
+ runner.windowswap (ch1, ch2);
+ return false;
+ }
+
+ BlChannel ch= DefaultChannel;
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlInteger x1= evalinteger ();
+ requiretoken (',');
+ BlInteger x2= expectinteger ();
+ requiretoken (',');
+ BlInteger y1= expectinteger ();
+ requiretoken (',');
+ BlInteger y2= expectinteger ();
+ require_endsentence ();
+ if (runner.isfileopen (ch) )
+ {
+ BlFile & bf= runner.getfile (ch);
+ if (bf.istextwindow () )
+ {
+ bf.reset (x1, x2, y1, y2);
+ return false;
+ }
+ }
+
+ auto_ptr <BlFile> pbf (newBlFileWindow (ch, x1, x2, y1, y2) );
+ runner.setfile (ch, pbf.get () );
+ pbf.release ();
+
+ return false;
+}
+
+void RunnerLineImpl::do_graphics_pen ()
+{
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger ink= evalinteger ();
+ graphics::setcolor (ink);
+ if (endsentence () )
+ return;
+ requiretoken (',');
+ }
+ BlInteger transpmode= expectinteger ();
+ graphics::settransparent (transpmode);
+ require_endsentence ();
+}
+
+void RunnerLineImpl::do_graphics_paper ()
+{
+ BlInteger ink= expectinteger ();
+ require_endsentence ();
+ graphics::setbackground (ink);
+}
+
+void RunnerLineImpl::do_graphics_cls ()
+{
+ gettoken ();
+ if (! endsentence () )
+ {
+ BlInteger ink= evalinteger ();
+ require_endsentence ();
+ graphics::setbackground (ink);
+ }
+ graphics::cls ();
+}
+
+bool RunnerLineImpl::do_GRAPHICS ()
+{
+ gettoken ();
+ switch (token.code)
+ {
+ case keyPEN:
+ do_graphics_pen ();
+ break;
+ case keyPAPER:
+ do_graphics_paper ();
+ break;
+ case keyCLS:
+ do_graphics_cls ();
+ break;
+ default:
+ throw ErrSyntax;
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_BEEP ()
+{
+ gettoken ();
+ require_endsentence ();
+
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::ring ();
+ else
+ cursor::ring ();
+ #else
+ runner.ring ();
+ #endif
+
+ return false;
+}
+
+bool RunnerLineImpl::do_DEFINT ()
+{
+ VarType type;
+ switch (token.code)
+ {
+ case keyDEFINT:
+ type= VarInteger; break;
+ case keyDEFSTR:
+ type= VarString; break;
+ case keyDEFREAL: case keyDEFSNG: case keyDEFDBL:
+ type= VarNumber; break;
+ default:
+ throw ErrBlassicInternal;
+ }
+ definevars (type);
+ return false;
+}
+
+bool RunnerLineImpl::do_INK ()
+{
+ int inknum= expectinteger ();
+ if (endsentence () )
+ {
+ // INK Spectrum style (set pen color).
+ getfile0 ().setcolor (inknum);
+ return false;
+ }
+ requiretoken (',');
+ int r= expectinteger ();
+ if (endsentence () )
+ {
+ graphics::ink (inknum, r);
+ return false;
+ }
+ requiretoken (',');
+ int g= expectinteger ();
+ if (endsentence () )
+ {
+ // Flashing ink in Amstrad CPC,
+ // just ignore second parameter.
+ graphics::ink (inknum, r);
+ return false;
+ }
+ requiretoken (',');
+ int b= expectinteger ();
+ require_endsentence ();
+ graphics::ink (inknum, r, g, b);
+ return false;
+}
+
+bool RunnerLineImpl::do_SET_TITLE ()
+{
+ std::string str= expectstring ();
+ require_endsentence ();
+
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::set_title (str);
+ else
+ cursor::set_title (str);
+ #else
+ runner.set_title (str);
+ #endif
+
+ return false;
+}
+
+bool RunnerLineImpl::do_TAG ()
+{
+ BlCode code= token.code;
+ ASSERT (code == keyTAG || code == keyTAGOFF);
+
+ //BlChannel ch= DefaultChannel;
+ //gettoken ();
+ //if (token.code == '#')
+ // ch= expectchannel ();
+ BlChannel ch= expectoptionalchannel ();
+
+ require_endsentence ();
+ BlFile & f= runner.getfile (ch);
+ if (code == keyTAG)
+ f.tag ();
+ else
+ f.tagoff ();
+ return false;
+}
+
+bool RunnerLineImpl::do_ORIGIN ()
+{
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ BlInteger minx= expectinteger ();
+ requiretoken (',');
+ BlInteger maxx= expectinteger ();
+ requiretoken (',');
+ BlInteger miny= expectinteger ();
+ requiretoken (',');
+ BlInteger maxy= expectinteger ();
+ require_endsentence ();
+ graphics::limits (minx, maxx, miny, maxy);
+ }
+ graphics::origin (x, y);
+ return false;
+}
+
+bool RunnerLineImpl::do_DEG ()
+{
+ ASSERT (token.code == keyDEG || token.code == keyRAD);
+ TrigonometricMode newmode= token.code == keyRAD ?
+ TrigonometricRad : TrigonometricDeg;
+ gettoken ();
+ require_endsentence ();
+ runner.trigonometric_mode (newmode);
+ return false;
+}
+
+bool RunnerLineImpl::do_INVERSE ()
+{
+ BlChannel ch= DefaultChannel;
+ gettoken ();
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlInteger inv= evalinteger ();
+ runner.getfile (ch).inverse (inv % 2);
+ return false;
+}
+
+bool RunnerLineImpl::do_IF_DEBUG ()
+{
+ BlInteger n= expectinteger ();
+ require_endsentence ();
+ // If the parameter is lower than the current debug level,
+ // ignore the rest of the line.
+ return n > sysvar::get16 (sysvar::DebugLevel);
+}
+
+bool RunnerLineImpl::do_WIDTH ()
+{
+ expecttoken (keyLPRINT);
+ BlFile & printer= getfile (PrinterChannel);
+ gettoken ();
+ if (token.code != ',')
+ {
+ BlInteger w= evalinteger ();
+ printer.setwidth (w);
+ if (endsentence () )
+ return false;
+ }
+ requiretoken (',');
+ BlInteger m= expectinteger ();
+ require_endsentence ();
+ printer.setmargin (m);
+ return false;
+}
+
+bool RunnerLineImpl::do_BRIGHT ()
+{
+ BlChannel ch= DefaultChannel;
+ gettoken ();
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ requiretoken (',');
+ gettoken ();
+ }
+ BlInteger br= evalinteger ();
+ runner.getfile (ch).bright (br % 2);
+ return false;
+}
+
+bool RunnerLineImpl::do_PLEASE ()
+{
+ gettoken ();
+ if (endsentence () )
+ throw ErrPolite;
+ if (token.code == keyPLEASE)
+ throw ErrNoTeDejo;
+
+ #if 1
+
+ return execute_instruction ();
+
+ #else
+
+ #if 0
+
+ mapfunc_t::const_iterator it=
+ mapfunc.find (token.code);
+ if (it == mapend)
+ throw ErrSyntax;
+ return (this->*it->second) ();
+
+ #else
+
+ return (this->*findfunc (token.code) ) ();
+
+ #endif
+
+ #endif
+}
+
+bool RunnerLineImpl::do_DRAWARC ()
+{
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ BlNumber g= 0;
+ if (token.code == ',')
+ g= expectnum ();
+ require_endsentence ();
+ graphics::drawarc (x, y, g);
+ return false;
+}
+
+bool RunnerLineImpl::do_PULL ()
+{
+ enum PullType { PullRepeat, PullFor, PullWhile, PullGosub };
+ gettoken ();
+ PullType type= PullRepeat;
+ switch (token.code)
+ {
+ case keyREPEAT:
+ gettoken ();
+ break;
+ case keyFOR:
+ type= PullFor;
+ gettoken ();
+ break;
+ case keyWHILE:
+ type= PullWhile;
+ gettoken ();
+ break;
+ case keyGOSUB:
+ type= PullGosub;
+ gettoken ();
+ break;
+ }
+ require_endsentence ();
+ switch (type)
+ {
+ case PullRepeat:
+ if (runner.repeat_empty () )
+ throw ErrUntilWithoutRepeat;
+ runner.repeat_pop ();
+ break;
+ case PullFor:
+ runner.for_top (); // Simple way to do a for stack check.
+ runner.for_pop ();
+ break;
+ case PullWhile:
+ if (runner.while_empty () )
+ throw ErrWendWithoutWhile;
+ runner.while_pop ();
+ break;
+ case PullGosub:
+ // Same as POP
+ {
+ ProgramPos pos;
+ runner.gosub_pop (pos);
+ }
+ break;
+ }
+ return false;
+}
+
+bool RunnerLineImpl::do_PAINT ()
+{
+ expecttoken ('(');
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ requiretoken (')');
+
+ int actual= graphics::getcolor ();
+ int paintattr= actual, borderattr= actual;
+ gettoken ();
+ if (token.code == ',')
+ {
+ gettoken ();
+ if (token.code != ',')
+ {
+ paintattr= evalinteger ();
+ borderattr= paintattr;
+ }
+ if (! endsentence () )
+ {
+ requiretoken (',');
+ borderattr= expectinteger ();
+ }
+
+ }
+ require_endsentence ();
+
+ graphics::paint (x, y, paintattr, borderattr);
+ return false;
+}
+
+bool RunnerLineImpl::do_FREE_MEMORY ()
+{
+ gettoken ();
+ if (endsentence () )
+ {
+ blassic::memory::dyn_freeall ();
+ return false;
+ }
+ BlInteger mempos= evalinteger ();
+ require_endsentence ();
+ blassic::memory::dyn_free (mempos);
+ return false;
+}
+
+bool RunnerLineImpl::do_SCROLL ()
+{
+ BlChannel ch= DefaultChannel;
+ int nlines= 1;
+ gettoken ();
+ if (! endsentence () )
+ {
+ if (token.code == '#')
+ {
+ ch= expectchannel ();
+ if (token.code == ',')
+ nlines= expectinteger ();
+ }
+ else
+ nlines= evalinteger ();
+ require_endsentence ();
+ }
+ runner.getfile (ch).scroll (nlines);
+ return false;
+}
+
+bool RunnerLineImpl::do_ZX_PLOT ()
+{
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ require_endsentence ();
+ graphics::zxplot (graphics::Point (x, y) );
+ return false;
+}
+
+bool RunnerLineImpl::do_ZX_UNPLOT ()
+{
+ BlInteger x= expectinteger ();
+ requiretoken (',');
+ BlInteger y= expectinteger ();
+ require_endsentence ();
+ graphics::zxplot (graphics::Point (x, y) );
+ return false;
+}
+
+bool RunnerLineImpl::do_ELSE ()
+{
+ // This is not the best possible way of treating ELSE,
+ // but can't diagnose an error of ELSE misplaced with
+ // the available info without reexploring the line,
+ // and that will be slow.
+ // Anyway, several old Basic I have tested do the same
+ // thing, and after all the goal is to be similar to
+ // these.
+ return true;
+}
+
+// End of runnerline_instructions.cpp
diff --git a/runnerline_print.cpp b/runnerline_print.cpp
new file mode 100644
index 0000000..f2628e1
--- /dev/null
+++ b/runnerline_print.cpp
@@ -0,0 +1,367 @@
+// runnerline_print.cpp
+// Revision 7-feb-2005
+
+#include "runnerline_impl.h"
+
+#include "using.h"
+#include "sysvar.h"
+#include "util.h"
+using util::to_string;
+
+#include "trace.h"
+
+#include <cassert>
+#define ASSERT assert
+
+namespace sysvar= blassic::sysvar;
+using namespace blassic::file;
+
+
+#define requiretoken(c) if (token.code == c) ; else throw ErrSyntax
+
+#define expecttoken(c) \
+ do { \
+ gettoken (); \
+ if (token.code != c) throw ErrSyntax; \
+ } while (0)
+
+void RunnerLineImpl::print_using (BlFile & out)
+{
+ TRACEFUNC (tr, "RunnerLineImpl::print_using");
+
+ std::string format= expectstring ();
+ VectorUsing usingf;
+ parseusing (format, usingf);
+ if (token.code == ',' || token.code == ';')
+ gettoken ();
+ const size_t l= usingf.size ();
+ size_t ind= 0;
+ Using * pf= usingf [ind];
+ for (;;)
+ {
+ if (ind == 0 && pf->isliteral () )
+ {
+ pf->putliteral (out);
+ ind= (ind + 1) % l;
+ if (ind == 0)
+ throw ErrFunctionCall;
+ pf= usingf [ind];
+ }
+ BlResult result;
+ eval (result);
+ switch (result.type () )
+ {
+ case VarNumber:
+ pf->putnumeric (out, result.number () );
+ break;
+ case VarInteger:
+ pf->putnumeric (out, result.number () );
+ break;
+ case VarString:
+ pf->putstring (out, result.str () );
+ break;
+ default:
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ ind= (ind + 1) % l;
+ pf= usingf [ind];
+ if (ind != 0 && pf->isliteral () )
+ {
+ pf->putliteral (out);
+ ind= (ind + 1) % l;
+ // Seen unnecessary, and is erroneous.
+ //if (ind == 0)
+ // throw ErrFunctionCall;
+ pf= usingf [ind];
+ }
+ if (endsentence () )
+ {
+ //out << '\n';
+ out.endline ();
+ break;
+ }
+ if (token.code == ';' || token.code == ',')
+ {
+ gettoken ();
+ if (endsentence () )
+ break;
+ }
+ }
+}
+
+namespace {
+
+class ChannelSave {
+ BlFile & bf;
+ bool inversesaved;
+ bool inversevalue;
+ bool inksaved;
+ int inkvalue;
+ bool papersaved;
+ int papervalue;
+ bool brightsaved;
+ bool brightvalue;
+public:
+ ChannelSave (BlFile & bf) :
+ bf (bf),
+ inversesaved (false),
+ inksaved (false),
+ papersaved (false),
+ brightsaved (false)
+ {
+ TRACEFUNC (tr, "ChannelSave::ChannelSave");
+ }
+ ~ChannelSave ()
+ {
+ TRACEFUNC (tr, "ChannelSave::~ChannelSave");
+
+ if (inversesaved)
+ bf.inverse (inversevalue);
+ if (brightsaved)
+ bf.bright (brightvalue);
+ if (inksaved)
+ bf.setcolor (inkvalue);
+ if (papersaved)
+ bf.setbackground (papervalue);
+ }
+ void inverse (bool inv)
+ {
+ if (! inversesaved)
+ {
+ inversevalue= bf.getinverse ();
+ inversesaved= true;
+ }
+ bf.inverse (inv);
+ }
+ void ink (int color)
+ {
+ if (! inksaved)
+ {
+ inkvalue= bf.getcolor ();
+ inksaved= true;
+ }
+ bf.setcolor (color);
+ }
+ void paper (int color)
+ {
+ if (! papersaved)
+ {
+ papervalue= bf.getbackground ();
+ papersaved= true;
+ }
+ bf.setbackground (color);
+ }
+ void bright (bool br)
+ {
+ if (! brightsaved)
+ {
+ brightvalue= bf.getbright ();
+ brightsaved= true;
+ }
+ bf.bright (br);
+ }
+};
+
+} // namespace
+
+bool RunnerLineImpl::do_PRINT ()
+{
+ TRACEFUNC (tr, "RunnerLineImpl::do_PRINT");
+
+ // Same function used for PRINT and LPRINT, differing only
+ // in the default channel.
+ BlChannel channel= (token.code == keyLPRINT) ?
+ PrinterChannel : DefaultChannel;
+ gettoken ();
+ if (token.code == '#')
+ {
+ channel= expectchannel ();
+ // Allow ';' for Spectrum compatibility.
+ if (token.code == ',' || token.code == ';')
+ gettoken ();
+ else
+ require_endsentence ();
+ }
+
+ TRMESSAGE (tr, "Channel: " + to_string (channel) );
+
+ BlFile & out= getfile (channel);
+
+ TRMESSAGE (tr, "Text window: " + to_string (out.istextwindow () ) );
+ TRMESSAGE (tr, "File: " + to_string (out.isfile () ) );
+
+ ChannelSave channelsave (out);
+
+ if (token.code == '@')
+ {
+ BlResult result;
+ expect (result);
+ BlInteger pos= result.integer ();
+ requiretoken (',');
+ gettoken ();
+ #if 0
+ BlInteger row= (pos / 32) + 1;
+ BlInteger col= (pos % 32) + 1;
+ if (graphics::ingraphicsmode () )
+ graphics::locate (row, col);
+ else
+ locate (row, col);
+ #else
+ out.gotoxy (pos % 32, pos / 32);
+ #endif
+ }
+ if (endsentence () )
+ {
+ //out << '\n';
+ out.endline ();
+ return false;
+ }
+
+ bool spacebeforenumber=
+ sysvar::hasFlags1 (sysvar::SpaceBefore);
+ BlResult result;
+ size_t n;
+ bool ended= false;
+ do {
+ switch (token.code) {
+ case ',':
+ case ';':
+ // Separators can be before any statement,
+ break;
+ case keyUSING:
+ print_using (out);
+ ended= true;
+ break;
+ case keyTAB:
+ //getparenarg (result);
+ // Not required to improve Sinclair ZX compatibility.
+ expect (result);
+ n= result.integer ();
+ if (! sysvar::hasFlags1 (sysvar::TabStyle) )
+ n-= 1;
+ out.tab (n);
+ break;
+ case keySPC:
+ getparenarg (result);
+ n= result.integer ();
+ //out << std::string (n, ' ');
+ out.putspaces (n);
+ break;
+ case keyAT:
+ out.flush ();
+ {
+ expect (result);
+ //BlInteger row= result.integer () + 1;
+ BlInteger row= result.integer ();
+ requiretoken (',');
+ expect (result);
+ //BlInteger col= result.integer () + 1;
+ BlInteger col= result.integer ();
+ #if 0
+ if (graphics::ingraphicsmode () )
+ graphics::locate (row, col);
+ else
+ locate (row, col);
+ #else
+ out.gotoxy (col, row);
+ #endif
+ }
+ break;
+ case keyINK:
+ out.flush ();
+ {
+ BlInteger color= expectinteger ();
+ channelsave.ink (color);
+ }
+ break;
+ case keyPAPER:
+ out.flush ();
+ {
+ BlInteger color= expectinteger ();
+ channelsave.paper (color);
+ }
+ break;
+ case keyINVERSE:
+ out.flush ();
+ {
+ BlInteger inv= expectinteger ();
+ channelsave.inverse (inv);
+ }
+ break;
+ case keyBRIGHT:
+ out.flush ();
+ {
+ BlInteger br= expectinteger ();
+ channelsave.bright (br);
+ }
+ break;
+ default:
+ eval (result);
+ switch (result.type () ) {
+ case VarString:
+ {
+ TRMESSAGE (tr, "string");
+ std::string txt= result.str ();
+ TRMESSAGE (tr, txt);
+ //out << result.str ();
+ out << txt;
+ }
+ break;
+ case VarNumber:
+ {
+ BlNumber n= result.number ();
+ if (spacebeforenumber && n >= 0)
+ out << ' ';
+ out << n;
+ }
+ break;
+ case VarInteger:
+ {
+ BlInteger n= result.integer ();
+ if (spacebeforenumber && n >= 0)
+ out << ' ';
+ out << n;
+ }
+ break;
+ default:
+ ASSERT (false);
+ throw ErrBlassicInternal;
+ }
+ }
+ if (ended)
+ break;
+ if (endsentence () )
+ {
+ //out << '\n';
+ out.endline ();
+ break;
+ }
+ #if 0
+ if (token.code != ';' && token.code != ',')
+ throw ErrSyntax;
+ if (token.code == ',')
+ out.tab ();
+ gettoken ();
+ #else
+ // Now separator is not required
+ switch (token.code)
+ {
+ case ',':
+ out.tab ();
+ gettoken ();
+ break;
+ case ';':
+ gettoken ();
+ break;
+ default:
+ ; // Nothing
+ }
+ #endif
+ } while (! endsentence () );
+ TRMESSAGE (tr, "Flushing channel");
+ out.flush ();
+ return false;
+}
+
+// End of runnerline_print.cpp
diff --git a/showerror.cpp b/showerror.cpp
new file mode 100644
index 0000000..73ba0fa
--- /dev/null
+++ b/showerror.cpp
@@ -0,0 +1,89 @@
+// showerror.cpp
+// Revision 9-jan-2005
+
+#include "showerror.h"
+
+#include "blassic.h"
+
+#include "error.h"
+
+#include "trace.h"
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#ifdef BLASSIC_USE_WINDOWS
+
+#include <windows.h>
+
+void showlasterror ()
+{
+ TRACEFUNC (tr, "showlasterror");
+
+ if (! showdebuginfo () )
+ return;
+
+ char * lpMsgBuf;
+ DWORD r= FormatMessage (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError (),
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (char *) & lpMsgBuf,
+ 0,
+ NULL);
+ if (r)
+ {
+ TRMESSAGE (tr, lpMsgBuf);
+ CharToOemBuff (lpMsgBuf, lpMsgBuf, r);
+ try
+ {
+ cerr << lpMsgBuf << endl;
+ }
+ catch (...)
+ {
+ r= 0;
+ }
+ LocalFree (lpMsgBuf);
+ }
+ if (! r)
+ {
+ static const char FAILED []=
+ "FormatMessage failed, can't show error info";
+ TRMESSAGE (tr, FAILED);
+ cerr << FAILED << endl;
+ }
+}
+
+#else
+
+#include <string.h>
+#include <errno.h>
+
+void showlasterror ()
+{
+ TRACEFUNC (tr, "showlasterror");
+
+ if (! showdebuginfo () )
+ return;
+
+ const char * message= strerror (errno);
+ TRMESSAGE (tr, message);
+ cerr << message << endl;
+}
+
+#endif
+
+void showlasterror (const char * str)
+{
+ TRACEFUNC (tr, "showlasterror (str)");
+
+ if (! showdebuginfo () )
+ return;
+
+ cerr << str << ": ";
+ showlasterror ();
+}
+
+// End of showerror.cpp
diff --git a/showerror.h b/showerror.h
new file mode 100644
index 0000000..f0122d2
--- /dev/null
+++ b/showerror.h
@@ -0,0 +1,7 @@
+// showerror.h
+// Revision 17-jul-2004
+
+void showlasterror ();
+void showlasterror (const char * str);
+
+// End of showerror.h
diff --git a/socket.cpp b/socket.cpp
new file mode 100644
index 0000000..7d5bc71
--- /dev/null
+++ b/socket.cpp
@@ -0,0 +1,272 @@
+// socket.cpp
+// Revision 24-apr-2009
+
+#include "socket.h"
+
+#include <string.h>
+
+//------------------------------------------------
+// Changed this: now do not use winsock in Cygwin.
+//------------------------------------------------
+//#if defined _Windows || defined __CYGWIN__ || defined __MINGW32__
+//
+#if defined _Windows || defined __MINGW32__
+
+#include <winsock.h>
+
+typedef SOCKET TypeSocket;
+const TypeSocket InvalidSocket= INVALID_SOCKET;
+inline bool isInvalidSocket (TypeSocket s)
+ { return s == INVALID_SOCKET; }
+
+namespace {
+
+class InitWinSock {
+ InitWinSock ()
+ {
+ WSADATA data;
+ r= WSAStartup (0x0101, & data);
+ }
+ ~InitWinSock ()
+ {
+ WSACleanup ();
+ }
+ int r;
+ static InitWinSock init;
+ struct avoid_ugly_warning { };
+ friend struct avoid_ugly_warning;
+};
+
+InitWinSock InitWinSock::init;
+
+} // namespace
+
+#else
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+typedef int TypeSocket;
+const TypeSocket InvalidSocket= -1;
+inline bool isInvalidSocket (TypeSocket s)
+ { return s < 0; }
+inline int closesocket (int handle) { return close (handle); }
+
+#endif
+
+#include <errno.h>
+
+#ifdef __BORLANDC__
+#pragma warn -inl
+#endif
+
+
+//**********************************************************
+// SocketError
+//**********************************************************
+
+std::string SocketError::strErr= "Socket error in ";
+
+SocketError::SocketError (const std::string & nstr)
+{
+ str= strErr;
+ str+= nstr;
+}
+
+SocketError::SocketError (const std::string & nstr, int errnum)
+{
+ str= strErr;
+ str+= nstr;
+ str+= ": ";
+ str+= strerror (errnum);
+}
+
+const char * SocketError::what () const throw ()
+{
+ return str.c_str ();
+}
+
+//**********************************************************
+// Socket::Internal
+//**********************************************************
+
+class Socket::Internal {
+public:
+ Internal () :
+ refcount (1), s (InvalidSocket), maxbuf (0), posbuf (0)
+ {
+ }
+ void addref () { ++refcount; }
+ void delref ()
+ {
+ if (--refcount == 0) {
+ if (! isInvalidSocket (s) )
+ closesocket (s);
+ delete this;
+ }
+ }
+ void set (TypeSocket ns) { s= ns; }
+ TypeSocket handle () { return s; }
+ int connect (sockaddr * name, int namelen)
+ {
+ //if (! isInvalidSocket (s) )
+ // throw SocketError ("connect: already connected");
+ return ::connect (s, name, namelen);
+ }
+ bool eof ()
+ {
+ if (posbuf < maxbuf)
+ return false;
+ getbuffer ();
+ return maxbuf == 0;
+ }
+ int recv (char * bufrec, size_t len, int flags= 0);
+ int send (const char * buffer, size_t len, int flags= 0)
+ {
+ return ::send (s, buffer, len, flags);
+ }
+ char get ()
+ {
+ if (posbuf >= maxbuf) {
+ getbuffer ();
+ if (maxbuf == 0) return 0;
+ }
+ return buffer [posbuf++];
+ }
+private:
+ size_t refcount;
+ TypeSocket s;
+ static const size_t bufsiz= 1024;
+ char buffer [bufsiz];
+ size_t maxbuf, posbuf;
+ void getbuffer ()
+ {
+ posbuf= 0;
+ maxbuf= 0;
+ int i= ::recv (s, buffer, bufsiz, 0);
+ if (i > 0)
+ maxbuf= i;
+ }
+};
+
+int Socket::Internal::recv (char * bufrec, size_t len, int flags)
+{
+ if (posbuf < maxbuf) {
+ size_t send= maxbuf - posbuf;
+ if (len < send) send= len;
+ for (size_t i= 0, j= posbuf; i < send; ++i, ++j)
+ bufrec [i]= buffer [j];
+ posbuf+= send;
+ return send;
+ }
+ return ::recv (s, bufrec, len, flags);
+}
+
+//**********************************************************
+// Socket
+//**********************************************************
+
+Socket::Socket ()
+{
+ in= new Internal;
+}
+
+Socket::Socket (const Socket & nsock)
+{
+ in= nsock.in;
+ in->addref ();
+}
+
+Socket::~Socket ()
+{
+ in->delref ();
+}
+
+Socket & Socket::operator = (const Socket & nsock)
+{
+ Internal * nin;
+ nin= nsock.in;
+ nin->addref ();
+ in->delref ();
+ in= nin;
+ return * this;
+}
+
+#if 0
+TypeSocket Socket::handle ()
+{
+ return in->handle ();
+}
+#endif
+
+bool Socket::eof ()
+{
+ return in->eof ();
+}
+
+std::string Socket::readline ()
+{
+ char c;
+ std::string str;
+ while ( (c= in->get () ) != '\n' && c != '\0')
+ str+= c;
+ #if 0
+ std::string::size_type l= str.size ();
+ if (l > 0 && str [l - 1] == '\r')
+ str.erase (l - 1);
+ #endif
+ return str;
+}
+
+int Socket::read (char * str, int len)
+{
+ return in->recv (str, len);
+}
+
+void Socket::write (const std::string & str)
+{
+ in->send (str.data (), str.size () );
+}
+
+void Socket::write (const char * str, size_t len)
+{
+ in->send (str, len);
+}
+
+//**********************************************************
+// TcpSocket
+//**********************************************************
+
+TcpSocket::TcpSocket ()
+{
+ protoent * pe= getprotobyname ("tcp");
+ int proto= pe ? pe->p_proto : 0;
+ TypeSocket s= socket (PF_INET, SOCK_STREAM, proto);
+ in->set (s);
+}
+
+//**********************************************************
+// TcpSocketClient
+//**********************************************************
+
+TcpSocketClient::TcpSocketClient
+ (const std::string & host, unsigned short port)
+{
+ hostent * hent= gethostbyname (host.c_str () );
+ if (! hent)
+ throw SocketError (std::string ("search from host ") + host,
+ errno);
+ sockaddr_in addr;
+ addr.sin_family= AF_INET;
+ addr.sin_port= htons (port);
+ addr.sin_addr= * (in_addr *) hent->h_addr_list [0];
+ if (in->connect ( (sockaddr *) & addr, sizeof (addr) ) != 0)
+ throw SocketError (std::string ("connect with ") + host,
+ errno);
+}
+
+// Fin de socket.cpp
diff --git a/socket.h b/socket.h
new file mode 100644
index 0000000..58b0b3a
--- /dev/null
+++ b/socket.h
@@ -0,0 +1,54 @@
+#ifndef INCLUDE_BLASSIC_SOCKET_H
+#define INCLUDE_BLASSIC_SOCKET_H
+
+// socket.h
+// Revision 6-feb-2005
+
+#include <string>
+#include <stdexcept>
+
+#ifdef __BORLANDC__
+#pragma warn -8026
+#endif
+
+class SocketError : public std::exception {
+public:
+ SocketError (const std::string & nstr);
+ SocketError (const std::string & nstr, int errnum);
+ ~SocketError () throw () { }
+ const char * what () const throw ();
+private:
+ std::string str;
+ static std::string strErr;
+};
+
+class Socket {
+public:
+ Socket ();
+ Socket (const Socket & nsock);
+ ~Socket ();
+ Socket & operator = (const Socket & nsock);
+ //TypeSocket handle ();
+ bool eof ();
+ std::string readline ();
+ int read (char * str, int len);
+ void write (const std::string & str);
+ void write (const char * str, size_t len);
+protected:
+ class Internal;
+ Internal * in;
+};
+
+class TcpSocket : public Socket {
+public:
+ TcpSocket ();
+};
+
+class TcpSocketClient : public TcpSocket {
+public:
+ TcpSocketClient (const std::string & host, unsigned short port);
+};
+
+#endif
+
+// End of socket.h
diff --git a/spectrum.def b/spectrum.def
new file mode 100644
index 0000000..c1948e9
--- /dev/null
+++ b/spectrum.def
@@ -0,0 +1,1556 @@
+DEFAULT
+
+00000000
+00111100
+01000010
+00000100
+00001000
+00000000
+00001000
+00000000
+
+32
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+33
+
+00000000
+00010000
+00010000
+00010000
+00010000
+00000000
+00010000
+00000000
+
+34
+
+00000000
+00100100
+00100100
+00000000
+00000000
+00000000
+00000000
+00000000
+
+35
+
+00000000
+00100100
+01111110
+00100100
+00100100
+01111110
+00100100
+00000000
+
+36
+
+00000000
+00001000
+00111110
+00101000
+00111110
+00001010
+00111110
+00001000
+
+37
+
+00000000
+01100010
+01100100
+00001000
+00010000
+00100110
+01000110
+00000000
+
+38
+
+00000000
+00010000
+00101000
+00010000
+00101010
+01000100
+00111010
+00000000
+
+39
+
+00000000
+00001000
+00010000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+40
+
+00000000
+00000100
+00001000
+00001000
+00001000
+00001000
+00000100
+00000000
+
+41
+
+00000000
+00100000
+00010000
+00010000
+00010000
+00010000
+00100000
+00000000
+
+42
+
+00000000
+00000000
+00010100
+00001000
+00111110
+00001000
+00010100
+00000000
+
+43
+
+00000000
+00000000
+00001000
+00001000
+00111110
+00001000
+00001000
+00000000
+
+44
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00001000
+00001000
+00010000
+
+45
+
+00000000
+00000000
+00000000
+00000000
+00111110
+00000000
+00000000
+00000000
+
+46
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00011000
+00011000
+00000000
+
+47
+
+00000000
+00000000
+00000010
+00000100
+00001000
+00010000
+00100000
+00000000
+
+48
+
+00000000
+00111100
+01000110
+01001010
+01010010
+01100010
+00111100
+00000000
+
+49
+
+00000000
+00011000
+00101000
+00001000
+00001000
+00001000
+00111110
+00000000
+
+50
+
+00000000
+00111100
+01000010
+00000010
+00111100
+01000000
+01111110
+00000000
+
+51
+
+00000000
+00111100
+01000010
+00001100
+00000010
+01000010
+00111100
+00000000
+
+52
+
+00000000
+00001000
+00011000
+00101000
+01001000
+01111110
+00001000
+00000000
+
+53
+
+00000000
+01111110
+01000000
+01111100
+00000010
+01000010
+00111100
+00000000
+
+54
+
+00000000
+00111100
+01000000
+01111100
+01000010
+01000010
+00111100
+00000000
+
+55
+
+00000000
+01111110
+00000010
+00000100
+00001000
+00010000
+00010000
+00000000
+
+56
+
+00000000
+00111100
+01000010
+00111100
+01000010
+01000010
+00111100
+00000000
+
+57
+
+00000000
+00111100
+01000010
+01000010
+00111110
+00000010
+00111100
+00000000
+
+58
+
+00000000
+00000000
+00000000
+00010000
+00000000
+00000000
+00010000
+00000000
+
+59
+
+00000000
+00000000
+00010000
+00000000
+00000000
+00010000
+00010000
+00100000
+
+60
+
+00000000
+00000000
+00000100
+00001000
+00010000
+00001000
+00000100
+00000000
+
+61
+
+00000000
+00000000
+00000000
+00111110
+00000000
+00111110
+00000000
+00000000
+
+62
+
+00000000
+00000000
+00010000
+00001000
+00000100
+00001000
+00010000
+00000000
+
+63
+
+00000000
+00111100
+01000010
+00000100
+00001000
+00000000
+00001000
+00000000
+
+64
+
+00000000
+00111100
+01001010
+01010110
+01011110
+01000000
+00111100
+00000000
+
+65
+
+00000000
+00111100
+01000010
+01000010
+01111110
+01000010
+01000010
+00000000
+
+66
+
+00000000
+01111100
+01000010
+01111100
+01000010
+01000010
+01111100
+00000000
+
+67
+
+00000000
+00111100
+01000010
+01000000
+01000000
+01000010
+00111100
+00000000
+
+68
+
+00000000
+01111000
+01000100
+01000010
+01000010
+01000100
+01111000
+00000000
+
+69
+
+00000000
+01111110
+01000000
+01111100
+01000000
+01000000
+01111110
+00000000
+
+70
+
+00000000
+01111110
+01000000
+01111100
+01000000
+01000000
+01000000
+00000000
+
+71
+
+00000000
+00111100
+01000010
+01000000
+01001110
+01000010
+00111100
+00000000
+
+72
+
+00000000
+01000010
+01000010
+01111110
+01000010
+01000010
+01000010
+00000000
+
+73
+
+00000000
+00111110
+00001000
+00001000
+00001000
+00001000
+00111110
+00000000
+
+74
+
+00000000
+00000010
+00000010
+00000010
+01000010
+01000010
+00111100
+00000000
+
+75
+
+00000000
+01000100
+01001000
+01110000
+01001000
+01000100
+01000010
+00000000
+
+76
+
+00000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01111110
+00000000
+
+77
+
+00000000
+01000010
+01100110
+01011010
+01000010
+01000010
+01000010
+00000000
+
+78
+
+00000000
+01000010
+01100010
+01010010
+01001010
+01000110
+01000010
+00000000
+
+79
+
+00000000
+00111100
+01000010
+01000010
+01000010
+01000010
+00111100
+00000000
+
+80
+
+00000000
+01111100
+01000010
+01000010
+01111100
+01000000
+01000000
+00000000
+
+81
+
+00000000
+00111100
+01000010
+01000010
+01010010
+01001010
+00111100
+00000000
+
+82
+
+00000000
+01111100
+01000010
+01000010
+01111100
+01000100
+01000010
+00000000
+
+83
+
+00000000
+00111100
+01000000
+00111100
+00000010
+01000010
+00111100
+00000000
+
+84
+
+00000000
+11111110
+00010000
+00010000
+00010000
+00010000
+00010000
+00000000
+
+85
+
+00000000
+01000010
+01000010
+01000010
+01000010
+01000010
+00111100
+00000000
+
+86
+
+00000000
+01000010
+01000010
+01000010
+01000010
+00100100
+00011000
+00000000
+
+87
+
+00000000
+01000010
+01000010
+01000010
+01000010
+01011010
+00100100
+00000000
+
+88
+
+00000000
+01000010
+00100100
+00011000
+00011000
+00100100
+01000010
+00000000
+
+89
+
+00000000
+10000010
+01000100
+00101000
+00010000
+00010000
+00010000
+00000000
+
+90
+
+00000000
+01111110
+00000100
+00001000
+00010000
+00100000
+01111110
+00000000
+
+91
+
+00000000
+00001110
+00001000
+00001000
+00001000
+00001000
+00001110
+00000000
+
+92
+
+00000000
+00000000
+01000000
+00100000
+00010000
+00001000
+00000100
+00000000
+
+93
+
+00000000
+01110000
+00010000
+00010000
+00010000
+00010000
+01110000
+00000000
+
+94
+
+00000000
+00010000
+00111000
+01010100
+00010000
+00010000
+00010000
+00000000
+
+95
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+11111111
+
+96
+
+00000000
+00011100
+00100010
+01111000
+00100000
+00100000
+01111110
+00000000
+
+97
+
+00000000
+00000000
+00111000
+00000100
+00111100
+01000100
+00111100
+00000000
+
+98
+
+00000000
+00100000
+00100000
+00111100
+00100010
+00100010
+00111100
+00000000
+
+99
+
+00000000
+00000000
+00011100
+00100000
+00100000
+00100000
+00011100
+00000000
+
+100
+
+00000000
+00000100
+00000100
+00111100
+01000100
+01000100
+00111100
+00000000
+
+101
+
+00000000
+00000000
+00111000
+01000100
+01111000
+01000000
+00111100
+00000000
+
+102
+
+00000000
+00001100
+00010000
+00011000
+00010000
+00010000
+00010000
+00000000
+
+103
+
+00000000
+00000000
+00111100
+01000100
+01000100
+00111100
+00000100
+00111000
+
+104
+
+00000000
+01000000
+01000000
+01111000
+01000100
+01000100
+01000100
+00000000
+
+105
+
+00000000
+00010000
+00000000
+00110000
+00010000
+00010000
+00111000
+00000000
+
+106
+
+00000000
+00000100
+00000000
+00000100
+00000100
+00000100
+00100100
+00011000
+
+107
+
+00000000
+00100000
+00101000
+00110000
+00110000
+00101000
+00100100
+00000000
+
+108
+
+00000000
+00010000
+00010000
+00010000
+00010000
+00010000
+00001100
+00000000
+
+109
+
+00000000
+00000000
+01101000
+01010100
+01010100
+01010100
+01010100
+00000000
+
+110
+
+00000000
+00000000
+01111000
+01000100
+01000100
+01000100
+01000100
+00000000
+
+111
+
+00000000
+00000000
+00111000
+01000100
+01000100
+01000100
+00111000
+00000000
+
+112
+
+00000000
+00000000
+01111000
+01000100
+01000100
+01111000
+01000000
+01000000
+
+113
+
+00000000
+00000000
+00111100
+01000100
+01000100
+00111100
+00000100
+00000110
+
+114
+
+00000000
+00000000
+00011100
+00100000
+00100000
+00100000
+00100000
+00000000
+
+115
+
+00000000
+00000000
+00111000
+01000000
+00111000
+00000100
+01111000
+00000000
+
+116
+
+00000000
+00010000
+00111000
+00010000
+00010000
+00010000
+00001100
+00000000
+
+117
+
+00000000
+00000000
+01000100
+01000100
+01000100
+01000100
+00111000
+00000000
+
+118
+
+00000000
+00000000
+01000100
+01000100
+00101000
+00101000
+00010000
+00000000
+
+119
+
+00000000
+00000000
+01000100
+01010100
+01010100
+01010100
+00101000
+00000000
+
+120
+
+00000000
+00000000
+01000100
+00101000
+00010000
+00101000
+01000100
+00000000
+
+121
+
+00000000
+00000000
+01000100
+01000100
+01000100
+00111100
+00000100
+00111000
+
+122
+
+00000000
+00000000
+01111100
+00001000
+00010000
+00100000
+01111100
+00000000
+
+123
+
+00000000
+00001110
+00001000
+00110000
+00001000
+00001000
+00001110
+00000000
+
+124
+
+00000000
+00001000
+00001000
+00001000
+00001000
+00001000
+00001000
+00000000
+
+125
+
+00000000
+01110000
+00010000
+00001100
+00010000
+00010000
+01110000
+00000000
+
+126
+
+00000000
+00010100
+00101000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+127
+
+00111100
+01000010
+10011001
+10100001
+10100001
+10011001
+01000010
+00111100
+
+128
+
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+00000000
+
+129
+
+00001111
+00001111
+00001111
+00001111
+00000000
+00000000
+00000000
+00000000
+
+130
+
+11110000
+11110000
+11110000
+11110000
+00000000
+00000000
+00000000
+00000000
+
+131
+
+11111111
+11111111
+11111111
+11111111
+00000000
+00000000
+00000000
+00000000
+
+132
+
+00000000
+00000000
+00000000
+00000000
+00001111
+00001111
+00001111
+00001111
+
+133
+
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+00001111
+
+134
+
+11110000
+11110000
+11110000
+11110000
+00001111
+00001111
+00001111
+00001111
+
+135
+
+11111111
+11111111
+11111111
+11111111
+00001111
+00001111
+00001111
+00001111
+
+136
+
+00000000
+00000000
+00000000
+00000000
+11110000
+11110000
+11110000
+11110000
+
+137
+
+00001111
+00001111
+00001111
+00001111
+11110000
+11110000
+11110000
+11110000
+
+138
+
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+11110000
+
+139
+
+11111111
+11111111
+11111111
+11111111
+11110000
+11110000
+11110000
+11110000
+
+140
+
+00000000
+00000000
+00000000
+00000000
+11111111
+11111111
+11111111
+11111111
+
+141
+
+00001111
+00001111
+00001111
+00001111
+11111111
+11111111
+11111111
+11111111
+
+142
+
+11110000
+11110000
+11110000
+11110000
+11111111
+11111111
+11111111
+11111111
+
+143
+
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+11111111
+
+144
+INVERT
+
+00000000
+00111100
+01000010
+01000010
+01111110
+01000010
+01000010
+00000000
+
+145
+INVERT
+
+00000000
+01111100
+01000010
+01111100
+01000010
+01000010
+01111100
+00000000
+
+146
+INVERT
+
+00000000
+00111100
+01000010
+01000000
+01000000
+01000010
+00111100
+00000000
+
+147
+INVERT
+
+00000000
+01111000
+01000100
+01000010
+01000010
+01000100
+01111000
+00000000
+
+148
+INVERT
+
+00000000
+01111110
+01000000
+01111100
+01000000
+01000000
+01111110
+00000000
+
+149
+INVERT
+
+00000000
+01111110
+01000000
+01111100
+01000000
+01000000
+01000000
+00000000
+
+150
+INVERT
+
+00000000
+00111100
+01000010
+01000000
+01001110
+01000010
+00111100
+00000000
+
+151
+INVERT
+
+00000000
+01000010
+01000010
+01111110
+01000010
+01000010
+01000010
+00000000
+
+152
+INVERT
+
+00000000
+00111110
+00001000
+00001000
+00001000
+00001000
+00111110
+00000000
+
+153
+INVERT
+
+00000000
+00000010
+00000010
+00000010
+01000010
+01000010
+00111100
+00000000
+
+154
+INVERT
+
+00000000
+01000100
+01001000
+01110000
+01001000
+01000100
+01000010
+00000000
+
+155
+INVERT
+
+00000000
+01000000
+01000000
+01000000
+01000000
+01000000
+01111110
+00000000
+
+156
+INVERT
+
+00000000
+01000010
+01100110
+01011010
+01000010
+01000010
+01000010
+00000000
+
+157
+INVERT
+
+00000000
+01000010
+01100010
+01010010
+01001010
+01000110
+01000010
+00000000
+
+158
+INVERT
+
+00000000
+00111100
+01000010
+01000010
+01000010
+01000010
+00111100
+00000000
+
+159
+INVERT
+
+00000000
+01111100
+01000010
+01000010
+01111100
+01000000
+01000000
+00000000
+
+160
+INVERT
+
+00000000
+00111100
+01000010
+01000010
+01010010
+01001010
+00111100
+00000000
+
+161
+INVERT
+
+00000000
+01111100
+01000010
+01000010
+01111100
+01000100
+01000010
+00000000
+
+162
+INVERT
+
+00000000
+00111100
+01000000
+00111100
+00000010
+01000010
+00111100
+00000000
+
+163
+INVERT
+
+00000000
+11111110
+00010000
+00010000
+00010000
+00010000
+00010000
+00000000
+
+164
+INVERT
+
+00000000
+01000010
+01000010
+01000010
+01000010
+01000010
+00111100
+00000000
+
+165
+INVERT
+
+00000000
+01000010
+01000010
+01000010
+01000010
+00100100
+00011000
+00000000
+
+166
+INVERT
+
+00000000
+01000010
+01000010
+01000010
+01000010
+01011010
+00100100
+00000000
+
+167
+INVERT
+
+00000000
+01000010
+00100100
+00011000
+00011000
+00100100
+01000010
+00000000
+
+168
+INVERT
+
+00000000
+10000010
+01000100
+00101000
+00010000
+00010000
+00010000
+00000000
+
+169
+INVERT
+
+00000000
+01111110
+00000100
+00001000
+00010000
+00100000
+01111110
+00000000
+
+# end
diff --git a/sysvar.cpp b/sysvar.cpp
new file mode 100644
index 0000000..a8fcc39
--- /dev/null
+++ b/sysvar.cpp
@@ -0,0 +1,153 @@
+// sysvar.cpp
+// Revision 6-feb-2005
+
+#include "sysvar.h"
+
+#include "charset.h"
+#include "trace.h"
+
+// For debugging.
+#include <sstream>
+
+
+namespace {
+
+BlChar system_vars [blassic::sysvar::EndSysVar];
+
+} // namespace
+
+
+size_t blassic::sysvar::address ()
+{
+ return reinterpret_cast <size_t> (system_vars);
+}
+
+void blassic::sysvar::set (size_t var, BlChar value)
+{
+ system_vars [var]= value;
+}
+
+void blassic::sysvar::set16 (size_t var, short value)
+{
+ poke16 (system_vars + var, value);
+}
+
+void blassic::sysvar::set32 (size_t var, BlInteger value)
+{
+ poke32 (system_vars + var, value);
+}
+
+BlChar blassic::sysvar::get (size_t var)
+{
+ return system_vars [var];
+}
+
+unsigned short blassic::sysvar::get16 (size_t var)
+{
+ return static_cast <unsigned short> (peek16 (system_vars + var) );
+}
+
+unsigned long blassic::sysvar::get32 (size_t var)
+{
+ return peek32 (system_vars + var);
+}
+
+// Flags operations.
+
+blassic::sysvar::Flags1Bit blassic::sysvar::getFlags1 ()
+{
+ return static_cast <Flags1Bit> (system_vars [Flags1] );
+}
+
+blassic::sysvar::Flags2Bit blassic::sysvar::getFlags2 ()
+{
+ return static_cast <Flags2Bit> (system_vars [Flags2] );
+}
+
+bool blassic::sysvar::hasFlags1 (Flags1Bit f)
+{
+ //return (getFlags1 () & f) != Flags1Clean;
+ return getFlags1 ().has (f);
+}
+
+bool blassic::sysvar::hasFlags2 (Flags2Bit f)
+{
+ //return (getFlags2 () & f) != Flags2Clean;
+ return getFlags2 ().has (f);
+}
+
+void blassic::sysvar::setFlags1 (Flags1Bit f)
+{
+ BlChar * const pflag= system_vars + Flags1;
+ *pflag|= f.get ();
+}
+
+void blassic::sysvar::setFlags2 (Flags2Bit f)
+{
+ BlChar * const pflag= system_vars + Flags2;
+ *pflag|= f.get ();
+}
+
+// Initialization
+
+void blassic::sysvar::init ()
+{
+ TRACEFUNC (tr, "blassic::sysvar::init");
+ #ifndef NDEBUG
+ {
+ std::ostringstream oss;
+ oss << "System vars address: " <<
+ static_cast <void *> (system_vars);
+ TRMESSAGE (tr, oss.str () );
+ }
+ #endif
+
+ set16 (GraphicsWidth, 0);
+ set16 (GraphicsHeight, 0);
+ set16 (NumArgs, 0);
+ set16 (VersionMajor, version::Major);
+ set16 (VersionMinor, version::Minor);
+ set16 (VersionRelease, version::Release);
+ set32 (AutoInit, 10);
+ set32 (AutoInc, 10);
+ set32 (CharGen, reinterpret_cast <size_t> (& charset::data) );
+ set (ShellResult, 0);
+ set (TypeOfVal, 0); // VAL simple, number only.
+ set (TypeOfNextCheck, 0); // Strict next check
+ set (TypeOfDimCheck, 0); // Need erase before dim already dimensioned
+ set16 (MaxHistory, 100);
+ setFlags1 (Flags1Clean);
+ // Bit 0: LOCATE style Microsoft (row, col),
+ // Bit 1: TAB style normal.
+ // Bit 2: THEN omitted not accepted.
+ // Bit 3: Without space before number in PRINT.
+ // Bit 4: Without initial space in STR$.
+ // Bit 5: Without convert LF to CR.
+ // Bit 6: Do not show debug info.
+ // Bit 7: Strict GOTO mode.
+
+ #ifdef BLASSIC_USE_WINDOWS
+ const BlChar defaultprinterline= 1;
+ #else
+ const BlChar defaultprinterline= 0;
+ #endif
+ set (PrinterLine, defaultprinterline);
+
+ // Changed this, the processor stack overflows easily
+ // in windows, at least in W98 with C++ Builder.
+ //set32 (MaxFnLevel, 1000); // Seems a good limit.
+ set32 (MaxFnLevel, 50);
+
+ set16 (DebugLevel, 0);
+ set16 (Zone, 8);
+ set (GraphRotate, 0);
+ setFlags2 (Flags2Clean);
+ // Bit 0: GOTO and GOSUB listed as one word.
+ // Bit 1: true is -1
+ // Bit 2: logical ops are binary
+ // Bit 3: blank lines as comments.
+ set16 (TronChannel, 0);
+ set (TronFlags, 0);
+}
+
+// Fin de sysvar.cpp
diff --git a/sysvar.h b/sysvar.h
new file mode 100644
index 0000000..bc880f2
--- /dev/null
+++ b/sysvar.h
@@ -0,0 +1,198 @@
+#ifndef INCLUDE_BLASSIC_SYSVAR_H
+#define INCLUDE_BLASSIC_SYSVAR_H
+
+// sysvar.h
+// Revision 6-feb-2005
+
+#if defined __BORLANDC__
+#pragma warn -8058
+#endif
+
+#include "blassic.h"
+
+
+namespace blassic {
+
+namespace sysvar {
+
+void init ();
+size_t address ();
+
+void set (size_t var, BlChar value);
+void set16 (size_t var, short value);
+void set32 (size_t var, BlInteger value);
+
+BlChar get (size_t var);
+unsigned short get16 (size_t var);
+unsigned long get32 (size_t var);
+
+const size_t
+ GraphicsWidth= 0,
+ GraphicsHeight= 2,
+ NumArgs= 4,
+ VersionMajor= 6,
+ VersionMinor= 8,
+ VersionRelease= 10,
+ AutoInit= 12,
+ AutoInc= 16,
+ CharGen= 20,
+ ShellResult= 24,
+ TypeOfVal= 25, // 0: simple, 1: expression evluation,
+ // else unimplemented.
+ TypeOfNextCheck= 26, // 0: normal, else ZX-type
+ TypeOfDimCheck= 27, // 0: cannot dim already dimensioned
+ // 1: Silently redim
+ MaxHistory= 28, // Max size of history buffer.
+ Flags1= 30, // Bit 0: LOCATE style. 0 Microsoft, 1 Amstrad CPC.
+ // Bit 1: TAB style: 0 normal, 1 Spectrum.
+ // Bit 2: THEN omitted: 0 is not accepted, 1 accepted.
+ // Bit 3: space before number in PRINT, 0 No, 1 Yes.
+ // Bit 4: initial space in STR$, 0 No, 1 Yes.
+ // Bit 5: convert LF to CR in GET and INKEY$
+ // Bit 6: Show debug info on certain errors.
+ // Bit 7: Relaxed GOTO mode.
+ PrinterLine= 31, // Type of printer line feed.
+ // 0 LF only.
+ // 1 CR + LF
+ // 2 CR only.
+ MaxFnLevel= 32, // Max level of FN calls.
+ DebugLevel= 36, // Level for IF_DEBUG
+ Zone= 38, // Size of zone for the , separator of PRINT.
+ GraphRotate= 40, // Type of graphics rotation:
+ // 0 no rotation.
+ // 1 90 degrees.
+ // Other: undefined
+ Flags2= 41, // Bit 0: GO TO and GO SUB separated in listings.
+ // Bit 1: if set true is positive.
+ // Bit 2: if set logical ops are boolean.
+ // Bit 3: if set blank lines in .bas text files
+ // are converted to comments.
+ // Bits 4-7: reserved.
+ TronChannel= 42, // Last channel used for tron or tron line.
+ TronFlags= 44, // Tron flags.
+ // Bit 0: tron ot tron line is active.
+ // Bit 1: tron line is active.
+ // Bits 2-7: reserved.
+ // 45: reserved
+ EndSysVar= 46;
+
+// Flags masks.
+// Implemented as classes to improve type safety
+// and avoid silly mistakes.
+
+class Flags1Bit {
+public:
+ explicit Flags1Bit (BlChar f) :
+ f (f)
+ { }
+ BlChar get () const { return f; }
+ bool has (const Flags1Bit f1bit) const;
+ friend bool operator == (const Flags1Bit f1, const Flags1Bit f2);
+ friend bool operator != (const Flags1Bit f1, const Flags1Bit f2);
+ friend Flags1Bit operator | (const Flags1Bit f1, const Flags1Bit f2);
+ friend Flags1Bit operator & (const Flags1Bit f1, const Flags1Bit f2);
+private:
+ BlChar f;
+};
+
+inline bool Flags1Bit::has (const Flags1Bit f1bit) const
+{
+ return (f & f1bit.f);
+}
+
+inline bool operator == (const Flags1Bit f1, const Flags1Bit f2)
+{
+ return f1.f == f2.f;
+}
+
+inline bool operator != (const Flags1Bit f1, const Flags1Bit f2)
+{
+ return f1.f != f2.f;
+}
+
+inline Flags1Bit operator | (const Flags1Bit f1, const Flags1Bit f2)
+{
+ return Flags1Bit (f1.f | f2.f);
+}
+
+inline Flags1Bit operator & (const Flags1Bit f1, const Flags1Bit f2)
+{
+ return Flags1Bit (f1.f & f2.f);
+}
+
+class Flags2Bit {
+public:
+ explicit Flags2Bit (BlChar f) :
+ f (f)
+ { }
+ BlChar get () const { return f; }
+ bool has (const Flags2Bit f2bit) const;
+ friend bool operator == (const Flags2Bit f1, const Flags2Bit f2);
+ friend bool operator != (const Flags2Bit f1, const Flags2Bit f2);
+ friend Flags2Bit operator | (const Flags2Bit f1, const Flags2Bit f2);
+ friend Flags2Bit operator & (const Flags2Bit f1, const Flags2Bit f2);
+private:
+ BlChar f;
+};
+
+inline bool Flags2Bit::has (const Flags2Bit f2bit) const
+{
+ return (f & f2bit.f);
+}
+
+inline bool operator == (const Flags2Bit f1, const Flags2Bit f2)
+{
+ return f1.f == f2.f;
+}
+
+inline bool operator != (const Flags2Bit f1, const Flags2Bit f2)
+{
+ return f1.f != f2.f;
+}
+
+inline Flags2Bit operator | (const Flags2Bit f1, const Flags2Bit f2)
+{
+ return Flags2Bit (f1.f | f2.f);
+}
+
+inline Flags2Bit operator & (const Flags2Bit f1, const Flags2Bit f2)
+{
+ return Flags2Bit (f1.f & f2.f);
+}
+
+const Flags1Bit
+ Flags1Clean (0),
+ LocateStyle (1),
+ TabStyle (2),
+ ThenOmitted (4),
+ SpaceBefore (8),
+ SpaceStr_s (16),
+ ConvertLFCR (32),
+ ShowDebugInfo (64),
+ RelaxedGoto (128),
+ Flags1Full (255);
+
+const Flags2Bit
+ Flags2Clean (0),
+ SeparatedGoto (1),
+ TruePositive (2),
+ BoolMode (4),
+ BlankComment (8),
+ Flags2Full (255);
+
+Flags1Bit getFlags1 ();
+Flags2Bit getFlags2 ();
+
+bool hasFlags1 (Flags1Bit f);
+bool hasFlags2 (Flags2Bit f);
+
+void setFlags1 (Flags1Bit f);
+void setFlags2 (Flags2Bit f);
+
+} // namespace sysvar
+
+} // namespace blassic
+
+#endif
+
+// Fin de sysvar.h
diff --git a/testdl.cpp b/testdl.cpp
new file mode 100644
index 0000000..7e21431
--- /dev/null
+++ b/testdl.cpp
@@ -0,0 +1,49 @@
+// testdl.cpp
+
+#ifdef _Windows
+#define EXTERN extern "C" __declspec (dllexport)
+#else
+#define EXTERN extern "C"
+#endif
+
+#ifdef _Windows
+#include <windows.h>
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#include <condefs.h>
+// string (iterator, iterator) gives this warnig:
+#pragma warn -8012
+#else
+#error Compiler not tested.
+#endif
+
+#endif
+
+#include <iostream>
+#include <string>
+
+using std::string;
+
+#ifdef _Windows
+
+#pragma argsused
+int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*)
+{
+ return 1;
+}
+
+#endif
+
+EXTERN int testfunc (int nparams, int * param)
+{
+ if (nparams != 1)
+ return 1;
+ string * pstr= reinterpret_cast <string *> (param [0]);
+ string nstr ( pstr->rbegin (), pstr->rend () );
+ // Do not use * pstr= nstr nor assign a string longer than * pstr.
+ pstr->assign (nstr);
+ return 0;
+}
+
+// Fin de testdl.cpp
diff --git a/token.cpp b/token.cpp
new file mode 100644
index 0000000..cfb64af
--- /dev/null
+++ b/token.cpp
@@ -0,0 +1,315 @@
+// token.cpp
+// Revision 25-jul-2004
+
+#include "token.h"
+#include <cctype>
+#include <sstream>
+
+using std::isalpha;
+using std::isdigit;
+using std::isxdigit;
+using std::isspace;
+
+Tokenizer::Tokenizer (const std::string & source) :
+ str (source), pos (0), limit (source.size () )
+{
+}
+
+unsigned char Tokenizer::peek ()
+{
+ if (pos < limit)
+ return str [pos];
+ else
+ return '\0';
+}
+
+unsigned char Tokenizer::peeknospace ()
+{
+ unsigned char c= '\0';
+ std::string::size_type p= pos;
+ while (p < limit && (c= str [p] ) == ' ')
+ ++p;
+ if (p < limit)
+ return c;
+ else
+ return '\0';
+}
+
+unsigned char Tokenizer::nextchar ()
+{
+ if (pos < limit)
+ return str [pos++];
+ else
+ return '\0';
+}
+
+unsigned char Tokenizer::nextcharnospace ()
+{
+ unsigned char c= '\0';
+ while (pos < limit && (c= str [pos] ) == ' ')
+ ++pos;
+ if (pos < limit)
+ {
+ ++pos;
+ return c;
+ }
+ else
+ return '\0';
+}
+
+void Tokenizer::ungetchar ()
+{
+ if (pos > 0)
+ --pos;
+}
+
+//namespace {
+
+inline bool isident (char c)
+{
+ return isalpha (c) || isdigit (c) || c == '_';
+}
+
+//}
+
+Tokenizer::Token Tokenizer::get ()
+{
+ unsigned char c= nextchar ();
+ if (c == '\0')
+ return Token (EndLine);
+
+ std::string str;
+ if (isspace (c) )
+ {
+ do {
+ str+= c;
+ } while (isspace (c= nextchar () ) );
+ if (c != '\0')
+ ungetchar ();
+ return Token (Blank, str);
+ }
+
+ switch (c)
+ {
+ case '"':
+ //str+= c;
+ while ( (c= nextchar () ) != '\0')
+ {
+ if (c == '"')
+ {
+ c= peek ();
+ if (c != '"')
+ break;
+ nextchar ();
+ }
+ str+= c;
+ }
+ return Token (Literal, str);
+ case '&':
+ // Hex, octal or binary number
+ str= '&';
+ c= nextchar ();
+ if (c == 'x' || c == 'X') // Binary
+ {
+ str+= c;
+ while ( (c= nextchar () ) == '0' || c == '1')
+ str+= c;
+ if (c != 0)
+ ungetchar ();
+ }
+ else if (c == 'o' || c == 'O') // Octal
+ {
+ str+= c;
+ while ( (c= nextchar () ) >= '0' && c <= '7')
+ str+= c;
+ if (c != 0)
+ ungetchar ();
+ }
+ else // Hexadecimal
+ {
+ if (c == 'h' || c == 'H')
+ {
+ str+= c;
+ c= nextchar ();
+ }
+ while (isxdigit (c) )
+ {
+ str+= c;
+ c= nextchar ();
+ }
+ if (c != 0)
+ ungetchar ();
+ }
+ return Token (Plain, str);
+ case '=':
+ {
+ str= c;
+ c= peeknospace ();
+ if (c == '>' || c == '<')
+ {
+ str+= c;
+ (void) nextcharnospace ();
+ }
+ }
+ return Token (Plain, str);
+ case '<':
+ str= c;
+ c= peeknospace ();
+ if (c == '=' || c == '>')
+ {
+ str+= c;
+ (void) nextcharnospace ();
+ }
+ return Token (Plain, str);
+ case '>':
+ str= c;
+ c= peeknospace ();
+ if (c == '=' || c == '<')
+ {
+ str+= c;
+ (void) nextcharnospace ();
+ }
+ return Token (Plain, str);
+ default:
+ ; // Later.
+ }
+
+ if (isalpha (c) )
+ {
+ do
+ {
+ str+= c;
+ } while ( isident (c= nextchar () ) );
+ if (c == '$')
+ str+= c;
+ else
+ if (c != '\0')
+ ungetchar ();
+ return Token (Plain, str);
+ }
+
+ if (isdigit (c) || c == '.')
+ {
+ bool nofloat= true;
+ while (isdigit (c) )
+ {
+ str+= c;
+ c= nextchar ();
+ }
+ if (c == '.')
+ {
+ str+= '.';
+ nofloat= false;
+ while ( isdigit (c= nextchar () ) )
+ str+= c;
+ }
+ if (c == 'e' || c == 'E')
+ {
+ str+= c;
+ nofloat= false;
+ c= nextchar ();
+ if (! isdigit (c) && c != '+' && c != '-')
+ {
+ // Data such as 1E
+ while (isident (c) )
+ {
+ str+= c;
+ c= nextchar ();
+ }
+ if (c != 0)
+ ungetchar ();
+ return Token (Plain, str);
+ }
+ if (c == '+' || c == '-')
+ {
+ str+= c;
+ c= nextchar ();
+ }
+ while (isdigit (c) )
+ {
+ str+= c;
+ c= nextchar ();
+ }
+ }
+ if (c != 0)
+ {
+ if (isident (c) )
+ {
+ do {
+ str+= c;
+ c= nextchar ();
+ } while (isident (c) );
+ if (c != 0)
+ ungetchar ();
+ return Token (Plain, str);
+ }
+ ungetchar ();
+ }
+ if (nofloat)
+ {
+ #if 0
+ std::istringstream iss (str);
+ BlInteger n;
+ iss >> n;
+ if (iss)
+ {
+ iss.get ();
+ //if (! iss)
+ if (iss.eof () )
+ return Token (n);
+ }
+ #else
+ BlInteger n= 0;
+ std::string::size_type i;
+ const std::string::size_type l= str.size ();
+ for (i= 0; i < l; ++i)
+ {
+ BlInteger digit= str [i] - '0';
+ if (n > (BlIntegerMax / 10) )
+ break;
+ n*= 10;
+ if (n > BlIntegerMax - digit)
+ break;
+ n+= digit;
+ }
+ if (i == l)
+ return Token (n);
+ #endif
+ }
+ return Token (Plain, str);
+ }
+
+ // If nothing else:
+ str= c;
+ return Token (Plain, str);
+}
+
+std::string Tokenizer::getrest ()
+{
+ std::string r;
+ char c;
+ while ( (c= nextchar () ) != 0)
+ {
+ if (c == '"')
+ {
+ r+= c;
+ while ( (c= nextchar () ) != '\0')
+ {
+ if (c == '"')
+ {
+ c= peek ();
+ if (c != '"')
+ break;
+ nextchar ();
+ }
+ r+= c;
+ }
+ r+= '\0';
+ }
+ else
+ r+= c;
+ }
+ return r;
+}
+
+// Fin de token.cpp
diff --git a/token.h b/token.h
new file mode 100644
index 0000000..3decdbc
--- /dev/null
+++ b/token.h
@@ -0,0 +1,53 @@
+#ifndef INCLUDE_BLASSIC_TOKEN_H
+#define INCLUDE_BLASSIC_TOKEN_H
+
+// token.h
+// Revision 7-feb-2005
+
+
+#include "blassic.h"
+
+#include <string>
+
+
+class Tokenizer {
+public:
+ enum Type { Empty, EndLine, Blank, Plain, Literal, Integer };
+ Tokenizer (const std::string & source);
+
+ // Members of token are public accessible for simplicity.
+ // Use with care.
+ class Token {
+ public:
+ Token () :
+ type (Empty)
+ { }
+ Token (Type t) :
+ type (t)
+ { }
+ Token (Type t, const std::string & str) :
+ type (t), str (str)
+ { }
+ Token (BlInteger n) :
+ type (Integer), n (n)
+ { }
+ Type type;
+ std::string str;
+ BlInteger n;
+ };
+ Token get ();
+ std::string getrest ();
+ unsigned char peek ();
+private:
+ unsigned char peeknospace ();
+ unsigned char nextchar ();
+ unsigned char nextcharnospace ();
+ void ungetchar ();
+ std::string str;
+ std::string::size_type pos;
+ const std::string::size_type limit;
+};
+
+#endif
+
+// Fin de token.h
diff --git a/trace.cpp b/trace.cpp
new file mode 100644
index 0000000..f5b50cc
--- /dev/null
+++ b/trace.cpp
@@ -0,0 +1,176 @@
+// trace.cpp
+// Revision 7-feb-2005
+
+#include "trace.h"
+
+
+#if __BORLANDC__ >= 0x0560
+#pragma warn -8091
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#ifdef HAVE_CSTDLIB
+#include <cstdlib>
+#else
+#include <stdlib.h>
+#endif
+
+#include <stdexcept>
+
+#include <string.h>
+
+using std::cerr;
+using std::endl;
+using std::ostream;
+using std::ofstream;
+using std::string;
+
+
+namespace {
+
+ostream * pout= 0;
+bool flag= true;
+size_t indent= 0;
+
+TraceFunc * initial= NULL;
+TraceFunc * * lastpos= & initial;
+
+ostream * opentracefile (const char * str)
+{
+ std::ofstream * pof=
+ new ofstream (str, std::ios::app | std::ios::out);
+ if (! pof->is_open () )
+ {
+ cerr << "Error opening " << str << endl;
+ delete pof;
+ pof= 0;
+ }
+ return pof;
+}
+
+void showinfo (const char * strenterexit, const char * strfunc)
+{
+ if (pout)
+ {
+ * pout << string (indent, ' ') << strenterexit << ' ';
+
+ if (std::uncaught_exception () )
+ * pout << "(throwing) ";
+
+ * pout << strfunc << endl;
+ }
+}
+
+const char BAD_USE []= "Bad use of TraceFunc";
+
+} // namespace
+
+TraceFunc::TraceFunc (const char * strFuncName) :
+ strfunc (strFuncName),
+ next (NULL)
+{
+ if (flag)
+ {
+ flag= false;
+ char * aux= getenv ("TRACEFUNC");
+ if (aux)
+ {
+ if (strcmp (aux, "-") == 0)
+ pout= & std::cerr;
+ else
+ pout= opentracefile (aux);
+ }
+ }
+
+ //tracelist.push_back (this);
+ previous= lastpos;
+ * lastpos= this;
+ lastpos= & next;
+
+ #if 0
+ if (pout)
+ {
+ * pout << string (indent, ' ') << "Enter ";
+
+ if (std::uncaught_exception () )
+ * pout << "(throwing) ";
+
+ * pout << strfunc << endl;
+ }
+ #else
+ showinfo ("Enter", strfunc);
+ #endif
+ ++indent;
+}
+
+TraceFunc::~TraceFunc ()
+{
+ --indent;
+
+ #if 0
+ if (pout)
+ {
+ * pout << string (indent, ' ') << "Exit ";
+
+ if (std::uncaught_exception () )
+ * pout << "(throwing) ";
+
+ * pout << strfunc << endl;
+ }
+ #else
+ showinfo ("Exit", strfunc);
+ #endif
+
+ if (next != NULL)
+ {
+ cerr << BAD_USE << endl;
+ abort ();
+ }
+ if (lastpos != & next)
+ {
+ //throw std::logic_error ("Bad use of TraceFunc");
+ cerr << BAD_USE << endl;
+ abort ();
+ }
+ lastpos= previous;
+ if (* lastpos != this)
+ {
+ cerr << BAD_USE << endl;
+ abort ();
+ }
+ * lastpos= NULL;
+}
+
+void TraceFunc::message (const std::string & strMes)
+{
+ if (pout)
+ {
+ * pout << string (indent, ' ') << strfunc;
+
+ if (std::uncaught_exception () )
+ * pout << "(throwing) ";
+
+ * pout << ": " << strMes << endl;
+ }
+}
+
+void TraceFunc::show (int)
+{
+ cerr << "\r\n";
+
+ if (initial == NULL)
+ cerr << "TraceFunc: no calls.";
+ else
+ {
+ cerr << "TraceFunc dump of calls: \r\n";
+ for (TraceFunc * act= initial; act != NULL; act= act->next)
+ cerr << act->strfunc << "\r\n";
+ cerr << "TraceFunc dump ended.";
+ }
+ cerr << "\r\n";
+}
+
+// Fin de trace.cpp
diff --git a/trace.h b/trace.h
new file mode 100644
index 0000000..6f671f8
--- /dev/null
+++ b/trace.h
@@ -0,0 +1,39 @@
+#ifndef INCLUDE_BLASSIC_TRACE_H
+#define INCLUDE_BLASSIC_TRACE_H
+
+// trace.h
+// Revision 7-feb-2005
+
+#include <cstddef>
+#include <string>
+
+
+class TraceFunc {
+public:
+ TraceFunc (const char * strFuncName);
+ ~TraceFunc ();
+ void message (const std::string & str);
+ static void show (int);
+private:
+ const char * strfunc;
+ TraceFunc * * previous;
+ TraceFunc * next;
+};
+
+#ifndef NDEBUG
+
+#define TRACEFUNC(tr,name) \
+ TraceFunc tr (name)
+#define TRMESSAGE(tr,text) \
+ tr.message (text)
+
+#else
+
+#define TRACEFUNC(tr,name)
+#define TRMESSAGE(tr,text)
+
+#endif
+
+#endif
+
+// Fin de trace.h
diff --git a/using.cpp b/using.cpp
new file mode 100644
index 0000000..18b7bd6
--- /dev/null
+++ b/using.cpp
@@ -0,0 +1,582 @@
+// using.cpp
+// Revision 9-jan-2005
+
+#include "using.h"
+#include "util.h"
+#include "trace.h"
+
+#include <sstream>
+#include <iomanip>
+#include <memory>
+using std::auto_ptr;
+#include <cstdio>
+using std::sprintf;
+#include <cstdlib>
+#include <cmath>
+#include <stdexcept>
+#include <algorithm>
+
+#include <cassert>
+#define ASSERT assert
+
+using namespace blassic::file;
+
+//**************************************
+// Auxiliary functions
+//**************************************
+
+namespace {
+
+const char poundsign= '\xA3';
+#ifdef _Windows
+const char eurosign= '\x80';
+#else
+const char eurosign= '\xA4';
+#endif
+
+bool charformat [256]= { false };
+
+bool initformat ()
+{
+ charformat [static_cast <unsigned char> ('#') ]= true;
+ charformat [static_cast <unsigned char> ('.') ]= true;
+ charformat [static_cast <unsigned char> ('+') ]= true;
+ charformat [static_cast <unsigned char> ('*') ]= true;
+ charformat [static_cast <unsigned char> ('$') ]= true;
+ charformat [static_cast <unsigned char> (poundsign) ]= true;
+ charformat [static_cast <unsigned char> (eurosign) ]= true;
+ charformat [static_cast <unsigned char> ('\\') ]= true;
+ charformat [static_cast <unsigned char> ('&') ]= true;
+ charformat [static_cast <unsigned char> ('!') ]= true;
+ return true;
+}
+
+bool initedformat= initformat ();
+
+bool ischarformat (char c)
+{
+ return charformat [static_cast <unsigned char> (c) ];
+}
+
+}
+
+//**************************************
+// Using
+//**************************************
+
+Using::~Using ()
+{ }
+
+bool Using::isliteral () const
+{ return false; }
+
+void Using::putliteral (BlFile &) const
+{ throw ErrMismatch; }
+
+void Using::putnumeric (BlFile &, BlNumber) const
+{ throw ErrMismatch; }
+
+void Using::putstring (BlFile &, const std::string &) const
+{ throw ErrMismatch; }
+
+//**************************************
+// UsingLiteral
+//**************************************
+
+UsingLiteral::UsingLiteral (std::istream & is)
+{
+ TRACEFUNC (tr, "UsingLiteral::UsingLiteral");
+
+ init (is);
+}
+
+UsingLiteral::UsingLiteral (std::istream & is,
+ const std::string & strinit) :
+ s (strinit)
+{
+ TRACEFUNC (tr, "UsingLiteral::UsingLiteral");
+
+ init (is);
+}
+
+UsingLiteral::UsingLiteral (const std::string & strinit) :
+ s (strinit)
+{
+ TRACEFUNC (tr, "UsingLiteral::UsingLiteral");
+}
+
+void UsingLiteral::init (std::istream & is)
+{
+ TRACEFUNC (tr, "UsingLiteral::init");
+
+ char c;
+ while (is >> c && ! ischarformat (c) )
+ {
+ s+= c;
+ }
+ ASSERT (! s.empty () );
+ TRMESSAGE (tr, std::string ("Literal is: \"") + s + '"');
+ if (is)
+ is.unget ();
+}
+
+bool UsingLiteral::isliteral () const
+{ return true; }
+
+void UsingLiteral::addstr (const std::string & stradd)
+{
+ s+= stradd;
+}
+
+void UsingLiteral::putliteral (BlFile & out) const
+{
+ out << s;
+}
+
+void UsingLiteral::putnumeric (BlFile &, BlNumber) const
+{ ASSERT (false); throw ErrBlassicInternal; }
+
+void UsingLiteral::putstring (BlFile &, const std::string &) const
+{ ASSERT (false); throw ErrBlassicInternal; }
+
+//**************************************
+// UsingNumeric
+//**************************************
+
+UsingNumeric::UsingNumeric (std::istream & is, std::string & tail) :
+ invalid (true),
+ digit (0),
+ decimal (0),
+ scientific (0),
+ milliards (false),
+ putsign (false),
+ signatend (false),
+ blankpositive (false),
+ asterisk (false),
+ dollar (false),
+ pound (false),
+ euro (false)
+{
+ TRACEFUNC (tr, "UsingNumeric::UsingNumeric");
+
+ char c;
+ is >> c;
+ ASSERT (is);
+ if (c == '+')
+ {
+ putsign= true;
+ s+= c;
+ is >> c;
+ }
+
+ if (is)
+ {
+ switch (c)
+ {
+ case '*':
+ s+= c;
+ if (! (is >> c) )
+ return;
+ if (c != '*')
+ {
+ TRMESSAGE (tr, std::string (1, c) +
+ " following *");
+ is.unget ();
+ return;
+ }
+ asterisk= true;
+ digit+= 2;
+ if (is >> c)
+ {
+ switch (c)
+ {
+ case '$':
+ dollar= true;
+ s+= c;
+ is >> c;
+ break;
+ case poundsign:
+ pound= true;
+ s+= c;
+ is >> c;
+ break;
+ case eurosign:
+ euro= true;
+ s+= c;
+ is >> c;
+ break;
+ }
+ }
+ break;
+ case '$':
+ case poundsign:
+ case eurosign:
+ s+= c;
+ {
+ char sign= c;
+ if (! (is >> c) )
+ return;
+ if (c != sign)
+ {
+ is.unget ();
+ return;
+ }
+ ++digit;
+ switch (sign)
+ {
+ case '$': dollar= true; break;
+ case poundsign: pound= true; break;
+ case eurosign: euro= true; break;
+ }
+ s+= c;
+ }
+ is >> c;
+ break;
+ }
+ }
+
+ while (is && c == '#')
+ {
+ invalid= false;
+ ++digit;
+ s+= c;
+ is >> c;
+ }
+ if (is)
+ {
+ if (c == '.')
+ {
+ s+= c;
+ while (is >> c && c == '#')
+ {
+ invalid= false;
+ ++decimal;
+ s+= c;
+ }
+ }
+ }
+ if (is)
+ {
+ if (c == '^')
+ {
+ ++scientific;
+ s+= c;
+ if (invalid)
+ return;
+ while (scientific < 5 && is >> c && c == '^')
+ ++scientific;
+ if (scientific == 5)
+ is >> c;
+ if (scientific < 4)
+ {
+ tail= std::string (scientific, '^');
+ scientific= 0;
+ }
+ else
+ scientific-= 2;
+ }
+ }
+ if (is && (c == '+' || c == '-') )
+ {
+ s+= c;
+ if (invalid)
+ return;
+ putsign= true;
+ signatend= true;
+ if (c == '-')
+ blankpositive= true;
+ is >> c;
+ }
+ if (is)
+ is.unget ();
+}
+
+namespace {
+
+class UsingOverflow { };
+
+}
+
+namespace {
+// Workaround for a problem in gcc
+double zero= 0.0;
+}
+
+void UsingNumeric::putliteral (BlFile &) const
+{ ASSERT (false); throw ErrBlassicInternal; }
+
+void UsingNumeric::putnumeric (BlFile & out, BlNumber n) const
+{
+ try
+ {
+ int negative;
+ if (scientific > 0)
+ {
+ size_t d= digit;
+ if (n < zero && ! putsign)
+ --d;
+ #if 0
+ int prec= d + decimal;
+ int dec;
+ char * aux= ecvt (n, prec, & dec, & negative);
+ int e= dec - static_cast <int> (d);
+ //if (scientific == 0 && e != 0)
+ // throw UsingOverflow ();
+ std::string stre= util::to_string (abs (e) );
+ int ezeroes= scientific - stre.size ();
+ if (ezeroes < 0)
+ throw UsingOverflow ();
+
+ if (putsign && ! signatend)
+ {
+ out << (negative ? '-' : '+');
+ }
+ if (! putsign && negative)
+ out << '-';
+ out << (std::string (aux, d) + '.' +
+ std::string (aux + d) ) <<
+ 'E' << (e < 0 ? '-' : '+') <<
+ std::string (ezeroes, '0') <<
+ stre;
+ #else
+ int prec= d + decimal - 1;
+ //std::cout << '(' << d << ',' << prec << ')' <<
+ // std::flush;
+ char buffer [64];
+ sprintf (buffer, "%+.*e", prec, n);
+ //std::cout << '[' << buffer << ']' << std::flush;
+ negative= buffer [0] == '-';
+ std::string aux= std::string (1, buffer [1]) +
+ (buffer + 3);
+ std::string::size_type pose= aux.find ('e');
+ if (pose != std::string::npos)
+ aux.erase (pose);
+ int e= static_cast <int>
+ (std::floor (std::log10 (fabs (n) ) ) ) +
+ - static_cast <int> (d) + 1;
+ std::string stre= util::to_string (abs (e) );
+ int ezeroes= scientific - stre.size ();
+ if (ezeroes < 0)
+ throw UsingOverflow ();
+ if (putsign && ! signatend)
+ {
+ out << (negative ? '-' : '+');
+ }
+ if (! putsign && negative)
+ out << '-';
+ out << (aux.substr (0, d) + '.' +
+ aux.substr (d) ) <<
+ 'E' << (e < 0 ? '-' : '+') <<
+ std::string (ezeroes, '0') <<
+ stre;
+ #endif
+ }
+ else
+ {
+ int numdig= 0;
+ negative= n < 0;
+ if (negative)
+ n= -n;
+ if (n != 0)
+ numdig= int (std::log10 (n * 10 ) );
+ if (numdig < 0)
+ numdig= 0;
+ size_t w= numdig;
+ if (digit > w)
+ w= digit;
+ size_t maxw= digit;
+ if (decimal > 0)
+ {
+ w+= decimal + 1;
+ maxw+= decimal + 1;
+ }
+ if (negative && ! putsign)
+ {
+ --w;
+ --maxw;
+ }
+ std::ostringstream oss;
+ if (decimal > 0)
+ oss.setf (std::ios::showpoint);
+
+ // Some implementations lack the fixed manipulator.
+ oss.setf (std::ios::fixed, std::ios::floatfield);
+ oss << std::setw (w) <<
+ //std::setprecision (decimal + numdig) <<
+ std::setprecision (decimal) <<
+ //std::fixed <<
+ n;
+ std::string strn= oss.str ();
+ if (digit == 0 && strn [0] == '0')
+ strn.erase (0, 1);
+ if (strn.size () > maxw)
+ throw UsingOverflow ();
+ if (dollar || pound || euro)
+ {
+ char sign= dollar ? '$' :
+ pound ? poundsign : eurosign;
+ strn.insert (strn.find_first_not_of (" "),
+ 1, sign);
+ }
+ if ( (putsign && ! signatend) ||
+ (! putsign && negative) )
+ {
+ std::string::size_type possign=
+ strn.find_first_not_of (" ");
+ if (possign == std::string::npos)
+ possign= 0;
+ strn.insert (possign, 1,
+ negative ? '-' : '+');
+ }
+ if (asterisk)
+ {
+ for (size_t i= 0,
+ l= strn.find_first_not_of (" ");
+ i < l; ++i)
+ {
+ strn [i]= '*';
+ }
+ }
+ out << strn;
+ }
+ if (signatend)
+ {
+ ASSERT (putsign);
+ out << (negative ? '-' :
+ blankpositive ? ' ' : '+' );
+ }
+ }
+ catch (UsingOverflow &)
+ {
+ out << '%' << n;
+ }
+}
+
+//**************************************
+// UsingString
+//**************************************
+
+UsingString::UsingString (std::istream & is) :
+ n (0)
+{
+ char c;
+ is >> c;
+ ASSERT (is);
+ switch (c)
+ {
+ case '\\':
+ n= 1;
+ while (is >> c && c == ' ')
+ ++n;
+ if (is)
+ {
+ if (c == '\\')
+ ++n;
+ else
+ is.unget ();
+ }
+ break;
+ case '&':
+ // Nothing in particular
+ break;
+ case '!':
+ n= 1;
+ break;
+ default:
+ throw ErrBlassicInternal;
+ }
+}
+
+void UsingString::putliteral (BlFile &) const
+{ ASSERT (false); throw ErrBlassicInternal; }
+
+void UsingString::putstring (BlFile & out, const std::string & str) const
+{
+ if (n > 0)
+ out << str.substr (0, n);
+ else
+ out << str;
+}
+
+//**************************************
+// VectorUsing
+//**************************************
+
+VectorUsing::VectorUsing ()
+{
+}
+
+VectorUsing::~VectorUsing ()
+{
+ std::for_each (v.begin (), v.end (), delete_it);
+}
+
+void VectorUsing::push_back (const Using & u)
+{
+ UsingLiteral * prev;
+ if (! v.empty () && u.isliteral () &&
+ (prev= dynamic_cast <UsingLiteral *> (v.back () ) ) != NULL)
+ {
+ prev->addstr (dynamic_cast <const UsingLiteral &> (u).str () );
+ return;
+ }
+ v.push_back (u.clone () );
+}
+
+//**************************************
+// parseusing
+//**************************************
+
+void parseusing (const std::string & str, VectorUsing & vu)
+{
+ TRACEFUNC (tr, "parseusing");
+
+ std::istringstream is (str);
+ is.unsetf (std::ios::skipws);
+ int c;
+ while ( (c= is.peek () ) != EOF)
+ {
+ switch (static_cast <char> (c) )
+ {
+ case '#':
+ case '.':
+ case '+':
+ case '*':
+ case '$':
+ case poundsign:
+ case eurosign:
+ {
+ std::string tail;
+ UsingNumeric un (is, tail);
+ if (un.isvalid () )
+ vu.push_back (un);
+ else
+ {
+ UsingLiteral ul (un.str () );
+ vu.push_back (ul);
+ }
+ if (! tail.empty () )
+ {
+ UsingLiteral ul (is, tail);
+ vu.push_back (ul);
+ }
+ }
+ break;
+ case '\\':
+ case '&':
+ case '!':
+ {
+ UsingString us (is);
+ vu.push_back (us);
+ }
+ break;
+ default:
+ {
+ UsingLiteral ul (is);
+ vu.push_back (ul);
+ }
+ }
+ }
+}
+
+// End of using.cpp
diff --git a/using.h b/using.h
new file mode 100644
index 0000000..ad73607
--- /dev/null
+++ b/using.h
@@ -0,0 +1,96 @@
+#ifndef INCLUDE_BLASSIC_USING_H
+#define INCLUDE_BLASSIC_USING_H
+
+// using.h
+// Revision 7-feb-2005
+
+#include "error.h"
+#include "file.h"
+
+#include <iostream>
+#include <string>
+
+
+class Using {
+protected:
+ Using () { }
+public:
+ virtual ~Using ();
+ virtual Using * clone () const= 0;
+ virtual bool isliteral () const;
+ virtual void putliteral (blassic::file::BlFile &) const= 0;
+ virtual void putnumeric (blassic::file::BlFile &, BlNumber) const;
+ virtual void putstring (blassic::file::BlFile &,
+ const std::string &) const;
+};
+
+class UsingLiteral : public Using {
+public:
+ UsingLiteral (std::istream & is);
+ UsingLiteral (std::istream & is, const std::string & strinit);
+ UsingLiteral (const std::string & strinit);
+ UsingLiteral * clone () const
+ { return new UsingLiteral (* this); }
+ bool isliteral () const;
+ const std::string & str () const { return s; }
+ void addstr (const std::string & stradd);
+ void putliteral (blassic::file::BlFile & out) const;
+ void putnumeric (blassic::file::BlFile &, BlNumber) const;
+ void putstring (blassic::file::BlFile &, const std::string &) const;
+private:
+ std::string s;
+ void init (std::istream & is);
+};
+
+class UsingNumeric : public Using {
+public:
+ UsingNumeric (std::istream & is, std::string & tail);
+ UsingNumeric * clone () const
+ { return new UsingNumeric (* this); }
+ const std::string & str () const { return s; }
+ bool isvalid () const { return ! invalid; }
+ void putliteral (blassic::file::BlFile &) const;
+ void putnumeric (blassic::file::BlFile & out, BlNumber n) const;
+private:
+ bool invalid;
+ std::string s;
+ size_t digit, decimal, scientific;
+ bool milliards, putsign, signatend, blankpositive;
+ bool asterisk, dollar, pound, euro;
+};
+
+class UsingString : public Using {
+public:
+ UsingString (std::istream & is);
+ UsingString * clone () const
+ { return new UsingString (* this); }
+ void putliteral (blassic::file::BlFile &) const;
+ void putstring (blassic::file::BlFile & out,
+ const std::string & str) const;
+private:
+ size_t n;
+};
+
+class VectorUsing
+{
+public:
+ VectorUsing ();
+ ~VectorUsing ();
+ size_t size () const { return v.size (); }
+ bool empty () const { return v.empty (); }
+ Using * & back () { return v.back (); }
+ Using * & operator [] (size_t i) { return v [i]; }
+ void push_back (const Using & u);
+private:
+ VectorUsing (const VectorUsing &); // Forbidden
+ VectorUsing & operator = (const VectorUsing &); // Forbidden
+ static void delete_it (const Using * u) { delete u; }
+
+ std::vector <Using *> v;
+};
+
+void parseusing (const std::string & str, VectorUsing & vu);
+
+#endif
+
+// End of using.h
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..d98a278
--- /dev/null
+++ b/util.h
@@ -0,0 +1,202 @@
+#ifndef INCLUDE_UTIL_H
+#define INCLUDE_UTIL_H
+
+// util.h
+// Revision 24-apr-2009
+
+#include <string>
+#include <sstream>
+#include <stdexcept>
+#include <iostream>
+
+#include <stdlib.h>
+
+#ifdef __BORLANDC__
+#pragma warn -8027
+#endif
+
+namespace util {
+
+inline std::string stringlset (const std::string & value,
+ std::string::size_type l)
+{
+ const std::string::size_type lvalue= value.size ();
+ if (lvalue < l)
+ return value + std::string (l - lvalue, ' ');
+ else if (lvalue > l)
+ return value.substr (0, l);
+ else
+ return value;
+}
+
+inline std::string stringrset (const std::string & value,
+ std::string::size_type l)
+{
+ const std::string::size_type lvalue= value.size ();
+ if (lvalue < l)
+ return std::string (l - lvalue, ' ') + value;
+ else if (lvalue > l)
+ return value.substr (0, l);
+ else
+ return value;
+}
+
+template <class DEST, class ORG, class EX>
+DEST checked_cast (ORG org, EX ex)
+{
+ DEST dest= static_cast <DEST> (org);
+ if (static_cast <ORG> (dest) != org)
+ throw ex;
+ return dest;
+}
+
+template <class C, size_t N>
+size_t dim_array (C (&) [N])
+{ return N; }
+
+template <class C, size_t N>
+size_t dim_array (const C (&) [N])
+{ return N; }
+
+template <class C>
+class auto_buffer
+{
+public:
+ auto_buffer (size_t ns) :
+ p (new C [ns]),
+ s (ns)
+ { }
+ auto_buffer () : p (0) { }
+ ~auto_buffer ()
+ { delete [] p; }
+ void release () { p= 0; }
+ void alloc (size_t ns)
+ {
+ delete [] p;
+ p= new C [ns];
+ s= ns;
+ }
+ operator C * () { return p; }
+ typedef C * iterator;
+ iterator begin () { return p; }
+ iterator end () { return p + s; }
+ // We define data for commodity, and better legibility
+ // than begin where not used as iterator.
+ C * data () { return p; }
+private:
+ auto_buffer (const auto_buffer &); // Forbidden
+ auto_buffer & operator = (const auto_buffer &); // Forbidden
+ C * p;
+ size_t s;
+};
+
+template <class C>
+class auto_alloc
+{
+public:
+ auto_alloc (size_t size) :
+ p (static_cast <C *> (malloc (size * sizeof (C) ) ) )
+ {
+ if (p == 0)
+ throw std::bad_alloc ();
+ }
+ ~auto_alloc ()
+ { free (p); }
+ void release () { p= 0; }
+ operator C * () { return p; }
+ C * data () { return p; } // Commodity when cast is needed
+private:
+ auto_alloc (const auto_alloc &); // Forbidden
+ auto_alloc & operator = (const auto_alloc &); // Forbidden
+ C * p;
+};
+
+// This template is intended for use as a pointer to a
+// private implementation that translates the constness of
+// the operations in the main class to the implementation.
+
+template <class C>
+class pimpl_ptr
+{
+public:
+ pimpl_ptr (C * ptr) :
+ p (ptr)
+ { }
+ ~pimpl_ptr ()
+ {
+ delete p;
+ }
+
+ // Bypass the acces control
+ C * get () const
+ { return p; }
+
+ // The dereference operator that preserves constness.
+ C & operator * ()
+ { return * p; }
+ const C & operator * () const
+ { return * p; }
+ C * operator -> ()
+ { return p; }
+ const C * operator -> () const
+ {
+ return p;
+ }
+private:
+ pimpl_ptr (const pimpl_ptr &); // Forbidden
+ pimpl_ptr & operator = (const pimpl_ptr &); // Forbidden
+ C * const p;
+};
+
+template <class C>
+std::string to_string (const C & c)
+{
+ std::ostringstream oss;
+ oss << c;
+ return oss.str ();
+}
+
+// Functions used to avoid warnings about unused parameters.
+
+template <class T>
+inline void touch (const T & t)
+{
+ (void) t;
+}
+template <class T1, class T2>
+inline void touch (const T1 & t1, const T2 & t2)
+{
+ (void) t1; (void) t2;
+}
+template <class T1, class T2, class T3>
+inline void touch (const T1 & t1, const T2 & t2, const T3 & t3)
+{
+ (void) t1; (void) t2; (void) t3;
+}
+template <class T1, class T2, class T3, class T4>
+inline void touch (const T1 & t1, const T2 & t2, const T3 & t3,
+ const T4 & t4)
+{
+ (void) t1; (void) t2; (void) t3;
+ (void) t4;
+}
+template <class T1, class T2, class T3, class T4, class T5>
+inline void touch (const T1 & t1, const T2 & t2, const T3 & t3,
+ const T4 & t4, const T5 & t5)
+{
+ (void) t1; (void) t2; (void) t3;
+ (void) t4; (void) t5;
+}
+template <class T1, class T2, class T3, class T4, class T5, class T6>
+inline void touch (const T1 & t1, const T2 & t2, const T3 & t3,
+ const T4 & t4, const T5 & t5, const T6 & t6)
+{
+ (void) t1; (void) t2; (void) t3;
+ (void) t4; (void) t5; (void) t6;
+}
+
+} // namespace
+
+#endif
+
+// End of util.h
diff --git a/var.cpp b/var.cpp
new file mode 100644
index 0000000..8aa85e6
--- /dev/null
+++ b/var.cpp
@@ -0,0 +1,715 @@
+// var.cpp
+// Revision 7-feb-2005
+
+//#define KEEP_IT_SIMPLE
+
+
+#include "var.h"
+#include "sysvar.h"
+#include "error.h"
+#include "util.h"
+
+#include <vector>
+#include <algorithm>
+#include <stdexcept>
+
+//#include <cctype>
+//using std::toupper;
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#ifdef __BORLANDC__
+#pragma warn -inl
+#if __BORLANDC__ >= 0x0560
+#pragma warn -8091
+#endif
+#endif
+
+#ifndef USE_HASH_MAP
+
+#include <map>
+#define MAP std::map
+
+#else
+
+#if __GNUC__ < 3
+#include <hash_map>
+#define N_MAP std
+#else
+#include <ext/hash_map>
+#define N_MAP __gnu_cxx
+#endif
+
+#define MAP N_MAP::hash_map
+
+namespace N_MAP {
+
+template <> struct hash <std::string>
+{
+ hash () : hashstr (hash <const char *> () ) { }
+ size_t operator () (const std::string & str) const
+ { return hashstr (str.c_str () ); }
+private:
+ hash <const char *> hashstr;
+};
+
+} // namespace N_MAP
+
+#endif
+
+namespace sysvar= blassic::sysvar;
+
+
+namespace {
+
+VarType tabletype [27];
+
+bool inittabletype ()
+{
+ std::fill_n (tabletype, util::dim_array (tabletype), VarNumber);
+ return true;
+}
+
+bool table_inited= inittabletype ();
+
+}
+
+VarType typeofvar (const std::string & name)
+{
+ switch (name [name.size () - 1] )
+ {
+ case '#':
+ // There is no single or double distiction.
+ return VarNumber;
+ case '!':
+ return VarNumber;
+ case '%':
+ return VarInteger;
+ case '$':
+ return VarString;
+ default:
+ //return tabletype [toupper (name [0]) - 'A'];
+ return tabletype [name [0] - 'A'];
+ }
+}
+
+void definevar (VarType type, char c)
+{
+ //tabletype [toupper (c) - 'A']= type;
+ tabletype [c - 'A']= type;
+}
+
+void definevar (VarType type, char cfrom, char cto)
+{
+ //size_t from= toupper (cfrom) - 'A';
+ //size_t to= toupper (cto) - 'A';
+ size_t from= cfrom - 'A';
+ size_t to= cto - 'A';
+ std::fill (tabletype + from, tabletype + to + 1, type);
+}
+
+namespace {
+
+template <char c>
+inline std::string stripvar (const std::string n)
+{
+ const std::string::size_type l= n.size () - 1;
+ if (n [l] == c)
+ return n.substr (0, l);
+ return n;
+}
+
+inline std::string stripvarnumber (const std::string & n)
+{
+ //return stripvar <'!'> (n);
+ const std::string::size_type l= n.size () - 1;
+ if (n [l] == '!' || n [l] == '#')
+ return n.substr (0, l);
+ return n;
+}
+
+inline std::string stripvarinteger (const std::string & n)
+{
+ return stripvar <'%'> (n);
+}
+
+inline std::string stripvarstring (const std::string & n)
+{
+ return stripvar <'$'> (n);
+}
+
+template <class C>
+inline void initnewvar (C &)
+{ }
+
+template <>
+inline void initnewvar (BlNumber & n)
+{ n= BlNumber (); }
+template <>
+inline void initnewvar (BlInteger & n)
+{ n= BlInteger (); }
+
+#ifndef KEEP_IT_SIMPLE
+
+template <class C>
+class Table {
+ static const size_t chunk_size= 512;
+ std::vector <C *> vc;
+ size_t n;
+ static void clearchunk (C * pc);
+public:
+ Table ();
+ ~Table ();
+ void clear ();
+ C * newvar ();
+};
+
+template <class C>
+Table<C>::Table () :
+ n (0)
+{ }
+
+template <class C>
+Table<C>::~Table ()
+{
+ clear ();
+}
+
+template <class C>
+void Table<C>::clearchunk (C * pc)
+{
+ delete [] pc;
+}
+
+template <class C>
+void Table<C>::clear ()
+{
+ std::for_each (vc.begin (), vc.end (), clearchunk);
+ vc.clear ();
+ n= 0;
+}
+
+template <class C>
+C * Table<C>::newvar ()
+{
+ size_t nelem= n % chunk_size;
+ if (nelem == 0)
+ {
+ C * pnc= new C [chunk_size];
+ vc.push_back (pnc);
+ }
+ size_t nchunk= n / chunk_size;
+ ++n;
+ return & vc [nchunk] [nelem];
+}
+
+Table <BlNumber> tablenumber;
+Table <BlInteger> tableinteger;
+Table <std::string> tablestring;
+
+template <class C>
+inline Table <C> & table ();
+
+template <>
+inline Table <BlNumber> & table <BlNumber> ()
+{ return tablenumber; }
+template <>
+inline Table <BlInteger> & table <BlInteger> ()
+{ return tableinteger; }
+template <>
+inline Table <std::string> & table <std::string> ()
+{ return tablestring; }
+
+MAP <std::string, BlNumber *> numvar;
+MAP <std::string, BlInteger *> integervar;
+MAP <std::string, std::string *> stringvar;
+
+template <class C>
+inline MAP <std::string, C *> & mapvar ();
+
+template <>
+inline MAP <std::string, BlNumber *> & mapvar <BlNumber> ()
+{ return numvar; }
+template <>
+inline MAP <std::string, BlInteger *> & mapvar <BlInteger> ()
+{ return integervar; }
+template <>
+inline MAP <std::string, std::string *> & mapvar <std::string> ()
+{ return stringvar; }
+
+template <class C>
+inline C * getaddr (const std::string name)
+{
+ C * addr= mapvar <C> () [name];
+ if (! addr)
+ {
+ addr= table <C> ().newvar ();
+ mapvar <C> () [name]= addr;
+ initnewvar (* addr);
+ }
+ return addr;
+}
+
+template <class C>
+inline void assignvar (const std::string & n, const C & value)
+{
+ C * pc= getaddr <C> (n);
+ * pc= value;
+}
+
+template <class C>
+inline C evaluatevar (const std::string & n)
+{
+ C * pc= getaddr <C> (n);
+ return * pc;
+}
+
+#else
+// Keep it Simple.
+
+MAP <std::string, BlNumber> varnumber;
+MAP <std::string, BlInteger> varinteger;
+MAP <std::string, std::string> varstring;
+
+#endif
+
+
+} // namespace
+
+void assignvarnumber (const std::string & name, BlNumber value)
+{
+ #ifndef KEEP_IT_SIMPLE
+ //assignvar (name, value);
+ // Ops, I forget to strip here.
+ assignvar (stripvarnumber (name), value);
+ #else
+ varnumber [stripvarnumber (name) ]= value;
+ #endif
+}
+
+void assignvarinteger (const std::string & name, BlInteger value)
+{
+ #ifndef KEEP_IT_SIMPLE
+ assignvar (stripvarinteger (name), value);
+ #else
+ varinteger [stripvarinteger (name) ]= value;
+ #endif
+}
+
+void assignvarstring (const std::string & name, const std::string & value)
+{
+ #ifndef KEEP_IT_SIMPLE
+ assignvar (stripvarstring (name), value);
+ #else
+ varstring [stripvarstring (name) ]= value;
+ #endif
+}
+
+BlNumber evaluatevarnumber (const std::string & name)
+{
+ #ifndef KEEP_IT_SIMPLE
+ //return evaluatevar <BlNumber> (name);
+ // Ops, I forget to strip here.
+ return evaluatevar <BlNumber> (stripvarnumber (name) );
+ #else
+ return varnumber [stripvarnumber (name) ];
+ #endif
+}
+
+BlInteger evaluatevarinteger (const std::string & name)
+{
+ #ifndef KEEP_IT_SIMPLE
+ return evaluatevar <BlInteger> (stripvarinteger (name) );
+ #else
+ return varinteger [stripvarinteger (name) ];
+ #endif
+}
+
+std::string evaluatevarstring (const std::string & name)
+{
+ #ifndef KEEP_IT_SIMPLE
+ return evaluatevar <std::string> (stripvarstring (name) );
+ #else
+ return varstring [stripvarstring (name) ];
+ #endif
+}
+
+BlNumber * addrvarnumber (const std::string & name)
+{
+ #ifndef KEEP_IT_SIMPLE
+ //return getaddr <BlNumber> (name);
+ // Ops, I forget to strip here.
+ return getaddr <BlNumber> (stripvarnumber (name) );
+ #else
+ return & varnumber [stripvarnumber (name) ];
+ #endif
+}
+
+BlInteger * addrvarinteger (const std::string & name)
+{
+ #ifndef KEEP_IT_SIMPLE
+ return getaddr <BlInteger> (stripvarinteger (name) );
+ #else
+ return & varinteger [stripvarinteger (name) ];
+ #endif
+}
+
+std::string * addrvarstring (const std::string & name)
+{
+ #ifndef KEEP_IT_SIMPLE
+ return getaddr <std::string> (stripvarstring (name) );
+ #else
+ return & varstring [stripvarstring (name) ];
+ #endif
+}
+
+//*********************************************************
+// ARRAYS
+//*********************************************************
+
+namespace {
+
+template <class C>
+class Array {
+public:
+ Array (const Dimension & nd);
+ Array (); // Default constructor required for map []
+ Array (const Array & a);
+ ~Array ();
+ void operator = (const Array & a);
+ const Dimension & dim () const { return d; }
+ C * getvalue (size_t n) { return value + n; }
+private:
+ Dimension d;
+ size_t * pcount;
+ C * value;
+ void addref ();
+ void delref ();
+};
+
+template <class C>
+Array <C>::Array (const Dimension & nd) :
+ d (nd),
+ pcount (new size_t),
+ value (new C [nd.elements () ] )
+{
+ if (value == NULL)
+ throw ErrOutMemory;
+ * pcount= 1;
+ std::for_each (value, value + nd.elements (),
+ initnewvar <C> );
+}
+
+template <class C>
+Array <C>::Array () : // Default constructor required for map []
+ pcount (new size_t),
+ value (new C [0] )
+{
+ * pcount= 1;
+}
+
+template <class C>
+Array <C>::Array (const Array & a) :
+ d (a.d),
+ pcount (a.pcount),
+ value (a.value)
+{
+ addref ();
+}
+
+template <class C>
+Array <C>::~Array ()
+{
+ delref ();
+}
+
+template <class C>
+void Array <C>::operator = (const Array & a)
+{
+ if (this != & a)
+ {
+ delref ();
+ d= a.d;
+ pcount= a.pcount;
+ value= a.value;
+ addref ();
+ }
+}
+
+template <class C>
+void Array <C>::addref ()
+{
+ ++ (* pcount);
+}
+
+template <class C>
+void Array <C>::delref ()
+{
+ if (-- (* pcount) == 0)
+ {
+ //cerr << "Array of dim " << d << " deleted" << endl;
+ delete [] value;
+ delete pcount;
+ }
+}
+
+#if 0
+template <class C>
+inline Array <C> makeArray (const Dimension & nd, C * nvalue)
+{
+ return Array <C> (nd, nvalue);
+}
+#endif
+
+template <class C>
+struct ArrayVar {
+ typedef MAP <std::string, Array <C> > map;
+ typedef typename map::iterator iterator;
+ typedef typename map::const_iterator const_iterator;
+ typedef typename map::value_type value_type;
+};
+
+MAP <std::string, Array <BlNumber> > arrayvarnumber;
+MAP <std::string, Array <BlInteger> > arrayvarinteger;
+MAP <std::string, Array <std::string> > arrayvarstring;
+
+template <class C>
+inline typename ArrayVar <C>::map & arrayvar ();
+// Se necesita como plantilla para usarlo en otras plantillas.
+// Lo definimos solamente para los tipos usados.
+
+template <>
+inline ArrayVar <BlNumber>::map &
+ arrayvar <BlNumber> ()
+{ return arrayvarnumber; }
+template <>
+inline ArrayVar <BlInteger>::map &
+ arrayvar <BlInteger> ()
+{ return arrayvarinteger; }
+template <>
+inline ArrayVar<std::string>::map &
+ arrayvar <std::string> ()
+{ return arrayvarstring; }
+
+template <class C>
+inline void dimvar (const std::string & name, const Dimension & d)
+{
+ typename ArrayVar <C>::iterator it= arrayvar <C> ().find (name),
+ end= arrayvar <C> ().end ();
+ //if (arrayvar <C> ().find (name) != arrayvar <C> ().end () )
+ // throw ErrAlreadyDim;
+ if (it != end && sysvar::get (sysvar::TypeOfDimCheck) == 0)
+ throw ErrAlreadyDim;
+ #if 0
+ size_t n= d.elements ();
+ util::auto_buffer <C> value (n);
+ arrayvar <C> () [name]= makeArray (d, value.data () );
+ #else
+ //Array <C> a (d);
+ //arrayvar <C> () [name]= a;
+ arrayvar <C> () [name]= Array <C> (d);
+ #endif
+ //std::for_each (value.begin (), value.end (), initnewvar <C> );
+ //value.release ();
+}
+
+template <class C>
+inline void erasevar (const std::string & name)
+{
+ typename ArrayVar <C>::const_iterator it=
+ arrayvar <C> ().find (name);
+ if (it == arrayvar <C> ().end () )
+ throw ErrFunctionCall;
+ arrayvar <C> ().erase (name);
+ //arrayvar <C> ().erase (* it);
+}
+
+Dimension defaultdimension (const Dimension & d)
+{
+ Dimension n;
+ for (size_t i= 0, l= d.size (); i < l; ++i)
+ n.add (10);
+ return n;
+}
+
+template <class C>
+void createdefault (const std::string & name, const Dimension & d)
+{
+ Dimension n= defaultdimension (d);
+ dimvar<C> (name, n);
+}
+
+template <class C>
+inline C * addrdim (const std::string & name, const Dimension & d)
+{
+ typename ArrayVar <C>::iterator it=
+ arrayvar <C> ().find (name);
+ if (it == arrayvar <C> ().end () )
+ {
+ createdefault <C> (name, d);
+ it= arrayvar <C> ().find (name);
+ if (it == arrayvar <C> ().end () )
+ {
+ if (showdebuginfo () )
+ cerr << "Default creation of array failed" <<
+ endl;
+ throw ErrBlassicInternal;
+ }
+ }
+ size_t n= it->second.dim ().evalpos (d);
+ //return it->second.value + n;
+ return it->second.getvalue (n);
+}
+
+template <class C>
+inline C valuedim (const std::string & name, const Dimension & d)
+{
+ return * addrdim <C> (name, d);
+}
+
+template <class C>
+inline void assigndim (const std::string & name,
+ const Dimension & d, const C & result)
+{
+ * addrdim <C> (name, d)= result;
+}
+
+} // namespace
+
+void dimvarnumber (const std::string & name, const Dimension & d)
+{
+ dimvar <BlNumber> (stripvarnumber (name), d);
+}
+
+void dimvarinteger (const std::string & name, const Dimension & d)
+{
+ dimvar <BlInteger> (stripvarinteger (name), d);
+}
+
+void dimvarstring (const std::string & name, const Dimension & d)
+{
+ dimvar <std::string> (stripvarstring (name), d);
+}
+
+void erasevarnumber (const std::string & name)
+{
+ erasevar <BlNumber> (stripvarnumber (name) );
+}
+
+void erasevarinteger (const std::string & name)
+{
+ erasevar <BlInteger> (stripvarinteger (name) );
+}
+
+void erasevarstring (const std::string & name)
+{
+ erasevar <std::string> (stripvarstring (name) );
+}
+
+BlNumber valuedimnumber (const std::string & name, const Dimension & d)
+{
+ return valuedim <BlNumber> (stripvarnumber (name), d);
+}
+
+BlInteger valuediminteger (const std::string & name, const Dimension & d)
+{
+ return valuedim <BlInteger> (stripvarinteger (name), d);
+}
+
+std::string valuedimstring (const std::string & name, const Dimension & d)
+{
+ return valuedim <std::string> (stripvarstring (name), d);
+}
+
+void assigndimnumber (const std::string & name, const Dimension & d,
+ BlNumber result)
+{
+ assigndim (stripvarnumber (name), d, result);
+}
+
+void assigndiminteger (const std::string & name, const Dimension & d,
+ BlInteger result)
+{
+ assigndim (stripvarinteger (name), d, result);
+}
+
+void assigndimstring (const std::string & name, const Dimension & d,
+ const std::string & result)
+{
+ assigndim (stripvarstring (name), d, result);
+}
+
+BlNumber * addrdimnumber (const std::string & name, const Dimension & d)
+{
+ return addrdim <BlNumber> (stripvarnumber (name), d);
+}
+
+BlInteger * addrdiminteger (const std::string & name, const Dimension & d)
+{
+ return addrdim <BlInteger> (stripvarinteger (name), d);
+}
+
+std::string * addrdimstring (const std::string & name, const Dimension & d)
+{
+ return addrdim <std::string> (stripvarstring (name), d);
+}
+
+//**********************************************************
+// Borrado de variables
+//**********************************************************
+
+namespace {
+
+#if 0
+template <class C>
+class FreeArray {
+public:
+ void operator ()
+ (const typename ArrayVar <C>::value_type & var)
+ {
+ delete [] var.second.value;
+ }
+};
+#endif
+
+template <class C>
+inline void cleararray ()
+{
+ //std::for_each (arrayvar <C> ().begin (), arrayvar <C> ().end (),
+ // FreeArray<C> () );
+ arrayvar <C> ().clear ();
+}
+
+#ifndef KEEP_IT_SIMPLE
+
+template <class C>
+void clear ()
+{
+ table <C> ().clear ();
+ mapvar <C> ().clear ();
+}
+
+#endif
+
+} // namespace
+
+void clearvars ()
+{
+ #ifndef KEEP_IT_SIMPLE
+ clear <BlNumber> ();
+ clear <BlInteger> ();
+ clear <std::string> ();
+ #else
+ varnumber.clear ();
+ varinteger.clear ();
+ varstring.clear ();
+ #endif
+
+ cleararray <BlNumber> ();
+ cleararray <BlInteger> ();
+ cleararray <std::string> ();
+}
+
+// Fin de var.cpp
diff --git a/var.h b/var.h
new file mode 100644
index 0000000..0cfa4d8
--- /dev/null
+++ b/var.h
@@ -0,0 +1,71 @@
+#ifndef INCLUDE_BLASSIC_VAR_H
+#define INCLUDE_BLASSIC_VAR_H
+
+// var.h
+// Revision 8-jan-2005
+
+#include "blassic.h"
+#include "dim.h"
+
+// Now defined in blassic.h to reduce dependencies.
+
+//enum VarType { VarUndef, VarNumber, VarString, VarInteger };
+
+//inline bool is_numeric_type (VarType v)
+//{ return v == VarNumber || v == VarInteger; }
+
+
+struct VarPointer {
+ VarType type;
+ union {
+ BlNumber * pnumber;
+ BlInteger * pinteger;
+ std::string * pstring;
+ };
+ std::string::size_type from, to;
+};
+
+VarType typeofvar (const std::string & name);
+
+void definevar (VarType type, char c);
+void definevar (VarType type, char cfrom, char cto);
+
+void clearvars ();
+void assignvarnumber (const std::string & name, BlNumber value);
+void assignvarinteger (const std::string & name, BlInteger value);
+void assignvarstring (const std::string & name, const std::string & value);
+
+BlNumber evaluatevarnumber (const std::string & name);
+BlInteger evaluatevarinteger (const std::string & name);
+std::string evaluatevarstring (const std::string & name);
+
+BlNumber * addrvarnumber (const std::string & name);
+BlInteger * addrvarinteger (const std::string & name);
+std::string * addrvarstring (const std::string & name);
+
+void dimvarnumber (const std::string & name, const Dimension & d);
+void dimvarinteger (const std::string & name, const Dimension & d);
+void dimvarstring (const std::string & name, const Dimension & d);
+
+void erasevarnumber (const std::string & name);
+void erasevarinteger (const std::string & name);
+void erasevarstring (const std::string & name);
+
+BlNumber valuedimnumber (const std::string & name, const Dimension & d);
+BlInteger valuediminteger (const std::string & name, const Dimension & d);
+std::string valuedimstring (const std::string & name, const Dimension & d);
+
+void assigndimnumber (const std::string & name, const Dimension & d,
+ BlNumber value);
+void assigndiminteger (const std::string & name, const Dimension & d,
+ BlInteger value);
+void assigndimstring (const std::string & name, const Dimension & d,
+ const std::string & value);
+
+BlNumber * addrdimnumber (const std::string & name, const Dimension & d);
+BlInteger * addrdiminteger (const std::string & name, const Dimension & d);
+std::string * addrdimstring (const std::string & name, const Dimension & d);
+
+#endif
+
+// Fin de var.h
diff --git a/version.cpp b/version.cpp
new file mode 100644
index 0000000..c41f295
--- /dev/null
+++ b/version.cpp
@@ -0,0 +1,13 @@
+// version.cpp
+
+// The configure script will parse the version::* lines
+// to get the vesion number.
+
+#include "blassic.h"
+
+const unsigned short
+ version::Major= 0,
+ version::Minor= 10,
+ version::Release= 2;
+
+// End of version.cpp
Un proyecto texto-plano.xyz