diff options
author | Julian <julian@sparx.micasa> | 2012-02-23 17:59:07 +0100 |
---|---|---|
committer | Julian <julian@sparx.micasa> | 2012-02-23 17:59:07 +0100 |
commit | a9461cd8861fd449806ccb6cf0827762bd1089c1 (patch) | |
tree | 263243bfcd4a4055e47db595cfef3c87043c1a8e | |
download | blassic-a9461cd8861fd449806ccb6cf0827762bd1089c1.tar.gz |
initializing repo from version 0.10.2 minus the example files
-rw-r--r-- | AUTHORS | 3 | ||||
-rw-r--r-- | COPYING | 674 | ||||
-rw-r--r-- | ChangeLog | 0 | ||||
-rw-r--r-- | INSTALL | 237 | ||||
-rw-r--r-- | Makefile.am | 208 | ||||
-rw-r--r-- | Makefile.in | 1413 | ||||
-rw-r--r-- | NEWS | 570 | ||||
-rw-r--r-- | README | 83 | ||||
-rw-r--r-- | acinclude.m4 | 198 | ||||
-rw-r--r-- | aclocal.m4 | 869 | ||||
-rwxr-xr-x | autogen.sh | 3 | ||||
-rw-r--r-- | blassic.cpp | 963 | ||||
-rw-r--r-- | blassic.h | 254 | ||||
-rw-r--r-- | blassic.spec.in | 63 | ||||
-rwxr-xr-x | bootstrap | 5 | ||||
-rw-r--r-- | charset.h | 25 | ||||
-rw-r--r-- | codeline.cpp | 990 | ||||
-rw-r--r-- | codeline.h | 60 | ||||
-rw-r--r-- | configure.ac | 295 | ||||
-rw-r--r-- | cpc.def | 2817 | ||||
-rw-r--r-- | cursor.cpp | 1477 | ||||
-rw-r--r-- | cursor.h | 56 | ||||
-rw-r--r-- | default.def | 2827 | ||||
-rw-r--r-- | dim.cpp | 64 | ||||
-rw-r--r-- | dim.h | 29 | ||||
-rw-r--r-- | directory.cpp | 252 | ||||
-rw-r--r-- | directory.h | 38 | ||||
-rw-r--r-- | dynamic.cpp | 222 | ||||
-rw-r--r-- | dynamic.h | 108 | ||||
-rw-r--r-- | edit.cpp | 515 | ||||
-rw-r--r-- | edit.h | 23 | ||||
-rw-r--r-- | element.cpp | 87 | ||||
-rw-r--r-- | element.h | 155 | ||||
-rw-r--r-- | error.cpp | 194 | ||||
-rw-r--r-- | error.h | 105 | ||||
-rw-r--r-- | file.cpp | 903 | ||||
-rw-r--r-- | file.h | 178 | ||||
-rw-r--r-- | fileconsole.cpp | 532 | ||||
-rw-r--r-- | filepopen.cpp | 1191 | ||||
-rw-r--r-- | fileprinter.cpp | 684 | ||||
-rw-r--r-- | filesocket.cpp | 152 | ||||
-rw-r--r-- | filewindow.cpp | 332 | ||||
-rw-r--r-- | function.cpp | 249 | ||||
-rw-r--r-- | function.h | 50 | ||||
-rw-r--r-- | gencharset.cpp | 221 | ||||
-rw-r--r-- | graphics.cpp | 8110 | ||||
-rw-r--r-- | graphics.h | 164 | ||||
-rw-r--r-- | key.cpp | 155 | ||||
-rw-r--r-- | key.h | 43 | ||||
-rw-r--r-- | keyword.cpp | 378 | ||||
-rw-r--r-- | keyword.h | 305 | ||||
-rw-r--r-- | mbf.cpp | 158 | ||||
-rw-r--r-- | mbf.h | 25 | ||||
-rw-r--r-- | memory.cpp | 166 | ||||
-rw-r--r-- | memory.h | 23 | ||||
-rw-r--r-- | msx.def | 2816 | ||||
-rw-r--r-- | program.cpp | 1611 | ||||
-rw-r--r-- | program.h | 47 | ||||
-rw-r--r-- | regexp.cpp | 302 | ||||
-rw-r--r-- | regexp.h | 38 | ||||
-rw-r--r-- | result.h | 558 | ||||
-rw-r--r-- | runner.cpp | 2190 | ||||
-rw-r--r-- | runner.h | 658 | ||||
-rw-r--r-- | runnerline.cpp | 26 | ||||
-rw-r--r-- | runnerline.h | 34 | ||||
-rw-r--r-- | runnerline_impl.cpp | 4347 | ||||
-rw-r--r-- | runnerline_impl.h | 531 | ||||
-rw-r--r-- | runnerline_instructions.cpp | 4277 | ||||
-rw-r--r-- | runnerline_print.cpp | 367 | ||||
-rw-r--r-- | showerror.cpp | 89 | ||||
-rw-r--r-- | showerror.h | 7 | ||||
-rw-r--r-- | socket.cpp | 272 | ||||
-rw-r--r-- | socket.h | 54 | ||||
-rw-r--r-- | spectrum.def | 1556 | ||||
-rw-r--r-- | sysvar.cpp | 153 | ||||
-rw-r--r-- | sysvar.h | 198 | ||||
-rw-r--r-- | testdl.cpp | 49 | ||||
-rw-r--r-- | token.cpp | 315 | ||||
-rw-r--r-- | token.h | 53 | ||||
-rw-r--r-- | trace.cpp | 176 | ||||
-rw-r--r-- | trace.h | 39 | ||||
-rw-r--r-- | using.cpp | 582 | ||||
-rw-r--r-- | using.h | 96 | ||||
-rw-r--r-- | util.h | 202 | ||||
-rw-r--r-- | var.cpp | 715 | ||||
-rw-r--r-- | var.h | 71 | ||||
-rw-r--r-- | version.cpp | 13 |
87 files changed, 52343 insertions, 0 deletions
@@ -0,0 +1,3 @@ +Author: Julián Albo, "NotFound". +julian.notfound@gmail.com +See also the 'THANKS' file. @@ -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 @@ -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: @@ -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. @@ -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, µ) != 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 +]) @@ -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 + @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 |