From a9461cd8861fd449806ccb6cf0827762bd1089c1 Mon Sep 17 00:00:00 2001 From: Julian Date: Thu, 23 Feb 2012 17:59:07 +0100 Subject: initializing repo from version 0.10.2 minus the example files --- AUTHORS | 3 + COPYING | 674 ++++ ChangeLog | 0 INSTALL | 237 ++ Makefile.am | 208 ++ Makefile.in | 1413 ++++++++ NEWS | 570 +++ README | 83 + acinclude.m4 | 198 ++ aclocal.m4 | 869 +++++ autogen.sh | 3 + blassic.cpp | 963 +++++ blassic.h | 254 ++ blassic.spec.in | 63 + bootstrap | 5 + charset.h | 25 + codeline.cpp | 990 ++++++ codeline.h | 60 + configure.ac | 295 ++ cpc.def | 2817 +++++++++++++++ cursor.cpp | 1477 ++++++++ cursor.h | 56 + default.def | 2827 +++++++++++++++ dim.cpp | 64 + dim.h | 29 + directory.cpp | 252 ++ directory.h | 38 + dynamic.cpp | 222 ++ dynamic.h | 108 + edit.cpp | 515 +++ edit.h | 23 + element.cpp | 87 + element.h | 155 + error.cpp | 194 ++ error.h | 105 + file.cpp | 903 +++++ file.h | 178 + fileconsole.cpp | 532 +++ filepopen.cpp | 1191 +++++++ fileprinter.cpp | 684 ++++ filesocket.cpp | 152 + filewindow.cpp | 332 ++ function.cpp | 249 ++ function.h | 50 + gencharset.cpp | 221 ++ graphics.cpp | 8110 +++++++++++++++++++++++++++++++++++++++++++ graphics.h | 164 + key.cpp | 155 + key.h | 43 + keyword.cpp | 378 ++ keyword.h | 305 ++ mbf.cpp | 158 + mbf.h | 25 + memory.cpp | 166 + memory.h | 23 + msx.def | 2816 +++++++++++++++ program.cpp | 1611 +++++++++ program.h | 47 + regexp.cpp | 302 ++ regexp.h | 38 + result.h | 558 +++ runner.cpp | 2190 ++++++++++++ runner.h | 658 ++++ runnerline.cpp | 26 + runnerline.h | 34 + runnerline_impl.cpp | 4347 +++++++++++++++++++++++ runnerline_impl.h | 531 +++ runnerline_instructions.cpp | 4277 +++++++++++++++++++++++ runnerline_print.cpp | 367 ++ showerror.cpp | 89 + showerror.h | 7 + socket.cpp | 272 ++ socket.h | 54 + spectrum.def | 1556 +++++++++ sysvar.cpp | 153 + sysvar.h | 198 ++ testdl.cpp | 49 + token.cpp | 315 ++ token.h | 53 + trace.cpp | 176 + trace.h | 39 + using.cpp | 582 ++++ using.h | 96 + util.h | 202 ++ var.cpp | 715 ++++ var.h | 71 + version.cpp | 13 + 87 files changed, 52343 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 acinclude.m4 create mode 100644 aclocal.m4 create mode 100755 autogen.sh create mode 100644 blassic.cpp create mode 100644 blassic.h create mode 100644 blassic.spec.in create mode 100755 bootstrap create mode 100644 charset.h create mode 100644 codeline.cpp create mode 100644 codeline.h create mode 100644 configure.ac create mode 100644 cpc.def create mode 100644 cursor.cpp create mode 100644 cursor.h create mode 100644 default.def create mode 100644 dim.cpp create mode 100644 dim.h create mode 100644 directory.cpp create mode 100644 directory.h create mode 100644 dynamic.cpp create mode 100644 dynamic.h create mode 100644 edit.cpp create mode 100644 edit.h create mode 100644 element.cpp create mode 100644 element.h create mode 100644 error.cpp create mode 100644 error.h create mode 100644 file.cpp create mode 100644 file.h create mode 100644 fileconsole.cpp create mode 100644 filepopen.cpp create mode 100644 fileprinter.cpp create mode 100644 filesocket.cpp create mode 100644 filewindow.cpp create mode 100644 function.cpp create mode 100644 function.h create mode 100644 gencharset.cpp create mode 100644 graphics.cpp create mode 100644 graphics.h create mode 100644 key.cpp create mode 100644 key.h create mode 100644 keyword.cpp create mode 100644 keyword.h create mode 100644 mbf.cpp create mode 100644 mbf.h create mode 100644 memory.cpp create mode 100644 memory.h create mode 100644 msx.def create mode 100644 program.cpp create mode 100644 program.h create mode 100644 regexp.cpp create mode 100644 regexp.h create mode 100644 result.h create mode 100644 runner.cpp create mode 100644 runner.h create mode 100644 runnerline.cpp create mode 100644 runnerline.h create mode 100644 runnerline_impl.cpp create mode 100644 runnerline_impl.h create mode 100644 runnerline_instructions.cpp create mode 100644 runnerline_print.cpp create mode 100644 showerror.cpp create mode 100644 showerror.h create mode 100644 socket.cpp create mode 100644 socket.h create mode 100644 spectrum.def create mode 100644 sysvar.cpp create mode 100644 sysvar.h create mode 100644 testdl.cpp create mode 100644 token.cpp create mode 100644 token.h create mode 100644 trace.cpp create mode 100644 trace.h create mode 100644 using.cpp create mode 100644 using.h create mode 100644 util.h create mode 100644 var.cpp create mode 100644 var.h create mode 100644 version.cpp diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..b1e648c --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Author: Julián Albo, "NotFound". +julian.notfound@gmail.com +See also the 'THANKS' file. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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. + + + Copyright (C) + + 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..d3c5b40 --- /dev/null +++ b/INSTALL @@ -0,0 +1,237 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..1bffb80 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,208 @@ +# Makefile.am +# Originally written by Pierre Sarrazin +# Changes and additions by Julián Albo +# Last revision 23-feb-2012 + +noinst_PROGRAMS = gencharset +bin_PROGRAMS = blassic + + +# This tells Automake that charset.cpp must be generated before +# anything else is compiled. + +# Changed, now use several charsets. +#BUILT_SOURCES = charset.cpp +# Testing other way. +#BUILT_SOURCES = charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp +BUILT_SOURCES = gencharset$(EXEEXT) + +# Needed to generate charset cpp files: + +gencharset_SOURCES = gencharset.cpp + +gencharset_CXXFLAGS = $(CXXFLAGS_FOR_BUILD) + +gencharset_LDFLAGS = + +# This way the .exe extension is appended when compiling for windows +# under linux, but it works anyway. +gencharset$(EXEEXT): gencharset.cpp + $(CXX_FOR_BUILD) $(gencharset_CXXFLAGS) $(gencharset_LDFLAGS) \ + -o gencharset$(EXEEXT) \ + gencharset.cpp + +# Character sets for graphics modes. + +#charset.cpp: $(srcdir)/charset.def gencharset +# ./gencharset $(srcdir)/charset.def charset.cpp +# test -f charset.cpp + +charset_default.cpp: $(srcdir)/default.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/default.def \ + charset_default.cpp default + test -f charset_default.cpp + +charset_cpc.cpp: $(srcdir)/cpc.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/cpc.def \ + charset_cpc.cpp cpc + test -f charset_cpc.cpp + +charset_spectrum.cpp: $(srcdir)/spectrum.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/spectrum.def \ + charset_spectrum.cpp spectrum + test -f charset_spectrum.cpp + +charset_msx.cpp: $(srcdir)/msx.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/msx.def \ + charset_msx.cpp msx + test -f charset_msx.cpp + + +blassic_SOURCES = \ + charset_default.cpp \ + charset_cpc.cpp \ + charset_spectrum.cpp \ + charset_msx.cpp \ + charset.h \ + blassic.cpp \ + blassic.h \ + codeline.cpp \ + codeline.h \ + cursor.cpp \ + cursor.h \ + dim.cpp \ + dim.h \ + directory.cpp \ + directory.h \ + dynamic.cpp \ + dynamic.h \ + edit.cpp \ + edit.h \ + element.h \ + element.cpp \ + error.cpp \ + error.h \ + file.cpp \ + file.h \ + fileconsole.cpp \ + filepopen.cpp \ + fileprinter.cpp \ + filesocket.cpp \ + filewindow.cpp \ + function.cpp \ + function.h \ + graphics.cpp \ + graphics.h \ + key.cpp \ + key.h \ + keyword.cpp \ + keyword.h \ + mbf.cpp \ + mbf.h \ + memory.cpp \ + memory.h \ + program.cpp \ + program.h \ + regexp.cpp \ + regexp.h \ + result.h \ + runner.cpp \ + runner.h \ + runnerline.cpp \ + runnerline.h \ + runnerline_impl.cpp \ + runnerline_impl.h \ + runnerline_instructions.cpp \ + runnerline_print.cpp \ + showerror.cpp \ + showerror.h \ + socket.cpp \ + socket.h \ + sysvar.cpp \ + sysvar.h \ + token.cpp \ + token.h \ + trace.cpp \ + trace.h \ + using.cpp \ + using.h \ + util.h \ + var.cpp \ + var.h \ + version.cpp + +blassic_CXXFLAGS = @SVGALIB_CFLAGS@ @BL_X_CFLAGS@ +blassic_LDFLAGS = @BL_X_LIBS@ +blassic_LDADD = @SVGALIB_LIBS@ @CYGWIN_FLAGS@ @BL_X_ADD@ + + +# testdl: a tiny library to test blassic dynamic link. + + +# Julian: modified this to allow cross-compiling. +#testdl.so: testdl.o +# gcc -shared -Wl,-soname,testdl.so -o testdl.so testdl.o +#testdl.o: testdl.cpp +# gcc -Wall -fPIC -c testdl.cpp + +#testdl_CXXFLAGS = \ +# -W -Wall -Wwrite-strings -Wstrict-prototypes \ +# -Wunused + +testdl.so: testdl.o + $(CXX) -shared -Wl,-soname,testdl.so $(LDFLAGS) -o testdl.so testdl.o + +testdl.o: testdl.cpp + $(CXX) -fPIC $(testdl_CXXFLAGS) -c testdl.cpp + + +rpm: dist + rpm -ta $(distdir).tar.gz + +EXTRA_DIST = \ + bootstrap autogen.sh \ + do_conf \ + do_confnodeb \ + do_confcross_arm \ + do_confcross_mingw \ + do_confhpux \ + blassic.spec \ + alphabet.blc automod.blc \ + blassic.bpr \ + testdl.bpr \ + random.dat \ + gencharset.cpp \ + charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp \ + default.def cpc.def spectrum.def msx.def \ + counter.sh \ + testdl.cpp + +#CLEANFILES = testdl.so $(BUILT_SOURCES) +CLEANFILES = testdl.so + +# When Automake needs to regenerate configure, the following options +# will be passed to aclocal, as in the bootstrap script. +ACLOCAL_AMFLAGS = -I . + + +# Boilerplate: + +auxdir = @ac_aux_dir@ +AUX_DIST = $(auxdir)/install-sh $(auxdir)/missing $(auxdir)/mkinstalldirs + +MAINTAINERCLEANFILES = \ + Makefile.in \ + aclocal.m4 \ + configure \ + sic/config-h.in \ + sic/stamp-h.in \ + $(AUX_DIST) \ + depcomp \ + config.guess \ + config.log \ + config.status \ + config.sub \ + install-sh \ + missing \ + mkinstalldirs + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..67c99d8 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,1413 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile.am +# Originally written by Pierre Sarrazin +# Changes and additions by Julián Albo +# Last revision 23-feb-2012 + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +noinst_PROGRAMS = gencharset$(EXEEXT) +bin_PROGRAMS = blassic$(EXEEXT) +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/blassic.spec.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ + config.guess config.sub depcomp install-sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = blassic.spec +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_blassic_OBJECTS = blassic-charset_default.$(OBJEXT) \ + blassic-charset_cpc.$(OBJEXT) \ + blassic-charset_spectrum.$(OBJEXT) \ + blassic-charset_msx.$(OBJEXT) blassic-blassic.$(OBJEXT) \ + blassic-codeline.$(OBJEXT) blassic-cursor.$(OBJEXT) \ + blassic-dim.$(OBJEXT) blassic-directory.$(OBJEXT) \ + blassic-dynamic.$(OBJEXT) blassic-edit.$(OBJEXT) \ + blassic-element.$(OBJEXT) blassic-error.$(OBJEXT) \ + blassic-file.$(OBJEXT) blassic-fileconsole.$(OBJEXT) \ + blassic-filepopen.$(OBJEXT) blassic-fileprinter.$(OBJEXT) \ + blassic-filesocket.$(OBJEXT) blassic-filewindow.$(OBJEXT) \ + blassic-function.$(OBJEXT) blassic-graphics.$(OBJEXT) \ + blassic-key.$(OBJEXT) blassic-keyword.$(OBJEXT) \ + blassic-mbf.$(OBJEXT) blassic-memory.$(OBJEXT) \ + blassic-program.$(OBJEXT) blassic-regexp.$(OBJEXT) \ + blassic-runner.$(OBJEXT) blassic-runnerline.$(OBJEXT) \ + blassic-runnerline_impl.$(OBJEXT) \ + blassic-runnerline_instructions.$(OBJEXT) \ + blassic-runnerline_print.$(OBJEXT) blassic-showerror.$(OBJEXT) \ + blassic-socket.$(OBJEXT) blassic-sysvar.$(OBJEXT) \ + blassic-token.$(OBJEXT) blassic-trace.$(OBJEXT) \ + blassic-using.$(OBJEXT) blassic-var.$(OBJEXT) \ + blassic-version.$(OBJEXT) +blassic_OBJECTS = $(am_blassic_OBJECTS) +blassic_DEPENDENCIES = +blassic_LINK = $(CXXLD) $(blassic_CXXFLAGS) $(CXXFLAGS) \ + $(blassic_LDFLAGS) $(LDFLAGS) -o $@ +am_gencharset_OBJECTS = gencharset-gencharset.$(OBJEXT) +gencharset_OBJECTS = $(am_gencharset_OBJECTS) +gencharset_LDADD = $(LDADD) +gencharset_LINK = $(CXXLD) $(gencharset_CXXFLAGS) $(CXXFLAGS) \ + $(gencharset_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(blassic_SOURCES) $(gencharset_SOURCES) +DIST_SOURCES = $(blassic_SOURCES) $(gencharset_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BL_X_ADD = @BL_X_ADD@ +BL_X_CFLAGS = @BL_X_CFLAGS@ +BL_X_LIBS = @BL_X_LIBS@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CXX_FOR_BUILD = @CXX_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +CYGWIN_FLAGS = @CYGWIN_FLAGS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVGALIB_CFLAGS = @SVGALIB_CFLAGS@ +SVGALIB_LIBS = @SVGALIB_LIBS@ +VERSION = @VERSION@ +XMKMF = @XMKMF@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# This tells Automake that charset.cpp must be generated before +# anything else is compiled. + +# Changed, now use several charsets. +#BUILT_SOURCES = charset.cpp +# Testing other way. +#BUILT_SOURCES = charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp +BUILT_SOURCES = gencharset$(EXEEXT) + +# Needed to generate charset cpp files: +gencharset_SOURCES = gencharset.cpp +gencharset_CXXFLAGS = $(CXXFLAGS_FOR_BUILD) +gencharset_LDFLAGS = +blassic_SOURCES = \ + charset_default.cpp \ + charset_cpc.cpp \ + charset_spectrum.cpp \ + charset_msx.cpp \ + charset.h \ + blassic.cpp \ + blassic.h \ + codeline.cpp \ + codeline.h \ + cursor.cpp \ + cursor.h \ + dim.cpp \ + dim.h \ + directory.cpp \ + directory.h \ + dynamic.cpp \ + dynamic.h \ + edit.cpp \ + edit.h \ + element.h \ + element.cpp \ + error.cpp \ + error.h \ + file.cpp \ + file.h \ + fileconsole.cpp \ + filepopen.cpp \ + fileprinter.cpp \ + filesocket.cpp \ + filewindow.cpp \ + function.cpp \ + function.h \ + graphics.cpp \ + graphics.h \ + key.cpp \ + key.h \ + keyword.cpp \ + keyword.h \ + mbf.cpp \ + mbf.h \ + memory.cpp \ + memory.h \ + program.cpp \ + program.h \ + regexp.cpp \ + regexp.h \ + result.h \ + runner.cpp \ + runner.h \ + runnerline.cpp \ + runnerline.h \ + runnerline_impl.cpp \ + runnerline_impl.h \ + runnerline_instructions.cpp \ + runnerline_print.cpp \ + showerror.cpp \ + showerror.h \ + socket.cpp \ + socket.h \ + sysvar.cpp \ + sysvar.h \ + token.cpp \ + token.h \ + trace.cpp \ + trace.h \ + using.cpp \ + using.h \ + util.h \ + var.cpp \ + var.h \ + version.cpp + +blassic_CXXFLAGS = @SVGALIB_CFLAGS@ @BL_X_CFLAGS@ +blassic_LDFLAGS = @BL_X_LIBS@ +blassic_LDADD = @SVGALIB_LIBS@ @CYGWIN_FLAGS@ @BL_X_ADD@ +EXTRA_DIST = \ + bootstrap autogen.sh \ + do_conf \ + do_confnodeb \ + do_confcross_arm \ + do_confcross_mingw \ + do_confhpux \ + blassic.spec \ + alphabet.blc automod.blc \ + blassic.bpr \ + testdl.bpr \ + random.dat \ + gencharset.cpp \ + charset_default.cpp charset_cpc.cpp charset_spectrum.cpp charset_msx.cpp \ + default.def cpc.def spectrum.def msx.def \ + counter.sh \ + testdl.cpp + + +#CLEANFILES = testdl.so $(BUILT_SOURCES) +CLEANFILES = testdl.so + +# When Automake needs to regenerate configure, the following options +# will be passed to aclocal, as in the bootstrap script. +ACLOCAL_AMFLAGS = -I . + +# Boilerplate: +auxdir = @ac_aux_dir@ +AUX_DIST = $(auxdir)/install-sh $(auxdir)/missing $(auxdir)/mkinstalldirs +MAINTAINERCLEANFILES = \ + Makefile.in \ + aclocal.m4 \ + configure \ + sic/config-h.in \ + sic/stamp-h.in \ + $(AUX_DIST) \ + depcomp \ + config.guess \ + config.log \ + config.status \ + config.sub \ + install-sh \ + missing \ + mkinstalldirs + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +blassic.spec: $(top_builddir)/config.status $(srcdir)/blassic.spec.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +blassic$(EXEEXT): $(blassic_OBJECTS) $(blassic_DEPENDENCIES) + @rm -f blassic$(EXEEXT) + $(blassic_LINK) $(blassic_OBJECTS) $(blassic_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-blassic.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_cpc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_default.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_msx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-charset_spectrum.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-codeline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-cursor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-dim.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-directory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-dynamic.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-edit.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-element.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-error.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-file.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-fileconsole.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-filepopen.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-fileprinter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-filesocket.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-filewindow.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-function.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-graphics.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-key.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-keyword.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-mbf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-program.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-regexp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runner.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline_impl.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline_instructions.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-runnerline_print.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-showerror.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-socket.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-sysvar.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-token.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-trace.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-using.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-var.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blassic-version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gencharset-gencharset.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +blassic-charset_default.o: charset_default.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_default.o -MD -MP -MF $(DEPDIR)/blassic-charset_default.Tpo -c -o blassic-charset_default.o `test -f 'charset_default.cpp' || echo '$(srcdir)/'`charset_default.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_default.Tpo $(DEPDIR)/blassic-charset_default.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_default.cpp' object='blassic-charset_default.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_default.o `test -f 'charset_default.cpp' || echo '$(srcdir)/'`charset_default.cpp + +blassic-charset_default.obj: charset_default.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_default.obj -MD -MP -MF $(DEPDIR)/blassic-charset_default.Tpo -c -o blassic-charset_default.obj `if test -f 'charset_default.cpp'; then $(CYGPATH_W) 'charset_default.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_default.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_default.Tpo $(DEPDIR)/blassic-charset_default.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_default.cpp' object='blassic-charset_default.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_default.obj `if test -f 'charset_default.cpp'; then $(CYGPATH_W) 'charset_default.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_default.cpp'; fi` + +blassic-charset_cpc.o: charset_cpc.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_cpc.o -MD -MP -MF $(DEPDIR)/blassic-charset_cpc.Tpo -c -o blassic-charset_cpc.o `test -f 'charset_cpc.cpp' || echo '$(srcdir)/'`charset_cpc.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_cpc.Tpo $(DEPDIR)/blassic-charset_cpc.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_cpc.cpp' object='blassic-charset_cpc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_cpc.o `test -f 'charset_cpc.cpp' || echo '$(srcdir)/'`charset_cpc.cpp + +blassic-charset_cpc.obj: charset_cpc.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_cpc.obj -MD -MP -MF $(DEPDIR)/blassic-charset_cpc.Tpo -c -o blassic-charset_cpc.obj `if test -f 'charset_cpc.cpp'; then $(CYGPATH_W) 'charset_cpc.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_cpc.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_cpc.Tpo $(DEPDIR)/blassic-charset_cpc.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_cpc.cpp' object='blassic-charset_cpc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_cpc.obj `if test -f 'charset_cpc.cpp'; then $(CYGPATH_W) 'charset_cpc.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_cpc.cpp'; fi` + +blassic-charset_spectrum.o: charset_spectrum.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_spectrum.o -MD -MP -MF $(DEPDIR)/blassic-charset_spectrum.Tpo -c -o blassic-charset_spectrum.o `test -f 'charset_spectrum.cpp' || echo '$(srcdir)/'`charset_spectrum.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_spectrum.Tpo $(DEPDIR)/blassic-charset_spectrum.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_spectrum.cpp' object='blassic-charset_spectrum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_spectrum.o `test -f 'charset_spectrum.cpp' || echo '$(srcdir)/'`charset_spectrum.cpp + +blassic-charset_spectrum.obj: charset_spectrum.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_spectrum.obj -MD -MP -MF $(DEPDIR)/blassic-charset_spectrum.Tpo -c -o blassic-charset_spectrum.obj `if test -f 'charset_spectrum.cpp'; then $(CYGPATH_W) 'charset_spectrum.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_spectrum.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_spectrum.Tpo $(DEPDIR)/blassic-charset_spectrum.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_spectrum.cpp' object='blassic-charset_spectrum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_spectrum.obj `if test -f 'charset_spectrum.cpp'; then $(CYGPATH_W) 'charset_spectrum.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_spectrum.cpp'; fi` + +blassic-charset_msx.o: charset_msx.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_msx.o -MD -MP -MF $(DEPDIR)/blassic-charset_msx.Tpo -c -o blassic-charset_msx.o `test -f 'charset_msx.cpp' || echo '$(srcdir)/'`charset_msx.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_msx.Tpo $(DEPDIR)/blassic-charset_msx.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_msx.cpp' object='blassic-charset_msx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_msx.o `test -f 'charset_msx.cpp' || echo '$(srcdir)/'`charset_msx.cpp + +blassic-charset_msx.obj: charset_msx.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-charset_msx.obj -MD -MP -MF $(DEPDIR)/blassic-charset_msx.Tpo -c -o blassic-charset_msx.obj `if test -f 'charset_msx.cpp'; then $(CYGPATH_W) 'charset_msx.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_msx.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-charset_msx.Tpo $(DEPDIR)/blassic-charset_msx.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='charset_msx.cpp' object='blassic-charset_msx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-charset_msx.obj `if test -f 'charset_msx.cpp'; then $(CYGPATH_W) 'charset_msx.cpp'; else $(CYGPATH_W) '$(srcdir)/charset_msx.cpp'; fi` + +blassic-blassic.o: blassic.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-blassic.o -MD -MP -MF $(DEPDIR)/blassic-blassic.Tpo -c -o blassic-blassic.o `test -f 'blassic.cpp' || echo '$(srcdir)/'`blassic.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-blassic.Tpo $(DEPDIR)/blassic-blassic.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='blassic.cpp' object='blassic-blassic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-blassic.o `test -f 'blassic.cpp' || echo '$(srcdir)/'`blassic.cpp + +blassic-blassic.obj: blassic.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-blassic.obj -MD -MP -MF $(DEPDIR)/blassic-blassic.Tpo -c -o blassic-blassic.obj `if test -f 'blassic.cpp'; then $(CYGPATH_W) 'blassic.cpp'; else $(CYGPATH_W) '$(srcdir)/blassic.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-blassic.Tpo $(DEPDIR)/blassic-blassic.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='blassic.cpp' object='blassic-blassic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-blassic.obj `if test -f 'blassic.cpp'; then $(CYGPATH_W) 'blassic.cpp'; else $(CYGPATH_W) '$(srcdir)/blassic.cpp'; fi` + +blassic-codeline.o: codeline.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-codeline.o -MD -MP -MF $(DEPDIR)/blassic-codeline.Tpo -c -o blassic-codeline.o `test -f 'codeline.cpp' || echo '$(srcdir)/'`codeline.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-codeline.Tpo $(DEPDIR)/blassic-codeline.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='codeline.cpp' object='blassic-codeline.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-codeline.o `test -f 'codeline.cpp' || echo '$(srcdir)/'`codeline.cpp + +blassic-codeline.obj: codeline.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-codeline.obj -MD -MP -MF $(DEPDIR)/blassic-codeline.Tpo -c -o blassic-codeline.obj `if test -f 'codeline.cpp'; then $(CYGPATH_W) 'codeline.cpp'; else $(CYGPATH_W) '$(srcdir)/codeline.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-codeline.Tpo $(DEPDIR)/blassic-codeline.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='codeline.cpp' object='blassic-codeline.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-codeline.obj `if test -f 'codeline.cpp'; then $(CYGPATH_W) 'codeline.cpp'; else $(CYGPATH_W) '$(srcdir)/codeline.cpp'; fi` + +blassic-cursor.o: cursor.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-cursor.o -MD -MP -MF $(DEPDIR)/blassic-cursor.Tpo -c -o blassic-cursor.o `test -f 'cursor.cpp' || echo '$(srcdir)/'`cursor.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-cursor.Tpo $(DEPDIR)/blassic-cursor.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cursor.cpp' object='blassic-cursor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-cursor.o `test -f 'cursor.cpp' || echo '$(srcdir)/'`cursor.cpp + +blassic-cursor.obj: cursor.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-cursor.obj -MD -MP -MF $(DEPDIR)/blassic-cursor.Tpo -c -o blassic-cursor.obj `if test -f 'cursor.cpp'; then $(CYGPATH_W) 'cursor.cpp'; else $(CYGPATH_W) '$(srcdir)/cursor.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-cursor.Tpo $(DEPDIR)/blassic-cursor.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='cursor.cpp' object='blassic-cursor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-cursor.obj `if test -f 'cursor.cpp'; then $(CYGPATH_W) 'cursor.cpp'; else $(CYGPATH_W) '$(srcdir)/cursor.cpp'; fi` + +blassic-dim.o: dim.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dim.o -MD -MP -MF $(DEPDIR)/blassic-dim.Tpo -c -o blassic-dim.o `test -f 'dim.cpp' || echo '$(srcdir)/'`dim.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dim.Tpo $(DEPDIR)/blassic-dim.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dim.cpp' object='blassic-dim.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dim.o `test -f 'dim.cpp' || echo '$(srcdir)/'`dim.cpp + +blassic-dim.obj: dim.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dim.obj -MD -MP -MF $(DEPDIR)/blassic-dim.Tpo -c -o blassic-dim.obj `if test -f 'dim.cpp'; then $(CYGPATH_W) 'dim.cpp'; else $(CYGPATH_W) '$(srcdir)/dim.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dim.Tpo $(DEPDIR)/blassic-dim.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dim.cpp' object='blassic-dim.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dim.obj `if test -f 'dim.cpp'; then $(CYGPATH_W) 'dim.cpp'; else $(CYGPATH_W) '$(srcdir)/dim.cpp'; fi` + +blassic-directory.o: directory.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-directory.o -MD -MP -MF $(DEPDIR)/blassic-directory.Tpo -c -o blassic-directory.o `test -f 'directory.cpp' || echo '$(srcdir)/'`directory.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-directory.Tpo $(DEPDIR)/blassic-directory.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='directory.cpp' object='blassic-directory.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-directory.o `test -f 'directory.cpp' || echo '$(srcdir)/'`directory.cpp + +blassic-directory.obj: directory.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-directory.obj -MD -MP -MF $(DEPDIR)/blassic-directory.Tpo -c -o blassic-directory.obj `if test -f 'directory.cpp'; then $(CYGPATH_W) 'directory.cpp'; else $(CYGPATH_W) '$(srcdir)/directory.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-directory.Tpo $(DEPDIR)/blassic-directory.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='directory.cpp' object='blassic-directory.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-directory.obj `if test -f 'directory.cpp'; then $(CYGPATH_W) 'directory.cpp'; else $(CYGPATH_W) '$(srcdir)/directory.cpp'; fi` + +blassic-dynamic.o: dynamic.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dynamic.o -MD -MP -MF $(DEPDIR)/blassic-dynamic.Tpo -c -o blassic-dynamic.o `test -f 'dynamic.cpp' || echo '$(srcdir)/'`dynamic.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dynamic.Tpo $(DEPDIR)/blassic-dynamic.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dynamic.cpp' object='blassic-dynamic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dynamic.o `test -f 'dynamic.cpp' || echo '$(srcdir)/'`dynamic.cpp + +blassic-dynamic.obj: dynamic.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-dynamic.obj -MD -MP -MF $(DEPDIR)/blassic-dynamic.Tpo -c -o blassic-dynamic.obj `if test -f 'dynamic.cpp'; then $(CYGPATH_W) 'dynamic.cpp'; else $(CYGPATH_W) '$(srcdir)/dynamic.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-dynamic.Tpo $(DEPDIR)/blassic-dynamic.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='dynamic.cpp' object='blassic-dynamic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-dynamic.obj `if test -f 'dynamic.cpp'; then $(CYGPATH_W) 'dynamic.cpp'; else $(CYGPATH_W) '$(srcdir)/dynamic.cpp'; fi` + +blassic-edit.o: edit.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-edit.o -MD -MP -MF $(DEPDIR)/blassic-edit.Tpo -c -o blassic-edit.o `test -f 'edit.cpp' || echo '$(srcdir)/'`edit.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-edit.Tpo $(DEPDIR)/blassic-edit.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='edit.cpp' object='blassic-edit.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-edit.o `test -f 'edit.cpp' || echo '$(srcdir)/'`edit.cpp + +blassic-edit.obj: edit.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-edit.obj -MD -MP -MF $(DEPDIR)/blassic-edit.Tpo -c -o blassic-edit.obj `if test -f 'edit.cpp'; then $(CYGPATH_W) 'edit.cpp'; else $(CYGPATH_W) '$(srcdir)/edit.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-edit.Tpo $(DEPDIR)/blassic-edit.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='edit.cpp' object='blassic-edit.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-edit.obj `if test -f 'edit.cpp'; then $(CYGPATH_W) 'edit.cpp'; else $(CYGPATH_W) '$(srcdir)/edit.cpp'; fi` + +blassic-element.o: element.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-element.o -MD -MP -MF $(DEPDIR)/blassic-element.Tpo -c -o blassic-element.o `test -f 'element.cpp' || echo '$(srcdir)/'`element.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-element.Tpo $(DEPDIR)/blassic-element.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='element.cpp' object='blassic-element.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-element.o `test -f 'element.cpp' || echo '$(srcdir)/'`element.cpp + +blassic-element.obj: element.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-element.obj -MD -MP -MF $(DEPDIR)/blassic-element.Tpo -c -o blassic-element.obj `if test -f 'element.cpp'; then $(CYGPATH_W) 'element.cpp'; else $(CYGPATH_W) '$(srcdir)/element.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-element.Tpo $(DEPDIR)/blassic-element.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='element.cpp' object='blassic-element.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-element.obj `if test -f 'element.cpp'; then $(CYGPATH_W) 'element.cpp'; else $(CYGPATH_W) '$(srcdir)/element.cpp'; fi` + +blassic-error.o: error.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-error.o -MD -MP -MF $(DEPDIR)/blassic-error.Tpo -c -o blassic-error.o `test -f 'error.cpp' || echo '$(srcdir)/'`error.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-error.Tpo $(DEPDIR)/blassic-error.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='error.cpp' object='blassic-error.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-error.o `test -f 'error.cpp' || echo '$(srcdir)/'`error.cpp + +blassic-error.obj: error.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-error.obj -MD -MP -MF $(DEPDIR)/blassic-error.Tpo -c -o blassic-error.obj `if test -f 'error.cpp'; then $(CYGPATH_W) 'error.cpp'; else $(CYGPATH_W) '$(srcdir)/error.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-error.Tpo $(DEPDIR)/blassic-error.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='error.cpp' object='blassic-error.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-error.obj `if test -f 'error.cpp'; then $(CYGPATH_W) 'error.cpp'; else $(CYGPATH_W) '$(srcdir)/error.cpp'; fi` + +blassic-file.o: file.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-file.o -MD -MP -MF $(DEPDIR)/blassic-file.Tpo -c -o blassic-file.o `test -f 'file.cpp' || echo '$(srcdir)/'`file.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-file.Tpo $(DEPDIR)/blassic-file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='file.cpp' object='blassic-file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-file.o `test -f 'file.cpp' || echo '$(srcdir)/'`file.cpp + +blassic-file.obj: file.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-file.obj -MD -MP -MF $(DEPDIR)/blassic-file.Tpo -c -o blassic-file.obj `if test -f 'file.cpp'; then $(CYGPATH_W) 'file.cpp'; else $(CYGPATH_W) '$(srcdir)/file.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-file.Tpo $(DEPDIR)/blassic-file.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='file.cpp' object='blassic-file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-file.obj `if test -f 'file.cpp'; then $(CYGPATH_W) 'file.cpp'; else $(CYGPATH_W) '$(srcdir)/file.cpp'; fi` + +blassic-fileconsole.o: fileconsole.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileconsole.o -MD -MP -MF $(DEPDIR)/blassic-fileconsole.Tpo -c -o blassic-fileconsole.o `test -f 'fileconsole.cpp' || echo '$(srcdir)/'`fileconsole.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileconsole.Tpo $(DEPDIR)/blassic-fileconsole.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileconsole.cpp' object='blassic-fileconsole.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileconsole.o `test -f 'fileconsole.cpp' || echo '$(srcdir)/'`fileconsole.cpp + +blassic-fileconsole.obj: fileconsole.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileconsole.obj -MD -MP -MF $(DEPDIR)/blassic-fileconsole.Tpo -c -o blassic-fileconsole.obj `if test -f 'fileconsole.cpp'; then $(CYGPATH_W) 'fileconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/fileconsole.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileconsole.Tpo $(DEPDIR)/blassic-fileconsole.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileconsole.cpp' object='blassic-fileconsole.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileconsole.obj `if test -f 'fileconsole.cpp'; then $(CYGPATH_W) 'fileconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/fileconsole.cpp'; fi` + +blassic-filepopen.o: filepopen.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filepopen.o -MD -MP -MF $(DEPDIR)/blassic-filepopen.Tpo -c -o blassic-filepopen.o `test -f 'filepopen.cpp' || echo '$(srcdir)/'`filepopen.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filepopen.Tpo $(DEPDIR)/blassic-filepopen.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filepopen.cpp' object='blassic-filepopen.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filepopen.o `test -f 'filepopen.cpp' || echo '$(srcdir)/'`filepopen.cpp + +blassic-filepopen.obj: filepopen.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filepopen.obj -MD -MP -MF $(DEPDIR)/blassic-filepopen.Tpo -c -o blassic-filepopen.obj `if test -f 'filepopen.cpp'; then $(CYGPATH_W) 'filepopen.cpp'; else $(CYGPATH_W) '$(srcdir)/filepopen.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filepopen.Tpo $(DEPDIR)/blassic-filepopen.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filepopen.cpp' object='blassic-filepopen.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filepopen.obj `if test -f 'filepopen.cpp'; then $(CYGPATH_W) 'filepopen.cpp'; else $(CYGPATH_W) '$(srcdir)/filepopen.cpp'; fi` + +blassic-fileprinter.o: fileprinter.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileprinter.o -MD -MP -MF $(DEPDIR)/blassic-fileprinter.Tpo -c -o blassic-fileprinter.o `test -f 'fileprinter.cpp' || echo '$(srcdir)/'`fileprinter.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileprinter.Tpo $(DEPDIR)/blassic-fileprinter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileprinter.cpp' object='blassic-fileprinter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileprinter.o `test -f 'fileprinter.cpp' || echo '$(srcdir)/'`fileprinter.cpp + +blassic-fileprinter.obj: fileprinter.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-fileprinter.obj -MD -MP -MF $(DEPDIR)/blassic-fileprinter.Tpo -c -o blassic-fileprinter.obj `if test -f 'fileprinter.cpp'; then $(CYGPATH_W) 'fileprinter.cpp'; else $(CYGPATH_W) '$(srcdir)/fileprinter.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-fileprinter.Tpo $(DEPDIR)/blassic-fileprinter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='fileprinter.cpp' object='blassic-fileprinter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-fileprinter.obj `if test -f 'fileprinter.cpp'; then $(CYGPATH_W) 'fileprinter.cpp'; else $(CYGPATH_W) '$(srcdir)/fileprinter.cpp'; fi` + +blassic-filesocket.o: filesocket.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filesocket.o -MD -MP -MF $(DEPDIR)/blassic-filesocket.Tpo -c -o blassic-filesocket.o `test -f 'filesocket.cpp' || echo '$(srcdir)/'`filesocket.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filesocket.Tpo $(DEPDIR)/blassic-filesocket.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filesocket.cpp' object='blassic-filesocket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filesocket.o `test -f 'filesocket.cpp' || echo '$(srcdir)/'`filesocket.cpp + +blassic-filesocket.obj: filesocket.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filesocket.obj -MD -MP -MF $(DEPDIR)/blassic-filesocket.Tpo -c -o blassic-filesocket.obj `if test -f 'filesocket.cpp'; then $(CYGPATH_W) 'filesocket.cpp'; else $(CYGPATH_W) '$(srcdir)/filesocket.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filesocket.Tpo $(DEPDIR)/blassic-filesocket.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filesocket.cpp' object='blassic-filesocket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filesocket.obj `if test -f 'filesocket.cpp'; then $(CYGPATH_W) 'filesocket.cpp'; else $(CYGPATH_W) '$(srcdir)/filesocket.cpp'; fi` + +blassic-filewindow.o: filewindow.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filewindow.o -MD -MP -MF $(DEPDIR)/blassic-filewindow.Tpo -c -o blassic-filewindow.o `test -f 'filewindow.cpp' || echo '$(srcdir)/'`filewindow.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filewindow.Tpo $(DEPDIR)/blassic-filewindow.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filewindow.cpp' object='blassic-filewindow.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filewindow.o `test -f 'filewindow.cpp' || echo '$(srcdir)/'`filewindow.cpp + +blassic-filewindow.obj: filewindow.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-filewindow.obj -MD -MP -MF $(DEPDIR)/blassic-filewindow.Tpo -c -o blassic-filewindow.obj `if test -f 'filewindow.cpp'; then $(CYGPATH_W) 'filewindow.cpp'; else $(CYGPATH_W) '$(srcdir)/filewindow.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-filewindow.Tpo $(DEPDIR)/blassic-filewindow.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='filewindow.cpp' object='blassic-filewindow.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-filewindow.obj `if test -f 'filewindow.cpp'; then $(CYGPATH_W) 'filewindow.cpp'; else $(CYGPATH_W) '$(srcdir)/filewindow.cpp'; fi` + +blassic-function.o: function.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-function.o -MD -MP -MF $(DEPDIR)/blassic-function.Tpo -c -o blassic-function.o `test -f 'function.cpp' || echo '$(srcdir)/'`function.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-function.Tpo $(DEPDIR)/blassic-function.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='function.cpp' object='blassic-function.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-function.o `test -f 'function.cpp' || echo '$(srcdir)/'`function.cpp + +blassic-function.obj: function.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-function.obj -MD -MP -MF $(DEPDIR)/blassic-function.Tpo -c -o blassic-function.obj `if test -f 'function.cpp'; then $(CYGPATH_W) 'function.cpp'; else $(CYGPATH_W) '$(srcdir)/function.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-function.Tpo $(DEPDIR)/blassic-function.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='function.cpp' object='blassic-function.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-function.obj `if test -f 'function.cpp'; then $(CYGPATH_W) 'function.cpp'; else $(CYGPATH_W) '$(srcdir)/function.cpp'; fi` + +blassic-graphics.o: graphics.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-graphics.o -MD -MP -MF $(DEPDIR)/blassic-graphics.Tpo -c -o blassic-graphics.o `test -f 'graphics.cpp' || echo '$(srcdir)/'`graphics.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-graphics.Tpo $(DEPDIR)/blassic-graphics.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='graphics.cpp' object='blassic-graphics.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-graphics.o `test -f 'graphics.cpp' || echo '$(srcdir)/'`graphics.cpp + +blassic-graphics.obj: graphics.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-graphics.obj -MD -MP -MF $(DEPDIR)/blassic-graphics.Tpo -c -o blassic-graphics.obj `if test -f 'graphics.cpp'; then $(CYGPATH_W) 'graphics.cpp'; else $(CYGPATH_W) '$(srcdir)/graphics.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-graphics.Tpo $(DEPDIR)/blassic-graphics.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='graphics.cpp' object='blassic-graphics.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-graphics.obj `if test -f 'graphics.cpp'; then $(CYGPATH_W) 'graphics.cpp'; else $(CYGPATH_W) '$(srcdir)/graphics.cpp'; fi` + +blassic-key.o: key.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-key.o -MD -MP -MF $(DEPDIR)/blassic-key.Tpo -c -o blassic-key.o `test -f 'key.cpp' || echo '$(srcdir)/'`key.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-key.Tpo $(DEPDIR)/blassic-key.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='key.cpp' object='blassic-key.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-key.o `test -f 'key.cpp' || echo '$(srcdir)/'`key.cpp + +blassic-key.obj: key.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-key.obj -MD -MP -MF $(DEPDIR)/blassic-key.Tpo -c -o blassic-key.obj `if test -f 'key.cpp'; then $(CYGPATH_W) 'key.cpp'; else $(CYGPATH_W) '$(srcdir)/key.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-key.Tpo $(DEPDIR)/blassic-key.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='key.cpp' object='blassic-key.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-key.obj `if test -f 'key.cpp'; then $(CYGPATH_W) 'key.cpp'; else $(CYGPATH_W) '$(srcdir)/key.cpp'; fi` + +blassic-keyword.o: keyword.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-keyword.o -MD -MP -MF $(DEPDIR)/blassic-keyword.Tpo -c -o blassic-keyword.o `test -f 'keyword.cpp' || echo '$(srcdir)/'`keyword.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-keyword.Tpo $(DEPDIR)/blassic-keyword.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='keyword.cpp' object='blassic-keyword.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-keyword.o `test -f 'keyword.cpp' || echo '$(srcdir)/'`keyword.cpp + +blassic-keyword.obj: keyword.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-keyword.obj -MD -MP -MF $(DEPDIR)/blassic-keyword.Tpo -c -o blassic-keyword.obj `if test -f 'keyword.cpp'; then $(CYGPATH_W) 'keyword.cpp'; else $(CYGPATH_W) '$(srcdir)/keyword.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-keyword.Tpo $(DEPDIR)/blassic-keyword.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='keyword.cpp' object='blassic-keyword.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-keyword.obj `if test -f 'keyword.cpp'; then $(CYGPATH_W) 'keyword.cpp'; else $(CYGPATH_W) '$(srcdir)/keyword.cpp'; fi` + +blassic-mbf.o: mbf.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-mbf.o -MD -MP -MF $(DEPDIR)/blassic-mbf.Tpo -c -o blassic-mbf.o `test -f 'mbf.cpp' || echo '$(srcdir)/'`mbf.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-mbf.Tpo $(DEPDIR)/blassic-mbf.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mbf.cpp' object='blassic-mbf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-mbf.o `test -f 'mbf.cpp' || echo '$(srcdir)/'`mbf.cpp + +blassic-mbf.obj: mbf.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-mbf.obj -MD -MP -MF $(DEPDIR)/blassic-mbf.Tpo -c -o blassic-mbf.obj `if test -f 'mbf.cpp'; then $(CYGPATH_W) 'mbf.cpp'; else $(CYGPATH_W) '$(srcdir)/mbf.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-mbf.Tpo $(DEPDIR)/blassic-mbf.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='mbf.cpp' object='blassic-mbf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-mbf.obj `if test -f 'mbf.cpp'; then $(CYGPATH_W) 'mbf.cpp'; else $(CYGPATH_W) '$(srcdir)/mbf.cpp'; fi` + +blassic-memory.o: memory.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-memory.o -MD -MP -MF $(DEPDIR)/blassic-memory.Tpo -c -o blassic-memory.o `test -f 'memory.cpp' || echo '$(srcdir)/'`memory.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-memory.Tpo $(DEPDIR)/blassic-memory.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='memory.cpp' object='blassic-memory.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-memory.o `test -f 'memory.cpp' || echo '$(srcdir)/'`memory.cpp + +blassic-memory.obj: memory.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-memory.obj -MD -MP -MF $(DEPDIR)/blassic-memory.Tpo -c -o blassic-memory.obj `if test -f 'memory.cpp'; then $(CYGPATH_W) 'memory.cpp'; else $(CYGPATH_W) '$(srcdir)/memory.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-memory.Tpo $(DEPDIR)/blassic-memory.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='memory.cpp' object='blassic-memory.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-memory.obj `if test -f 'memory.cpp'; then $(CYGPATH_W) 'memory.cpp'; else $(CYGPATH_W) '$(srcdir)/memory.cpp'; fi` + +blassic-program.o: program.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-program.o -MD -MP -MF $(DEPDIR)/blassic-program.Tpo -c -o blassic-program.o `test -f 'program.cpp' || echo '$(srcdir)/'`program.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-program.Tpo $(DEPDIR)/blassic-program.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='program.cpp' object='blassic-program.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-program.o `test -f 'program.cpp' || echo '$(srcdir)/'`program.cpp + +blassic-program.obj: program.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-program.obj -MD -MP -MF $(DEPDIR)/blassic-program.Tpo -c -o blassic-program.obj `if test -f 'program.cpp'; then $(CYGPATH_W) 'program.cpp'; else $(CYGPATH_W) '$(srcdir)/program.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-program.Tpo $(DEPDIR)/blassic-program.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='program.cpp' object='blassic-program.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-program.obj `if test -f 'program.cpp'; then $(CYGPATH_W) 'program.cpp'; else $(CYGPATH_W) '$(srcdir)/program.cpp'; fi` + +blassic-regexp.o: regexp.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-regexp.o -MD -MP -MF $(DEPDIR)/blassic-regexp.Tpo -c -o blassic-regexp.o `test -f 'regexp.cpp' || echo '$(srcdir)/'`regexp.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-regexp.Tpo $(DEPDIR)/blassic-regexp.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='regexp.cpp' object='blassic-regexp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-regexp.o `test -f 'regexp.cpp' || echo '$(srcdir)/'`regexp.cpp + +blassic-regexp.obj: regexp.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-regexp.obj -MD -MP -MF $(DEPDIR)/blassic-regexp.Tpo -c -o blassic-regexp.obj `if test -f 'regexp.cpp'; then $(CYGPATH_W) 'regexp.cpp'; else $(CYGPATH_W) '$(srcdir)/regexp.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-regexp.Tpo $(DEPDIR)/blassic-regexp.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='regexp.cpp' object='blassic-regexp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-regexp.obj `if test -f 'regexp.cpp'; then $(CYGPATH_W) 'regexp.cpp'; else $(CYGPATH_W) '$(srcdir)/regexp.cpp'; fi` + +blassic-runner.o: runner.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runner.o -MD -MP -MF $(DEPDIR)/blassic-runner.Tpo -c -o blassic-runner.o `test -f 'runner.cpp' || echo '$(srcdir)/'`runner.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runner.Tpo $(DEPDIR)/blassic-runner.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runner.cpp' object='blassic-runner.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runner.o `test -f 'runner.cpp' || echo '$(srcdir)/'`runner.cpp + +blassic-runner.obj: runner.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runner.obj -MD -MP -MF $(DEPDIR)/blassic-runner.Tpo -c -o blassic-runner.obj `if test -f 'runner.cpp'; then $(CYGPATH_W) 'runner.cpp'; else $(CYGPATH_W) '$(srcdir)/runner.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runner.Tpo $(DEPDIR)/blassic-runner.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runner.cpp' object='blassic-runner.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runner.obj `if test -f 'runner.cpp'; then $(CYGPATH_W) 'runner.cpp'; else $(CYGPATH_W) '$(srcdir)/runner.cpp'; fi` + +blassic-runnerline.o: runnerline.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline.o -MD -MP -MF $(DEPDIR)/blassic-runnerline.Tpo -c -o blassic-runnerline.o `test -f 'runnerline.cpp' || echo '$(srcdir)/'`runnerline.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline.Tpo $(DEPDIR)/blassic-runnerline.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline.cpp' object='blassic-runnerline.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline.o `test -f 'runnerline.cpp' || echo '$(srcdir)/'`runnerline.cpp + +blassic-runnerline.obj: runnerline.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline.Tpo -c -o blassic-runnerline.obj `if test -f 'runnerline.cpp'; then $(CYGPATH_W) 'runnerline.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline.Tpo $(DEPDIR)/blassic-runnerline.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline.cpp' object='blassic-runnerline.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline.obj `if test -f 'runnerline.cpp'; then $(CYGPATH_W) 'runnerline.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline.cpp'; fi` + +blassic-runnerline_impl.o: runnerline_impl.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_impl.o -MD -MP -MF $(DEPDIR)/blassic-runnerline_impl.Tpo -c -o blassic-runnerline_impl.o `test -f 'runnerline_impl.cpp' || echo '$(srcdir)/'`runnerline_impl.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_impl.Tpo $(DEPDIR)/blassic-runnerline_impl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_impl.cpp' object='blassic-runnerline_impl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_impl.o `test -f 'runnerline_impl.cpp' || echo '$(srcdir)/'`runnerline_impl.cpp + +blassic-runnerline_impl.obj: runnerline_impl.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_impl.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline_impl.Tpo -c -o blassic-runnerline_impl.obj `if test -f 'runnerline_impl.cpp'; then $(CYGPATH_W) 'runnerline_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_impl.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_impl.Tpo $(DEPDIR)/blassic-runnerline_impl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_impl.cpp' object='blassic-runnerline_impl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_impl.obj `if test -f 'runnerline_impl.cpp'; then $(CYGPATH_W) 'runnerline_impl.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_impl.cpp'; fi` + +blassic-runnerline_instructions.o: runnerline_instructions.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_instructions.o -MD -MP -MF $(DEPDIR)/blassic-runnerline_instructions.Tpo -c -o blassic-runnerline_instructions.o `test -f 'runnerline_instructions.cpp' || echo '$(srcdir)/'`runnerline_instructions.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_instructions.Tpo $(DEPDIR)/blassic-runnerline_instructions.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_instructions.cpp' object='blassic-runnerline_instructions.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_instructions.o `test -f 'runnerline_instructions.cpp' || echo '$(srcdir)/'`runnerline_instructions.cpp + +blassic-runnerline_instructions.obj: runnerline_instructions.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_instructions.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline_instructions.Tpo -c -o blassic-runnerline_instructions.obj `if test -f 'runnerline_instructions.cpp'; then $(CYGPATH_W) 'runnerline_instructions.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_instructions.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_instructions.Tpo $(DEPDIR)/blassic-runnerline_instructions.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_instructions.cpp' object='blassic-runnerline_instructions.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_instructions.obj `if test -f 'runnerline_instructions.cpp'; then $(CYGPATH_W) 'runnerline_instructions.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_instructions.cpp'; fi` + +blassic-runnerline_print.o: runnerline_print.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_print.o -MD -MP -MF $(DEPDIR)/blassic-runnerline_print.Tpo -c -o blassic-runnerline_print.o `test -f 'runnerline_print.cpp' || echo '$(srcdir)/'`runnerline_print.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_print.Tpo $(DEPDIR)/blassic-runnerline_print.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_print.cpp' object='blassic-runnerline_print.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_print.o `test -f 'runnerline_print.cpp' || echo '$(srcdir)/'`runnerline_print.cpp + +blassic-runnerline_print.obj: runnerline_print.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-runnerline_print.obj -MD -MP -MF $(DEPDIR)/blassic-runnerline_print.Tpo -c -o blassic-runnerline_print.obj `if test -f 'runnerline_print.cpp'; then $(CYGPATH_W) 'runnerline_print.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_print.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-runnerline_print.Tpo $(DEPDIR)/blassic-runnerline_print.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='runnerline_print.cpp' object='blassic-runnerline_print.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-runnerline_print.obj `if test -f 'runnerline_print.cpp'; then $(CYGPATH_W) 'runnerline_print.cpp'; else $(CYGPATH_W) '$(srcdir)/runnerline_print.cpp'; fi` + +blassic-showerror.o: showerror.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-showerror.o -MD -MP -MF $(DEPDIR)/blassic-showerror.Tpo -c -o blassic-showerror.o `test -f 'showerror.cpp' || echo '$(srcdir)/'`showerror.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-showerror.Tpo $(DEPDIR)/blassic-showerror.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='showerror.cpp' object='blassic-showerror.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-showerror.o `test -f 'showerror.cpp' || echo '$(srcdir)/'`showerror.cpp + +blassic-showerror.obj: showerror.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-showerror.obj -MD -MP -MF $(DEPDIR)/blassic-showerror.Tpo -c -o blassic-showerror.obj `if test -f 'showerror.cpp'; then $(CYGPATH_W) 'showerror.cpp'; else $(CYGPATH_W) '$(srcdir)/showerror.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-showerror.Tpo $(DEPDIR)/blassic-showerror.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='showerror.cpp' object='blassic-showerror.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-showerror.obj `if test -f 'showerror.cpp'; then $(CYGPATH_W) 'showerror.cpp'; else $(CYGPATH_W) '$(srcdir)/showerror.cpp'; fi` + +blassic-socket.o: socket.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-socket.o -MD -MP -MF $(DEPDIR)/blassic-socket.Tpo -c -o blassic-socket.o `test -f 'socket.cpp' || echo '$(srcdir)/'`socket.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-socket.Tpo $(DEPDIR)/blassic-socket.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='socket.cpp' object='blassic-socket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-socket.o `test -f 'socket.cpp' || echo '$(srcdir)/'`socket.cpp + +blassic-socket.obj: socket.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-socket.obj -MD -MP -MF $(DEPDIR)/blassic-socket.Tpo -c -o blassic-socket.obj `if test -f 'socket.cpp'; then $(CYGPATH_W) 'socket.cpp'; else $(CYGPATH_W) '$(srcdir)/socket.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-socket.Tpo $(DEPDIR)/blassic-socket.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='socket.cpp' object='blassic-socket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-socket.obj `if test -f 'socket.cpp'; then $(CYGPATH_W) 'socket.cpp'; else $(CYGPATH_W) '$(srcdir)/socket.cpp'; fi` + +blassic-sysvar.o: sysvar.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-sysvar.o -MD -MP -MF $(DEPDIR)/blassic-sysvar.Tpo -c -o blassic-sysvar.o `test -f 'sysvar.cpp' || echo '$(srcdir)/'`sysvar.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-sysvar.Tpo $(DEPDIR)/blassic-sysvar.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sysvar.cpp' object='blassic-sysvar.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-sysvar.o `test -f 'sysvar.cpp' || echo '$(srcdir)/'`sysvar.cpp + +blassic-sysvar.obj: sysvar.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-sysvar.obj -MD -MP -MF $(DEPDIR)/blassic-sysvar.Tpo -c -o blassic-sysvar.obj `if test -f 'sysvar.cpp'; then $(CYGPATH_W) 'sysvar.cpp'; else $(CYGPATH_W) '$(srcdir)/sysvar.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-sysvar.Tpo $(DEPDIR)/blassic-sysvar.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='sysvar.cpp' object='blassic-sysvar.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-sysvar.obj `if test -f 'sysvar.cpp'; then $(CYGPATH_W) 'sysvar.cpp'; else $(CYGPATH_W) '$(srcdir)/sysvar.cpp'; fi` + +blassic-token.o: token.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-token.o -MD -MP -MF $(DEPDIR)/blassic-token.Tpo -c -o blassic-token.o `test -f 'token.cpp' || echo '$(srcdir)/'`token.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-token.Tpo $(DEPDIR)/blassic-token.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='token.cpp' object='blassic-token.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-token.o `test -f 'token.cpp' || echo '$(srcdir)/'`token.cpp + +blassic-token.obj: token.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-token.obj -MD -MP -MF $(DEPDIR)/blassic-token.Tpo -c -o blassic-token.obj `if test -f 'token.cpp'; then $(CYGPATH_W) 'token.cpp'; else $(CYGPATH_W) '$(srcdir)/token.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-token.Tpo $(DEPDIR)/blassic-token.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='token.cpp' object='blassic-token.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-token.obj `if test -f 'token.cpp'; then $(CYGPATH_W) 'token.cpp'; else $(CYGPATH_W) '$(srcdir)/token.cpp'; fi` + +blassic-trace.o: trace.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-trace.o -MD -MP -MF $(DEPDIR)/blassic-trace.Tpo -c -o blassic-trace.o `test -f 'trace.cpp' || echo '$(srcdir)/'`trace.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-trace.Tpo $(DEPDIR)/blassic-trace.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='trace.cpp' object='blassic-trace.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-trace.o `test -f 'trace.cpp' || echo '$(srcdir)/'`trace.cpp + +blassic-trace.obj: trace.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-trace.obj -MD -MP -MF $(DEPDIR)/blassic-trace.Tpo -c -o blassic-trace.obj `if test -f 'trace.cpp'; then $(CYGPATH_W) 'trace.cpp'; else $(CYGPATH_W) '$(srcdir)/trace.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-trace.Tpo $(DEPDIR)/blassic-trace.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='trace.cpp' object='blassic-trace.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-trace.obj `if test -f 'trace.cpp'; then $(CYGPATH_W) 'trace.cpp'; else $(CYGPATH_W) '$(srcdir)/trace.cpp'; fi` + +blassic-using.o: using.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-using.o -MD -MP -MF $(DEPDIR)/blassic-using.Tpo -c -o blassic-using.o `test -f 'using.cpp' || echo '$(srcdir)/'`using.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-using.Tpo $(DEPDIR)/blassic-using.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='using.cpp' object='blassic-using.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-using.o `test -f 'using.cpp' || echo '$(srcdir)/'`using.cpp + +blassic-using.obj: using.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-using.obj -MD -MP -MF $(DEPDIR)/blassic-using.Tpo -c -o blassic-using.obj `if test -f 'using.cpp'; then $(CYGPATH_W) 'using.cpp'; else $(CYGPATH_W) '$(srcdir)/using.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-using.Tpo $(DEPDIR)/blassic-using.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='using.cpp' object='blassic-using.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-using.obj `if test -f 'using.cpp'; then $(CYGPATH_W) 'using.cpp'; else $(CYGPATH_W) '$(srcdir)/using.cpp'; fi` + +blassic-var.o: var.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-var.o -MD -MP -MF $(DEPDIR)/blassic-var.Tpo -c -o blassic-var.o `test -f 'var.cpp' || echo '$(srcdir)/'`var.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-var.Tpo $(DEPDIR)/blassic-var.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='var.cpp' object='blassic-var.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-var.o `test -f 'var.cpp' || echo '$(srcdir)/'`var.cpp + +blassic-var.obj: var.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-var.obj -MD -MP -MF $(DEPDIR)/blassic-var.Tpo -c -o blassic-var.obj `if test -f 'var.cpp'; then $(CYGPATH_W) 'var.cpp'; else $(CYGPATH_W) '$(srcdir)/var.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-var.Tpo $(DEPDIR)/blassic-var.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='var.cpp' object='blassic-var.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-var.obj `if test -f 'var.cpp'; then $(CYGPATH_W) 'var.cpp'; else $(CYGPATH_W) '$(srcdir)/var.cpp'; fi` + +blassic-version.o: version.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-version.o -MD -MP -MF $(DEPDIR)/blassic-version.Tpo -c -o blassic-version.o `test -f 'version.cpp' || echo '$(srcdir)/'`version.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-version.Tpo $(DEPDIR)/blassic-version.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='version.cpp' object='blassic-version.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-version.o `test -f 'version.cpp' || echo '$(srcdir)/'`version.cpp + +blassic-version.obj: version.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -MT blassic-version.obj -MD -MP -MF $(DEPDIR)/blassic-version.Tpo -c -o blassic-version.obj `if test -f 'version.cpp'; then $(CYGPATH_W) 'version.cpp'; else $(CYGPATH_W) '$(srcdir)/version.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/blassic-version.Tpo $(DEPDIR)/blassic-version.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='version.cpp' object='blassic-version.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(blassic_CXXFLAGS) $(CXXFLAGS) -c -o blassic-version.obj `if test -f 'version.cpp'; then $(CYGPATH_W) 'version.cpp'; else $(CYGPATH_W) '$(srcdir)/version.cpp'; fi` + +gencharset-gencharset.o: gencharset.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -MT gencharset-gencharset.o -MD -MP -MF $(DEPDIR)/gencharset-gencharset.Tpo -c -o gencharset-gencharset.o `test -f 'gencharset.cpp' || echo '$(srcdir)/'`gencharset.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/gencharset-gencharset.Tpo $(DEPDIR)/gencharset-gencharset.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gencharset.cpp' object='gencharset-gencharset.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -c -o gencharset-gencharset.o `test -f 'gencharset.cpp' || echo '$(srcdir)/'`gencharset.cpp + +gencharset-gencharset.obj: gencharset.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -MT gencharset-gencharset.obj -MD -MP -MF $(DEPDIR)/gencharset-gencharset.Tpo -c -o gencharset-gencharset.obj `if test -f 'gencharset.cpp'; then $(CYGPATH_W) 'gencharset.cpp'; else $(CYGPATH_W) '$(srcdir)/gencharset.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/gencharset-gencharset.Tpo $(DEPDIR)/gencharset-gencharset.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='gencharset.cpp' object='gencharset-gencharset.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(gencharset_CXXFLAGS) $(CXXFLAGS) -c -o gencharset-gencharset.obj `if test -f 'gencharset.cpp'; then $(CYGPATH_W) 'gencharset.cpp'; else $(CYGPATH_W) '$(srcdir)/gencharset.cpp'; fi` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d $(distdir) || mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-binPROGRAMS clean-generic clean-noinstPROGRAMS ctags \ + dist dist-all dist-bzip2 dist-gzip dist-lzma dist-shar \ + dist-tarZ dist-zip distcheck distclean distclean-compile \ + distclean-generic distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS + + +# This way the .exe extension is appended when compiling for windows +# under linux, but it works anyway. +gencharset$(EXEEXT): gencharset.cpp + $(CXX_FOR_BUILD) $(gencharset_CXXFLAGS) $(gencharset_LDFLAGS) \ + -o gencharset$(EXEEXT) \ + gencharset.cpp + +# Character sets for graphics modes. + +#charset.cpp: $(srcdir)/charset.def gencharset +# ./gencharset $(srcdir)/charset.def charset.cpp +# test -f charset.cpp + +charset_default.cpp: $(srcdir)/default.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/default.def \ + charset_default.cpp default + test -f charset_default.cpp + +charset_cpc.cpp: $(srcdir)/cpc.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/cpc.def \ + charset_cpc.cpp cpc + test -f charset_cpc.cpp + +charset_spectrum.cpp: $(srcdir)/spectrum.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/spectrum.def \ + charset_spectrum.cpp spectrum + test -f charset_spectrum.cpp + +charset_msx.cpp: $(srcdir)/msx.def gencharset.cpp charset.h + ./gencharset$(EXEEXT) $(srcdir)/msx.def \ + charset_msx.cpp msx + test -f charset_msx.cpp + +# testdl: a tiny library to test blassic dynamic link. + +# Julian: modified this to allow cross-compiling. +#testdl.so: testdl.o +# gcc -shared -Wl,-soname,testdl.so -o testdl.so testdl.o +#testdl.o: testdl.cpp +# gcc -Wall -fPIC -c testdl.cpp + +#testdl_CXXFLAGS = \ +# -W -Wall -Wwrite-strings -Wstrict-prototypes \ +# -Wunused + +testdl.so: testdl.o + $(CXX) -shared -Wl,-soname,testdl.so $(LDFLAGS) -o testdl.so testdl.o + +testdl.o: testdl.cpp + $(CXX) -fPIC $(testdl_CXXFLAGS) -c testdl.cpp + +rpm: dist + rpm -ta $(distdir).tar.gz +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..5bfc64c --- /dev/null +++ b/NEWS @@ -0,0 +1,570 @@ +Version 0.10.1 + + Added msx option and charset. + +Version 0.10.0 + + Improved configure, easier and with more options. + + New system var to control if blank lines are converted + to comments when loading a program in text mode, and + command line option --comblank to set it. + + Now the graphics system is not initialized until a + graphics mode is established. Under X the X server + can be established or changed on the fly by channging + the value of the DISPLAY environment variable. + + String slicing operations ZX Basic style using [ ]. + + Added SCROLL, ZX_PLOT and ZX_UNPLOT instructions. + + Additional optional parameters for COPYCHR$. + + Characters redefinition Spectrum style now extends + to Z. + + LABEL can be used as function, giving the line number + where the label is defined. Useful with 'IF ERL = ...', + for example. + + RENUM takes another optional argument, to stop + renumbering at certain line. + + Changed default charset, added charsets spectrum and + cpc, selected when used the corresponding command + line option and with a new syntax for SYMBOL AFTER. + + RETURN now admits an optional line number argument. + + FN RETURN instruction added. + + POPEN now can be bidirectional and capture the error + output. This feature may or not works well in windows, + depending on the windows versions, more work in this + is needed. + + CHAIN MERGE now does not affect the current program + if the loading of the chained fails. + + Line number 0 is now valid (and you can even ON ERROR GOTO + to it, but only with a LABEL). + + New machine type command line option --appleII + + New operator \ for integer division. + + New system flags to control if true value is -1 or 1 + and if the logical operators are binary or boolean. + + GO TO and GO SUB are now accepted. They can be listed + as two words using a new system flag. <= and others + also are accepted with embedded spaces. + + New system flag to allow GOTO and other jump instructions + refer to a line number inexistent, using the next line in + that case. + + New command line options --errout, --norun, --tron and + --tronline. + + Processing of command line options reworked. Now a option + inexistent is not taken as a filename, generates an error + instead. + + Better LABEL caching and error detection. + + Now can be compiled without graphics in platforms where + they are supported just by commenting the line + #define BLASSIC_HAS_GRAPHICS + in graphics.cpp + + Added flag in system vars to control if debug info is showed + on certain errors, and --info command line option to turn + it on. More debug info added to be used with this. + + Added UCASE$ and LCASE$ aliases for UPPER$ and LOWER$. + + Added GET and PUT graphic variants. + + Corrected bug of LINE ... B in windows. + + Added function ALLOC_MEMORY and instruction FREE_MEMORY, + this allows use of machine code in operating systems with + protection against execution in data areas. + + Regular expression functions (currently not working under + windows). + + INSTR with initial value less than 1 now gives error. + + Corrected READ: now a comma at the end of a DATA sentence + is valid. + + EOF now works with random files. Also added the LOC function + for him. + + +Version 0.8.1 + + -p command line option to print expressions. + + - in command line means read program from standard input. + + Suffix # for floating point variables is now accepted. + +Version 0.8.0 + + THEN omitted and flag that controls if it's accepetd. + + Flags to insert space before non negative numbers in PRINT + and in STR$, and to convert LF to CR in GET a$ and INKEY$. + + LOF, FREEFILE, INKEY and ROUND functions added. + + LSET and RSET corrected, and now works with standalone vars. + + FIELD now assign the field variables, and accepts matrix + elements. + + END now closes files. + + => , =< and >< added. + + PULL instruction and his variants added. + + MID$ instruction now accepts subindexed variables and works + with fields. + + Command line options --gwbasic, --allflags and --lfcr added. + + CLOSE without parameters, CLEAR and others now does not close + window channels. + + WIDTH LPRINT now accepts a second parameter for setting left + margin. + + Graphics modes can be rotated, with system var and command + line option --rotate. + + ZONE now works in text mode. + + The end of command line options is marked with --. + + FIELD CLEAR and FIELD APPEND instructions. + + Text input in graphics mode now uses accent dead keys. + + **BREAK** when launched program from command line now goes + to standard error. + + Automatic conversions from floating point to integer now + are rounded and can result in overflow error. + + PAINT instruction. + + Now compiles again when no graphics library found. + + Functions to convert to and from MBF format (floating point + format used in several Basic): MKSMBF$, MKDMBF$, CVSMBF and + CVDMBF. + +Version 0.7.2 + + ASC now does not require parenthesis. + + SCREEN$ function. + + --cpc and --spectrum command line options. + + Command line option -m now accepts mode by name. + + BRIGHT instruction and PRINT modifier. + + Added BINARY to open modes for files. + + Spectrum syntax for CIRCLE is now accepted. + + DRAWARC instruction. + +Version 0.7.1 + + POPEN in unix versions now redirects the standard streams + to /dev/null. + + FILES to printer channel now uses correct line width. + + "Sin soporte de graficos" and some other messages still in + spanish are translated. + + Moving in the history buffer now places the cursor at the end + of line. + + New flag in Flags1 system variable controls TAB style. + + INKEY$ now accepts a channel parameter and can be used with files. + + Avoided high use of CPU on unix when waiting a key in graphics mode. + + PAUSE 0 now does a usleep (0) on unix. + + Implemented the effect of the ; initial in INPUT and LINE INPUT + (previously was accepted but does nothing). + + Functions found on Sinclair Basics (and some other funtions) now + does not require parenthesis (USR only when used whith UDG). + + VAL$ function. + +Version 0.7.0 + + USR "Spectrum graphic characters style". + + Corrected bug with APPEND mode. + + Printer support with LPRINT and LLIST. + + WIDTH LPRINT instruction. + + ZONE implemented at least! + + Solved problems with popen under Windows (I hope). + +Version 0.6.1 + + MODE 0 when graphics not available now is not an error. + + Added underline mode to console emulation in graphics mode. + + Bug RESTORE always set line 0 corrected. + + Bug ' after DATA corrected. + + Bug vars whith suffix ! corrected. + + IF_DEBUG instruction, DebugLevel system var, --debug command + line option. + +Version 0.6.0 + + Corrected an obscure bug in windows. + + FILES now gives error when file not found and has an optional + channel parameter. + + Problem with popen as direct command in windows solved in + windows 98, but now does not work on XP. Compiling with + MinGW the problem dissapears. Borland's fault? + + FN recursion level limited, controled by a new system var. + + Instructions TAG, TAGOFF, ORIGIN, DEG, RAD and INVERSE. + + Crash when copychr out of screen corrected. + + Delete key in graphics mode in linux/unix now acts as Delete. + + Now compiles under Cygwin and under MinGW. Can be compiled on + unix with curses instead of ncurses or without any curses. + + USING corrected, now does not require the ecvt function, + that is not provided in all platforms. + + New system var Flags1, bit 0 control LOCATE style + Microsoft (row, col) or Amstrad CPC (col, row). + + Graphic window on Windows can be minimized. + + New graphics modes pcw, pcw2, cpc0 and cpc1, mode cpc2 corrected. + + MODE has new optional arguments zoomx and zoomy. + + Control characters in graphics mode now acts like both Amstrad + CPC in Basic and Amstrad CPC and PCW in CP/M. + + Line feed now has no automatic CR in graphics mode. + + CLEAR and similars now does a RESTORE. + + Separators between PRINT items are no longer required. + + INK Spectrum syntax is now accepeted. + + INK, PAPER and INVERSE as PRINT specifiers Spectrum style. + + Bug local integer variables incorrectly restored, solved + + Workaround for a possible compiler error on arm. + +Version 0.5.7 + + cursor.cpp not compiled under gcc 2.95, corrected. + + Bug MODE segfaulting in console, corrected. + + Some READ improvement. + + STRERR$ function. + + CLEAR INK instruction. + + DEC$ function. + + PRINT USING improved, now with scientific notation and + currency sign for dollar, pound and euro. + + Bug editing chars with code > 127 ignored, corrected. + + POS and VPOS functions. + + Line editing in INPUT and LINE INPUT now also works in + text mode in unix. + + TAB now works correctly in text mode. + + Speed improvement in text output in graphics mode. + + INPUT corrected, LINE INPUT improved. + + CLEAR INPUT instruction. + + Better handling of multiline FN functions. + + GOTO (and others) to a line number that not exist now + is an error. + + SET_TITLE instruction. + +Version 0.5.6 + + Instructions BEEP, DEFINT, DEFSTR, DEFREAL, DEFSNG and DEFDBL. + + RESUME without error is an error even with line number. + + Function COPYCHR$. + + Instruction WINDOW SWAP. + + Functions TEST and TESTR. + + Instruction INK. + + Solved problem when running from telnet in hp-ux. + +Version 0.5.5 + + SINH, COSH, TANH, ASINH, ACOSH and ATANH functions. + + Better handling of math errors. + + ATAN2 function. + + Command history. + + Behaviour of RUN, CLEAR and NEW corrected. + + Bug MODE not destroyed the window channels, corrected. + + FINDFIRST$ and FINDNEXT$ functions. + +Version 0.5.4 + + Command line option -x to exclude keywords. + + #include directive in text programs. + + Functions RINSTR, FIND_FIRST_OF, FIND_LAST_OF, + FIND_FIRST_NOT_OF and FIND_LAST_NOT_OF. + + LET as operator. + + SYMBOL AFTER instruction. + +Version 0.5.3 + + Bugs in ellipses and arcs of ellipses with high + eccentricity, corrected. + + INPUT & LINE INPUT now works in graphics mode. + + Corrected bug synchronized mode not reset when changing mode. + +Version 0.5.2 + + CIRCLE extended to ellipses. + +Version 0.5.1 + + Bug in CLS in graphics mode corrected. + + Cleaner circles. + + The syntax of the CIRCLE instruction has been changed and + completed for compatibility with Gwbasic. + + Bug DRAW string debug output not cleaned, corrected. + +Version 0.5.0 + + Speed improvement. + + "PRINT , , 1" now is valid syntax. Same in WRITE. + + Better implementation of FILES. + + XPOS, YPOS, PEEK16 and PEEK32 functions. + + DRAWR, PLOTR, MOVER, POKE16, POKE32, RENUM, CIRCLE, MASK, + WINDOW and GRAPHICS instructions. + + Completed the syntax of PLOT, PLOTR, DRAW, DRAWR, MOVE + and MOVER with ink and ink mode parameters. + + Adapated some instructions to work with text windows. + + MODE string, when string can be "spectrum" or "cpc2" + + Bug PRINT AT invert arguments, corrected. + + Bug PRINT AT does not always work, corrected. + + Added variant: VAL evaluates expressions (can run more Sinclair + ZX family programs). Activable with "POKE SYSVARPTR + 25, 1". + + New command line options -m mode and -d. + + Added variant "Next check relaxed", needed for many ZX-81 + and Spectrum programas. Activable with "POKE SYSVARPTR + 26, 1". + + Added variant can DIM an array already dimensioned, needed + for ZX programs. Activable with "POKE SYVARPTR + 27, 1". + + New sample programs. + + Memory leak in ERASE corrected. + + Bug on negative integer DATA corrected. + +Version 0.4.5 + + EDIT command. Line editing in AUTO and in prompt. + + Prompt "Ok" instead of "]" (sorry, Apple ]['s nostalgics). + +Version 0.4.4 + + Bug DATA terminated with comma, corrected. + + Mouse secondary button and button release. + + Special keys support improved. + +Version 0.4.3 + + Mouse support in graphics mode (keywords XMOUSE and YMOUSE). + + Special keys are recongnized in linux in text mode. + + The return value of the SHELL instruction is saved + in a system var. + +Version 0.4.2 + + Now compiles with Kylix. + + Workarounds for bugs that cause crash on some platforms + when a syntax error is generated. + + Bug ON BREAK CONT causes internal error on INPUT. + + Bug AUTO n causes syntax error. + +Version 0.4.1 + + TRON LINE. + + Channel specification in TRON. + + Doesn't use hash_map in gcc 3. + + Corrected problem in gcc 2.95.2 + + Big numbers whitout decimal nor exponent are now handled + correctly on all platforms. + +Version 0.4.0 + + Integer type variables. Integer and real suffixes. + + DEF STR, DEF INT, DEF REAL + + Comments with ' + + No keywords in comments. + + MERGE and CHAIN MERGE now try .blc and .bas extensions + and work with binary files. + + OSNAME$ + + Tabs in graphics mode. + +Version 0.3.5 + + CHAIN, CHAIN MERGE + + Bug some instructions don't continue processing current line. + +Version 0.3.4 + + ON BREAK STOP / CONT / GOSUB + + SYNCHRONIZE, PAUSE. + + Bug LOCATE in graphics mode started in 0 instead of 1, corrected. + + Bug PRINT AT doesn't work in graphics mode, corrected. + +Version 0.3.3 + + Bug scroll & cls in invert mode corrected. + + Bug scroll fills white instead of current paper corrected. + + Bug blank or empty USING corrected. + + Bug INPUT only positive integer coorrected. + + FIX and CINT functions. + + Preliminary support for colors on text mode. + +Version 0.3.2 + + PAPER, PEN, SHELL, CHDIR, MKDIR and RMDIR instructions. + + Syntax of LINE has changed, now is like Gwbasic. + + Simple implementation of FILES. + + Text output in graphics mode now in colors and with + transparent option. + + Error corrections to compile on C++ Builder 6. + + Graphics modes now works on Win 2000 and XP. + +Version 0.3.1 + + POP, NAME, KILL and FILES instructions (FILES not implemented). + + MIN and MAX functions. + + Corrected bug in Makefile. + + Some changes to avoid errors and warnings on some versions + of gcc and C++ Builder. + + Some code cleanup. + + File not found on OPEN for input. diff --git a/README b/README new file mode 100644 index 0000000..ac5abef --- /dev/null +++ b/README @@ -0,0 +1,83 @@ + NOTES ABOUT CURRENT VERSION + +There are problems using some versions of gcc on some platforms. +In case Blassic core dumps on exiting or when a program has an +error, compile it using -O0 + +The regular expression functions are not supported under windows. + +The bidirectional POPEN may or may not work on windows depending +on the windows version used. + +Now configure admits several options: --disable-graphics to compile +without graphics support and --disable-curses to compile without +curses nor ncurses. In the last case, CLS, LOCATE and other +instructions when used in text mode are silently ignored. In the +former, trying to enter in graphics mode generates an error. +If curses is enabled, first ncurses is tested, if not available +curses is used instead. The --disable-ncurses option skips the +ncurses test and uses always curses. + +When configuring for unix/linux, using --without-x has the same +effect as --disable-graphics. For windows is ignored. + +Several scripts to call configure are provided, see the do_conf* +files. + + + NOTES ABOUT CROSS-COMPILING BLASSIC + +The cross-compiling has been simplified in Blasic 0.10.0, it must now +automatically use the native compiler to create gencharset. If this +fails you can manually compile it, or create a dummy, it does not +need to be executed unless the charset data files are modified. + + + * * * + + +To run the test of dynamic linking of functions do: + + make testdl.so + + ./blassic testdl + +On windows with Borland C++ Builder build the project testdl and do: + + blassic testdl + +There is no other documentation than the testdl.cpp source, sorry. + + + * * * + + + BASIC /bay'-sic/ n. + +A programming language, originally designed for Dartmouth's experimental +timesharing system in the early 1960s, which for many years was the leading +cause of brain damage in proto-hackers. Edsger W. Dijkstra observed in +"Selected Writings on Computing: A Personal Perspective" that "It is +practically impossible to teach good programming style to students that have +had prior exposure to BASIC: as potential programmers they are mentally +mutilated beyond hope of regeneration." This is another case (like Pascal) +of the cascading lossage that happens when a language deliberately designed +as an educational toy gets taken too seriously. A novice can write short +BASIC programs (on the order of 10-20 lines) very easily; writing anything +longer (a) is very painful, and (b) encourages bad habits that will make it +harder to use more powerful languages well. This wouldn't be so bad if +historical accidents hadn't made BASIC so common on low-end micros in the +1980s. As it is, it probably ruined tens of thousands of potential wizards. + + "The new hacker's dictionary" + +I disagree with this point of view, but... + + ***************************** + ** You have been warned! ** + ***************************** + + +(C) 2001-2005 Julián Albo + +julian.notfound@gmail.com diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 0000000..767d71a --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,198 @@ +# Configure paths for SVGAlib +# Created by Pierre Sarrazin +# 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 +#include +#include +#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 +#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 /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 + +#include +#include +#include +//#include +#include +#include + +#include +#include +#include + + +#ifdef BLASSIC_USE_WINDOWS + +#include + +#else + +#include +#include +#include +#include + +#endif + +#if defined __BORLANDC__ && defined _Windows + +#include + +#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 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 & 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 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 + (static_cast (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 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 +#else +#include +#endif + +#include +#include +#include + +// 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 & nargs); + +inline BlInteger peek16 (const BlChar * p) +{ + #ifdef BLASSIC_INTEL + return * reinterpret_cast (p); + #else + return p [0] | (static_cast (p [1]) << 8); + #endif +} + +inline void poke16 (BlChar * p, short n) +{ + #ifdef BLASSIC_INTEL + * reinterpret_cast (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 (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 (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 (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 +#include +#include +#include +#include + +#include + +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 (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 (c) ); +} + + +inline bool is_hexdigit (char c) +{ + return isxdigit (static_cast (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 (c + '9' - 'a' + 1); + else if (isupper (c) ) + c= static_cast (c + '9' - 'A' + 1); + return c - '0'; +} + +inline bool is_beginidentifier (char c) +{ + return isalpha (static_cast (c) ) /* || c == '_' */; +} + +inline bool is_identifier (char c) +{ + return isalnum (static_cast (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 ('_')]= '_'; + + 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 (& 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 + (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 ]) + + ;; +esac + +# Check availability of hyperbolic trigonometric functions. + +AC_CHECK_DECLS([asinh, acosh, atanh], , , [#include ] ) + + +############################################################################### + + +AC_ARG_ENABLE(installed-examples, AC_HELP_STRING( + [--enable-installed-examples], + [Install the example programs [[yes]]] ), + [ + if test "_$enableval" = "_no"; then + INSTALL_EXAMPLE_PROGS=no + else + INSTALL_EXAMPLE_PROGS=yes + fi + ], + [ + INSTALL_EXAMPLE_PROGS=yes + ] +) + +AM_CONDITIONAL(INSTALL_EXAMPLE_PROGS, [test "_$INSTALL_EXAMPLE_PROGS" = _yes]) + + + + +############################################################################### + +# Generate files. +AC_OUTPUT([ + Makefile + blassic.spec +]) diff --git a/cpc.def b/cpc.def new file mode 100644 index 0000000..2f2dafd --- /dev/null +++ b/cpc.def @@ -0,0 +1,2817 @@ + + 0 + +11111111 +11000011 +11000011 +11000011 +11000011 +11000011 +11000011 +11111111 + + 1 + +11111111 +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 + + 2 + +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +11111111 + + 3 + +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 +11111111 + + 4 + +00001100 +00011000 +00110000 +01111110 +00001100 +00011000 +00110000 +00000000 + + 5 + +11111111 +11000011 +11100111 +11011011 +11011011 +11100111 +11000011 +11111111 + + 6 + +00000000 +00000001 +00000011 +00000110 +11001100 +01111000 +00110000 +00000000 + + 7 + +00111100 +01100110 +11000011 +11000011 +11111111 +00100100 +11100111 +00000000 + + 8 + +00000000 +00000000 +00110000 +01100000 +11111111 +01100000 +00110000 +00000000 + + 9 + +00000000 +00000000 +00001100 +00000110 +11111111 +00000110 +00001100 +00000000 + + 10 + +00011000 +00011000 +00011000 +00011000 +11011011 +01111110 +00111100 +00011000 + + 11 + +00011000 +00111100 +01111110 +11011011 +00011000 +00011000 +00011000 +00011000 + + 12 + +00011000 +01011010 +00111100 +10011001 +11011011 +01111110 +00111100 +00011000 + + 13 + +00000000 +00000011 +00110011 +01100011 +11111110 +01100000 +00110000 +00000000 + + 14 + +00111100 +01100110 +11111111 +11011011 +11011011 +11111111 +01100110 +00111100 + + 15 + +00111100 +01100110 +11000011 +11011011 +11011011 +11000011 +01100110 +00111100 + + 16 + +11111111 +11000011 +11000011 +11111111 +11000011 +11000011 +11000011 +11111111 + + 17 + +00111100 +01111110 +11011011 +11011011 +11011111 +11000011 +01100110 +00111100 + + 18 + +00111100 +01100110 +11000011 +11011111 +11011011 +11011011 +01111110 +00111100 + + 19 + +00111100 +01100110 +11000011 +11111011 +11011011 +11011011 +01111110 +00111100 + + 20 + +00111100 +01111110 +11011011 +11011011 +11111011 +11000011 +01100110 +00111100 + + 21 + +00000000 +00000001 +00110011 +00011110 +11001110 +01111011 +00110001 +00000000 + + 22 + +01111110 +01100110 +01100110 +01100110 +01100110 +01100110 +01100110 +11100111 + + 23 + +00000011 +00000011 +00000011 +11111111 +00000011 +00000011 +00000011 +00000000 + + 24 + +11111111 +01100110 +00111100 +00011000 +00011000 +00111100 +01100110 +11111111 + + 25 + +00011000 +00011000 +00111100 +00111100 +00111100 +00111100 +00011000 +00011000 + + 26 + +00111100 +01100110 +01100110 +00110000 +00011000 +00000000 +00011000 +00000000 + + 27 + +00111100 +01100110 +11000011 +11111111 +11000011 +11000011 +01100110 +00111100 + + 28 + +11111111 +11011011 +11011011 +11011011 +11111011 +11000011 +11000011 +11111111 + + 29 + +11111111 +11000011 +11000011 +11111011 +11011011 +11011011 +11011011 +11111111 + + 30 + +11111111 +11000011 +11000011 +11011111 +11011011 +11011011 +11011011 +11111111 + + 31 + +11111111 +11011011 +11011011 +11011011 +11011111 +11000011 +11000011 +11111111 + + 32 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 33 + +00011000 +00011000 +00011000 +00011000 +00011000 +00000000 +00011000 +00000000 + + 34 + +01101100 +01101100 +01101100 +00000000 +00000000 +00000000 +00000000 +00000000 + + 35 + +01101100 +01101100 +11111110 +01101100 +11111110 +01101100 +01101100 +00000000 + + 36 + +00011000 +00111110 +01011000 +00111100 +00011010 +01111100 +00011000 +00000000 + + 37 + +00000000 +11000110 +11001100 +00011000 +00110000 +01100110 +11000110 +00000000 + + 38 + +00111000 +01101100 +00111000 +01110110 +11011100 +11001100 +01110110 +00000000 + + 39 + +00011000 +00011000 +00110000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 40 + +00001100 +00011000 +00110000 +00110000 +00110000 +00011000 +00001100 +00000000 + + 41 + +00110000 +00011000 +00001100 +00001100 +00001100 +00011000 +00110000 +00000000 + + 42 + +00000000 +01100110 +00111100 +11111111 +00111100 +01100110 +00000000 +00000000 + + 43 + +00000000 +00011000 +00011000 +01111110 +00011000 +00011000 +00000000 +00000000 + + 44 + +00000000 +00000000 +00000000 +00000000 +00000000 +00011000 +00011000 +00110000 + + 45 + +00000000 +00000000 +00000000 +01111110 +00000000 +00000000 +00000000 +00000000 + + 46 + +00000000 +00000000 +00000000 +00000000 +00000000 +00011000 +00011000 +00000000 + + 47 + +00000110 +00001100 +00011000 +00110000 +01100000 +11000000 +10000000 +00000000 + + 48 + +01111100 +11000110 +11001110 +11010110 +11100110 +11000110 +01111100 +00000000 + + 49 + +00011000 +00111000 +00011000 +00011000 +00011000 +00011000 +01111110 +00000000 + + 50 + +00111100 +01100110 +00000110 +00111100 +01100000 +01100110 +01111110 +00000000 + + 51 + +00111100 +01100110 +00000110 +00011100 +00000110 +01100110 +00111100 +00000000 + + 52 + +00011100 +00111100 +01101100 +11001100 +11111110 +00001100 +00011110 +00000000 + + 53 + +01111110 +01100010 +01100000 +01111100 +00000110 +01100110 +00111100 +00000000 + + 54 + +00111100 +01100110 +01100000 +01111100 +01100110 +01100110 +00111100 +00000000 + + 55 + +01111110 +01100110 +00000110 +00001100 +00011000 +00011000 +00011000 +00000000 + + 56 + +00111100 +01100110 +01100110 +00111100 +01100110 +01100110 +00111100 +00000000 + + 57 + +00111100 +01100110 +01100110 +00111110 +00000110 +01100110 +00111100 +00000000 + + 58 + +00000000 +00000000 +00011000 +00011000 +00000000 +00011000 +00011000 +00000000 + + 59 + +00000000 +00000000 +00011000 +00011000 +00000000 +00011000 +00011000 +00110000 + + 60 + +00001100 +00011000 +00110000 +01100000 +00110000 +00011000 +00001100 +00000000 + + 61 + +00000000 +00000000 +01111110 +00000000 +00000000 +01111110 +00000000 +00000000 + + 62 + +01100000 +00110000 +00011000 +00001100 +00011000 +00110000 +01100000 +00000000 + + 63 + +00111100 +01100110 +01100110 +00001100 +00011000 +00000000 +00011000 +00000000 + + 64 + +01111100 +11000110 +11011110 +11011110 +11011110 +11000000 +01111100 +00000000 + + 65 + +00011000 +00111100 +01100110 +01100110 +01111110 +01100110 +01100110 +00000000 + + 66 + +11111100 +01100110 +01100110 +01111100 +01100110 +01100110 +11111100 +00000000 + + 67 + +00111100 +01100110 +11000000 +11000000 +11000000 +01100110 +00111100 +00000000 + + 68 + +11111000 +01101100 +01100110 +01100110 +01100110 +01101100 +11111000 +00000000 + + 69 + +11111110 +01100010 +01101000 +01111000 +01101000 +01100010 +11111110 +00000000 + + 70 + +11111110 +01100010 +01101000 +01111000 +01101000 +01100000 +11110000 +00000000 + + 71 + +00111100 +01100110 +11000000 +11000000 +11001110 +01100110 +00111110 +00000000 + + 72 + +01100110 +01100110 +01100110 +01111110 +01100110 +01100110 +01100110 +00000000 + + 73 + +01111110 +00011000 +00011000 +00011000 +00011000 +00011000 +01111110 +00000000 + + 74 + +00011110 +00001100 +00001100 +00001100 +11001100 +11001100 +01111000 +00000000 + + 75 + +11100110 +01100110 +01101100 +01111000 +01101100 +01100110 +11100110 +00000000 + + 76 + +11110000 +01100000 +01100000 +01100000 +01100010 +01100110 +11111110 +00000000 + + 77 + +11000110 +11101110 +11111110 +11111110 +11010110 +11000110 +11000110 +00000000 + + 78 + +11000110 +11100110 +11110110 +11011110 +11001110 +11000110 +11000110 +00000000 + + 79 + +00111000 +01101100 +11000110 +11000110 +11000110 +01101100 +00111000 +00000000 + + 80 + +11111100 +01100110 +01100110 +01111100 +01100000 +01100000 +11110000 +00000000 + + 81 + +00111000 +01101100 +11000110 +11000110 +11011010 +11001100 +01110110 +00000000 + + 82 + +11111100 +01100110 +01100110 +01111100 +01101100 +01100110 +11100110 +00000000 + + 83 + +00111100 +01100110 +01100000 +00111100 +00000110 +01100110 +00111100 +00000000 + + 84 + +01111110 +01011010 +00011000 +00011000 +00011000 +00011000 +00111100 +00000000 + + 85 + +01100110 +01100110 +01100110 +01100110 +01100110 +01100110 +00111100 +00000000 + + 86 + +01100110 +01100110 +01100110 +01100110 +01100110 +00111100 +00011000 +00000000 + + 87 + +11000110 +11000110 +11000110 +11010110 +11111110 +11101110 +11000110 +00000000 + + 88 + +11000110 +01101100 +00111000 +00111000 +01101100 +11000110 +11000110 +00000000 + + 89 + +01100110 +01100110 +01100110 +00111100 +00011000 +00011000 +00111100 +00000000 + + 90 + +11111110 +11000110 +10001100 +00011000 +00110010 +01100110 +11111110 +00000000 + + 91 + +00111100 +00110000 +00110000 +00110000 +00110000 +00110000 +00111100 +00000000 + + 92 + +11000000 +01100000 +00110000 +00011000 +00001100 +00000110 +00000010 +00000000 + + 93 + +00111100 +00001100 +00001100 +00001100 +00001100 +00001100 +00111100 +00000000 + + 94 + +00011000 +00111100 +01111110 +00011000 +00011000 +00011000 +00011000 +00000000 + + 95 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111111 + + 96 + +00110000 +00011000 +00001100 +00000000 +00000000 +00000000 +00000000 +00000000 + + 97 + +00000000 +00000000 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 98 + +11100000 +01100000 +01111100 +01100110 +01100110 +01100110 +11011100 +00000000 + + 99 + +00000000 +00000000 +00111100 +01100110 +01100000 +01100110 +00111100 +00000000 + + 100 + +00011100 +00001100 +01111100 +11001100 +11001100 +11001100 +01110110 +00000000 + + 101 + +00000000 +00000000 +00111100 +01100110 +01111110 +01100000 +00111100 +00000000 + + 102 + +00011100 +00110110 +00110000 +01111000 +00110000 +00110000 +01111000 +00000000 + + 103 + +00000000 +00000000 +00111110 +01100110 +01100110 +00111110 +00000110 +01111100 + + 104 + +11100000 +01100000 +01101100 +01110110 +01100110 +01100110 +11100110 +00000000 + + 105 + +00011000 +00000000 +00111000 +00011000 +00011000 +00011000 +00111100 +00000000 + + 106 + +00000110 +00000000 +00001110 +00000110 +00000110 +01100110 +01100110 +00111100 + + 107 + +11100000 +01100000 +01100110 +01101100 +01111000 +01101100 +11100110 +00000000 + + 108 + +00111000 +00011000 +00011000 +00011000 +00011000 +00011000 +00111100 +00000000 + + 109 + +00000000 +00000000 +01101100 +11111110 +11010110 +11010110 +11000110 +00000000 + + 110 + +00000000 +00000000 +11011100 +01100110 +01100110 +01100110 +01100110 +00000000 + + 111 + +00000000 +00000000 +00111100 +01100110 +01100110 +01100110 +00111100 +00000000 + + 112 + +00000000 +00000000 +11011100 +01100110 +01100110 +01111100 +01100000 +11110000 + + 113 + +00000000 +00000000 +01110110 +11001100 +11001100 +01111100 +00001100 +00011110 + + 114 + +00000000 +00000000 +11011100 +01110110 +01100000 +01100000 +11110000 +00000000 + + 115 + +00000000 +00000000 +00111100 +01100000 +00111100 +00000110 +01111100 +00000000 + + 116 + +00110000 +00110000 +01111100 +00110000 +00110000 +00110110 +00011100 +00000000 + + 117 + +00000000 +00000000 +01100110 +01100110 +01100110 +01100110 +00111110 +00000000 + + 118 + +00000000 +00000000 +01100110 +01100110 +01100110 +00111100 +00011000 +00000000 + + 119 + +00000000 +00000000 +11000110 +11010110 +11010110 +11111110 +01101100 +00000000 + + 120 + +00000000 +00000000 +11000110 +01101100 +00111000 +01101100 +11000110 +00000000 + + 121 + +00000000 +00000000 +01100110 +01100110 +01100110 +00111110 +00000110 +01111100 + + 122 + +00000000 +00000000 +01111110 +01001100 +00011000 +00110010 +01111110 +00000000 + + 123 + +00001110 +00011000 +00011000 +01110000 +00011000 +00011000 +00001110 +00000000 + + 124 + +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00000000 + + 125 + +01110000 +00011000 +00011000 +00001110 +00011000 +00011000 +01110000 +00000000 + + 126 + +01110110 +11011100 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 127 + +11001100 +00110011 +11001100 +00110011 +11001100 +00110011 +11001100 +00110011 + + 128 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 129 + +11110000 +11110000 +11110000 +11110000 +00000000 +00000000 +00000000 +00000000 + + 130 + +00001111 +00001111 +00001111 +00001111 +00000000 +00000000 +00000000 +00000000 + + 131 + +11111111 +11111111 +11111111 +11111111 +00000000 +00000000 +00000000 +00000000 + + 132 + +00000000 +00000000 +00000000 +00000000 +11110000 +11110000 +11110000 +11110000 + + 133 + +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 + + 134 + +00001111 +00001111 +00001111 +00001111 +11110000 +11110000 +11110000 +11110000 + + 135 + +11111111 +11111111 +11111111 +11111111 +11110000 +11110000 +11110000 +11110000 + + 136 + +00000000 +00000000 +00000000 +00000000 +00001111 +00001111 +00001111 +00001111 + + 137 + +11110000 +11110000 +11110000 +11110000 +00001111 +00001111 +00001111 +00001111 + + 138 + +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 + + 139 + +11111111 +11111111 +11111111 +11111111 +00001111 +00001111 +00001111 +00001111 + + 140 + +00000000 +00000000 +00000000 +00000000 +11111111 +11111111 +11111111 +11111111 + + 141 + +11110000 +11110000 +11110000 +11110000 +11111111 +11111111 +11111111 +11111111 + + 142 + +00001111 +00001111 +00001111 +00001111 +11111111 +11111111 +11111111 +11111111 + + 143 + +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 + + 144 + +00000000 +00000000 +00000000 +00011000 +00011000 +00000000 +00000000 +00000000 + + 145 + +00011000 +00011000 +00011000 +00011000 +00011000 +00000000 +00000000 +00000000 + + 146 + +00000000 +00000000 +00000000 +00011111 +00011111 +00000000 +00000000 +00000000 + + 147 + +00011000 +00011000 +00011000 +00011111 +00001111 +00000000 +00000000 +00000000 + + 148 + +00000000 +00000000 +00000000 +00011000 +00011000 +00011000 +00011000 +00011000 + + 149 + +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 + + 150 + +00000000 +00000000 +00000000 +00001111 +00011111 +00011000 +00011000 +00011000 + + 151 + +00011000 +00011000 +00011000 +00011111 +00011111 +00011000 +00011000 +00011000 + + 152 + +00000000 +00000000 +00000000 +11111000 +11111000 +00000000 +00000000 +00000000 + + 153 + +00011000 +00011000 +00011000 +11111000 +11110000 +00000000 +00000000 +00000000 + + 154 + +00000000 +00000000 +00000000 +11111111 +11111111 +00000000 +00000000 +00000000 + + 155 + +00011000 +00011000 +00011000 +11111111 +11111111 +00000000 +00000000 +00000000 + + 156 + +00000000 +00000000 +00000000 +11110000 +11111000 +00011000 +00011000 +00011000 + + 157 + +00011000 +00011000 +00011000 +11111000 +11111000 +00011000 +00011000 +00011000 + + 158 + +00000000 +00000000 +00000000 +11111111 +11111111 +00011000 +00011000 +00011000 + + 159 + +00011000 +00011000 +00011000 +11111111 +11111111 +00011000 +00011000 +00011000 + + 160 + +00010000 +00111000 +01101100 +11000110 +00000000 +00000000 +00000000 +00000000 + + 161 + +00001100 +00011000 +00110000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 162 + +01100110 +01100110 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 163 + +00111100 +01100110 +01100000 +11111000 +01100000 +01100110 +11111110 +00000000 + + 164 + +00111000 +01000100 +10111010 +10100010 +10111010 +01000100 +00111000 +00000000 + + 165 + +01111110 +11110100 +11110100 +01110100 +00110100 +00110100 +00110100 +00000000 + + 166 + +00011110 +00110000 +00111000 +01101100 +00111000 +00011000 +11110000 +00000000 + + 167 + +00011000 +00011000 +00001100 +00000000 +00000000 +00000000 +00000000 +00000000 + + 168 + +01000000 +11000000 +01000100 +01001100 +01010100 +00011110 +00000100 +00000000 + + 169 + +01000000 +11000000 +01001100 +01010010 +01000100 +00001000 +00011110 +00000000 + + 170 + +11100000 +00010000 +01100010 +00010110 +11101010 +00001111 +00000010 +00000000 + + 171 + +00000000 +00011000 +00011000 +01111110 +00011000 +00011000 +01111110 +00000000 + + 172 + +00011000 +00011000 +00000000 +01111110 +00000000 +00011000 +00011000 +00000000 + + 173 + +00000000 +00000000 +00000000 +01111110 +00000110 +00000110 +00000000 +00000000 + + 174 + +00011000 +00000000 +00011000 +00110000 +01100110 +01100110 +00111100 +00000000 + + 175 + +00011000 +00000000 +00011000 +00011000 +00011000 +00011000 +00011000 +00000000 + + 176 + +00000000 +00000000 +01110011 +11011110 +11001100 +11011110 +01110011 +00000000 + + 177 + +01111100 +11000110 +11000110 +11111100 +11000110 +11000110 +11111000 +11000000 + + 178 + +00000000 +01100110 +01100110 +00111100 +01100110 +01100110 +00111100 +00000000 + + 179 + +00111100 +01100000 +01100000 +00111100 +01100110 +01100110 +00111100 +00000000 + + 180 + +00000000 +00000000 +00011110 +00110000 +01111100 +00110000 +00011110 +00000000 + + 181 + +00111000 +01101100 +11000110 +11111110 +11000110 +01101100 +00111000 +00000000 + + 182 + +00000000 +11000000 +01100000 +00110000 +00111000 +01101100 +11000110 +00000000 + + 183 + +00000000 +00000000 +01100110 +01100110 +01100110 +01111100 +01100000 +01100000 + + 184 + +00000000 +00000000 +00000000 +11111110 +01101100 +01101100 +01101100 +00000000 + + 185 + +00000000 +00000000 +00000000 +01111110 +11011000 +11011000 +01110000 +00000000 + + 186 + +00000011 +00000110 +00001100 +00111100 +01100110 +00111100 +01100000 +11000000 + + 187 + +00000011 +00000110 +00001100 +01100110 +01100110 +00111100 +01100000 +11000000 + + 188 + +00000000 +11100110 +00111100 +00011000 +00111000 +01101100 +11000111 +00000000 + + 189 + +00000000 +00000000 +01100110 +11000011 +11011011 +11011011 +01111110 +00000000 + + 190 + +11111110 +11000110 +01100000 +00110000 +01100000 +11000110 +11111110 +00000000 + + 191 + +00000000 +01111100 +11000110 +11000110 +11000110 +01101100 +11101110 +00000000 + + 192 + +00011000 +00110000 +01100000 +11000000 +10000000 +00000000 +00000000 +00000000 + + 193 + +00011000 +00001100 +00000110 +00000011 +00000001 +00000000 +00000000 +00000000 + + 194 + +00000000 +00000000 +00000000 +00000001 +00000011 +00000110 +00001100 +00011000 + + 195 + +00000000 +00000000 +00000000 +10000000 +11000000 +01100000 +00110000 +00011000 + + 196 + +00011000 +00111100 +01100110 +11000011 +10000001 +00000000 +00000000 +00000000 + + 197 + +00011000 +00001100 +00000110 +00000011 +00000011 +00000110 +00001100 +00011000 + + 198 + +00000000 +00000000 +00000000 +10000001 +11000011 +01100110 +00111100 +00011000 + + 199 + +00011000 +00110000 +01100000 +11000000 +11000000 +01100000 +00110000 +00011000 + + 200 + +00011000 +00110000 +01100000 +11000001 +10000011 +00000110 +00001100 +00011000 + + 201 + +00011000 +00001100 +00000110 +10000011 +11000001 +01100000 +00110000 +00011000 + + 202 + +00011000 +00111100 +01100110 +11000011 +11000011 +01100110 +00111100 +00011000 + + 203 + +11000011 +11100111 +01111110 +00111100 +00111100 +01111110 +11100111 +11000011 + + 204 + +00000011 +00000111 +00001110 +00011100 +00111000 +01110000 +11100000 +11000000 + + 205 + +11000000 +11100000 +01110000 +00111000 +00011100 +00001110 +00000111 +00000011 + + 206 + +11001100 +11001100 +00110011 +00110011 +11001100 +11001100 +00110011 +00110011 + + 207 + +10101010 +01010101 +10101010 +01010101 +10101010 +01010101 +10101010 +01010101 + + 208 + +11111111 +11111111 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 209 + +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 + + 210 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111111 +11111111 + + 211 + +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 + + 212 + +11111111 +11111110 +11111100 +11111000 +11110000 +11100000 +11000000 +10000000 + + 213 + +11111111 +01111111 +00111111 +00011111 +00001111 +00000111 +00000011 +00000001 + + 214 + +00000001 +00000011 +00000111 +00001111 +00011111 +00111111 +01111111 +11111111 + + 215 + +10000000 +11000000 +11100000 +11110000 +11111000 +11111100 +11111110 +11111111 + + 216 + +10101010 +01010101 +10101010 +01010101 +00000000 +00000000 +00000000 +00000000 + + 217 + +00001010 +00000101 +00001010 +00000101 +00001010 +00000101 +00001010 +00000101 + + 218 + +00000000 +00000000 +00000000 +00000000 +10101010 +01010101 +10101010 +01010101 + + 219 + +10100000 +01010000 +10100000 +01010000 +10100000 +01010000 +10100000 +01010000 + + 220 + +10101010 +01010100 +10101000 +01010000 +10100000 +01000000 +10000000 +00000000 + + 221 + +10101010 +01010101 +00101010 +00010101 +00001010 +00000101 +00000010 +00000001 + + 222 + +00000001 +00000010 +00000101 +00001010 +00010101 +00101010 +01010101 +10101010 + + 223 + +00000000 +10000000 +01000000 +10100000 +01010000 +10101000 +01010100 +10101010 + + 224 + +01111110 +11111111 +10011001 +11111111 +10111101 +11000011 +11111111 +01111110 + + 225 + +01111110 +11111111 +10011001 +11111111 +11000011 +10111101 +11111111 +01111110 + + 226 + +00111000 +00111000 +11111110 +11111110 +11111110 +00010000 +00111000 +00000000 + + 227 + +00010000 +00111000 +01111100 +11111110 +01111100 +00111000 +00010000 +00000000 + + 228 + +01101100 +11111110 +11111110 +11111110 +01111100 +00111000 +00010000 +00000000 + + 229 + +00010000 +00111000 +01111100 +11111110 +11111110 +00010000 +00111000 +00000000 + + 230 + +00000000 +00111100 +01100110 +11000011 +11000011 +01100110 +00111100 +00000000 + + 231 + +00000000 +00111100 +01111110 +11111111 +11111111 +01111110 +00111100 +00000000 + + 232 + +00000000 +01111110 +01100110 +01100110 +01100110 +01100110 +01111110 +00000000 + + 233 + +00000000 +01111110 +01111110 +01111110 +01111110 +01111110 +01111110 +00000000 + + 234 + +00001111 +00000111 +00001101 +01111000 +11001100 +11001100 +11001100 +01111000 + + 235 + +00111100 +01100110 +01100110 +01100110 +00111100 +00011000 +01111110 +00011000 + + 236 + +00001100 +00001100 +00001100 +00001100 +00001100 +00111100 +01111100 +00111000 + + 237 + +00011000 +00011100 +00011110 +00011011 +00011000 +01111000 +11111000 +01110000 + + 238 + +10011001 +01011010 +00100100 +11000011 +11000011 +00100100 +01011010 +10011001 + + 239 + +00010000 +00111000 +00111000 +00111000 +00111000 +00111000 +01111100 +11010110 + + 240 + +00011000 +00111100 +01111110 +11111111 +00011000 +00011000 +00011000 +00011000 + + 241 + +00011000 +00011000 +00011000 +00011000 +11111111 +01111110 +00111100 +00011000 + + 242 + +00010000 +00110000 +01110000 +11111111 +11111111 +01110000 +00110000 +00010000 + + 243 + +00001000 +00001100 +00001110 +11111111 +11111111 +00001110 +00001100 +00001000 + + 244 + +00000000 +00000000 +00011000 +00111100 +01111110 +11111111 +11111111 +00000000 + + 245 + +00000000 +00000000 +11111111 +11111111 +01111110 +00111100 +00011000 +00000000 + + 246 + +10000000 +11100000 +11111000 +11111110 +11111000 +11100000 +10000000 +00000000 + + 247 + +00000010 +00001110 +00111110 +11111110 +00111110 +00001110 +00000010 +00000000 + + 248 + +00111000 +00111000 +10010010 +01111100 +00010000 +00101000 +00101000 +00101000 + + 249 + +00111000 +00111000 +00010000 +11111110 +00010000 +00101000 +01000100 +10000010 + + 250 + +00111000 +00111000 +00010010 +01111100 +10010000 +00101000 +00100100 +00100010 + + 251 + +00111000 +00111000 +10010000 +01111100 +00010010 +00101000 +01001000 +10001000 + + 252 + +00000000 +00111100 +00011000 +00111100 +00111100 +00111100 +00011000 +00000000 + + 253 + +00111100 +11111111 +11111111 +00011000 +00001100 +00011000 +00110000 +00011000 + + 254 + +00011000 +00111100 +01111110 +00011000 +00011000 +01111110 +00111100 +00011000 + + 255 + +00000000 +00100100 +01100110 +11111111 +01100110 +00100100 +00000000 +00000000 + diff --git a/cursor.cpp b/cursor.cpp new file mode 100644 index 0000000..1dde81a --- /dev/null +++ b/cursor.cpp @@ -0,0 +1,1477 @@ +// cursor.cpp +// Revision 24-apr-2009 + +#include "cursor.h" + +#include "blassic.h" + +#include "key.h" +#include "util.h" +#include "error.h" +#include "showerror.h" + +#include "trace.h" + +#include +using std::cerr; +using std::endl; + +#include +#include +#include + +#include + +#ifdef BLASSIC_USE_WINDOWS + + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined HAVE_IO_H || ! defined BLASSIC_CONFIG +#include +#endif + + +#else + + +#include +#include +#include +#include +#include +#define ASSERT assert + +#include + +// 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 + +#elif defined BLASSIC_CONFIG_USE_CURSES + +#include + +#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 +#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 +#include + +// 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 +#include + +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 (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 (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 ::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 kname_t; + kname_t kname; + std::map 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 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 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 + + +namespace cursor { + +void initconsole (); +void quitconsole (); + +size_t getwidth (); + +void cursorvisible (); +void cursorinvisible (); +void showcursor (); +void hidecursor (); + +void cls (); + +//void locate (int row, int col); +void gotoxy (int x, int y); +int getcursorx (); +void movecharforward (); +void movecharback (); +void movecharforward (size_t n); +void movecharback (size_t n); +void movecharup (); +void movechardown (); +void movecharup (size_t n); +void movechardown (size_t n); +void savecursorpos (); +void restorecursorpos (); + +void textcolor (int color); +void textbackground (int color); + +std::string inkey (); +std::string getkey (); +bool pollin (); + +void clean_input (); + +void ring (); + +void set_title (const std::string & title); + +} // namespace cursor + +#endif + +// Fin de cursor.h diff --git a/default.def b/default.def new file mode 100644 index 0000000..ec487e1 --- /dev/null +++ b/default.def @@ -0,0 +1,2827 @@ + 0 + +01111110 +11000011 +10011001 +11110011 +11100111 +11111111 +11100111 +01111110 + + 1 + +00000000 +01110110 +11011100 +00000000 +01110110 +11011100 +00000000 +00000000 + + 2 + +01110110 +11011000 +11011000 +11011100 +11011000 +11011000 +01110110 +00000000 + + 3 + +00000000 +00000000 +01101110 +11011000 +11011110 +11011000 +01101110 +00000000 + + 4 + +00010000 +00111000 +01111100 +11111110 +01111100 +00111000 +00010000 +00000000 + + 5 + +10100000 +10100000 +11100000 +10101110 +10100100 +00000100 +00000100 +00000100 + + 6 + +11100000 +10000000 +11000000 +10001110 +10001000 +00001100 +00001000 +00001000 + + 7 + +01100000 +10000000 +10000000 +10001100 +01101010 +00001100 +00001010 +00001010 + + 8 + +10000000 +10000000 +10000000 +10001110 +11101000 +00001100 +00001000 +00001000 + + 9 + +00100010 +10001000 +00100010 +10001000 +00100010 +10001000 +00100010 +10001000 + + 10 + +01010101 +10101010 +01010101 +10101010 +01010101 +10101010 +01010101 +10101010 + + 11 + +11101110 +10111011 +11101110 +10111011 +11101110 +10111011 +11101110 +10111011 + + 12 + +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 + + 13 + +00000000 +00000000 +00000000 +00000000 +11111111 +11111111 +11111111 +11111111 + + 14 + +11111111 +11111111 +11111111 +11111111 +00000000 +00000000 +00000000 +00000000 + + 15 + +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 + + 16 + +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 + + 17 + +10010000 +11010000 +11110000 +10110100 +10010100 +00000100 +00000100 +00000111 + + 18 + +10100000 +10100000 +10100000 +10101110 +01000100 +00000100 +00000100 +00000100 + + 19 + +00011000 +00110000 +01100000 +00110000 +00011000 +00000000 +11111100 +00000000 + + 20 + +01100000 +00110000 +00011000 +00110000 +01100000 +00000000 +11111100 +00000000 + + 21 + +00000000 +00001100 +11111110 +00011000 +00110000 +11111110 +01100000 +00000000 + + 22 + +00000010 +00001110 +00111110 +11111110 +00111110 +00001110 +00000010 +00000000 + + 23 + +10000000 +11100000 +11111000 +11111110 +11111000 +11100000 +10000000 +00000000 + + 24 + +00011000 +00111100 +01111110 +00011000 +00011000 +00011000 +00011000 +00000000 + + 25 + +00011000 +00011000 +00011000 +00011000 +01111110 +00111100 +00011000 +00000000 + + 26 + +00000000 +00011000 +00001100 +11111110 +00001100 +00011000 +00000000 +00000000 + + 27 + +00000000 +00110000 +01100000 +11111110 +01100000 +00110000 +00000000 +00000000 + + 28 + +00011000 +00111100 +01111110 +00011000 +00011000 +01111110 +00111100 +00011000 + + 29 + +00000000 +00100100 +01100110 +11111111 +01100110 +00100100 +00000000 +00000000 + + 30 + +00000110 +00000110 +00110110 +01100110 +11111110 +01100000 +00110000 +00000000 + + 31 + +00000000 +11000000 +01111100 +01101110 +01101100 +01101100 +01101100 +00000000 + + 32 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 33 + +00110000 +01111000 +01111000 +00110000 +00110000 +00000000 +00110000 +00000000 + + 34 + +01101100 +01101100 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 35 + +01101100 +01101100 +11111110 +01101100 +11111110 +01101100 +01101100 +00000000 + + 36 + +00110000 +01111100 +11000000 +01111000 +00001100 +11111000 +00110000 +00000000 + + 37 + +00000000 +11000110 +11001100 +00011000 +00110000 +01100110 +11000110 +00000000 + + 38 + +00111000 +01101100 +00111000 +01110110 +11011100 +11001100 +01110110 +00000000 + + 39 + +00110000 +00110000 +01100000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 40 + +00011000 +00110000 +01100000 +01100000 +01100000 +00110000 +00011000 +00000000 + + 41 + +01100000 +00110000 +00011000 +00011000 +00011000 +00110000 +01100000 +00000000 + + 42 + +00000000 +01100110 +00111100 +11111111 +00111100 +01100110 +00000000 +00000000 + + 43 + +00000000 +00110000 +00110000 +11111100 +00110000 +00110000 +00000000 +00000000 + + 44 + +00000000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +01100000 + + 45 + +00000000 +00000000 +00000000 +11111100 +00000000 +00000000 +00000000 +00000000 + + 46 + +00000000 +00000000 +00000000 +00000000 +00000000 +00110000 +00110000 +00000000 + + 47 + +00000000 +00000110 +00001100 +00011000 +00110000 +01100000 +11000000 +00000000 + + 48 + +01111100 +11000110 +11000110 +11010110 +11000110 +11000110 +01111100 +00000000 + + 49 + +00110000 +01110000 +00110000 +00110000 +00110000 +00110000 +11111100 +00000000 + + 50 + +01111000 +11001100 +00001100 +00111000 +01100000 +11001100 +11111100 +00000000 + + 51 + +01111000 +11001100 +00001100 +00111000 +00001100 +11001100 +01111000 +00000000 + + 52 + +00011100 +00111100 +01101100 +11001100 +11111110 +00001100 +00011110 +00000000 + + 53 + +11111100 +11000000 +11111000 +00001100 +00001100 +11001100 +01111000 +00000000 + + 54 + +00111000 +01100000 +11000000 +11111000 +11001100 +11001100 +01111000 +00000000 + + 55 + +11111100 +11001100 +00001100 +00011000 +00110000 +00110000 +00110000 +00000000 + + 56 + +01111000 +11001100 +11001100 +01111000 +11001100 +11001100 +01111000 +00000000 + + 57 + +01111000 +11001100 +11001100 +01111100 +00001100 +00011000 +01110000 +00000000 + + 58 + +00000000 +00110000 +00110000 +00000000 +00000000 +00110000 +00110000 +00000000 + + 59 + +00000000 +00110000 +00110000 +00000000 +00000000 +00110000 +00110000 +01100000 + + 60 + +00011000 +00110000 +01100000 +11000000 +01100000 +00110000 +00011000 +00000000 + + 61 + +00000000 +00000000 +11111100 +00000000 +00000000 +11111100 +00000000 +00000000 + + 62 + +01100000 +00110000 +00011000 +00001100 +00011000 +00110000 +01100000 +00000000 + + 63 + +01111000 +11001100 +00001100 +00011000 +00110000 +00000000 +00110000 +00000000 + + 64 + +01111100 +11000110 +11011110 +11011110 +11011110 +11000000 +01111000 +00000000 + + 65 + +00110000 +01111000 +11001100 +11001100 +11111100 +11001100 +11001100 +00000000 + + 66 + +11111100 +01100110 +01100110 +01111100 +01100110 +01100110 +11111100 +00000000 + + 67 + +00111100 +01100110 +11000000 +11000000 +11000000 +01100110 +00111100 +00000000 + + 68 + +11111000 +01101100 +01100110 +01100110 +01100110 +01101100 +11111000 +00000000 + + 69 + +11111110 +01100010 +01101000 +01111000 +01101000 +01100010 +11111110 +00000000 + + 70 + +11111110 +01100010 +01101000 +01111000 +01101000 +01100000 +11110000 +00000000 + + 71 + +00111100 +01100110 +11000000 +11000000 +11001110 +01100110 +00111110 +00000000 + + 72 + +11001100 +11001100 +11001100 +11111100 +11001100 +11001100 +11001100 +00000000 + + 73 + +01111000 +00110000 +00110000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 74 + +00011110 +00001100 +00001100 +00001100 +11001100 +11001100 +01111000 +00000000 + + 75 + +11100110 +01100110 +01101100 +01111000 +01101100 +01100110 +11100110 +00000000 + + 76 + +11110000 +01100000 +01100000 +01100000 +01100010 +01100110 +11111110 +00000000 + + 77 + +11000110 +11101110 +11111110 +11111110 +11010110 +11000110 +11000110 +00000000 + + 78 + +11000110 +11100110 +11110110 +11011110 +11001110 +11000110 +11000110 +00000000 + + 79 + +00111000 +01101100 +11000110 +11000110 +11000110 +01101100 +00111000 +00000000 + + 80 + +11111100 +01100110 +01100110 +01111100 +01100000 +01100000 +11110000 +00000000 + + 81 + +01111000 +11001100 +11001100 +11001100 +11011100 +01111000 +00011100 +00000000 + + 82 + +11111100 +01100110 +01100110 +01111100 +01101100 +01100110 +11100110 +00000000 + + 83 + +01111000 +11001100 +11100000 +01110000 +00011100 +11001100 +01111000 +00000000 + + 84 + +11111100 +10110100 +00110000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 85 + +11001100 +11001100 +11001100 +11001100 +11001100 +11001100 +01111000 +00000000 + + 86 + +11001100 +11001100 +11001100 +11001100 +11001100 +01111000 +00110000 +00000000 + + 87 + +11000110 +11000110 +11000110 +11010110 +11111110 +11101110 +11000110 +00000000 + + 88 + +11000110 +11000110 +01101100 +00111000 +01101100 +11000110 +11000110 +00000000 + + 89 + +11001100 +11001100 +11001100 +01111000 +00110000 +00110000 +01111000 +00000000 + + 90 + +11111110 +11000110 +00001100 +00011000 +00110000 +01100110 +11111110 +00000000 + + 91 + +01111000 +01100000 +01100000 +01100000 +01100000 +01100000 +01111000 +00000000 + + 92 + +00000000 +11000000 +01100000 +00110000 +00011000 +00001100 +00000110 +00000000 + + 93 + +01111000 +00011000 +00011000 +00011000 +00011000 +00011000 +01111000 +00000000 + + 94 + +00011000 +00111100 +01100110 +00000000 +00000000 +00000000 +00000000 +00000000 + + 95 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111111 + + 96 + +00110000 +00110000 +00011000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 97 + +00000000 +00000000 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 98 + +11100000 +01100000 +01100000 +01111100 +01100110 +01100110 +11011100 +00000000 + + 99 + +00000000 +00000000 +01111000 +11001100 +11000000 +11001100 +01111000 +00000000 + + 100 + +00011100 +00001100 +00001100 +01111100 +11001100 +11001100 +01110110 +00000000 + + 101 + +00000000 +00000000 +01111000 +11001100 +11111100 +11000000 +01111000 +00000000 + + 102 + +00111000 +01101100 +01100000 +11110000 +01100000 +01100000 +11110000 +00000000 + + 103 + +00000000 +00000000 +01110110 +11001100 +11001100 +01111100 +00001100 +11111000 + + 104 + +11100000 +01100000 +01101100 +01110110 +01100110 +01100110 +11100110 +00000000 + + 105 + +00110000 +00000000 +01110000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 106 + +00001100 +00000000 +00001100 +00001100 +00001100 +11001100 +11001100 +01111000 + + 107 + +11100000 +01100000 +01100110 +01101100 +01111000 +01101100 +11100110 +00000000 + + 108 + +01110000 +00110000 +00110000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 109 + +00000000 +00000000 +11001100 +11111110 +11111110 +11010110 +11000110 +00000000 + + 110 + +00000000 +00000000 +11111000 +11001100 +11001100 +11001100 +11001100 +00000000 + + 111 + +00000000 +00000000 +01111000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 112 + +00000000 +00000000 +11011100 +01100110 +01100110 +01111100 +01100000 +11110000 + + 113 + +00000000 +00000000 +01110110 +11001100 +11001100 +01111100 +00001100 +00011110 + + 114 + +00000000 +00000000 +11011100 +01110110 +01100110 +01100000 +11110000 +00000000 + + 115 + +00000000 +00000000 +01111100 +11000000 +01111000 +00001100 +11111000 +00000000 + + 116 + +00010000 +00110000 +01111100 +00110000 +00110000 +00110100 +00011000 +00000000 + + 117 + +00000000 +00000000 +11001100 +11001100 +11001100 +11001100 +01110110 +00000000 + + 118 + +00000000 +00000000 +11001100 +11001100 +11001100 +01111000 +00110000 +00000000 + + 119 + +00000000 +00000000 +11000110 +11010110 +11111110 +11111110 +01101100 +00000000 + + 120 + +00000000 +00000000 +11000110 +01101100 +00111000 +01101100 +11000110 +00000000 + + 121 + +00000000 +00000000 +11001100 +11001100 +11001100 +01111100 +00001100 +11111000 + + 122 + +00000000 +00000000 +11111100 +10011000 +00110000 +01100100 +11111100 +00000000 + + 123 + +00011100 +00110000 +00110000 +11100000 +00110000 +00110000 +00011100 +00000000 + + 124 + +00110000 +00110000 +00110000 +00110000 +00110000 +00110000 +00110000 +00000000 + + 125 + +11100000 +00110000 +00110000 +00011100 +00110000 +00110000 +11100000 +00000000 + + 126 + +01110110 +11011100 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 127 + +11001100 +00000000 +11001100 +11001100 +01111000 +00110000 +01111000 +00000000 + + 128 + +# Changed this to allow the use of the euro in windows. + +#00000000 +#11111111 +#00000000 +#00000000 +#00000000 +#00000000 +#00000000 +#00000000 + +00111000 +01100100 +11110000 +01100000 +11110000 +01100100 +00111000 +00000000 + + 129 + +00011000 +00011000 +00011000 +00011000 +00000000 +00000000 +00000000 +00000000 + + 130 + +00000000 +00000000 +00000000 +00011111 +00000000 +00000000 +00000000 +00000000 + + 131 + +00011000 +00011000 +00011000 +00011111 +00000000 +00000000 +00000000 +00000000 + + 132 + +00000000 +00000000 +00000000 +00000000 +00011000 +00011000 +00011000 +00011000 + + 133 + +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 +00011000 + + 134 + +00000000 +00000000 +00000000 +00011111 +00011000 +00011000 +00011000 +00011000 + + 135 + +00011000 +00011000 +00011000 +00011111 +00011000 +00011000 +00011000 +00011000 + + 136 + +00000000 +00000000 +00000000 +11111000 +00000000 +00000000 +00000000 +00000000 + + 137 + +00011000 +00011000 +00011000 +11111000 +00000000 +00000000 +00000000 +00000000 + + 138 + +00000000 +00000000 +00000000 +11111111 +00000000 +00000000 +00000000 +00000000 + + 139 + +00011000 +00011000 +00011000 +11111111 +00000000 +00000000 +00000000 +00000000 + + 140 + +00000000 +00000000 +00000000 +11111000 +00011000 +00011000 +00011000 +00011000 + + 141 + +00011000 +00011000 +00011000 +11111000 +00011000 +00011000 +00011000 +00011000 + + 142 + +00000000 +00000000 +00000000 +11111111 +00011000 +00011000 +00011000 +00011000 + + 143 + +00011000 +00011000 +00011000 +11111111 +00011000 +00011000 +00011000 +00011000 + + 144 + +00000000 +00000000 +00000000 +00000000 +00000000 +11111111 +00000000 +00000000 + + 145 + +01101100 +01101100 +01101100 +01101100 +01111100 +00000000 +00000000 +00000000 + + 146 + +00000000 +00000000 +01111111 +01100000 +01111111 +00000000 +00000000 +00000000 + + 147 + +01101100 +01101100 +01101111 +01100000 +01111111 +00000000 +00000000 +00000000 + + 148 + +00000000 +00000000 +01111100 +01101100 +01101100 +01101100 +01101100 +01101100 + + 149 + +01101100 +01101100 +01101100 +01101100 +01101100 +01101100 +01101100 +01101100 + + 150 + +00000000 +00000000 +01111111 +01100000 +01101111 +01101100 +01101100 +01101100 + + 151 + +01101100 +01101100 +01101111 +01100000 +01101111 +01101100 +01101100 +01101100 + + 152 + +00000000 +00000000 +11111100 +00001100 +11111100 +00000000 +00000000 +00000000 + + 153 + +01101100 +01101100 +11101100 +00001100 +11111100 +00000000 +00000000 +00000000 + + 154 + +00000000 +00000000 +11111111 +00000000 +11111111 +00000000 +00000000 +00000000 + + 155 + +01101100 +01101100 +11101111 +00000000 +11111111 +00000000 +00000000 +00000000 + + 156 + +00000000 +00000000 +11111100 +00001100 +11101100 +01101100 +01101100 +01101100 + + 157 + +01101100 +01101100 +11101100 +00001100 +11101100 +01101100 +01101100 +01101100 + + 158 + +00000000 +00000000 +11111111 +00000000 +11101111 +01101100 +01101100 +01101100 + + 159 + +01101100 +01101100 +11101111 +00000000 +11101111 +01101100 +01101100 +01101100 + + 160 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11000110 +11111110 + + 161 + +00000000 +00110000 +00000000 +00110000 +00110000 +01111000 +01111000 +00110000 + + 162 + +00110000 +01111000 +11001100 +11000000 +11001100 +01111000 +00110000 +00000000 + + 163 + +00111000 +01101100 +01100100 +11110000 +01100000 +11100110 +11111100 +00000000 + + 164 + +00111000 +01100100 +11110000 +01100000 +11110000 +01100100 +00111000 +00000000 + + 165 + +11001100 +11001100 +01111000 +11111100 +00110000 +11111100 +00110000 +00110000 + + 166 + +01001000 +01111000 +10000100 +01100000 +00011000 +10000100 +01111000 +00000000 + + 167 + +00111110 +01100001 +00111100 +01100110 +01100110 +00111100 +10000110 +01111100 + + 168 + +01111000 +00000000 +01111100 +11000000 +01111000 +00001100 +11111000 +00000000 + + 169 + +01111100 +10000010 +10011010 +10100010 +10100010 +10011010 +10000010 +01111100 + + 170 + +00111100 +01101100 +00111110 +00000000 +01111110 +00000000 +00000000 +00000000 + + 171 + +00000000 +00110011 +01100110 +11001100 +01100110 +00110011 +00000000 +00000000 + + 172 + +00000000 +00000000 +00000000 +11111100 +00001100 +00001100 +00000000 +00000000 + + 173 + +00000000 +00000000 +00000000 +01111100 +00000000 +00000000 +00000000 +00000000 + + 174 + +01111100 +10000010 +10110010 +10101010 +10110010 +10101010 +10000010 +01111100 + + 175 + +11111111 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 176 + +01110000 +11011000 +01110000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 177 + +00110000 +00110000 +11111100 +00110000 +00110000 +00000000 +11111100 +00000000 + + 178 + +01110000 +11011000 +00110000 +01100000 +11111000 +00000000 +00000000 +00000000 + + 179 + +01110000 +11011000 +00110000 +11011000 +01110000 +00000000 +00000000 +00000000 + + 180 + +01101100 +11111110 +11001100 +00011000 +00110000 +01100110 +11111110 +00000000 + + 181 + +00000000 +00000000 +11001100 +11001100 +11001100 +11001100 +11110110 +11000000 + + 182 + +01111111 +11011011 +01111011 +00111011 +00011011 +00011011 +00011011 +00000000 + + 183 + +00000000 +00000000 +00000000 +00011000 +00011000 +00000000 +00000000 +00000000 + + 184 + +01111000 +00000000 +11111100 +10011000 +00110000 +01100100 +11111100 +00000000 + + 185 + +01100000 +11100000 +01100000 +01100000 +11110000 +00000000 +00000000 +00000000 + + 186 + +00111000 +01101100 +00111000 +00000000 +01111100 +00000000 +00000000 +00000000 + + 187 + +00000000 +11001100 +01100110 +00110011 +01100110 +11001100 +00000000 +00000000 + + 188 + +01111110 +11011000 +11011000 +11011100 +11011000 +11011000 +01111110 +00000000 + + 189 + +00000000 +00000000 +01111110 +11011011 +11011110 +11011000 +01111110 +00000000 + + 190 + +11001100 +00000000 +11001100 +01111000 +00110000 +00110000 +01111000 +00000000 + + 191 + +00000000 +00011000 +00000000 +00011000 +00110000 +01100000 +01100110 +00111100 + + 192 + +01100000 +00110000 +01111000 +11001100 +11111100 +11001100 +11001100 +00000000 + + 193 + +00011000 +00110000 +01111000 +11001100 +11111100 +11001100 +11001100 +00000000 + + 194 + +01111000 +10000100 +01111000 +11001100 +11111100 +11001100 +11001100 +00000000 + + 195 + +01110110 +11011100 +01111000 +11001100 +11111100 +11001100 +11001100 +00000000 + + 196 + +11001100 +00000000 +01111000 +11001100 +11111100 +11001100 +11001100 +00000000 + + 197 + +00110000 +01001000 +01111000 +11001100 +11111100 +11001100 +11001100 +00000000 + + 198 + +00111110 +01111000 +11011000 +11111100 +11011000 +11011000 +11011110 +00000000 + + 199 + +00111100 +01100110 +11000000 +11000000 +01100110 +00111100 +00001100 +01111000 + + 200 + +01100000 +00110000 +11111110 +01100010 +01111000 +01100010 +11111110 +00000000 + + 201 + +00001100 +00011000 +11111110 +01100010 +01111000 +01100010 +11111110 +00000000 + + 202 + +00111000 +01101100 +11111110 +01100010 +01111000 +01100010 +11111110 +00000000 + + 203 + +01101100 +00000000 +11111110 +01100010 +01111000 +01100010 +11111110 +00000000 + + 204 + +01100000 +00110000 +01111000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 205 + +00011000 +00110000 +01111000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 206 + +01111000 +11001100 +01111000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 207 + +11001100 +00000000 +01111000 +00110000 +00110000 +00110000 +01111000 +00000000 + + 208 + +11111000 +01101100 +01100110 +11110110 +01100110 +01101100 +11111000 +00000000 + + 209 + +01110110 +11011100 +11100110 +11110110 +11011110 +11001110 +11000110 +00000000 + + 210 + +01100000 +00110000 +01111000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 211 + +00011000 +00110000 +01111000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 212 + +01111000 +11001100 +01111000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 213 + +01110110 +11011100 +01111000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 214 + +11001100 +00000000 +01111000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 215 + +00000000 +01101100 +00111000 +00111000 +01101100 +00000000 +00000000 +00000000 + + 216 + +00111110 +01101100 +11011110 +11010110 +11110110 +01101100 +11111000 +00000000 + + 217 + +01100000 +00110000 +11001100 +11001100 +11001100 +11001100 +01111000 +00000000 + + 218 + +00011000 +00110000 +11001100 +11001100 +11001100 +11001100 +01111000 +00000000 + + 219 + +01111000 +11001100 +00000000 +11001100 +11001100 +11001100 +01111000 +00000000 + + 220 + +11001100 +00000000 +11001100 +11001100 +11001100 +11001100 +01111000 +00000000 + + 221 + +00011000 +00110000 +11001100 +11001100 +01111000 +00110000 +01111000 +00000000 + + 222 + +11110000 +01100000 +01111100 +01100110 +01111100 +01100000 +11110000 +00000000 + + 223 + +01111100 +11000110 +11000110 +11001100 +11000110 +11010110 +11011100 +10000000 + + 224 + +01100000 +00110000 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 225 + +00011000 +00110000 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 226 + +01111000 +10000100 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 227 + +01110110 +11011100 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 228 + +01101100 +00000000 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 229 + +00111000 +01101100 +01111000 +00001100 +01111100 +11001100 +01110110 +00000000 + + 230 + +00000000 +00000000 +01111110 +00011011 +01111110 +11011000 +01111110 +00000000 + + 231 + +00000000 +01111000 +11001100 +11000000 +11001100 +01111000 +00011000 +01110000 + + 232 + +01100000 +00110000 +01111000 +11001100 +11111100 +11000000 +01111000 +00000000 + + 233 + +00001100 +00011000 +01111000 +11001100 +11111100 +11000000 +01111000 +00000000 + + 234 + +01111000 +10000100 +01111000 +11001100 +11111100 +11000000 +01111000 +00000000 + + 235 + +11001100 +00000000 +01111000 +11001100 +11111100 +11000000 +01111000 +00000000 + + 236 + +01100000 +00110000 +00000000 +01110000 +00110000 +00110000 +01111000 +00000000 + + 237 + +00011000 +00110000 +00000000 +01110000 +00110000 +00110000 +01111000 +00000000 + + 238 + +01110000 +11011000 +00000000 +01110000 +00110000 +00110000 +01111000 +00000000 + + 239 + +00000000 +11011000 +00000000 +01110000 +00110000 +00110000 +01111000 +00000000 + + 240 + +01111000 +01110000 +00011000 +01111100 +11001100 +11001100 +01111000 +00000000 + + 241 + +01110110 +11011100 +11111000 +11001100 +11001100 +11001100 +11001100 +00000000 + + 242 + +01100000 +00110000 +00000000 +01111000 +11001100 +11001100 +01111000 +00000000 + + 243 + +00011000 +00110000 +00000000 +01111000 +11001100 +11001100 +01111000 +00000000 + + 244 + +01111000 +11001100 +00000000 +01111000 +11001100 +11001100 +01111000 +00000000 + + 245 + +01110110 +11011100 +00000000 +01111000 +11001100 +11001100 +01111000 +00000000 + + 246 + +00000000 +11001100 +00000000 +01111000 +11001100 +11001100 +01111000 +00000000 + + 247 + +00000000 +00110000 +00000000 +11111100 +00000000 +00110000 +00000000 +00000000 + + 248 + +00000000 +00000000 +01111100 +11011100 +11111100 +11101100 +11111000 +00000000 + + 249 + +01100000 +00110000 +11001100 +11001100 +11001100 +11001100 +01110110 +00000000 + + 250 + +00011000 +00110000 +11001100 +11001100 +11001100 +11001100 +01110110 +00000000 + + 251 + +01111000 +11001100 +00000000 +11001100 +11001100 +11001100 +01110110 +00000000 + + 252 + +11001100 +00000000 +11001100 +11001100 +11001100 +11001100 +01110110 +00000000 + + 253 + +00011000 +00110000 +11001100 +11001100 +11001100 +01111100 +00001100 +11111000 + + 254 + +11110000 +01100000 +01111000 +01101100 +01101100 +01111000 +01100000 +11110000 + + 255 + +11001100 +00000000 +11001100 +11001100 +11001100 +01111100 +00001100 +11111000 + diff --git a/dim.cpp b/dim.cpp new file mode 100644 index 0000000..5e2bedf --- /dev/null +++ b/dim.cpp @@ -0,0 +1,64 @@ +// dim.cpp +// Revision 14-oct-2003 + +#include "dim.h" +#include "error.h" + +#include + +class dim_calc { +public: + dim_calc () : r (1) { } + void operator () (const size_t n) + { r*= n + 1; } + size_t value () { return r; } +private: + size_t r; +}; + +size_t Dimension::elements () const +{ + dim_calc r= std::for_each (dim.begin (), dim.end (), dim_calc () ); + return r.value (); +} + +size_t Dimension::evalpos (const Dimension & d) const +{ + size_t n= size (); + if (d.size () != n) + throw ErrBadSubscript; + size_t pos= d [0]; + if (pos > dim [0]) + throw ErrBadSubscript; + for (size_t i= 1; i < n; ++i) + { + if (d [i] > dim [i] ) + throw ErrBadSubscript; + pos*= dim [i] + 1; + pos+= d [i]; + } + return pos; +} + +// Only for debug. + +std::ostream & operator << (std::ostream & os, const Dimension & d) +{ + size_t s= d.size (); + if (s == 0) + os << "(empty)"; + else + { + os << '('; + for (size_t i= 0; i < s; ++i) + { + os << d [i]; + if (i < s -1) + os << ", "; + } + os << ')'; + } + return os; +} + +// Fin de dim.cpp diff --git a/dim.h b/dim.h new file mode 100644 index 0000000..c02dcb8 --- /dev/null +++ b/dim.h @@ -0,0 +1,29 @@ +#ifndef INCLUDE_BLASSIC_DIM_H +#define INCLUDE_BLASSIC_DIM_H + +// dim.h +// Revision 6-jul-2004 + +#include +#include +#include + +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 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 +#include + +// 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 +#include +#include +#include +#include + +#else + +#include +#include +#include + +#ifdef __MINGW32__ +#include +#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 (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 (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 + +#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 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 +#include +using std::cerr; +using std::endl; + + +#if (defined __unix__ || defined __linux__ || defined __NetBSD__) && \ + ! defined __CYGWIN__ +// Kylix defines only __linux__ + + +#ifdef __hpux__ + + +#include + +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 (value); + return (DynamicUsrFunc) (value); + } + else + throw ErrNoDynamicSymbol; +} + +#else +// Unix no hp-ux + + +#include + +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 (value); + return (DynamicUsrFunc) value; + } + else + throw ErrNoDynamicSymbol; +} + +#endif + + +#elif defined BLASSIC_USE_WINDOWS + + +#include +#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 + +//#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 + +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 + +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 +#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 +#include + +#include +#define ASSERT assert + +namespace sysvar= blassic::sysvar; +using namespace blassic::file; + + +namespace { + +std::deque 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 (c); + } + bf.flush (); +} + +class Edit { +public: + Edit (BlFile & bf, std::string & str, + size_t npos, size_t inicol, bool lineend); + ~Edit (); + bool do_it (); +private: + BlFile & bf; + std::string & str; + size_t npos; + size_t inicol; + size_t width; + bool textwindow; + size_t histsize; + size_t histpos; + bool intagmode; + bool lineend; + + std::string savestr; + + //void getwidth (); + void back (); + void forward (); + void deletechar (); + void showrest (); + void showinitial (); + void up (); + void down (); +}; + +Edit::Edit (BlFile & bf, std::string & str, + size_t npos, size_t inicol, bool lineend) : + bf (bf), + str (str), + npos (npos), + inicol (inicol), + width (bf.getwidth () ), + textwindow (bf.istextwindow () ), + histsize (history.size () ), + histpos (histsize), + intagmode (bf.istagactive () ), + lineend (lineend) +{ + TRACEFUNC (tr, "Edit::~Edit"); + TRMESSAGE (tr, "lineend: " + to_string (lineend) ); + + if (textwindow) + graphics::synchronize_suspend (); + if (intagmode) + bf.tagoff (); +} + +Edit::~Edit () +{ + TRACEFUNC (tr, "Edit::~Edit"); + + if (textwindow) + graphics::synchronize_restart (); + if (intagmode) + bf.tag (); +} + +void Edit::back () +{ + if (textwindow) + { + --npos; + bf.movecharback (); + return; + } + if ( (npos-- + inicol) % width != 0) + bf.movecharback (); + else + { + bf.movecharup (); + bf.movecharforward (width - 1); + } +} + +void Edit::forward () +{ + ++npos; + if (textwindow) + { + bf.movecharforward (); + return; + } + if ( (npos + inicol) % width != 0) + bf.movecharforward (); + else + { + if (npos == str.size () ) + { + //bf.movecharforward (); + //bf << '\n'; + bf.endline (); + bf.flush (); + } + else + { + //bf << '\r'; + //bf.flush (); + bf.movecharback (width - 1); + bf.movechardown (); + } + } +} + +void Edit::deletechar () +{ + if (npos < str.size () ) + { + str.erase (npos, 1); + // Vil chapuza. + str+= ' '; + showrest (); + str.erase (str.size () - 1); + } +} + +void Edit::showrest () +{ + //TRACEFUNC (tr, "Edit::showrest"); + + if (npos == str.size () ) + return; + //bf << str.substr (npos); + //bf.flush (); + showstring (bf, str.substr (npos) ); + + size_t l= str.size (); + size_t nlines= (l + inicol) / width; + size_t actualline= (npos + inicol) / width; + size_t actualcol= (npos + inicol) % width; + size_t lastcol= (l + inicol) % width; + if (lastcol == 0 && nlines > 0) + { + if (! textwindow) + { + #ifndef __WIN32__ + --nlines; + // The cursor position remains + // in the last valid column. + lastcol= width - 1; + //lastcol= width; + #endif + } + } + bf.movecharup (nlines - actualline); + if (actualcol < lastcol) + { + //TRMESSAGE (tr, std::string ("moving back " + + // to_string (lastcol - actualcol) ) ); + bf.movecharback (lastcol - actualcol); + } + else if (actualcol > lastcol) + { + //TRMESSAGE (tr, "moving forward"); + bf.movecharforward (actualcol - lastcol); + } + else if (actualcol == width - 1) + { + // Without this the cursor sometimes keep in the next line. + bf.movecharback (); + bf.movecharforward (); + } +} + +void Edit::showinitial () +{ + //TRACEFUNC (tr, "Edit::showinitial"); + + //bf << '\r' << str; + //bf.flush (); + + //bf << '\r'; + //bf.movecharforward (inicol); + + showstring (bf, str); + + size_t l= str.size () + inicol; + size_t nlines= l / width; + size_t actualline= (npos + inicol) / width; + size_t actualcol= (npos + inicol) % width; + size_t lastcol= l % width; + + #ifndef __WIN32__ + if (lastcol == 0 && nlines > 0) + { + --nlines; + lastcol= width - 1; + } + #endif + + bf.movecharup (nlines - actualline); + if (actualcol < lastcol) + bf.movecharback (lastcol - actualcol); + else + bf.movecharforward (actualcol - lastcol); + //bf << '\r'; + //bf.flush (); + //movecharforward (npos); +} + +void Edit::up () +{ + if (histpos > 0) + { + if (histpos == histsize) + savestr= str; + std::string::size_type oldsize= str.size (); + --histpos; + str= history [histpos]; + while (npos > 0) + back (); + std::string::size_type + actualsize= str.size (); + if (oldsize > actualsize) + { + showstring (bf, std::string (oldsize, ' ') ); + npos= oldsize; + for (size_t i= 0; i < oldsize; ++i) + back (); + } + //showinitial (); + showstring (bf, str); + npos= actualsize; + } +} + +void Edit::down () +{ + if (histpos < histsize) + { + std::string::size_type oldsize= str.size (); + ++histpos; + if (histpos < histsize) + str= history [histpos]; + else + str= savestr; + while (npos > 0) + back (); + std::string::size_type + actualsize= str.size (); + if (oldsize > actualsize) + { + showstring (bf, std::string (oldsize, ' ') ); + npos= oldsize; + for (size_t i= 0; i < oldsize; ++i) + back (); + } + //showinitial (); + showstring (bf, str); + npos= actualsize; + } +} + +bool Edit::do_it () +{ + TRACEFUNC (tr, "Edit::do_it"); + + showinitial (); + + bool editing= true; + bool retval= true; + while (editing) + { + bf.showcursor (); + //TRMESSAGE (tr, "Waiting key"); + std::string key= bf.getkey (); + //TRMESSAGE (tr, "Received key"); + bf.hidecursor (); + if (key.size () == 1) + { + unsigned char c= key [0]; + switch (c) + { + case '\r': case '\n': + editing= false; + break; + case '\x1B': + editing= false; + retval= false; + break; + case '\t': + { + //size_t n= npos + 1; + //n+= 7 - (n % 8); + //n-= npos ; + size_t n= 8 - npos % 8; + str.insert (npos, n, ' '); + showrest (); + for (size_t i= 0; i < n; ++i) + forward (); + } + break; + case '\3': // Ctrl-C + editing= false; + retval= false; + break; + case '\5': // Ctrl-E, test debug + //bf << str.substr (npos) << '\n'; + //bf.flush (); + showstring (bf, str.substr (npos) ); + //bf << '\n'; + bf.endline (); + bf.flush (); + showinitial (); + break; + case '\x8': + case '\x7F': + if (npos > 0) + { + back (); + deletechar (); + } + break; + default: + if (c >= ' ') + { + str.insert (npos, 1, c); + showrest (); + forward (); + } + } + } + else if (key == "RIGHT") + { + if (npos < str.size () ) + { + forward (); + } + } + else if (key == "LEFT") + { + if (npos > 0) + { + back (); + } + } + else if (key == "DELETE") + { + if (npos < str.size () ) + deletechar (); + } + else if (key == "HOME") + { + while (npos > 0) + back (); + } + else if (key == "END") + { + const size_t l= str.size (); + while (npos < l) + forward (); + } + else if (key == "UP") + up (); + else if (key == "DOWN") + down (); + } + //hidecursor (); + + if (lineend) + { + // After exit, cursor must be positioned after the line edited. + //bf << str.substr (npos) << '\n'; + bf << str.substr (npos); + bf.endline (); + bf.flush (); + } + + if (retval) + { + size_t maxhist= getmaxhistory (); + if (maxhist == 0) + maxhist= 1; + if (histsize >= maxhist) + { + history.erase (history.begin (), + history.begin () + histsize - maxhist + 1); + } + if (! str.empty () && (history.empty () || + history [history.size () - 1] != str) ) + history.push_back (str); + } + + return retval; +} + +} // namespace + +bool blassic::edit::editline (BlFile & bf, std::string & str, + size_t npos, size_t inicol, bool lineend) +{ + TRACEFUNC (tr, "editline - string"); + { + std::ostringstream oss; + oss << "Inicol: " << inicol; + TRMESSAGE (tr, oss.str () ); + } + + Edit edit (bf, str, npos, inicol, lineend); + return edit.do_it (); +} + +#if 0 + +bool editline (BlFile & bf, Program & program, BlLineNumber bln, + std::string & str) +{ + TRACEFUNC (tr, "editline - line number->string"); + + std::string buffer; + { + BlFileOutString bfos; + program.list (bln, bln, bfos); + buffer= bfos.str (); + if (buffer.empty () ) + { + //bfos << bln << " \n"; + bfos << bln << ' '; + bfos.endline (); + buffer= bfos.str (); + } + } + buffer.erase (buffer.size () - 1); + TRMESSAGE (tr, std::string (1, '\'') + buffer + '\''); + + static const std::string number ("01234567890"); + size_t inipos= buffer.find_first_of (number); + ASSERT (inipos != std::string::npos); + inipos= buffer.find_first_not_of (number, inipos); + ASSERT (inipos != std::string::npos); + ++inipos; + + bool r; + if ( (r= editline (bf, buffer, inipos) ) == true) + str= buffer; + return r; +} + +bool editline (BlFile & bf, Program & program, BlLineNumber bln) +{ + TRACEFUNC (tr, "editline - line number"); + + std::string buffer; + bool r; + if ( (r= editline (bf, program, bln, buffer) ) == true) + { + CodeLine code; + code.scan (buffer); + BlLineNumber nline= code.number (); + if (nline == LineDirectCommand) + throw ErrBlassicInternal; + else + { + if (code.empty () ) + program.deletelines (nline, nline); + else + program.insert (code); + } + } + return r; +} + +#endif + +// End of edit.cpp diff --git a/edit.h b/edit.h new file mode 100644 index 0000000..5d8076b --- /dev/null +++ b/edit.h @@ -0,0 +1,23 @@ +#ifndef INCLUDE_BLASSIC_EDIT_H +#define INCLUDE_BLASSIC_EDIT_H + +// edit.h +// Revision 23-jul-2004 + +#include "blassic.h" +#include "file.h" + +namespace blassic { + +namespace edit { + +bool editline (blassic::file::BlFile & bf, std::string & str, + size_t npos, size_t inicol= 0, bool lineend= true); + +} // namespace blassic + +} // namespace edit + +#endif + +// End of edit.h diff --git a/element.cpp b/element.cpp new file mode 100644 index 0000000..6c53db2 --- /dev/null +++ b/element.cpp @@ -0,0 +1,87 @@ +// element.cpp +// Revision 8-jan-2005 + +#include "element.h" + +#include "var.h" +#include "trace.h" + +ForElementNumber::ForElementNumber (const std::string & nvar, + ProgramPos pos, + BlNumber initial, BlNumber nmax, BlNumber nstep) : + ForElement (nvar, pos), + max (nmax), + step (nstep) +{ + varaddr= addrvarnumber (nvar); + * varaddr= initial; +} + +ForElementNumberInc::ForElementNumberInc (const std::string & var, + ProgramPos pos, + BlNumber initial, BlNumber max, BlNumber step) : + ForElementNumber (var, pos, initial, max, step) +{ + //TRACEFUNC (tr, "ForElementNumberInc::ForElementNumberInc"); +} + +bool ForElementNumberInc::next () +{ + * varaddr+= step; + return * varaddr <= max; +} + +ForElementNumberDec::ForElementNumberDec (const std::string & var, + ProgramPos pos, + BlNumber initial, BlNumber max, BlNumber step) : + ForElementNumber (var, pos, initial, max, step) +{ + //TRACEFUNC (tr, "ForElementNumberDec::ForElementNumberDec"); +} + +bool ForElementNumberDec::next () +{ + * varaddr+= step; + return * varaddr >= max; +} + +ForElementInteger::ForElementInteger (const std::string & nvar, + ProgramPos pos, + BlInteger initial, BlInteger nmax, BlInteger nstep) : + ForElement (nvar, pos), + max (nmax), + step (nstep) +{ + varaddr= addrvarinteger (nvar); + * varaddr= initial; +} + +ForElementIntegerInc::ForElementIntegerInc (const std::string & var, + ProgramPos pos, + BlInteger initial, BlInteger max, BlInteger step) : + ForElementInteger (var, pos, initial, max, step) +{ + //TRACEFUNC (tr, "ForElementIntegerInc::ForElementIntegerInc"); +} + +bool ForElementIntegerInc::next () +{ + * varaddr+= step; + return * varaddr <= max; +} + +ForElementIntegerDec::ForElementIntegerDec (const std::string & var, + ProgramPos pos, + BlInteger initial, BlInteger max, BlInteger step) : + ForElementInteger (var, pos, initial, max, step) +{ + //TRACEFUNC (tr, "ForElementIntegerDec::ForElementIntegerDec"); +} + +bool ForElementIntegerDec::next () +{ + * varaddr+= step; + return * varaddr >= max; +} + +// End of element.cpp diff --git a/element.h b/element.h new file mode 100644 index 0000000..25d903d --- /dev/null +++ b/element.h @@ -0,0 +1,155 @@ +#ifndef INCLUDE_ELEMENT_H +#define INCLUDE_ELEMENT_H + +// element.h +// Revision 1-jan-2005 + +#include "blassic.h" + +#include + +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 +#include + +namespace sysvar= blassic::sysvar; + + +namespace { + +struct errcode { + const BlErrNo err; + const char * const str; + errcode (BlErrNo nerr, const char * nstr) : + err (nerr), + str (nstr) + { } +}; + +// Can't declare const or Borland can't expand find_if. Why? +errcode table []= { + errcode (ErrNoError, "No error"), + errcode (ErrSyntax, "Syntax horror"), + errcode (ErrMismatch, "Type mismatch"), + errcode (ErrGosubWithoutReturn, "GOSUB without RETURN"), + errcode (ErrReturnWithoutGosub, "RETURN without GOSUB"), + errcode (ErrNextWithoutFor, "NEXT without FOR"), + errcode (ErrNotImplemented, "Not implemented"), + errcode (ErrDivZero, "Division by zero"), + errcode (ErrDataExhausted, "Data exhausted"), + errcode (ErrInvalidCommand, "Invalid command"), + errcode (ErrPolite, "Programmer is too polite"), + errcode (ErrBadSubscript, "Bad Subscript"), + errcode (ErrOutMemory, "Out of memory"), + errcode (ErrAlreadyDim, "Array already dimensioned"), + errcode (ErrNoContinue, "Cannot CONTinue"), + errcode (ErrFileNumber, "Bad file number"), + errcode (ErrFileMode, "Bad file mode"), + errcode (ErrFileAlreadyOpen, "File already open"), + errcode (ErrFileRead, "Error reading file"), + errcode (ErrFileWrite, "Error writing file"), + errcode (ErrUntilWithoutRepeat, "UNTIL without REPEAT"), + errcode (ErrWendWithoutWhile, "WEND without WHILE"), + errcode (ErrWhileWithoutWend, "WHILE without WEND"), + errcode (ErrBlassicInternal, "Internal Blassic error"), + errcode (ErrNoDynamicLibrary, "Dynamic library not found"), + errcode (ErrNoDynamicSymbol, "Symbol not found in dynamic library"), + errcode (ErrCannotResume, "Cannot RESUME"), + errcode (ErrNoLabel, "Label does not exist"), + errcode (ErrMisplacedLocal, "LOCAL out of subroutine"), + errcode (ErrFieldOverflow, "FIELD overflow"), + errcode (ErrFileNotFound, "File not found"), + errcode (ErrLineExhausted, "Line numbers exhausted"), + errcode (ErrFunctionNoDefined, "User function undefined"), + errcode (ErrIncompleteDef, "User function incomplete"), + errcode (ErrInvalidDirect, "Invalid direct command"), + errcode (ErrBadRecord, "Bad record number"), + errcode (ErrFunctionCall, "Illegal function call"), + errcode (ErrSocket, "Socket error"), + errcode (ErrRenameFile, "Rename file error"), + errcode (ErrOperatingSystem, "Operating system error"), + errcode (ErrPastEof, "Input past EOF"), + errcode (ErrNoGraphics, "Graphics mode required"), + errcode (ErrImproperArgument, "Improper argument"), + errcode (ErrDomain, "Domain error"), + errcode (ErrRange, "Result out of range"), + errcode (ErrLineNotExist, "Line does not exist"), + errcode (ErrFnRecursion, "FN recursion too deep"), + errcode (ErrOverflow, "Overflow"), + errcode (ErrRegexp, "Bad regular expression"), + errcode (ErrDynamicUnsupported, "Dymanic link not supported"), + errcode (ErrRepeatWithoutUntil, "REPEAT without UNTIL"), + errcode (ErrUnexpectedFnEnd, "FN END outside DEF FN"), + errcode (ErrNoFnEnd, "FN without FN END"), + errcode (ErrDuplicateLabel, "Duplicate LABEL"), + errcode (ErrNoTeDejo, "That won't work"), +}; + +errcode * table_end= table + util::dim_array (table); + +class is_err { +public: + is_err (BlErrNo err) : err (err) + { } + bool operator () (const errcode & ec) const + { return ec.err == err; } +private: + BlErrNo err; +}; + +} // namespace + +//*********************************************** +// class BlError +//*********************************************** + +BlError::BlError () : + err (ErrNoError) +{ } + +BlError::BlError (BlErrNo nerr) : + err (nerr) +{ } + +BlError::BlError (BlErrNo nerr, ProgramPos npos) : + err (nerr), + pos (npos) +{ } + +void BlError::clear () +{ + err= ErrNoError; + pos= ProgramPos (); +} + +void BlError::set (BlErrNo nerr, ProgramPos npos) +{ + err= nerr; + pos= npos; +} + +void BlError::seterr (BlErrNo nerr) +{ + err= nerr; +} + +BlErrNo BlError::geterr () const +{ + return err; +} + +ProgramPos BlError::getpos () const +{ + return pos; +} + +std::ostream & operator << (std::ostream & os, const BlError & bl) +{ + os << ErrStr (bl.err); + const BlLineNumber line= bl.getpos ().getnum (); + if (line != LineDirectCommand) + os << " in " << line; + //os << '\n'; + return os; +} + +//*********************************************** +// class BlBreakInPos +//*********************************************** + +BlBreakInPos::BlBreakInPos (ProgramPos pos) : + pos (pos) +{ } + +ProgramPos BlBreakInPos::getpos () const +{ + return pos; +} + +std::ostream & operator << (std::ostream & os, const BlBreakInPos & bbip) +{ + os << "**BREAK**"; + BlLineNumber line= bbip.getpos ().getnum (); + if (line != LineDirectCommand) + os << " in " << line; + return os; +} + +//*********************************************** +// Other functions +//*********************************************** + +std::string ErrStr (BlErrNo err) +{ + const errcode * perr= std::find_if (table, table_end, is_err (err) ); + if (perr != table_end) + return perr->str; + std::ostringstream strbuf; + strbuf << "Error " << err; + return strbuf.str (); +} + +bool showdebuginfo () +{ + //return sysvar::getFlags1 () & sysvar::ShowDebugInfo; + return sysvar::hasFlags1 (sysvar::ShowDebugInfo); +} + +// Fin de error.cpp diff --git a/error.h b/error.h new file mode 100644 index 0000000..27882bb --- /dev/null +++ b/error.h @@ -0,0 +1,105 @@ +#ifndef INCLUDE_BLASSIC_ERROR_H +#define INCLUDE_BLASSIC_ERROR_H + +// error.h +// Revision 7-feb-2005 + + +#include "blassic.h" + +#include +#include + + +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 +#include +#include +#include +#include + +// para strerror (errno) +#include +#include + +#include +using std::cerr; +using std::endl; + +#include +#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 (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 (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 &) +{ throw ErrFileMode; } + +void BlFile::field_append (const std::vector &) +{ 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 (c) ); +} + +std::string BlFileRegular::read (size_t n) +{ + util::auto_buffer 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 & elem); + void field_append (const std::vector & 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 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 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 & 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 & elem) +{ + field_clear (); + field_append (elem); +} + +namespace { + +class field_var_is { +public: + field_var_is (const std::string & name, const Dimension & dim) : + name (name), dim (dim) + { } + bool operator () (const BlFileRandom::field_chunk & chunk) + { + return chunk.name == name && chunk.dim == dim; + } +private: + const std::string & name; + const Dimension & dim; +}; + +} // namespace + +bool BlFileRandom::assign (const std::string & name, const Dimension & dim, + const std::string & value, Align align) +{ + vchunk::iterator pe= std::find_if (chunk.begin (), chunk.end (), + field_var_is (name, dim) ); + if (pe == chunk.end () ) + return false; + if (pe->size == 0) + return true; + char * init= buf + pe->pos; + std::string str; + + // Changed the behaviour: now does the same as gwbasic. + + #if 0 + std::string::size_type l= value.size (); + if (align == AlignLeft) + { + if (l < pe->size) + str= value + std::string (pe->size - l, ' '); + else + str= value.substr (0, pe->size); + } + else + { + if (l < pe->size) + str= std::string (pe->size - l, ' ') + value; + else + str= value.substr (l - pe->size); + } + #else + if (align == AlignLeft) + str= util::stringlset (value, pe->size); + else + str= util::stringrset (value, pe->size); + #endif + ASSERT (str.size () == pe->size); + #if 0 + std::copy (str.begin (), str.end (), init); + #else + str.copy (init, pe->size); + #endif + // Now also assign to the standalone var, so that the + // value assiged can be checked. + if (dim.empty () ) + assignvarstring (name, str); + else + assigndimstring (name, dim, str); + return true; +} + +bool BlFileRandom::assign_mid (const std::string & name, + const Dimension & dim, + const std::string & value, + size_t inipos, std::string::size_type len) +{ + vchunk::iterator pe= std::find_if (chunk.begin (), chunk.end (), + field_var_is (name, dim) ); + if (pe == chunk.end () ) + return false; + const size_t size= pe->size; + if (size == 0) + return true; + if (inipos >= size) + return true; + char * const init= buf + pe->pos; + char * const initmid= init + inipos; + size_t l= size - inipos; + if (len > l) + len= l; + std::string str= value.substr (0, len); + if (str.size () < len) + str+= std::string (len - str.size (), ' '); + str.copy (initmid, str.size () ); + // Now also assign to the standalone var, so that the + // value assiged can be checked. + if (dim.empty () ) + assignvarstring (name, std::string (init, size) ); + else + assigndimstring (name, dim, std::string (init, size) ); + return true; +} + +BlInteger BlFileRandom::lof () +{ + return lengthoffileread (fs); +} + +} // namespace file + +} // namespace blassic + +// Fin de file.cpp diff --git a/file.h b/file.h new file mode 100644 index 0000000..50f543d --- /dev/null +++ b/file.h @@ -0,0 +1,178 @@ +#ifndef INCLUDE_BLASSIC_FILE_H +#define INCLUDE_BLASSIC_FILE_H + +// file.h +// Revision 7-feb-2005 + +#ifdef __BORLANDC__ +#pragma warn -8022 +#endif + +#include "blassic.h" + +#include "dim.h" + +#include +#include +#include +#include +#include + +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 & elem); + virtual void field_append (const std::vector & 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 +using std::cerr; +using std::endl; +#include +#include + +#ifndef BLASSIC_USE_WINDOWS + +#include + +#else + +#include +#undef max +#undef min +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined HAVE_IO_H || ! defined BLASSIC_CONFIG +#include +#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 (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 aux (l); + OemToCharBuff (str.data (), aux, l); + str= std::string (aux, l); + } + + #endif +} + +std::string BlFileConsole::read (size_t n) +{ + util::auto_buffer buf (n); + in.read (buf, n); + return std::string (buf, n); +} + +void BlFileConsole::tab () +{ + int zone= static_cast (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 (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 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 +using std::cerr; +using std::endl; + +#ifndef BLASSIC_USE_WINDOWS + +#include +#include + +#include +#include + +// Suggested in autoconf manual. +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(star_val) ((unsigned) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + + +#include +#include + +#else + +#include +#undef min +#undef max + +#endif + +// para strerror (errno) +#include +#include + +#include + +#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 (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 (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 +//#include + +#include +using std::cerr; +using std::endl; + +#include +using std::auto_ptr; + +#include +#define ASSERT assert + +#ifdef BLASSIC_USE_WINDOWS + +#include +#undef min +#undef max + +#else + +#include +#include +#include +#include +#include + +#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 (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 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 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 +#include + +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 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 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 + + +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 +#include +#include +#include +#include +// bitset in gcc 2.95 uses min whithout defining it. +// Then we include something that does. +#include +#include + +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 (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 (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 (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 ( (* 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 +#include +#include +#include +#include + +#include +using std::auto_ptr; + +#include +#include + +#include +#include +#include + +// Para depuracion +#include +using std::cerr; +using std::endl; +#if defined __unix__ || defined __linux__ +#include +#endif +#include +#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 +#include +#include +#include + +#endif +// BLASSIC_USE_SVGALIB + +#ifdef BLASSIC_USE_X + +#include +#include +#include + +#endif +// BLASSIC_USE_X + +#ifdef BLASSIC_USE_WINDOWS + +#include +#include +#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 q; + CriticalSection cs; +}; + +#if 0 +const size_t MAXKEYSYM= 65535; +std::vector 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 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 (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 +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 (screenwidth - x - 1); + x= newx; + } + break; + } +} + +template +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 (screenwidth - y - 1); + y= newy; + } + break; + } +} + +template +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 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 ( 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 (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 (~ 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 + (xj); + point [n].y= static_cast + (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 (ch [i]) << ", "; + } + TRMESSAGE (tr, oss.str () ); + } + #endif + + char chinv [8]; + for (int i= 0; i < 8; ++i) + chinv [i]= static_cast (~ ch [i]); + + //for (int i= 0; i < 256; ++i) + int iFrom= static_cast (from); + int iTo= static_cast (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 (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 & 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 + +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 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 (c < 0 ? c - .5 : c + .5); + out_y= static_cast (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 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 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 (c < 0 ? c - .5 : c + .5); + out_y= static_cast (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 > visited; + ColorTester test; +public: + Painter (ColorValue paint, ColorValue border) : + paint (paint), + border (border), + visited (screenwidth, std::vector (screenheight) ) + { + } + + bool check (int x, int y) + { + if (! check_limit (x, y) ) + return false; + std::vector ::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 > visited; + ColorTester test; +public: + Painter (ColorValue paint, ColorValue border) : + paint (paint), + border (border), + visited (screenwidth, std::vector (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 > & visit, + ColorTester & test) + { + if (! check_limit (x, y) ) + return false; + std::vector ::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 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 > + visit (screenwidth, vector (screenheight) ); + std::deque 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 > visited; + std::deque processlist, nextlist; + ColorTester test; +public: + Painter (ColorValue paint, ColorValue border) : + paint (paint), + border (border), + visited (screenwidth, std::vector (screenheight) ) + { + } + bool check (int x, int y) + { + if (! check_limit (x, y) ) + return false; + std::vector ::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 (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 (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 (c) ); + unsigned char c1= static_cast (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 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 (params [0] ) % 16); + } + void do_SI () // 15 + { + setcolor (static_cast (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 (params [0] ) ); + } + void do_ETB () // 23 + { + // Ink mode, only CPC modes are allowed. + graphics::setdrawmode + (static_cast (params [0] ) % 4); + } + void do_CAN () // 24 + { + std::swap (foreground, background); + } + void do_EM () // 25 + { + int symbol= static_cast (params [0] ); + // Avoid generate an error if out of range. + if (symbol < symbol_after_is) + return; + unsigned char byte [8]; + params.copy (reinterpret_cast (& byte [0] ), 8, 1); + graphics::definesymbol (symbol, byte); + } + void do_SUB () // 26 + { + set (static_cast (params [0] ), + static_cast (params [1] ), + static_cast (params [2] ), + static_cast (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 (params [0] ) % 16; + int color= static_cast (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 (params [0] ); + int yy= static_cast (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 (params [0] ) - 32; + x= static_cast (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 (& 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 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 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 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 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 (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 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 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 & points); +int test (int x, int y, bool relative); + +void circle (int x, int y, int radius); +void arccircle (int x, int y, int radius, + BlNumber arcbeg, BlNumber arcend); +void ellipse (int x, int y, int rx, int ry); +void arcellipse (int x, int y, int rx, int ry, + BlNumber arcbeg, BlNumber arcend); + +void paint (int x, int y, int paintattr, int borderattr); + +void mask (int m); +void maskdrawfirstpoint (bool f); +void draw (const std::string & str); +Point getlast (); + +std::string getkey (); +std::string inkey (); +bool pollin (); +int keypressed (int keynum); + +void charout (char c); +void stringout (const std::string & str); + +void charout (BlChannel ch, char c); +void stringout (BlChannel ch, const std::string & str); +std::string copychr (BlChannel ch, BlChar from, BlChar to); + +std::string screenchr (int x, int y); + +void definewindow (BlChannel n, int x1, int x2, int y1, int y2); +void undefinewindow (BlChannel ch); + +size_t getlinewidth (); +size_t getlinewidth (BlChannel ch); + +//void locate (int row, int col); +void gotoxy (int x, int y); +void tab (size_t n); +void movecharforward (size_t n); +void movecharback (size_t n); +void movecharup (size_t n); +void movechardown (size_t n); + +void gotoxy (BlChannel ch, int x, int y); +void tab (BlChannel ch); +void tab (BlChannel ch, size_t x); +void movecharforward (BlChannel ch, size_t n); +void movecharback (BlChannel ch, size_t n); +void movecharup (BlChannel ch, size_t n); +void movechardown (BlChannel ch, size_t n); + +void scroll (BlChannel ch, int n); + +void symbolafter (int symbol); +void definesymbol (int symbol, const unsigned char (& byte) [8] ); +void synchronize (bool mode); +void synchronize (); +void synchronize_suspend (); +void synchronize_restart (); + +int xmouse (); +int ymouse (); + +int xpos (); +int xpos (BlChannel ch); +int ypos (); +int ypos (BlChannel ch); + +void tag (BlChannel ch); +void tagoff (BlChannel ch); +bool istagactive (BlChannel ch); + +void showcursor (); +void hidecursor (); + +void showcursor (BlChannel ch); +void hidecursor (BlChannel ch); + +void inverse (BlChannel ch, bool active); +bool getinverse (BlChannel ch); +void bright (BlChannel ch, bool active); +bool getbright (BlChannel ch); + +void clean_input (); + +void ring (); + +void set_title (const std::string & title); +void set_default_title (const std::string & title); + +void get_image (int x1, int y1, int x2, int y2, const std::string & name); +void put_image (int x, int y, const std::string & name, int mode); +void clear_images (); + +} // namespace graphics + +#endif + +// Fin de graphics.h diff --git a/key.cpp b/key.cpp new file mode 100644 index 0000000..b7946e5 --- /dev/null +++ b/key.cpp @@ -0,0 +1,155 @@ +// key.cpp +// Revision 9-jan-2005 + +#include "key.h" +#include "trace.h" +#include "blassic.h" + +#include + +#include // For debug info only. + +//#ifdef _Windows +#ifdef BLASSIC_USE_WINDOWS + +#include + +#elif defined BLASSIC_USE_X + +#include + +#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 mapkey_t; + +mapkey_t mapkey; + +inline void assignmapkey (unsigned int code, const std::string & name) +{ + #ifndef NDEBUG + mapkey_t::iterator it; + if ( (it= mapkey.find (code) ) != mapkey.end () ) + { + std::cerr << "Error: key " << name << + " has equal code than " << it->second << + std::endl; + throw 1; + } + #endif + mapkey [code]= name; +} + +bool initmapkey () +{ + TRACEFUNC (tr, "initmapkey"); + + //#ifdef _Windows + #ifdef BLASSIC_USE_WINDOWS + + assignmapkey (VK_PRIOR, strPAGEUP); + assignmapkey (VK_NEXT, strPAGEDOWN); + assignmapkey (VK_END, strEND); + assignmapkey (VK_HOME, strHOME); + assignmapkey (VK_LEFT, strLEFT); + assignmapkey (VK_UP, strUP); + assignmapkey (VK_RIGHT, strRIGHT); + assignmapkey (VK_DOWN, strDOWN); + assignmapkey (VK_INSERT, strINSERT); + assignmapkey (VK_DELETE, strDELETE); + assignmapkey (VK_F1, strF1); + assignmapkey (VK_F2, strF2); + assignmapkey (VK_F3, strF3); + assignmapkey (VK_F4, strF4); + assignmapkey (VK_F5, strF5); + assignmapkey (VK_F6, strF6); + assignmapkey (VK_F7, strF7); + assignmapkey (VK_F8, strF8); + assignmapkey (VK_F9, strF9); + assignmapkey (VK_F10, strF10); + assignmapkey (VK_F11, strF11); + assignmapkey (VK_F12, strF12); + + #elif defined BLASSIC_USE_X + + assignmapkey (XK_Prior, strPAGEUP); + assignmapkey (XK_KP_Prior, strPAGEUP); + assignmapkey (XK_Next, strPAGEDOWN); + assignmapkey (XK_KP_Next, strPAGEDOWN); + assignmapkey (XK_End, strEND); + assignmapkey (XK_KP_End, strEND); + assignmapkey (XK_Home, strHOME); + assignmapkey (XK_KP_Home, strHOME); + assignmapkey (XK_Left, strLEFT); + assignmapkey (XK_KP_Left, strLEFT); + assignmapkey (XK_Up, strUP); + assignmapkey (XK_KP_Up, strUP); + assignmapkey (XK_Right, strRIGHT); + assignmapkey (XK_KP_Right, strRIGHT); + assignmapkey (XK_Down, strDOWN); + assignmapkey (XK_KP_Down, strDOWN); + assignmapkey (XK_Insert, strINSERT); + assignmapkey (XK_KP_Insert, strINSERT); + assignmapkey (XK_Delete, strDELETE); + assignmapkey (XK_KP_Delete, strDELETE); + assignmapkey (XK_F1, strF1); + assignmapkey (XK_F2, strF2); + assignmapkey (XK_F3, strF3); + assignmapkey (XK_F4, strF4); + assignmapkey (XK_F5, strF5); + assignmapkey (XK_F6, strF6); + assignmapkey (XK_F7, strF7); + assignmapkey (XK_F8, strF8); + assignmapkey (XK_F9, strF9); + assignmapkey (XK_F10, strF10); + assignmapkey (XK_F11, strF11); + assignmapkey (XK_F12, strF12); + + #endif + + return true; +} + +const bool mapkeyinited= initmapkey (); + +} // namespace + +std::string string_from_key (unsigned int key) +{ + mapkey_t::const_iterator it= mapkey.find (key); + if (it != mapkey.end () ) + return it->second; + return std::string (); +} + +// End of key.cpp diff --git a/key.h b/key.h new file mode 100644 index 0000000..9e94c0f --- /dev/null +++ b/key.h @@ -0,0 +1,43 @@ +#ifndef INCLUDE_BLASSIC_KEY_H +#define INCLUDE_BLASSIC_KEY_H + +// key.h +// Revision 7-feb-2005 + +#include + + +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 +#include +#include +#include +#include +#include + +// 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 { +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 { +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 exclude; + +} // namespace + +void excludekeyword (const std::string & str) +{ + TRACEFUNC (tr, "excludekeyword"); + + std::string stru= stringupper (str); + if (find_if (table, table_end, key_is (stru) ) != table_end) + { + exclude.insert (stru); + TRMESSAGE (tr, std::string ("Excluding ") + stru); + } +} + +BlCode keyword (const std::string & str) +{ + std::string stru= stringupper (str); + BlCode code= std::find_if (table, table_end, key_is (stru) )->code; + if (code != 0) + if (exclude.find (stru) != exclude.end () ) + return 0; + return code; +} + +std::string decodekeyword (BlCode s) +{ + if (s == keyGOTO || s == keyGOSUB) + { + if (sysvar::hasFlags2 (sysvar::SeparatedGoto) ) + return (s == keyGOTO) ? + "GO TO" : + "GO SUB"; + } + return std::find_if (table, table_end, code_is (s) )->key; +} + +// Fin de keyword.cpp diff --git a/keyword.h b/keyword.h new file mode 100644 index 0000000..7ca062d --- /dev/null +++ b/keyword.h @@ -0,0 +1,305 @@ +#ifndef INCLUDE_BLASSIC_KEYWORD_H +#define INCLUDE_BLASSIC_KEYWORD_H + +// keyword.h +// Revision 9-jan-2005 + +#include "blassic.h" + +const BlCode + keyColon= ':', + keyPlus= '+', + keyMinus= '-', + keyMult= '*', + keyDiv= '/', + keyDivInt= '\\', + keyEqual= '=', + keyMinor= '<', + keyGreater= '>', + keyOpenPar= '(', + keyClosePar= ')', + keyComma= ',', + keySharp= '#', + keyPower= '^', + + keyEND= 0x0101, + keyLIST= 0x0102, + keyREM= 0x0103, + keyLOAD= 0x0104, + keySAVE= 0x0105, + keyNEW= 0x0106, + keyEXIT= 0x0107, + keyRUN= 0x0108, + keyPRINT= 0x0109, + keyFOR= 0x010A, + keyNEXT= 0x010B, + keyTO= 0x010C, + keySTEP= 0x010D, + keyIF= 0x010E, + keyTHEN= 0x010F, + keyELSE= 0x0110, + keyTRON= 0x0111, + keyTROFF= 0x0112, + keyLET= 0x0113, + keyGOTO= 0x0114, + keySTOP= 0x0115, + keyCONT= 0x0116, + keyCLEAR= 0x0117, + keyGOSUB= 0x0118, + keyRETURN= 0x0119, + keyPOKE= 0x011A, + keyDATA= 0x011B, + keyREAD= 0x011C, + keyRESTORE= 0x011D, + keyINPUT= 0x011E, + keyLINE= 0x011F, + keyRANDOMIZE= 0x0120, + keyPLEASE= 0x0121, + keyAUTO= 0x0122, + keyDIM= 0x0123, + keySYSTEM= 0x0124, + keyON= 0x0125, + keyERROR= 0x0126, + keyOPEN= 0x0127, + keyCLOSE= 0x0128, + keyOUTPUT= 0x0129, + keyAS= 0x012A, + keyLOCATE= 0x012B, + keyCLS= 0x012C, + keyAPPEND= 0x012D, + keyWRITE= 0x012E, + keyMODE= 0x012F, + keyMOVE= 0x0130, + keyCOLOR= 0x0131, + keyGET= 0x0132, + keyLABEL= 0x0133, + keyDELIMITER= 0x0134, + keyREPEAT= 0x0135, + keyUNTIL= 0x0136, + keyWHILE= 0x0137, + keyWEND= 0x0138, + keyPLOT= 0x0139, + keyPOPEN= 0x013A, + keyRESUME= 0x013B, + keyDELETE= 0x013C, + keyLOCAL= 0x013D, + keyRANDOM= 0x013E, + keyPUT= 0x013F, + keyFIELD= 0x0140, + keyLSET= 0x0141, + keyRSET= 0x0142, + keySOCKET= 0x0143, + keyDRAW= 0x0144, + keyDEF= 0x0145, + keyFN= 0x0146, + keyERASE= 0x0147, + keySWAP= 0x0148, + keySYMBOL= 0x0149, + keyZONE= 0x014A, + keyPOP= 0x014B, + keyNAME= 0x014C, + keyKILL= 0x014D, + keyFILES= 0x014E, + keyPAPER= 0x014F, + keyPEN= 0x0150, + keySHELL= 0x0151, + keyMERGE= 0x0152, + keyCHDIR= 0x0153, + keyMKDIR= 0x0154, + keyRMDIR= 0x0155, + keyBREAK= 0x0156, + keySYNCHRONIZE= 0x0157, + keyPAUSE= 0x0158, + keyCHAIN= 0x0159, + keySTR= 0x015A, + keyREAL= 0x015B, + keyENVIRON= 0x015C, + keyEDIT= 0x015D, + keyDRAWR= 0x015E, + keyPLOTR= 0x015F, + keyMOVER= 0x0160, + keyPOKE16= 0x0161, + keyPOKE32= 0x0162, + keyRENUM= 0x0163, + keyCIRCLE= 0x0164, + keyMASK= 0x0165, + keyWINDOW= 0x0166, + keyGRAPHICS= 0x0167, + keyAFTER= 0x0168, + keyBEEP= 0x0169, + keyDEFINT= 0x016A, + keyDEFSTR= 0x016B, + keyDEFREAL= 0x016C, + keyDEFSNG= 0x016D, + keyDEFDBL= 0x016E, + keyINK= 0x016F, + keySET_TITLE= 0x0170, + keyTAG= 0x0171, + keyTAGOFF= 0x0172, + keyORIGIN= 0x0173, + keyDEG= 0x0174, + keyRAD= 0x0175, + keyINVERSE= 0x0176, + keyIF_DEBUG= 0x0177, + keyLPRINT= 0x0178, + keyLLIST= 0x0179, + keyWIDTH= 0x017A, + keyBRIGHT= 0x017B, + keyBINARY= 0x017C, + keyDRAWARC= 0x017D, + keyPULL= 0x017E, + keyPAINT= 0x017F, + keyFREE_MEMORY= 0x0180, + keySCROLL= 0x0181, + keyZX_PLOT= 0x0182, + keyZX_UNPLOT= 0x0183, + + keyMID_S= 0x0201, + keyLEFT_S= 0x0202, + keyRIGHT_S= 0x0203, + keyCHR_S= 0x0204, + keyENVIRON_S= 0x0205, + keySTRING_S= 0x0206, + keyOSFAMILY_S= 0x0207, + keyHEX_S= 0x0208, + keySPACE_S= 0x0209, + keyUPPER_S= 0x020A, + keyLOWER_S= 0x020B, + keySTR_S= 0x020C, + keyOCT_S= 0x020D, + keyBIN_S= 0x020E, + keyINKEY_S= 0x020F, + keyPROGRAMARG_S= 0x0210, + keyDATE_S= 0x0211, + keyTIME_S= 0x0212, + keyINPUT_S= 0x0213, + keyMKI_S= 0x0214, + keyMKS_S= 0x0215, + keyMKD_S= 0x0216, + keyMKL_S= 0x0217, + keyTRIM_S= 0x0218, + keyLTRIM_S= 0x0219, + keyRTRIM_S= 0x021A, + keyOSNAME_S= 0x021B, + keyFINDFIRST_S= 0x021C, + keyFINDNEXT_S= 0x021D, + keyCOPYCHR_S= 0x021E, + keySTRERR_S= 0x021F, + keyDEC_S= 0x0220, + keyVAL_S= 0x0221, + keySCREEN_S= 0x0222, + keyMKSMBF_S= 0x0223, + keyMKDMBF_S= 0x0224, + keyREGEXP_REPLACE_S= 0x0225, + keyUCASE_S= 0x0226, + keyLCASE_S= 0x0227, + + keyASC= 0x0301, + keyLEN= 0x0302, + keyPEEK= 0x0303, + keyPROGRAMPTR= 0x0304, + keyRND= 0x0305, + keyINT= 0x0306, + keySIN= 0x0307, + keyCOS= 0x0308, + keyPI= 0x0309, + keyTAN= 0x030A, + keySQR= 0x030B, + keyASIN= 0x030C, + keyACOS= 0x030D, + keyINSTR= 0x030E, + keyATAN= 0x030F, + keyABS= 0x0310, + keyUSR= 0x0311, + keyVAL= 0x0312, + keyEOF= 0x0313, + keyVARPTR= 0x0314, + keySYSVARPTR= 0x0315, + keySGN= 0x0316, + keyLOG= 0x0317, + keyLOG10= 0x0318, + keyEXP= 0x0319, + keyTIME= 0x031A, + keyERR= 0x031B, + keyERL= 0x031C, + keyCVI= 0x031D, + keyCVS= 0x031E, + keyCVD= 0x031F, + keyCVL= 0x0320, + keyMIN= 0x0321, + keyMAX= 0x0322, + keyCINT= 0x0323, + keyFIX= 0x0324, + keyXMOUSE= 0x0325, + keyYMOUSE= 0x0326, + keyXPOS= 0x0327, + keyYPOS= 0x0328, + keyPEEK16= 0x0329, + keyPEEK32= 0x032A, + keyRINSTR= 0x032B, + keyFIND_FIRST_OF= 0x032C, + keyFIND_LAST_OF= 0x032D, + keyFIND_FIRST_NOT_OF= 0x032E, + keyFIND_LAST_NOT_OF= 0x032F, + keySINH= 0x0330, + keyCOSH= 0x0331, + keyTANH= 0x0332, + keyASINH= 0x0333, + keyACOSH= 0x0334, + keyATANH= 0x0335, + keyATAN2= 0x0336, + keyTEST= 0x0337, + keyTESTR= 0x0338, + keyPOS= 0x0339, + keyVPOS= 0x033A, + keyLOF= 0x033B, + keyFREEFILE= 0x033C, + keyINKEY= 0x033D, + keyROUND= 0x033E, + keyCVSMBF= 0x033F, + keyCVDMBF= 0x0340, + keyREGEXP_INSTR= 0x0341, + keyALLOC_MEMORY= 0x0342, + keyLOC= 0x0343, + + keyNOT= 0x0401, + keyOR= 0x0402, + keyAND= 0x0403, + keyTAB= 0x0404, + keySPC= 0x0405, + keyAT= 0x0406, + keyXOR= 0x0407, + keyMOD= 0x0408, + keyUSING= 0x0409, + + keyIDENTIFIER= 0x0601, // Not in program. + keyNUMBER= 0x0602, // Not in program. + keySTRING= 0x0603, // Not in program. + keyDISTINCT= 0x0604, + keyMINOREQUAL= 0x0605, + keyGREATEREQUAL= 0x0606, + keyINTEGER= 0x0607, // Not in program. + keyEQUALMINOR= 0x0608, + keyEQUALGREATER= 0x0609, + keyGREATERMINOR= 0x060A, + keyENDLINE= 0x06FF, // Not in program. + + keyMAX_CODE_USED= 0x06FF; + + +inline bool iskey (unsigned char c) +{ + // Por ahora. + return c == '\x01' || c == '\x02' || c == '\x03' || + c == '\x04' || c == '\x06'; +} + +const BlChar INTEGER_PREFIX= '\x05'; + +void excludekeyword (const std::string & str); +BlCode keyword (const std::string & str); +std::string decodekeyword (BlCode s); + +#endif + +// Fin de keyword.h diff --git a/mbf.cpp b/mbf.cpp new file mode 100644 index 0000000..039a024 --- /dev/null +++ b/mbf.cpp @@ -0,0 +1,158 @@ +// mbf.cpp +// Revision 9-jul-2004 + +#include "mbf.h" +#include "error.h" + +#include + +// For debugging: +#include +#include + +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 (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 (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 (log (v) / log (2) ); + v/= pow (2, e - 23); + unsigned long l= static_cast (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 (e + 128 + 1); + unsigned char b2= static_cast (l / (256 * 256) ); + unsigned char b1= static_cast ((l / 256) % 256); + unsigned char b0= static_cast (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 (log (v) / log (2) ); + v/= pow (2, e - 55); + //unsigned long l= static_cast (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 (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 (l - 256 * ll); + l= ll; + modf (l / 256, & ll); + unsigned char b1= static_cast (l - 256 * ll); + l= ll; + modf (l / 256, & ll); + unsigned char b2= static_cast (l - 256 * ll); + l= ll; + modf (l / 256, & ll); + unsigned char b3= static_cast (l - 256 * ll); + l= ll; + modf (l / 256, & ll); + unsigned char b4= static_cast (l - 256 * ll); + l= ll; + modf (l / 256, & ll); + unsigned char b5= static_cast (l - 256 * ll); + l= ll; + unsigned char b6= static_cast (l); + #endif + b6&= 0x7F; + if (negative) + b6|= 0x80; + + #if 0 + std::cerr << std::setw (2) << int (b0) << int (b1) << + int (b2) << int (b3) << std::endl; + #endif + + return std::string (1, char (b0) ) + char (b1) + char (b2) + + char (b3) + char (b4) + char (b5) + char (b6) + char (b7); +} + +// End of mbf.cpp diff --git a/mbf.h b/mbf.h new file mode 100644 index 0000000..d02b489 --- /dev/null +++ b/mbf.h @@ -0,0 +1,25 @@ +#ifndef INCLUDE_BLASSIC_MBF_H +#define INCLUDE_BLASSIC_MBF_H + +// mbf.h +// Revision 7-feb-2005 + +// Routines to convert from/to Microsoft Binary Format. + + +#include + + +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 + +#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 +using std::cerr; +using std::endl; + +#include +#include + +//#include +#include + +namespace { + +//typedef std::set memused_t; +typedef std::map 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 (aux); +} + +void blassic::memory::dyn_free (size_t mempos) +{ + TRACEFUNC (tr, "memory::free"); + + void * aux= reinterpret_cast (mempos); + memused_t::iterator it= memused.find (aux); + if (it == memused.end () ) + { + if (showdebuginfo () ) + cerr << "Trying to free address " << mempos << + " but is not allocated" << endl; + throw ErrFunctionCall; + } + + #ifdef HAVE_SYS_MMAN_H + + size_t memsize= it->second; + + #endif + + memused.erase (it); + + #ifndef HAVE_SYS_MMAN_H + + ::free (aux); + + #else + + //munmap (aux, memsize); + do_munmap (aux, memsize); + + #endif +} + +void blassic::memory::dyn_freeall () +{ + TRACEFUNC (tr, "memory::freeall"); + + bool something= false; + while (! memused.empty () ) + { + something= true; + memused_t::iterator it= memused.begin (); + + #ifndef HAVE_SYS_MMAN_H + + ::free (it->first); + + #else + + //munmap (it->first, it->second); + do_munmap (it->first, it->second); + + #endif + + memused.erase (it); + } + + if (! something) + TRMESSAGE (tr, "Nothing to free"); +} + +// End of memory.cpp diff --git a/memory.h b/memory.h new file mode 100644 index 0000000..ab52085 --- /dev/null +++ b/memory.h @@ -0,0 +1,23 @@ +#ifndef INCLUDE_BLASSIC_MEMORY_H +#define INCLUDE_BLASSIC_MEMORY_H + +// memory.h +// Revision 1-feb-2005 + +#include "blassic.h" + +namespace blassic { + +namespace memory { + +size_t dyn_alloc (size_t memsize); +void dyn_free (size_t mempos); +void dyn_freeall (); + +} // namespace memory + +} // namespace blassic + +#endif + +// End of memory.h diff --git a/msx.def b/msx.def new file mode 100644 index 0000000..be50075 --- /dev/null +++ b/msx.def @@ -0,0 +1,2816 @@ + + 0 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 1 + +00111100 +01000010 +10100101 +10000001 +10100101 +10011001 +01000010 +00111100 + + 2 + +00111100 +01111110 +11011011 +11111111 +11111111 +11011011 +01100110 +00111100 + + 3 + +01101100 +11111110 +11111110 +11111110 +01111100 +00111000 +00010000 +00000000 + + 4 + +00010000 +00111000 +01111100 +11111110 +01111100 +00111000 +00010000 +00000000 + + 5 + +00010000 +00111000 +01010100 +11111110 +01010100 +00010000 +00111000 +00000000 + + 6 + +00010000 +00111000 +01111100 +11111110 +11111110 +00010000 +00111000 +00000000 + + 7 + +00000000 +00000000 +00000000 +00110000 +00110000 +00000000 +00000000 +00000000 + + 8 + +11111111 +11111111 +11111111 +11100111 +11100111 +11111111 +11111111 +11111111 + + 9 + +00111000 +01000100 +10000010 +10000010 +10000010 +01000100 +00111000 +00000000 + + 10 + +11000111 +10111011 +01111101 +01111101 +01111101 +10111011 +11000111 +11111111 + + 11 + +00001111 +00000011 +00000101 +01111001 +10001000 +10001000 +10001000 +01110000 + + 12 + +00111000 +01000100 +01000100 +01000100 +00111000 +00010000 +01111100 +00010000 + + 13 + +00110000 +00101000 +00100100 +00100100 +00101000 +00100000 +11100000 +11000000 + + 14 + +00111100 +00100100 +00111100 +00100100 +00100100 +11100100 +11011100 +00011000 + + 15 + +00010000 +01010100 +00111000 +11101110 +00111000 +01010100 +00010000 +00000000 + + 16 + +00010000 +00010000 +00010000 +01111100 +00010000 +00010000 +00010000 +00010000 + + 17 + +00010000 +00010000 +00010000 +11111111 +00000000 +00000000 +00000000 +00000000 + + 18 + +00000000 +00000000 +00000000 +11111111 +00010000 +00010000 +00010000 +00010000 + + 19 + +00010000 +00010000 +00010000 +11110000 +00010000 +00010000 +00010000 +00010000 + + 20 + +00010000 +00010000 +00010000 +00011111 +00010000 +00010000 +00010000 +00010000 + + 21 + +00010000 +00010000 +00010000 +11111111 +00010000 +00010000 +00010000 +00010000 + + 22 + +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 +00010000 + + 23 + +00000000 +00000000 +00000000 +11111111 +00000000 +00000000 +00000000 +00000000 + + 24 + +00000000 +00000000 +00000000 +00011111 +00010000 +00010000 +00010000 +00010000 + + 25 + +00000000 +00000000 +00000000 +11110000 +00010000 +00010000 +00010000 +00010000 + + 26 + +00010000 +00010000 +00010000 +00011111 +00000000 +00000000 +00000000 +00000000 + + 27 + +00010000 +00010000 +00010000 +11110000 +00000000 +00000000 +00000000 +00000000 + + 28 + +10000001 +01000010 +00100100 +00011000 +00011000 +00100100 +01000010 +10000001 + + 29 + +00000001 +00000010 +00000100 +00001000 +00010000 +00100000 +01000000 +10000000 + + 30 + +10000000 +01000000 +00100000 +00010000 +00001000 +00000100 +00000010 +00000001 + + 31 + +00000000 +00010000 +00010000 +11111111 +00010000 +00010000 +00000000 +00000000 + + 32 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 33 + +00100000 +00100000 +00100000 +00100000 +00000000 +00000000 +00100000 +00000000 + + 34 + +01010000 +01010000 +01010000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 35 + +01010000 +01010000 +11111000 +01010000 +11111000 +01010000 +01010000 +00000000 + + 36 + +00100000 +01111000 +10100000 +01110000 +00101000 +11110000 +00100000 +00000000 + + 37 + +11000000 +11001000 +00010000 +00100000 +01000000 +10011000 +00011000 +00000000 + + 38 + +01000000 +10100000 +01000000 +10101000 +10010000 +10011000 +01100000 +00000000 + + 39 + +00010000 +00100000 +01000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 40 + +00010000 +00100000 +01000000 +01000000 +01000000 +00100000 +00010000 +00000000 + + 41 + +01000000 +00100000 +00010000 +00010000 +00010000 +00100000 +01000000 +00000000 + + 42 + +00100000 +10101000 +01110000 +00100000 +01110000 +10101000 +00100000 +00000000 + + 43 + +00000000 +00100000 +00100000 +11111000 +00100000 +00100000 +00000000 +00000000 + + 44 + +00000000 +00000000 +00000000 +00000000 +00000000 +00100000 +00100000 +01000000 + + 45 + +00000000 +00000000 +00000000 +01111000 +00000000 +00000000 +00000000 +00000000 + + 46 + +00000000 +00000000 +00000000 +00000000 +00000000 +01100000 +01100000 +00000000 + + 47 + +00000000 +00000000 +00001000 +00010000 +00100000 +01000000 +10000000 +00000000 + + 48 + +01110000 +10001000 +10011000 +10101000 +11001000 +10001000 +01110000 +00000000 + + 49 + +00100000 +01100000 +10100000 +00100000 +00100000 +00100000 +11111000 +00000000 + + 50 + +01110000 +10001000 +00001000 +00010000 +01100000 +10000000 +11111000 +00000000 + + 51 + +01110000 +10001000 +00001000 +00110000 +00001000 +10001000 +01110000 +00000000 + + 52 + +00010000 +00110000 +01010000 +10010000 +11111000 +00010000 +00010000 +00000000 + + 53 + +11111000 +10000000 +11100000 +00010000 +00001000 +00010000 +11100000 +00000000 + + 54 + +00110000 +01000000 +10000000 +11110000 +10001000 +10001000 +01110000 +00000000 + + 55 + +11111000 +10001000 +00010000 +00100000 +00100000 +00100000 +00100000 +00000000 + + 56 + +01110000 +10001000 +10001000 +01110000 +10001000 +10001000 +01110000 +00000000 + + 57 + +01110000 +10001000 +10001000 +01111000 +00001000 +00010000 +01100000 +00000000 + + 58 + +00000000 +00000000 +00100000 +00000000 +00000000 +00100000 +00000000 +00000000 + + 59 + +00000000 +00000000 +00100000 +00000000 +00000000 +00100000 +00100000 +01000000 + + 60 + +00011000 +00110000 +01100000 +11000000 +01100000 +00110000 +00011000 +00000000 + + 61 + +00000000 +00000000 +11111000 +00000000 +11111000 +00000000 +00000000 +00000000 + + 62 + +11000000 +01100000 +00110000 +00011000 +00110000 +01100000 +11000000 +00000000 + + 63 + +01110000 +10001000 +00001000 +00010000 +00100000 +00000000 +00100000 +00000000 + + 64 + +01110000 +10001000 +00001000 +01101000 +10101000 +10101000 +01110000 +00000000 + + 65 + +00100000 +01010000 +10001000 +10001000 +11111000 +10001000 +10001000 +00000000 + + 66 + +11110000 +01001000 +01001000 +01110000 +01001000 +01001000 +11110000 +00000000 + + 67 + +00110000 +01001000 +10000000 +10000000 +10000000 +01001000 +00110000 +00000000 + + 68 + +11100000 +01010000 +01001000 +01001000 +01001000 +01010000 +11100000 +00000000 + + 69 + +11111000 +10000000 +10000000 +11110000 +10000000 +10000000 +11111000 +00000000 + + 70 + +11111000 +10000000 +10000000 +11110000 +10000000 +10000000 +10000000 +00000000 + + 71 + +01110000 +10001000 +10000000 +10111000 +10001000 +10001000 +01110000 +00000000 + + 72 + +10001000 +10001000 +10001000 +11111000 +10001000 +10001000 +10001000 +00000000 + + 73 + +01110000 +00100000 +00100000 +00100000 +00100000 +00100000 +01110000 +00000000 + + 74 + +00111000 +00010000 +00010000 +00010000 +10010000 +10010000 +01100000 +00000000 + + 75 + +10001000 +10010000 +10100000 +11000000 +10100000 +10010000 +10001000 +00000000 + + 76 + +10000000 +10000000 +10000000 +10000000 +10000000 +10000000 +11111000 +00000000 + + 77 + +10001000 +11011000 +10101000 +10101000 +10001000 +10001000 +10001000 +00000000 + + 78 + +10001000 +11001000 +11001000 +10101000 +10011000 +10011000 +10001000 +00000000 + + 79 + +01110000 +10001000 +10001000 +10001000 +10001000 +10001000 +01110000 +00000000 + + 80 + +11110000 +10001000 +10001000 +11110000 +10000000 +10000000 +10000000 +00000000 + + 81 + +01110000 +10001000 +10001000 +10001000 +10101000 +10010000 +01101000 +00000000 + + 82 + +11110000 +10001000 +10001000 +11110000 +10100000 +10010000 +10001000 +00000000 + + 83 + +01110000 +10001000 +10000000 +01110000 +00001000 +10001000 +01110000 +00000000 + + 84 + +11111000 +00100000 +00100000 +00100000 +00100000 +00100000 +00100000 +00000000 + + 85 + +10001000 +10001000 +10001000 +10001000 +10001000 +10001000 +01110000 +00000000 + + 86 + +10001000 +10001000 +10001000 +10001000 +01010000 +01010000 +00100000 +00000000 + + 87 + +10001000 +10001000 +10001000 +10101000 +10101000 +11011000 +10001000 +00000000 + + 88 + +10001000 +10001000 +01010000 +00100000 +01010000 +10001000 +10001000 +00000000 + + 89 + +10001000 +10001000 +10001000 +01110000 +00100000 +00100000 +00100000 +00000000 + + 90 + +11111000 +00001000 +00010000 +00100000 +01000000 +10000000 +11111000 +00000000 + + 91 + +01110000 +01000000 +01000000 +01000000 +01000000 +01000000 +01110000 +00000000 + + 92 + +00000000 +00000000 +10000000 +01000000 +00100000 +00010000 +00001000 +00000000 + + 93 + +01110000 +00010000 +00010000 +00010000 +00010000 +00010000 +01110000 +00000000 + + 94 + +00100000 +01010000 +10001000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 95 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111000 +00000000 + + 96 + +01000000 +00100000 +00010000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 97 + +00000000 +00000000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 98 + +10000000 +10000000 +10110000 +11001000 +10001000 +11001000 +10110000 +00000000 + + 99 + +00000000 +00000000 +01110000 +10001000 +10000000 +10001000 +01110000 +00000000 + + 100 + +00001000 +00001000 +01101000 +10011000 +10001000 +10011000 +01101000 +00000000 + + 101 + +00000000 +00000000 +01110000 +10001000 +11111000 +10000000 +01110000 +00000000 + + 102 + +00010000 +00101000 +00100000 +11111000 +00100000 +00100000 +00100000 +00000000 + + 103 + +00000000 +00000000 +01101000 +10011000 +10011000 +01101000 +00001000 +01110000 + + 104 + +10000000 +10000000 +11110000 +10001000 +10001000 +10001000 +10001000 +00000000 + + 105 + +00100000 +00000000 +01100000 +00100000 +00100000 +00100000 +01110000 +00000000 + + 106 + +00010000 +00000000 +00110000 +00010000 +00010000 +00010000 +10010000 +01100000 + + 107 + +01000000 +01000000 +01001000 +01010000 +01100000 +01010000 +01001000 +00000000 + + 108 + +01100000 +00100000 +00100000 +00100000 +00100000 +00100000 +01110000 +00000000 + + 109 + +00000000 +00000000 +11010000 +10101000 +10101000 +10101000 +10101000 +00000000 + + 110 + +00000000 +00000000 +10110000 +11001000 +10001000 +10001000 +10001000 +00000000 + + 111 + +00000000 +00000000 +01110000 +10001000 +10001000 +10001000 +01110000 +00000000 + + 112 + +00000000 +00000000 +10110000 +11001000 +11001000 +10110000 +10000000 +10000000 + + 113 + +00000000 +00000000 +01101000 +10011000 +10011000 +01101000 +00001000 +00001000 + + 114 + +00000000 +00000000 +10110000 +11001000 +10000000 +10000000 +10000000 +00000000 + + 115 + +00000000 +00000000 +01111000 +10000000 +11110000 +00001000 +11110000 +00000000 + + 116 + +01000000 +01000000 +11110000 +01000000 +01000000 +01001000 +00110000 +00000000 + + 117 + +00000000 +00000000 +10010000 +10010000 +10010000 +10010000 +01101000 +00000000 + + 118 + +00000000 +00000000 +10001000 +10001000 +10001000 +01010000 +00100000 +00000000 + + 119 + +00000000 +00000000 +10001000 +10101000 +10101000 +10101000 +01010000 +00000000 + + 120 + +00000000 +00000000 +10001000 +01010000 +00100000 +01010000 +10001000 +00000000 + + 121 + +00000000 +00000000 +10001000 +10001000 +10011000 +01101000 +00001000 +01110000 + + 122 + +00000000 +00000000 +11111000 +00010000 +00100000 +01000000 +11111000 +00000000 + + 123 + +00011000 +00100000 +00100000 +01000000 +00100000 +00100000 +00011000 +00000000 + + 124 + +00100000 +00100000 +00100000 +00000000 +00100000 +00100000 +00100000 +00000000 + + 125 + +11000000 +00100000 +00100000 +00010000 +00100000 +00100000 +11000000 +00000000 + + 126 + +01000000 +10101000 +00010000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 127 + +00000000 +00000000 +00100000 +01010000 +11111000 +00000000 +00000000 +00000000 + + 128 + +01110000 +10001000 +10000000 +10000000 +10001000 +01110000 +00100000 +01100000 + + 129 + +10010000 +00000000 +00000000 +10010000 +10010000 +10010000 +01101000 +00000000 + + 130 + +00010000 +00100000 +01110000 +10001000 +11111000 +10000000 +01110000 +00000000 + + 131 + +00100000 +01010000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 132 + +01001000 +00000000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 133 + +00100000 +00010000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 134 + +00100000 +00000000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 135 + +00000000 +01110000 +10000000 +10000000 +10000000 +01110000 +00010000 +01100000 + + 136 + +00100000 +01010000 +01110000 +10001000 +11111000 +10000000 +01110000 +00000000 + + 137 + +01010000 +00000000 +01110000 +10001000 +11111000 +10000000 +01110000 +00000000 + + 138 + +00100000 +00010000 +01110000 +10001000 +11111000 +10000000 +01110000 +00000000 + + 139 + +01010000 +00000000 +00000000 +01100000 +00100000 +00100000 +01110000 +00000000 + + 140 + +00100000 +01010000 +00000000 +01100000 +00100000 +00100000 +01110000 +00000000 + + 141 + +01000000 +00100000 +00000000 +01100000 +00100000 +00100000 +01110000 +00000000 + + 142 + +01010000 +00000000 +00100000 +01010000 +10001000 +11111000 +10001000 +00000000 + + 143 + +00100000 +00000000 +00100000 +01010000 +10001000 +11111000 +10001000 +00000000 + + 144 + +00010000 +00100000 +11111000 +10000000 +11110000 +10000000 +11111000 +00000000 + + 145 + +00000000 +00000000 +01101100 +00010010 +01111110 +10010000 +01101110 +00000000 + + 146 + +00111110 +01010000 +10010000 +10011100 +11110000 +10010000 +10011110 +00000000 + + 147 + +01100000 +10010000 +00000000 +01100000 +10010000 +10010000 +01100000 +00000000 + + 148 + +10010000 +00000000 +00000000 +01100000 +10010000 +10010000 +01100000 +00000000 + + 149 + +01000000 +00100000 +00000000 +01100000 +10010000 +10010000 +01100000 +00000000 + + 150 + +01000000 +10100000 +00000000 +10100000 +10100000 +10100000 +01010000 +00000000 + + 151 + +01000000 +00100000 +00000000 +10100000 +10100000 +10100000 +01010000 +00000000 + + 152 + +10010000 +00000000 +10010000 +10010000 +10110000 +01010000 +00010000 +11100000 + + 153 + +01010000 +00000000 +01110000 +10001000 +10001000 +10001000 +01110000 +00000000 + + 154 + +01010000 +00000000 +10001000 +10001000 +10001000 +10001000 +01110000 +00000000 + + 155 + +00100000 +00100000 +01111000 +10000000 +10000000 +01111000 +00100000 +00100000 + + 156 + +00011000 +00100100 +00100000 +11111000 +00100000 +11100010 +01011100 +00000000 + + 157 + +10001000 +01010000 +00100000 +11111000 +00100000 +11111000 +00100000 +00000000 + + 158 + +11000000 +10100000 +10100000 +11001000 +10011100 +10001000 +10001000 +10001100 + + 159 + +00011000 +00100000 +00100000 +11111000 +00100000 +00100000 +00100000 +01000000 + + 160 + +00010000 +00100000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 161 + +00010000 +00100000 +00000000 +01100000 +00100000 +00100000 +01110000 +00000000 + + 162 + +00100000 +01000000 +00000000 +01100000 +10010000 +10010000 +01100000 +00000000 + + 163 + +00100000 +01000000 +00000000 +10010000 +10010000 +10010000 +01101000 +00000000 + + 164 + +01010000 +10100000 +00000000 +10100000 +11010000 +10010000 +10010000 +00000000 + + 165 + +00101000 +01010000 +00000000 +11001000 +10101000 +10011000 +10001000 +00000000 + + 166 + +00000000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 +11111000 + + 167 + +00000000 +01100000 +10010000 +10010000 +10010000 +01100000 +00000000 +11110000 + + 168 + +00100000 +00000000 +00100000 +01000000 +10000000 +10001000 +01110000 +00000000 + + 169 + +00000000 +00000000 +00000000 +11111000 +10000000 +10000000 +00000000 +00000000 + + 170 + +00000000 +00000000 +00000000 +11111000 +00001000 +00001000 +00000000 +00000000 + + 171 + +10000100 +10001000 +10010000 +10101000 +01010100 +10000100 +00001000 +00011100 + + 172 + +10000100 +10001000 +10010000 +10101000 +01011000 +10101000 +00111100 +00001000 + + 173 + +00100000 +00000000 +00000000 +00100000 +00100000 +00100000 +00100000 +00000000 + + 174 + +00000000 +00000000 +00100100 +01001000 +10010000 +01001000 +00100100 +00000000 + + 175 + +00000000 +00000000 +10010000 +01001000 +00100100 +01001000 +10010000 +00000000 + + 176 + +00101000 +01010000 +00100000 +01010000 +10001000 +11111000 +10001000 +00000000 + + 177 + +00101000 +01010000 +01110000 +00001000 +01111000 +10001000 +01111000 +00000000 + + 178 + +00101000 +01010000 +00000000 +01110000 +00100000 +00100000 +01110000 +00000000 + + 179 + +00101000 +01010000 +00000000 +00100000 +00100000 +00100000 +01110000 +00000000 + + 180 + +00101000 +01010000 +00000000 +01110000 +10001000 +10001000 +01110000 +00000000 + + 181 + +01010000 +10100000 +00000000 +01100000 +10010000 +10010000 +01100000 +00000000 + + 182 + +00101000 +01010000 +00000000 +10001000 +10001000 +10001000 +01110000 +00000000 + + 183 + +01010000 +10100000 +00000000 +10100000 +10100000 +10100000 +01010000 +00000000 + + 184 + +11111100 +01001000 +01001000 +01001000 +11101000 +00001000 +01010000 +00100000 + + 185 + +00000000 +01010000 +00000000 +01010000 +01010000 +01010000 +00010000 +00100000 + + 186 + +11000000 +01000100 +11001000 +01010100 +11101100 +01010100 +10011110 +00000100 + + 187 + +00010000 +10101000 +01000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 188 + +00000000 +00100000 +01010000 +10001000 +01010000 +00100000 +00000000 +00000000 + + 189 + +10001000 +00010000 +00100000 +01000000 +10000000 +00101000 +00000000 +00000000 + + 190 + +01111100 +10101000 +10101000 +01101000 +00101000 +00101000 +00101000 +00000000 + + 191 + +00111000 +01000000 +00110000 +01001000 +01001000 +00110000 +00001000 +01110000 + + 192 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +11111111 +11111111 + + 193 + +11110000 +11110000 +11110000 +11110000 +00001111 +00001111 +00001111 +00001111 + + 194 + +00000000 +00000000 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 + + 195 + +11111111 +11111111 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 + + 196 + +00000000 +00000000 +00000000 +00111100 +00111100 +00000000 +00000000 +00000000 + + 197 + +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +00000000 +00000000 + + 198 + +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 +11000000 + + 199 + +00001111 +00001111 +00001111 +00001111 +11110000 +11110000 +11110000 +11110000 + + 200 + +11111100 +11111100 +11111100 +11111100 +11111100 +11111100 +11111100 +11111100 + + 201 + +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 +00000011 + + 202 + +00111111 +00111111 +00111111 +00111111 +00111111 +00111111 +00111111 +00111111 + + 203 + +00010001 +00100010 +01000100 +10001000 +00010001 +00100010 +01000100 +10001000 + + 204 + +10001000 +01000100 +00100010 +00010001 +10001000 +01000100 +00100010 +00010001 + + 205 + +11111110 +01111100 +00111000 +00010000 +00000000 +00000000 +00000000 +00000000 + + 206 + +00000000 +00000000 +00000000 +00000000 +00010000 +00111000 +01111100 +11111110 + + 207 + +10000000 +11000000 +11100000 +11110000 +11100000 +11000000 +10000000 +00000000 + + 208 + +00000001 +00000011 +00000111 +00001111 +00000111 +00000011 +00000001 +00000000 + + 209 + +11111111 +01111110 +00111100 +00011000 +00011000 +00111100 +01111110 +11111111 + + 210 + +10000001 +11000011 +11100111 +11111111 +11111111 +11100111 +11000011 +10000001 + + 211 + +11110000 +11110000 +11110000 +11110000 +00000000 +00000000 +00000000 +00000000 + + 212 + +00000000 +00000000 +00000000 +00000000 +00001111 +00001111 +00001111 +00001111 + + 213 + +00001111 +00001111 +00001111 +00001111 +00000000 +00000000 +00000000 +00000000 + + 214 + +00000000 +00000000 +00000000 +00000000 +11110000 +11110000 +11110000 +11110000 + + 215 + +00110011 +00110011 +11001100 +11001100 +00110011 +00110011 +11001100 +11001100 + + 216 + +00000000 +00100000 +00100000 +01010000 +01010000 +10001000 +11111000 +00000000 + + 217 + +00100000 +00100000 +01110000 +00100000 +01110000 +00100000 +00100000 +00000000 + + 218 + +00000000 +00000000 +00000000 +01010000 +10001000 +10101000 +01010000 +00000000 + + 219 + +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 +11111111 + + 220 + +00000000 +00000000 +00000000 +00000000 +11111111 +11111111 +11111111 +11111111 + + 221 + +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 +11110000 + + 222 + +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 +00001111 + + 223 + +11111111 +11111111 +11111111 +11111111 +00000000 +00000000 +00000000 +00000000 + + 224 + +00000000 +00000000 +01101000 +10010000 +10010000 +10010000 +01101000 +00000000 + + 225 + +00110000 +01001000 +01001000 +01110000 +01001000 +01001000 +01110000 +11000000 + + 226 + +11111000 +10001000 +10000000 +10000000 +10000000 +10000000 +10000000 +00000000 + + 227 + +11111000 +01010000 +01010000 +01010000 +01010000 +01010000 +10011000 +00000000 + + 228 + +11111000 +10001000 +01000000 +00100000 +01000000 +10001000 +11111000 +00000000 + + 229 + +00000000 +00000000 +01111000 +10010000 +10010000 +10010000 +01100000 +00000000 + + 230 + +00000000 +01010000 +01010000 +01010000 +01010000 +01101000 +10000000 +10000000 + + 231 + +00000000 +01010000 +10100000 +00100000 +00100000 +00100000 +00100000 +00000000 + + 232 + +11111000 +00100000 +01110000 +10101000 +10101000 +01110000 +00100000 +11111000 + + 233 + +00100000 +01010000 +10001000 +11111000 +10001000 +01010000 +00100000 +00000000 + + 234 + +01110000 +10001000 +10001000 +10001000 +01010000 +01010000 +11011000 +00000000 + + 235 + +00110000 +01000000 +01000000 +00100000 +01010000 +01010000 +01010000 +00100000 + + 236 + +00000000 +00000000 +00000000 +01010000 +10101000 +10101000 +01010000 +00000000 + + 237 + +00001000 +01110000 +10101000 +10101000 +10101000 +01110000 +10000000 +00000000 + + 238 + +00111000 +01000000 +10000000 +11111000 +10000000 +01000000 +00111000 +00000000 + + 239 + +01110000 +10001000 +10001000 +10001000 +10001000 +10001000 +10001000 +00000000 + + 240 + +00000000 +11111000 +00000000 +11111000 +00000000 +11111000 +00000000 +00000000 + + 241 + +00100000 +00100000 +11111000 +00100000 +00100000 +00000000 +11111000 +00000000 + + 242 + +11000000 +00110000 +00001000 +00110000 +11000000 +00000000 +11111000 +00000000 + + 243 + +00011000 +01100000 +10000000 +01100000 +00011000 +00000000 +11111000 +00000000 + + 244 + +00010000 +00101000 +00100000 +00100000 +00100000 +00100000 +00100000 +00100000 + + 245 + +00100000 +00100000 +00100000 +00100000 +00100000 +00100000 +10100000 +01000000 + + 246 + +00000000 +00100000 +00000000 +11111000 +00000000 +00100000 +00000000 +00000000 + + 247 + +00000000 +01010000 +10100000 +00000000 +01010000 +10100000 +00000000 +00000000 + + 248 + +00000000 +00011000 +00100100 +00100100 +00011000 +00000000 +00000000 +00000000 + + 249 + +00000000 +00110000 +01111000 +01111000 +00110000 +00000000 +00000000 +00000000 + + 250 + +00000000 +00000000 +00000000 +00000000 +00110000 +00000000 +00000000 +00000000 + + 251 + +00111110 +00100000 +00100000 +00100000 +10100000 +01100000 +00100000 +00000000 + + 252 + +10100000 +01010000 +01010000 +01010000 +00000000 +00000000 +00000000 +00000000 + + 253 + +01000000 +10100000 +00100000 +01000000 +11100000 +00000000 +00000000 +00000000 + + 254 + +00000000 +00111000 +00111000 +00111000 +00111000 +00111000 +00111000 +00000000 + + 255 + +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 diff --git a/program.cpp b/program.cpp new file mode 100644 index 0000000..2d24c29 --- /dev/null +++ b/program.cpp @@ -0,0 +1,1611 @@ +// program.cpp +// Revision 24-apr-2009 + +#include "program.h" + +#include "keyword.h" +#include "error.h" +#include "sysvar.h" +#include "util.h" +using util::to_string; +#include "trace.h" + +#include +#include +#include +#include +#include +#include +#include + +using std::string; +// For debugging. +using std::cerr; +using std::endl; +using std::flush; + +#include +#define ASSERT assert + +#include + +#ifndef USE_HASH_MAP + +#include +#define MAP std::map + +#else + +#if __GNUC__ < 3 +#include +#define N_MAP std +#else +#include +#define N_MAP __gnu_cxx +#endif + +#define MAP N_MAP::hash_map + +namespace N_MAP { + +template <> struct hash +{ + hash () : hashstr (hash () ) { } + size_t operator () (const std::string & str) const + { return hashstr (str.c_str () ); } +private: + hash 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 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 linecache_t; + typedef MAP linecache_t; + linecache_t linecache; + + typedef MAP 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 (& n), + LineEndProgram); + setLineLength (reinterpret_cast (& 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 + (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 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 (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 (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 newprog (newblock); + //is.read (reinterpret_cast (newprog.data () ), + // newsize); + + ProgramImpl other; + other.resize (newsize); + is.read (reinterpret_cast (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 + +#include + +#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 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 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 + +//#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 + +// 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 (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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#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 (fLine ? 3 : 1); + BlChar oldflags= sysvar::get (sysvar::TronFlags); + flags= flags | (oldflags & static_cast (~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 (~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 (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 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 pf (graphics::ingraphicsmode () ? + newBlFileWindow (DefaultChannel) : + newBlFileConsole () ); + setfile (DefaultChannel, pf.get () ); + pf.release (); +} + +void GlobalRunner::resetfileprinter () +{ + auto_ptr pf (newBlFilePrinter () ); + setfile (PrinterChannel, pf.get () ); + pf.release (); +} + +void GlobalRunner::close_all () +{ + std::vector 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 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 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 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 & 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 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 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 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 +#include +#include +#include + + +// ********************* 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 ChanFile; + typedef std::map 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 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 > 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 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// cmath is not used because in some platforms asinh and others +// are declared only in math.h +#include + +#if defined __unix__ || defined __linux__ +// Using uname on unix, linux and cygwin. +#include +#endif + +#include +#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 + (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 + (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 + (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 + (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 (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 (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 (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 (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 (peek32 (addr) ) ); + result= peek32 (addr); +} + +void RunnerLineImpl::val_PROGRAMPTR (BlResult & result) +{ + gettoken (); + //result= BlNumber (size_t (program.programptr () ) ); + result= static_cast (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 (runner.geterr () ); + gettoken (); +} + +void RunnerLineImpl::val_ERL (BlResult & result) +{ + result= static_cast (runner.geterrline () ); + gettoken (); +} + +void RunnerLineImpl::val_FIX (BlResult & result) +{ + valnumericfunc (auxFIX, result); +} + +void RunnerLineImpl::val_XMOUSE (BlResult & result) +{ + result= static_cast (graphics::xmouse () ); + gettoken (); +} + +void RunnerLineImpl::val_YMOUSE (BlResult & result) +{ + result= static_cast (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 + (c - 'a' + base); + else if (c >= 'A' && c <= 'Z') + c= static_cast + (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 vparam; + util::auto_buffer 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 vparam; + while (token.code == ',') + { + expect (result); + vparam.push_back (result.integer () ); + ++nparams; + } + requiretoken (')'); + gettoken (); + //util::auto_buffer 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 + (addrvarnumber (varname) ); + break; + case VarInteger: + addr= reinterpret_cast + (addrvarinteger (varname) ); + break; + case VarString: + addr= reinterpret_cast + (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 + (addrdimnumber (varname, dims) ); + break; + case VarInteger: + addr= reinterpret_cast + (addrdiminteger (varname, dims) ); + break; + case VarString: + addr= reinterpret_cast + (addrdimstring (varname, dims) ); + break; + default: + throw ErrBlassicInternal; + } + gettoken (); + } + break; + default: + throw ErrSyntax; + } + //result= BlNumber (addr); + result= static_cast (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 (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 + ( (* reinterpret_cast (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 (graphics::test (x, y, false) ); +} + +void RunnerLineImpl::val_TESTR (BlResult & result) +{ + expecttoken ('('); + int x= expectinteger (); + requiretoken (','); + int y= expectinteger (); + requiretoken (')'); + gettoken (); + result= static_cast (graphics::test (x, y, true) ); +} + +void RunnerLineImpl::val_POS (BlResult & result) +{ + result= static_cast (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 (& f), sizeof (float) ); + result= str; +} + +void RunnerLineImpl::val_MKD_S (BlResult & result) +{ + getparenarg (result); + double f= result.number (); + std::string str (reinterpret_cast (& 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 (expectnum () ); + if (token.code == ',') + { + to= static_cast (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 (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 (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 pfnrunnerline + // (new RunnerLineImpl (runner) ); + //CodeLine & fncodeline= pfnrunnerline->getcodeline (); + //fncodeline= f.getcode (); + + CodeLine fncodeline (f.getcode () ); + auto_ptr 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 (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 +#include + +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 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 +using std::auto_ptr; + +#include +using std::cerr; +using std::endl; +using std::flush; + +#include +#include + +#include +#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 aux (size); + is.read (aux, size); + result.assign (aux, size); + } + assignvarstring (varname, result); + } + else + { + char * init; + { + BlNumber bn= evalnum (); + init= reinterpret_cast (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 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 + (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 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 (result); + seedvalue= util::checked_cast + (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 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 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 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 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 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 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 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 (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 + (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 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 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 (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 (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 (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 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 (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 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 (radius / elliptic); + ry= radius; + } + else + { + rx= radius; + ry= static_cast (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 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 +#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 +using std::cerr; +using std::endl; + +#ifdef BLASSIC_USE_WINDOWS + +#include + +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 +#include + +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 + +//------------------------------------------------ +// Changed this: now do not use winsock in Cygwin. +//------------------------------------------------ +//#if defined _Windows || defined __CYGWIN__ || defined __MINGW32__ +// +#if defined _Windows || defined __MINGW32__ + +#include + +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 +#include +#include +#include +#include +#include + +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 + +#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 +#include + +#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 + + +namespace { + +BlChar system_vars [blassic::sysvar::EndSysVar]; + +} // namespace + + +size_t blassic::sysvar::address () +{ + return reinterpret_cast (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 (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 (system_vars [Flags1] ); +} + +blassic::sysvar::Flags2Bit blassic::sysvar::getFlags2 () +{ + return static_cast (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 (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 (& 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 + +#ifdef __BORLANDC__ +#pragma hdrstop +#include +// string (iterator, iterator) gives this warnig: +#pragma warn -8012 +#else +#error Compiler not tested. +#endif + +#endif + +#include +#include + +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 (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 +#include + +using std::isalpha; +using std::isdigit; +using std::isxdigit; +using std::isspace; + +Tokenizer::Tokenizer (const std::string & source) : + str (source), pos (0), limit (source.size () ) +{ +} + +unsigned char Tokenizer::peek () +{ + if (pos < limit) + return str [pos]; + else + return '\0'; +} + +unsigned char Tokenizer::peeknospace () +{ + unsigned char c= '\0'; + std::string::size_type p= pos; + while (p < limit && (c= str [p] ) == ' ') + ++p; + if (p < limit) + return c; + else + return '\0'; +} + +unsigned char Tokenizer::nextchar () +{ + if (pos < limit) + return str [pos++]; + else + return '\0'; +} + +unsigned char Tokenizer::nextcharnospace () +{ + unsigned char c= '\0'; + while (pos < limit && (c= str [pos] ) == ' ') + ++pos; + if (pos < limit) + { + ++pos; + return c; + } + else + return '\0'; +} + +void Tokenizer::ungetchar () +{ + if (pos > 0) + --pos; +} + +//namespace { + +inline bool isident (char c) +{ + return isalpha (c) || isdigit (c) || c == '_'; +} + +//} + +Tokenizer::Token Tokenizer::get () +{ + unsigned char c= nextchar (); + if (c == '\0') + return Token (EndLine); + + std::string str; + if (isspace (c) ) + { + do { + str+= c; + } while (isspace (c= nextchar () ) ); + if (c != '\0') + ungetchar (); + return Token (Blank, str); + } + + switch (c) + { + case '"': + //str+= c; + while ( (c= nextchar () ) != '\0') + { + if (c == '"') + { + c= peek (); + if (c != '"') + break; + nextchar (); + } + str+= c; + } + return Token (Literal, str); + case '&': + // Hex, octal or binary number + str= '&'; + c= nextchar (); + if (c == 'x' || c == 'X') // Binary + { + str+= c; + while ( (c= nextchar () ) == '0' || c == '1') + str+= c; + if (c != 0) + ungetchar (); + } + else if (c == 'o' || c == 'O') // Octal + { + str+= c; + while ( (c= nextchar () ) >= '0' && c <= '7') + str+= c; + if (c != 0) + ungetchar (); + } + else // Hexadecimal + { + if (c == 'h' || c == 'H') + { + str+= c; + c= nextchar (); + } + while (isxdigit (c) ) + { + str+= c; + c= nextchar (); + } + if (c != 0) + ungetchar (); + } + return Token (Plain, str); + case '=': + { + str= c; + c= peeknospace (); + if (c == '>' || c == '<') + { + str+= c; + (void) nextcharnospace (); + } + } + return Token (Plain, str); + case '<': + str= c; + c= peeknospace (); + if (c == '=' || c == '>') + { + str+= c; + (void) nextcharnospace (); + } + return Token (Plain, str); + case '>': + str= c; + c= peeknospace (); + if (c == '=' || c == '<') + { + str+= c; + (void) nextcharnospace (); + } + return Token (Plain, str); + default: + ; // Later. + } + + if (isalpha (c) ) + { + do + { + str+= c; + } while ( isident (c= nextchar () ) ); + if (c == '$') + str+= c; + else + if (c != '\0') + ungetchar (); + return Token (Plain, str); + } + + if (isdigit (c) || c == '.') + { + bool nofloat= true; + while (isdigit (c) ) + { + str+= c; + c= nextchar (); + } + if (c == '.') + { + str+= '.'; + nofloat= false; + while ( isdigit (c= nextchar () ) ) + str+= c; + } + if (c == 'e' || c == 'E') + { + str+= c; + nofloat= false; + c= nextchar (); + if (! isdigit (c) && c != '+' && c != '-') + { + // Data such as 1E + while (isident (c) ) + { + str+= c; + c= nextchar (); + } + if (c != 0) + ungetchar (); + return Token (Plain, str); + } + if (c == '+' || c == '-') + { + str+= c; + c= nextchar (); + } + while (isdigit (c) ) + { + str+= c; + c= nextchar (); + } + } + if (c != 0) + { + if (isident (c) ) + { + do { + str+= c; + c= nextchar (); + } while (isident (c) ); + if (c != 0) + ungetchar (); + return Token (Plain, str); + } + ungetchar (); + } + if (nofloat) + { + #if 0 + std::istringstream iss (str); + BlInteger n; + iss >> n; + if (iss) + { + iss.get (); + //if (! iss) + if (iss.eof () ) + return Token (n); + } + #else + BlInteger n= 0; + std::string::size_type i; + const std::string::size_type l= str.size (); + for (i= 0; i < l; ++i) + { + BlInteger digit= str [i] - '0'; + if (n > (BlIntegerMax / 10) ) + break; + n*= 10; + if (n > BlIntegerMax - digit) + break; + n+= digit; + } + if (i == l) + return Token (n); + #endif + } + return Token (Plain, str); + } + + // If nothing else: + str= c; + return Token (Plain, str); +} + +std::string Tokenizer::getrest () +{ + std::string r; + char c; + while ( (c= nextchar () ) != 0) + { + if (c == '"') + { + r+= c; + while ( (c= nextchar () ) != '\0') + { + if (c == '"') + { + c= peek (); + if (c != '"') + break; + nextchar (); + } + r+= c; + } + r+= '\0'; + } + else + r+= c; + } + return r; +} + +// Fin de token.cpp diff --git a/token.h b/token.h new file mode 100644 index 0000000..3decdbc --- /dev/null +++ b/token.h @@ -0,0 +1,53 @@ +#ifndef INCLUDE_BLASSIC_TOKEN_H +#define INCLUDE_BLASSIC_TOKEN_H + +// token.h +// Revision 7-feb-2005 + + +#include "blassic.h" + +#include + + +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 +#include +#include + +#ifdef HAVE_CSTDLIB +#include +#else +#include +#endif + +#include + +#include + +using std::cerr; +using std::endl; +using std::ostream; +using std::ofstream; +using std::string; + + +namespace { + +ostream * pout= 0; +bool flag= true; +size_t indent= 0; + +TraceFunc * initial= NULL; +TraceFunc * * lastpos= & initial; + +ostream * opentracefile (const char * str) +{ + std::ofstream * pof= + new ofstream (str, std::ios::app | std::ios::out); + if (! pof->is_open () ) + { + cerr << "Error opening " << str << endl; + delete pof; + pof= 0; + } + return pof; +} + +void showinfo (const char * strenterexit, const char * strfunc) +{ + if (pout) + { + * pout << string (indent, ' ') << strenterexit << ' '; + + if (std::uncaught_exception () ) + * pout << "(throwing) "; + + * pout << strfunc << endl; + } +} + +const char BAD_USE []= "Bad use of TraceFunc"; + +} // namespace + +TraceFunc::TraceFunc (const char * strFuncName) : + strfunc (strFuncName), + next (NULL) +{ + if (flag) + { + flag= false; + char * aux= getenv ("TRACEFUNC"); + if (aux) + { + if (strcmp (aux, "-") == 0) + pout= & std::cerr; + else + pout= opentracefile (aux); + } + } + + //tracelist.push_back (this); + previous= lastpos; + * lastpos= this; + lastpos= & next; + + #if 0 + if (pout) + { + * pout << string (indent, ' ') << "Enter "; + + if (std::uncaught_exception () ) + * pout << "(throwing) "; + + * pout << strfunc << endl; + } + #else + showinfo ("Enter", strfunc); + #endif + ++indent; +} + +TraceFunc::~TraceFunc () +{ + --indent; + + #if 0 + if (pout) + { + * pout << string (indent, ' ') << "Exit "; + + if (std::uncaught_exception () ) + * pout << "(throwing) "; + + * pout << strfunc << endl; + } + #else + showinfo ("Exit", strfunc); + #endif + + if (next != NULL) + { + cerr << BAD_USE << endl; + abort (); + } + if (lastpos != & next) + { + //throw std::logic_error ("Bad use of TraceFunc"); + cerr << BAD_USE << endl; + abort (); + } + lastpos= previous; + if (* lastpos != this) + { + cerr << BAD_USE << endl; + abort (); + } + * lastpos= NULL; +} + +void TraceFunc::message (const std::string & strMes) +{ + if (pout) + { + * pout << string (indent, ' ') << strfunc; + + if (std::uncaught_exception () ) + * pout << "(throwing) "; + + * pout << ": " << strMes << endl; + } +} + +void TraceFunc::show (int) +{ + cerr << "\r\n"; + + if (initial == NULL) + cerr << "TraceFunc: no calls."; + else + { + cerr << "TraceFunc dump of calls: \r\n"; + for (TraceFunc * act= initial; act != NULL; act= act->next) + cerr << act->strfunc << "\r\n"; + cerr << "TraceFunc dump ended."; + } + cerr << "\r\n"; +} + +// Fin de trace.cpp diff --git a/trace.h b/trace.h new file mode 100644 index 0000000..6f671f8 --- /dev/null +++ b/trace.h @@ -0,0 +1,39 @@ +#ifndef INCLUDE_BLASSIC_TRACE_H +#define INCLUDE_BLASSIC_TRACE_H + +// trace.h +// Revision 7-feb-2005 + +#include +#include + + +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 +#include +#include +using std::auto_ptr; +#include +using std::sprintf; +#include +#include +#include +#include + +#include +#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 ('#') ]= true; + charformat [static_cast ('.') ]= true; + charformat [static_cast ('+') ]= true; + charformat [static_cast ('*') ]= true; + charformat [static_cast ('$') ]= true; + charformat [static_cast (poundsign) ]= true; + charformat [static_cast (eurosign) ]= true; + charformat [static_cast ('\\') ]= true; + charformat [static_cast ('&') ]= true; + charformat [static_cast ('!') ]= true; + return true; +} + +bool initedformat= initformat (); + +bool ischarformat (char c) +{ + return charformat [static_cast (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 (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 + (std::floor (std::log10 (fabs (n) ) ) ) + + - static_cast (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 (v.back () ) ) != NULL) + { + prev->addstr (dynamic_cast (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 (c) ) + { + case '#': + case '.': + case '+': + case '*': + case '$': + case poundsign: + case eurosign: + { + std::string tail; + UsingNumeric un (is, tail); + if (un.isvalid () ) + vu.push_back (un); + else + { + UsingLiteral ul (un.str () ); + vu.push_back (ul); + } + if (! tail.empty () ) + { + UsingLiteral ul (is, tail); + vu.push_back (ul); + } + } + break; + case '\\': + case '&': + case '!': + { + UsingString us (is); + vu.push_back (us); + } + break; + default: + { + UsingLiteral ul (is); + vu.push_back (ul); + } + } + } +} + +// End of using.cpp diff --git a/using.h b/using.h new file mode 100644 index 0000000..ad73607 --- /dev/null +++ b/using.h @@ -0,0 +1,96 @@ +#ifndef INCLUDE_BLASSIC_USING_H +#define INCLUDE_BLASSIC_USING_H + +// using.h +// Revision 7-feb-2005 + +#include "error.h" +#include "file.h" + +#include +#include + + +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 v; +}; + +void parseusing (const std::string & str, VectorUsing & vu); + +#endif + +// End of using.h diff --git a/util.h b/util.h new file mode 100644 index 0000000..d98a278 --- /dev/null +++ b/util.h @@ -0,0 +1,202 @@ +#ifndef INCLUDE_UTIL_H +#define INCLUDE_UTIL_H + +// util.h +// Revision 24-apr-2009 + +#include +#include +#include +#include + +#include + +#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 +DEST checked_cast (ORG org, EX ex) +{ + DEST dest= static_cast (org); + if (static_cast (dest) != org) + throw ex; + return dest; +} + +template +size_t dim_array (C (&) [N]) +{ return N; } + +template +size_t dim_array (const C (&) [N]) +{ return N; } + +template +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 auto_alloc +{ +public: + auto_alloc (size_t size) : + p (static_cast (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 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 +std::string to_string (const C & c) +{ + std::ostringstream oss; + oss << c; + return oss.str (); +} + +// Functions used to avoid warnings about unused parameters. + +template +inline void touch (const T & t) +{ + (void) t; +} +template +inline void touch (const T1 & t1, const T2 & t2) +{ + (void) t1; (void) t2; +} +template +inline void touch (const T1 & t1, const T2 & t2, const T3 & t3) +{ + (void) t1; (void) t2; (void) t3; +} +template +inline void touch (const T1 & t1, const T2 & t2, const T3 & t3, + const T4 & t4) +{ + (void) t1; (void) t2; (void) t3; + (void) t4; +} +template +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 +inline void touch (const T1 & t1, const T2 & t2, const T3 & t3, + const T4 & t4, const T5 & t5, const T6 & t6) +{ + (void) t1; (void) t2; (void) t3; + (void) t4; (void) t5; (void) t6; +} + +} // namespace + +#endif + +// End of util.h diff --git a/var.cpp b/var.cpp new file mode 100644 index 0000000..8aa85e6 --- /dev/null +++ b/var.cpp @@ -0,0 +1,715 @@ +// var.cpp +// Revision 7-feb-2005 + +//#define KEEP_IT_SIMPLE + + +#include "var.h" +#include "sysvar.h" +#include "error.h" +#include "util.h" + +#include +#include +#include + +//#include +//using std::toupper; + +#include +using std::cerr; +using std::endl; + +#ifdef __BORLANDC__ +#pragma warn -inl +#if __BORLANDC__ >= 0x0560 +#pragma warn -8091 +#endif +#endif + +#ifndef USE_HASH_MAP + +#include +#define MAP std::map + +#else + +#if __GNUC__ < 3 +#include +#define N_MAP std +#else +#include +#define N_MAP __gnu_cxx +#endif + +#define MAP N_MAP::hash_map + +namespace N_MAP { + +template <> struct hash +{ + hash () : hashstr (hash () ) { } + size_t operator () (const std::string & str) const + { return hashstr (str.c_str () ); } +private: + hash 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 +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 +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 Table { + static const size_t chunk_size= 512; + std::vector vc; + size_t n; + static void clearchunk (C * pc); +public: + Table (); + ~Table (); + void clear (); + C * newvar (); +}; + +template +Table::Table () : + n (0) +{ } + +template +Table::~Table () +{ + clear (); +} + +template +void Table::clearchunk (C * pc) +{ + delete [] pc; +} + +template +void Table::clear () +{ + std::for_each (vc.begin (), vc.end (), clearchunk); + vc.clear (); + n= 0; +} + +template +C * Table::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 tablenumber; +Table tableinteger; +Table tablestring; + +template +inline Table & table (); + +template <> +inline Table & table () +{ return tablenumber; } +template <> +inline Table & table () +{ return tableinteger; } +template <> +inline Table & table () +{ return tablestring; } + +MAP numvar; +MAP integervar; +MAP stringvar; + +template +inline MAP & mapvar (); + +template <> +inline MAP & mapvar () +{ return numvar; } +template <> +inline MAP & mapvar () +{ return integervar; } +template <> +inline MAP & mapvar () +{ return stringvar; } + +template +inline C * getaddr (const std::string name) +{ + C * addr= mapvar () [name]; + if (! addr) + { + addr= table ().newvar (); + mapvar () [name]= addr; + initnewvar (* addr); + } + return addr; +} + +template +inline void assignvar (const std::string & n, const C & value) +{ + C * pc= getaddr (n); + * pc= value; +} + +template +inline C evaluatevar (const std::string & n) +{ + C * pc= getaddr (n); + return * pc; +} + +#else +// Keep it Simple. + +MAP varnumber; +MAP varinteger; +MAP 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 (name); + // Ops, I forget to strip here. + return evaluatevar (stripvarnumber (name) ); + #else + return varnumber [stripvarnumber (name) ]; + #endif +} + +BlInteger evaluatevarinteger (const std::string & name) +{ + #ifndef KEEP_IT_SIMPLE + return evaluatevar (stripvarinteger (name) ); + #else + return varinteger [stripvarinteger (name) ]; + #endif +} + +std::string evaluatevarstring (const std::string & name) +{ + #ifndef KEEP_IT_SIMPLE + return evaluatevar (stripvarstring (name) ); + #else + return varstring [stripvarstring (name) ]; + #endif +} + +BlNumber * addrvarnumber (const std::string & name) +{ + #ifndef KEEP_IT_SIMPLE + //return getaddr (name); + // Ops, I forget to strip here. + return getaddr (stripvarnumber (name) ); + #else + return & varnumber [stripvarnumber (name) ]; + #endif +} + +BlInteger * addrvarinteger (const std::string & name) +{ + #ifndef KEEP_IT_SIMPLE + return getaddr (stripvarinteger (name) ); + #else + return & varinteger [stripvarinteger (name) ]; + #endif +} + +std::string * addrvarstring (const std::string & name) +{ + #ifndef KEEP_IT_SIMPLE + return getaddr (stripvarstring (name) ); + #else + return & varstring [stripvarstring (name) ]; + #endif +} + +//********************************************************* +// ARRAYS +//********************************************************* + +namespace { + +template +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 +Array ::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 ); +} + +template +Array ::Array () : // Default constructor required for map [] + pcount (new size_t), + value (new C [0] ) +{ + * pcount= 1; +} + +template +Array ::Array (const Array & a) : + d (a.d), + pcount (a.pcount), + value (a.value) +{ + addref (); +} + +template +Array ::~Array () +{ + delref (); +} + +template +void Array ::operator = (const Array & a) +{ + if (this != & a) + { + delref (); + d= a.d; + pcount= a.pcount; + value= a.value; + addref (); + } +} + +template +void Array ::addref () +{ + ++ (* pcount); +} + +template +void Array ::delref () +{ + if (-- (* pcount) == 0) + { + //cerr << "Array of dim " << d << " deleted" << endl; + delete [] value; + delete pcount; + } +} + +#if 0 +template +inline Array makeArray (const Dimension & nd, C * nvalue) +{ + return Array (nd, nvalue); +} +#endif + +template +struct ArrayVar { + typedef MAP > map; + typedef typename map::iterator iterator; + typedef typename map::const_iterator const_iterator; + typedef typename map::value_type value_type; +}; + +MAP > arrayvarnumber; +MAP > arrayvarinteger; +MAP > arrayvarstring; + +template +inline typename ArrayVar ::map & arrayvar (); +// Se necesita como plantilla para usarlo en otras plantillas. +// Lo definimos solamente para los tipos usados. + +template <> +inline ArrayVar ::map & + arrayvar () +{ return arrayvarnumber; } +template <> +inline ArrayVar ::map & + arrayvar () +{ return arrayvarinteger; } +template <> +inline ArrayVar::map & + arrayvar () +{ return arrayvarstring; } + +template +inline void dimvar (const std::string & name, const Dimension & d) +{ + typename ArrayVar ::iterator it= arrayvar ().find (name), + end= arrayvar ().end (); + //if (arrayvar ().find (name) != arrayvar ().end () ) + // throw ErrAlreadyDim; + if (it != end && sysvar::get (sysvar::TypeOfDimCheck) == 0) + throw ErrAlreadyDim; + #if 0 + size_t n= d.elements (); + util::auto_buffer value (n); + arrayvar () [name]= makeArray (d, value.data () ); + #else + //Array a (d); + //arrayvar () [name]= a; + arrayvar () [name]= Array (d); + #endif + //std::for_each (value.begin (), value.end (), initnewvar ); + //value.release (); +} + +template +inline void erasevar (const std::string & name) +{ + typename ArrayVar ::const_iterator it= + arrayvar ().find (name); + if (it == arrayvar ().end () ) + throw ErrFunctionCall; + arrayvar ().erase (name); + //arrayvar ().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 +void createdefault (const std::string & name, const Dimension & d) +{ + Dimension n= defaultdimension (d); + dimvar (name, n); +} + +template +inline C * addrdim (const std::string & name, const Dimension & d) +{ + typename ArrayVar ::iterator it= + arrayvar ().find (name); + if (it == arrayvar ().end () ) + { + createdefault (name, d); + it= arrayvar ().find (name); + if (it == arrayvar ().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 +inline C valuedim (const std::string & name, const Dimension & d) +{ + return * addrdim (name, d); +} + +template +inline void assigndim (const std::string & name, + const Dimension & d, const C & result) +{ + * addrdim (name, d)= result; +} + +} // namespace + +void dimvarnumber (const std::string & name, const Dimension & d) +{ + dimvar (stripvarnumber (name), d); +} + +void dimvarinteger (const std::string & name, const Dimension & d) +{ + dimvar (stripvarinteger (name), d); +} + +void dimvarstring (const std::string & name, const Dimension & d) +{ + dimvar (stripvarstring (name), d); +} + +void erasevarnumber (const std::string & name) +{ + erasevar (stripvarnumber (name) ); +} + +void erasevarinteger (const std::string & name) +{ + erasevar (stripvarinteger (name) ); +} + +void erasevarstring (const std::string & name) +{ + erasevar (stripvarstring (name) ); +} + +BlNumber valuedimnumber (const std::string & name, const Dimension & d) +{ + return valuedim (stripvarnumber (name), d); +} + +BlInteger valuediminteger (const std::string & name, const Dimension & d) +{ + return valuedim (stripvarinteger (name), d); +} + +std::string valuedimstring (const std::string & name, const Dimension & d) +{ + return valuedim (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 (stripvarnumber (name), d); +} + +BlInteger * addrdiminteger (const std::string & name, const Dimension & d) +{ + return addrdim (stripvarinteger (name), d); +} + +std::string * addrdimstring (const std::string & name, const Dimension & d) +{ + return addrdim (stripvarstring (name), d); +} + +//********************************************************** +// Borrado de variables +//********************************************************** + +namespace { + +#if 0 +template +class FreeArray { +public: + void operator () + (const typename ArrayVar ::value_type & var) + { + delete [] var.second.value; + } +}; +#endif + +template +inline void cleararray () +{ + //std::for_each (arrayvar ().begin (), arrayvar ().end (), + // FreeArray () ); + arrayvar ().clear (); +} + +#ifndef KEEP_IT_SIMPLE + +template +void clear () +{ + table ().clear (); + mapvar ().clear (); +} + +#endif + +} // namespace + +void clearvars () +{ + #ifndef KEEP_IT_SIMPLE + clear (); + clear (); + clear (); + #else + varnumber.clear (); + varinteger.clear (); + varstring.clear (); + #endif + + cleararray (); + cleararray (); + cleararray (); +} + +// Fin de var.cpp diff --git a/var.h b/var.h new file mode 100644 index 0000000..0cfa4d8 --- /dev/null +++ b/var.h @@ -0,0 +1,71 @@ +#ifndef INCLUDE_BLASSIC_VAR_H +#define INCLUDE_BLASSIC_VAR_H + +// var.h +// Revision 8-jan-2005 + +#include "blassic.h" +#include "dim.h" + +// Now defined in blassic.h to reduce dependencies. + +//enum VarType { VarUndef, VarNumber, VarString, VarInteger }; + +//inline bool is_numeric_type (VarType v) +//{ return v == VarNumber || v == VarInteger; } + + +struct VarPointer { + VarType type; + union { + BlNumber * pnumber; + BlInteger * pinteger; + std::string * pstring; + }; + std::string::size_type from, to; +}; + +VarType typeofvar (const std::string & name); + +void definevar (VarType type, char c); +void definevar (VarType type, char cfrom, char cto); + +void clearvars (); +void assignvarnumber (const std::string & name, BlNumber value); +void assignvarinteger (const std::string & name, BlInteger value); +void assignvarstring (const std::string & name, const std::string & value); + +BlNumber evaluatevarnumber (const std::string & name); +BlInteger evaluatevarinteger (const std::string & name); +std::string evaluatevarstring (const std::string & name); + +BlNumber * addrvarnumber (const std::string & name); +BlInteger * addrvarinteger (const std::string & name); +std::string * addrvarstring (const std::string & name); + +void dimvarnumber (const std::string & name, const Dimension & d); +void dimvarinteger (const std::string & name, const Dimension & d); +void dimvarstring (const std::string & name, const Dimension & d); + +void erasevarnumber (const std::string & name); +void erasevarinteger (const std::string & name); +void erasevarstring (const std::string & name); + +BlNumber valuedimnumber (const std::string & name, const Dimension & d); +BlInteger valuediminteger (const std::string & name, const Dimension & d); +std::string valuedimstring (const std::string & name, const Dimension & d); + +void assigndimnumber (const std::string & name, const Dimension & d, + BlNumber value); +void assigndiminteger (const std::string & name, const Dimension & d, + BlInteger value); +void assigndimstring (const std::string & name, const Dimension & d, + const std::string & value); + +BlNumber * addrdimnumber (const std::string & name, const Dimension & d); +BlInteger * addrdiminteger (const std::string & name, const Dimension & d); +std::string * addrdimstring (const std::string & name, const Dimension & d); + +#endif + +// Fin de var.h diff --git a/version.cpp b/version.cpp new file mode 100644 index 0000000..c41f295 --- /dev/null +++ b/version.cpp @@ -0,0 +1,13 @@ +// version.cpp + +// The configure script will parse the version::* lines +// to get the vesion number. + +#include "blassic.h" + +const unsigned short + version::Major= 0, + version::Minor= 10, + version::Release= 2; + +// End of version.cpp -- cgit v1.2.3