Index: PYING.txt
===================================================================
--- /COPYING.txt (revision 87)
+++ (revision )
@@ -1,674 +1,0 @@
- 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
-.
Index: ADME.SVN.txt
===================================================================
--- /README.SVN.txt (revision 87)
+++ (revision )
@@ -1,25 +1,0 @@
-
- The Punched Paper Project -- Subversion access
- ==============================================
-
- The Punched Paper Project sources are stored on the technikum29.de servers.
- They are reachable at
-
- svn://technikum29.de/paper-tape-project
- Web SVN: http://dev.technikum29.de/websvn
-
- until the svn repository moved to
-
- svn://technikum29.de/punched-paper-project
-
- You can access the subversion reposity anonymously. So simply checkout
- the sources at your unix box using the svn terminal client:
-
- you@unix-box$ svn checkout svn://technikum29.de/paper-tape-project
-
- Or use your favourite SVN client (on Windows e.g. TortoiseSVN).
-
- If you want to contribute, simply mail the technikum29.de development
- team at development@[this domain] and ask for a subversion account.
-
- --Sven, 19.07.08, 13.03.09
Index: /README.txt
===================================================================
--- /README.txt (revision 87)
+++ /README.txt (revision 1)
@@ -1,15 +1,91 @@
- The Punched Paper Project
- =========================
+ The Paper tape project
+ ======================
- This is the root directory from the Punched Paper Project. Please
- read the documentation in the documentation/ folder or navigate
- your browser to
+ The paper tape project is a big crowd of programs, scripts and binary
+ data and experiments which made it possible to read and punch
+ paper tapes.
- http://dev.technikum29.de/projekte/paper-tape-project/documentation/
+ Everything is written in German, so if you don't understand something,
+ feel free to mail me (technikum29.de @ - nospam - @ sven; read it the
+ other way around).
- See README.SVN.txt for instructions how to use the svn repository
- and COPYING.txt for the GNU GENERAL PUBLIC LICENSE.
+ Sven, 05.05.2008
+
+ You can read much more about the projects at:
+ * http://privat.technikum29.de/svens-projekte/Lochstreifen
+ * http://dev.technikum29.de/wiki/Projekte/Lochstreifen
- Sven Koeppel, Friday the 13.03.2009
+ 1. Perl paper tape tools
+ ------------------------
+ There are some self-explanatory perl scripts which draw paper tapes
+ (ASCII art), generate labels in different "fonts", parse ASCII
+ number files, etc.
+
+
+ 2. Userspace punch driver
+ -------------------------
+ This is a linux ppdev driver for the FACIT 4070 Tape punch-75 CPS
+ paper tape puncher (parallel port). The file puncher.c implements
+ this driver.
+ After connecting the puncher to the computer and before switching
+ it on, you must run setoff-strobe[.c], otherwise it will directly
+ start punching like an idiot.
+
+ The usage of puncher[.c] is quite simple:
+
+ $ cat files-to-punch | ./puncher
+
+ of course you need the ppdev driver in your linux kernel. Make sure
+ /dev/parport0 exists.
+
+ # modprobe ppdev
+ # chmod 777 /dev/parport0
+
+ There is a nice interactive perl frontend which generates a label
+ for your paper tape:
+
+ $ ./puncher-frontend.pl files-to-punch
+
+
+ 3. User space paper tape reader
+ -------------------------------
+ This ppdev userspace driver drives the GHIELMETTI FER 201. Most
+ things from the puncher driver also apply here, especially the
+ setoff-strobe program which stops the reader from running all
+ the time.
+
+ Usage of reader[.c]:
+
+ $ ./reader > read-in-file.bin
+
+ The program is not really completed, thus it won't correctly
+ detect the end of the paper tape, but it stops automatically
+ some time after the paper tape run out.
+
+
+ 4. Paper Tape Visualisator
+ --------------------------
+ The visualisator program is a modular C program which draws
+ nice pictures of paper tapes using the cairo graphics library.
+ Thus it can produce SVG and PNG output and is highly
+ configurable. There exists multiple frontends, among others a
+ terminal frontend (CLI); a web frontend (PHP & Ajax), using
+ the terminal program; and a very nice GTK user interface which
+ is capable of loading very huge files (multiple MegaBytes)
+ because it doesn't have to render the whole paper tape at once.
+
+ Especially the gtk frontend still tends to crash unexpectedly,
+ besides there is a very strange bug while rendering the paper
+ tape partially in the viewport which I could not solve until
+ now.
+
+ The PHP frontend is quite complex, but very friendly to DAUs
+ (a german expression for "PEBKAC") due to the ability to fold
+ the huge formular. It should be running stable but hasn't
+ really be tested so far. Thanks to caching every generated image
+ it should even stand very much rendering requests.
+
+
+
Index: /daten/beispieldatei
===================================================================
--- /daten/beispieldatei (revision 1)
+++ /daten/beispieldatei (revision 1)
@@ -0,0 +1,57 @@
+ "Km-Statistik Auto"
+
+In diesem Textdokument koennen die zu stanzenden Zahlen frei
+gemixt mit Text werden -- sie werden einfach automatisch
+rausgelesen. Dazu muessen sie nur ganz am Anfang einer Zeile
+stehen (kein Leerzeichen o.ae. davor). Dadrueber, dadrunter
+und dahinter (moeglichst mit Leerzeichen abtrennen) kann dann
+stehen, was will.
+
+224 BOP
+0 Nur 0 (als Ziffer) sollte hier nicht stehen.
+50 JFP
+47 PSR
+27 END
+224 BOP
+
+Mit diesen willkuerlichen Trennerzeichen sind Zahlen dahinter ok
+und werden ignoriert:
+
+0 # 0
+9 # CPY
+2 # 52
+
+0
+9
+2
+usw...
+
+47 HLT J
+6 JKF
+0
+
+15 J
+9 CPY
+2 Nr. 52
+
+--------------
+ Ausgabe: LF
+--------------
+
+0
+50
+49
+27
+
+200 BOS 1(8)
+
+--------------
+ Ausgabe: 3x Space
+--------------
+
+0
+50
+24
+27 END
+
+usw.
Index: /daten/udo-30.03.08.txt
===================================================================
--- /daten/udo-30.03.08.txt (revision 1)
+++ /daten/udo-30.03.08.txt (revision 1)
@@ -0,0 +1,190 @@
+e0 # 224
+00 # 0
+32 # 50
+2f # 47
+18 # 24
+1b # 27
+e6 # 230
+00 # 0
+74 # 116
+15 # 21
+1b # 27
+2f # 47
+06 # 6
+00 # 0
+0f # 15
+0c # 12
+02 # 2
+00 # 0
+32 # 50
+18 # 24
+1b # 27
+00 # 0
+74 # 116
+30 # 48
+1b # 27
+88 # 136
+2f # 47
+06 # 6
+02 # 2
+0f # 15
+18 # 24
+01 # 1
+0d # 13
+09 # 9
+01 # 1
+0f # 15
+0c # 12
+00 # 0
+00 # 0
+74 # 116
+28 # 40
+1b # 27
+00 # 0
+32 # 50
+18 # 24
+1b # 27
+c8 # 200
+00 # 0
+74 # 116
+30 # 48
+30 # 48
+5c # 92
+5c # 92
+5c # 92
+5c # 92
+5c # 92
+5c # 92
+5c # 92
+5c # 92
+28 # 40
+2c # 44
+30 # 48
+30 # 48
+1b # 27
+01 # 1
+0c # 12
+00 # 0
+00 # 0
+74 # 116
+28 # 40
+30 # 48
+30 # 48
+7d # 125
+7d # 125
+7d # 125
+7d # 125
+7d # 125
+7d # 125
+7d # 125
+7d # 125
+28 # 40
+1b # 27
+00 # 0
+32 # 50
+30 # 48
+1b # 27
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+18 # 24
+00 # 0
+cc # 204
+00 # 0
+09 # 9
+0f # 15
+00 # 0
+09 # 9
+01 # 1
+00 # 0
+09 # 9
+02 # 2
+00 # 0
+09 # 9
+03 # 3
+00 # 0
+09 # 9
+04 # 4
+00 # 0
+09 # 9
+05 # 5
+00 # 0
+09 # 9
+06 # 6
+00 # 0
+09 # 9
+07 # 7
+00 # 0
+09 # 9
+08 # 8
+00 # 0
+09 # 9
+09 # 9
+00 # 0
+09 # 9
+0a # 10
+00 # 0
+09 # 9
+0b # 11
+00 # 0
+09 # 9
+0c # 12
+00 # 0
+74 # 116
+74 # 116
+76 # 118
+6c # 108
+7c # 124
+4a # 74
+1b # 27
+00 # 0
+32 # 50
+30 # 48
+1b # 27
+e0 # 224
Index: /perl-tools/alter-udo-parser
===================================================================
--- /perl-tools/alter-udo-parser (revision 1)
+++ /perl-tools/alter-udo-parser (revision 1)
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+#
+# Usage: udo-parser.pl [DATEINAME]
+# liest von Textdatei oder stdin eine Datei in Udos favorisiertem Format,
+# nach dem Zeilen etwa so aussehen:
+# "[hexadezimal] # [dezimal]"
+# Pro Zeile ein Byte.
+# Gibt auf STDOUT den Bytestrom aus.
+#
+# Geschrieben 30.03.2008 21:00
+#
+
+my $handler = STDIN;
+open($handler, '<', $ARGV[0]) if(@ARGV > 0);
+
+my $line=0;
+my $hex,$dec;
+while(<$handler>) {
+ $line++;
+ unless(/([0-9a-fA-F]{2})\s*#\s*([0-9]{1,3})/) {
+ print STDERR "Zeile $line: Formatfehler! Überspringe Zeile $line...\n";
+ next;
+ }
+
+ $hex=$1; $dec=$2;
+ if(hex $hex ne $dec) {
+ print STDERR "Zeile $line: Hex($hex)/Dez($dec)-Angabe stimmen nicht überein (hex entspricht ",hex $hex,").\n";
+ print STDERR "Zeile $line: Nutze Dezimal-Angabe fuer Streifen\n";
+ }
+
+ print pack("C", $dec);
+ # ja das wars schon ;)
+}
Index: /perl-tools/byte-tester
===================================================================
--- /perl-tools/byte-tester (revision 1)
+++ /perl-tools/byte-tester (revision 1)
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+#
+# Erzeugt aus Parametern (dezimal) Bytes und gibt diese auf stdout aus.
+# keine größeren parameter als 64000 ;)
+#
+
+foreach (@ARGV) {
+ print pack("C", $_);
+}
Index: /perl-tools/hex-meter
===================================================================
--- /perl-tools/hex-meter (revision 1)
+++ /perl-tools/hex-meter (revision 1)
@@ -0,0 +1,9 @@
+#!/usr/bin/perl
+# Udos kleines Lochstreifen-Meterband.
+#
+
+for($x=0; $x < $ARGV[0]; $x++) {
+ for($y=0; $y<2**8; $y++) {
+ print pack('C', $y);
+ }
+}
Index: /perl-tools/how-long-is-this-papertape
===================================================================
--- /perl-tools/how-long-is-this-papertape (revision 1)
+++ /perl-tools/how-long-is-this-papertape (revision 1)
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+#
+# kleines (Spaß)programm: Wie lang ist diese Datei als Lochstreifen?
+# Benutzung:
+# ./programm.pl [datei1] [datei2] [datei3] [usw...]
+#
+
+my $total_l = 0; my $l;
+foreach (@ARGV) {
+ $l = (stat)[7];
+ print "$_: $l bytes = ".bytes2cm($l)." cm\n";
+ $total_l += $l;
+}
+print "total: $total_l bytes = ".bytes2cm($total_l)." cm\n"
+ unless($l eq $total_l); # nur ein Argument.
+
+sub bytes2cm {
+ my $bytes = shift;
+ # inch = $bytes/10;
+ # centimeter = inch / 2.54
+ my $cm = ($bytes / 10) * 2.54;
+}
Index: /perl-tools/label-it
===================================================================
--- /perl-tools/label-it (revision 1)
+++ /perl-tools/label-it (revision 1)
@@ -0,0 +1,169 @@
+#!/usr/bin/perl
+#
+# Gibt alle Parameter als "Schrift" auf Lochstreifen (stdout) aus.
+#
+
+my $debug = 0;
+
+my %letters = (# 12345678
+ 'a' => ['********',
+ ' * *',
+ ' * *',
+ '********'],
+ 'b' => ['********',
+ '* * *',
+ '* * *',
+ '******* '],
+ 'c' => ['********',
+ '* *',
+ '* *'],
+ 'd' => ['********',
+ '* *',
+ '* *',
+ ' ****** '],
+ 'e' => ['********',
+ '* * *',
+ '* * *'],
+ 'f' => ['********',
+ ' * *',
+ ' * *'],
+ 'g' => ['********',
+ '* *',
+ '* * *',
+ '***** *'],
+ 'h' => ['********',
+ ' * ',
+ '********'],
+ 'i' => ['* *',
+ '********',
+ '* *'],
+ 'j' => ['*** *',
+ '* *',
+ '********'],
+ 'k' => ['********',
+ ' ** ',
+ '*** **'],
+ 'l' => ['********',
+ '* ',
+ '* '],
+ 'm' => ['********',
+ ' *',
+ ' ** ',
+ ' *',
+ '********'],
+ 'n' => ['********',
+ ' * ',
+ ' **** ',
+ ' * ',
+ '********'],
+ 'o' => ['********',
+ '* *',
+ '********'],
+ 'p' => ['********',
+ ' * *',
+ ' *****'],
+ 'q' => ['********',
+ '* *',
+ '** *',
+ '********'],
+ 'r' => ['********',
+ ' * *',
+ '*** ****'],
+ 's' => [' ****',
+ '* * *',
+ '***** *'],
+ 't' => [' *',
+ '********',
+ ' *'],
+ 'u' => ['********',
+ '* ',
+ '********'],
+ 'v' => [' ******',
+ '* ',
+ ' ******'],
+ 'w' => [' ******',
+ '* ',
+ ' * ',
+ '* ',
+ ' ******'],
+ 'x' => ['*** **',
+ ' *** ',
+ '*** **'],
+ 'y' => [' ****',
+ '* * ',
+ ' *******'],
+ 'z' => ['** *',
+ '* *** *',
+ '* **'],
+ '1' => [' * ',
+ '********'],
+ '2' => ['** * ',
+ '* ** *',
+ '* ***'],
+ '3' => ['* * *',
+ '* * *',
+ '********'],
+ '4' => [' ****',
+ ' * ',
+ '********',
+ ' * '],
+ '5' => ['* *****',
+ '* * *',
+ '* * *',
+ '**** *'],
+ '6' => [' **** ',
+ '*** * ',
+ '* * *',
+ '**** * '],
+ '7' => [' *',
+ ' * *',
+ '********'],
+ '8' => ['********',
+ '* * *',
+ '********'],
+ '9' => [' *****',
+ ' * *',
+ '********'],
+ '0' => ['*********',
+ '* *',
+ '* *** *',
+ '* *',
+ '*********']
+);
+
+$x = 0; # ARGV-Counter
+foreach (@ARGV) {
+ # vor wort ein Leerzeichen lassen wenns nicht das erste ist
+ print pack("C", 0) x 2 unless($x++ == 0);
+
+ #print STDERR "Parameter $_:\n" if $debug;
+ foreach(my $cpos=0; $cpos < length; $cpos++) {
+ my $char = lc substr $_, $cpos, 1;
+ print STDERR "Zeichen $char:\n" if $debug;
+ unless(exists $letters{$char}) {
+ print STDERR "Buchstabe $char kann nicht gedruckt werden\n";
+ next;
+ }
+
+ # anonymes Array einlesen und jeweils string zu octett formen
+ foreach (@{$letters{$char}}) {
+ my $byte = 0;
+ $byte += 1 if(isPunched($_, 0));
+ $byte += 2 if(isPunched($_, 1));
+ $byte += 4 if(isPunched($_, 2));
+ $byte += 8 if(isPunched($_, 3));
+ $byte += 16 if(isPunched($_, 4));
+ $byte += 32 if(isPunched($_, 5));
+ $byte += 64 if(isPunched($_, 6));
+ $byte += 128 if(isPunched($_, 7));
+ my $pack = pack("C", $byte);
+ printf STDERR "$_: Zahl = $byte = $pack = %d\n", $pack if $debug;
+ print $pack;
+ } # foreach zeichenreihe
+ # Nach Zeichen eine Reihe Platz lassen:
+ print pack("C", 0);
+ } # foreach zeichen
+} # foreach parameter
+
+sub isPunched { return substr($_[0], $_[1], 1) eq '*'; }
+
Index: /perl-tools/punch-simulator
===================================================================
--- /perl-tools/punch-simulator (revision 1)
+++ /perl-tools/punch-simulator (revision 1)
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+# kleines quick & dirty script zum Anzeigen von BYTES aus
+# der Standardeingabe als Lochstreifen auf der Konsole
+# (Standardausgabe)
+# automatische Umwandlung von ASCII => Bytes o.ä. wird
+# nicht vorgenommen - das Script verhält sich damit wie
+# der Lochkartenpuncher
+#
+
+while() { # pro Zeile...
+ foreach($cpos=0; $cpos < length; $cpos++) {
+ $char = substr($_, $cpos, 1);
+ $char = ord($char);
+ #printf "Byte: %b\n", $char;
+
+ print '|';
+ $against = 0x01; # binär 0000 0001
+ for($pos=0; $pos < 8; $pos++) {
+ print '.' if($pos == 3); # Lochführung an pos. 3
+ $check = $char;
+ $check = ($check >> $pos);
+ if(($check & $against) == 0) {
+ print ' '; # bit nicht gesetzt
+ } else {
+ print '*'; # bit gesetzt
+ }
+ }
+ print "|\n";
+ } # for
+} # while
+
+exit 0; # fehlerlos enden.
+
+
+
Index: /perl-tools/read-file
===================================================================
--- /perl-tools/read-file (revision 1)
+++ /perl-tools/read-file (revision 1)
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+#
+# Usage: read-file.pl [DATEINAME]
+# liest von Textdatei oder stdin Zahlen. Diese muessen am Zeilenanfang
+# stehen - ignoriert werden ferner Kommentare dahinter, durch
+# Leerzeichen getrennt, sowie generell Zeilen mit Kommentaren - diese
+# Zeilen sollten mit einem Kommentarzeichen wie # oder / beginnen.
+#
+
+my $handler = STDIN;
+open($handler, '<', $ARGV[0]) if(@ARGV > 0);
+
+while(<$handler>) {
+ next unless(/^([0-9]+)/);
+ #print STDERR "Zahl $1\n"; # gibt nix zu debuggen ;)
+ print pack("C", $1);
+}
Index: /perl-tools/strip-null-bytes
===================================================================
--- /perl-tools/strip-null-bytes (revision 1)
+++ /perl-tools/strip-null-bytes (revision 1)
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+#
+# Strippt Nullbytes vorne und hinten von STDIN-Daten
+# oder Parameter (Datei) weg.
+#
+
+my @data = split/\s+/, join ' ', <>;
+
+# strip at beginning
+$x=0;
+for(@data) {
+$x++;
+ print STDERR "$x: $_\n";
+ unless( /^00?$/ ) {
+ print STDERR "$x: $_ No more nullbytes.\n";
+ }
+
+ last unless /^00?$/;
+ shift(@data);
+}
+
+#@data = reverse(@data);
+#do STRIP;
+#@data = reverse(@data);
+
+map { print pack("C", hex $_) } @data;
Index: /perl-tools/udo-parser
===================================================================
--- /perl-tools/udo-parser (revision 1)
+++ /perl-tools/udo-parser (revision 1)
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+#
+# Usage: udo2-parser.pl [DATEINAME]
+# liest von Textdatei oder stdin eine Datei in Udos favorisiertem Format,
+# einfach hexoktetts mit leerzeichen voneinander getrennt
+#
+# Geschrieben 03.04.08
+#
+#
+
+print pack("C", hex $_) for(split(/\s+/, join '', <>));
+
+#$zero_beginning = 1;
+#
+#my $s;
+#while(<>) {
+# if($zero_beginning) {
+# next if /00?/;
+# $zero_beginning = 0;
+## }
+# $s .= $_;
+#
+#}
+#
+#print pack("C", hex $_) for (split(/\s+/, map { }, <>));
Index: /reader/reader.c
===================================================================
--- /reader/reader.c (revision 1)
+++ /reader/reader.c (revision 1)
@@ -0,0 +1,314 @@
+/**
+ * GHIELMETTI FER 201 paper tape reader
+ * Linux parallel port userspace driver (ppdev)
+ *
+ * Reads bytes from the reader and prints them to
+ * STDOUT. Verbose output will be on stderr.
+ *
+ * CHANGELOG:
+ * 12.04.08 initially written
+ *
+ * Dieses Programm wurde auf Basis des FACIT
+ * userspace drivers geschrieben.
+ *
+ * (c) 2008 Sven Koeppel
+ * This program is free software...:
+ * http://www.gnu.org/licenses/
+ *
+ **/
+
+#include
+#include
+#include
+#include /* lowlevel io */
+#include
+#include /* var argument list */
+#include /* nanosleep */
+
+#include
+#include
+#include
+
+#include // debugging
+
+#define PARPORT_DEVICE "/dev/parport0"
+
+/*#ifdef DEBUG
+#define DPRINTF(bla...) fprintf(stderr,bla)
+#else
+#define DPRINTF(bla...)
+#endif*/
+
+#define DPRINTF(bla...) { if(debug_flag) fprintf(stderr,bla); }
+
+
+unsigned char debug_flag; /* switch: Debug an/aus? */
+size_t write_puncher(int fd, unsigned char buf);
+void visualize_byte(unsigned char buf);
+
+
+int mtime(long long since) {
+ /* gibt Millisekunden zurueck seit since. since sind dabei die
+ Millisekunden seit der Unix-Epoche. Ein initiales since kann
+ per mtime(0) gefunden werden. */
+ struct timeval time;
+ gettimeofday(&time, NULL);
+ // Sec*10^3
+ return (time.tv_sec * 1000 + (long long)(time.tv_usec / 1000)) - since;
+}
+
+int u_time(long long since) {
+ /* gibt Mikrosekunden zurueck seit since. since sind dabei die
+ Mikrosekunden seit der Unix-Epoche. Ein initiales since kann
+ per mtime(0) gefunden werden. */
+ struct timeval time;
+ gettimeofday(&time, NULL);
+ // Sec*10^6
+ return (time.tv_sec * 1000 * 1000 + time.tv_usec) - since;
+}
+
+
+int main(int argc, char **argv) {
+ int parport_fd;
+ int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
+ long long time_since_beginning; // etwas lustige Zeitmessung
+ int x; // debug
+
+ fprintf(stderr, "FER 201 Paper tape reader user space driver\n");
+ fprintf(stderr, "time ms |123.45678| hex=dec\n");
+
+ // Aufrufparameter analsyieren
+ debug_flag = 0;
+ opterr = 0;
+ int c;
+ while( (c = getopt(argc, argv, "dh")) != -1)
+ switch(c) {
+ case 'd':
+ debug_flag = 1;
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: program [-d] [-h]\n");
+ return 0;
+ //default:
+ }
+
+ DPRINTF("opening device...\n");
+ parport_fd = open(PARPORT_DEVICE, O_RDWR);
+ if(parport_fd == -1) {
+ perror("opening device failed");
+ return 1;
+ }
+
+ /* Claim the port */
+ DPRINTF("claiming port...\n");
+ if(ioctl(parport_fd, PPCLAIM)) {
+ perror ("claiming port (PPCLAIM)");
+ close (parport_fd);
+ return 1;
+ }
+
+ /*DPRINTF("Setting IEEE protocol..\n");
+ mode = IEEE1284_MODE_COMPAT;
+ if(ioctl(parport_fd, PPSETMODE, &mode)) {
+ perror("Setting PPSETMODE");
+ close(parport_fd);
+ return 1;
+ }*/
+
+ /* Go straight into compatibility mode: */
+ DPRINTF("Setting IEEE netogation...\n");
+ mode = IEEE1284_MODE_COMPAT; //BYTE; //COMPAT;
+ if(ioctl(parport_fd, PPNEGOT, &mode)) {
+ perror ("Setting compatibilty mode (PPNEGOT)");
+ close (parport_fd);
+ return 1;
+ }
+
+ DPRINTF("Setting off data line drivers..\n");
+ mode = 1;
+ if(ioctl(parport_fd, PPDATADIR, &mode)) {
+ perror("Setting PPDATADIR");
+ close(parport_fd);
+ return 1;
+ }
+
+ DPRINTF("Resetting reader...\n");
+ {
+ unsigned char mask = (PARPORT_CONTROL_STROBE|PARPORT_CONTROL_AUTOFD);
+ if(ioctl(parport_fd, PPWCONTROL, &mask))
+ return -3;
+ usleep(20);
+ }
+
+ /*
+ DPRINTF("Waiting for Puncher beeing ready for signals...\n");
+ {
+ unsigned char status;
+ if(ioctl(parport_fd, PPRSTATUS, &status)) return -1;
+ if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
+ DPRINTF("Puncher is BUSY!\n");
+ usleep(8000);
+ }
+ }
+ */
+
+ time_since_beginning = mtime(0);
+ for(x=0;;x++) {
+ unsigned char buf; /* the read-in-byte buffer */
+ int ret; /* multipurpose return value */
+
+ ret = read_byte(parport_fd, &buf);
+ if(ret < 0) {
+ printf("read byte: %i!", ret);
+ //perror("read byte");
+ close(parport_fd);
+ return 1;
+ }
+
+ /* Visualisierung der Zeile */
+ fprintf(stderr, "%5ims ", (int)(mtime(time_since_beginning)));
+ visualize_byte(buf);
+ fprintf(stderr, " 0x%02x=%03i\n", buf, buf);
+
+ // ausgeben auf STDOUT.
+ putchar((int)buf);
+ fflush(stdout); // kein buffern.
+
+ usleep(10*1000);
+ }
+
+ DPRINTF("finished\n");
+ ioctl(parport_fd, PPRELEASE);
+ close(parport_fd);
+ return 0;
+}
+
+void visualize_byte(unsigned char buf) {
+ /* Zeichnet Lochstreifen-Byte (wie das Perl-Proggi) */
+ unsigned char against = 0x01;
+ unsigned char check;
+ int pos;
+
+ fprintf(stderr, "|");
+ for(pos=0; pos < 8; pos++) {
+ if(pos == 3) /* Streifenfuehrung */
+ fprintf(stderr, ".");
+ check = buf;
+ check >>= pos;
+
+ if((check & against) == 0)
+ fprintf(stderr, " "); /* bit nicht gesetzt */
+ else
+ fprintf(stderr, "*"); /* bit gesetzt */
+ } /*for */
+ fprintf(stderr, "|");
+}
+
+int read_byte(int fd, unsigned char *byte) {
+ /**
+ * Der eigentliche, geraetespezifische Treiber befindet
+ * sich auch erst hier.
+ *
+ */
+ static unsigned char mask_strobe = (PARPORT_CONTROL_STROBE|PARPORT_CONTROL_INIT);
+ static unsigned char mask_null = (0x00);
+ unsigned char status;
+ long long time;
+ int x; // temporaer
+
+ // erst mal warten, bis Schalter geschlossen ist.
+ if(ioctl(fd, PPRSTATUS, &status))
+ return -5;
+ if(!(status & PARPORT_STATUS_SELECT)) {
+ DPRINTF("Warte, bis Schalter geschlossen ist");
+ while(!(status & PARPORT_STATUS_SELECT)) {
+ if(ioctl(fd, PPRSTATUS, &status))
+ return -5;
+ DPRINTF(".");
+ sleep(1);
+ }
+ }
+
+ //DPRINTF("Strobe pulsed.\n");
+ if(ioctl(fd, PPWCONTROL, &mask_strobe))
+ return -3;
+ time = u_time(0);
+
+ // in den ersten 2ms passiert selten etwas
+ for(x=0;;) {
+ //DPRINTF("%5i. Signale: ", (int)(u_time(time)));
+ if(ioctl(fd, PPRSTATUS, &status))
+ return -4;
+ if(!(status & PARPORT_STATUS_ACK)) {
+ //DPRINTF("Lesesignal ");
+ if(!x) {
+ if(u_time(time) > 4*1000) {
+ DPRINTF("Lesesignal erst nach 4ms!\n");
+ }
+ ioctl(fd, PPRDATA, byte);
+ ioctl(fd, PPWCONTROL, &mask_null);
+ x++;
+ }
+ } else if(u_time(time) > 9*1000) {
+ DPRINTF("Lesesignal kommt nicht!\n");
+ usleep(2);
+ }
+
+ if(!(status & PARPORT_STATUS_BUSY)) {
+ //DPRINTF("Busy ");
+ if(u_time(time) > 10*1000) {
+ break; // alles klar.
+ }
+ } else if(u_time(time) > 90*1000) {
+ DPRINTF("Busy missing nach 9ms!\n");
+ DPRINTF("BEende.\n");
+ exit(0);
+ }
+
+ if(!(status & PARPORT_STATUS_SELECT))
+ DPRINTF("Schalter offen! ");
+ //DPRINTF("\n");
+
+ if(0==1) {
+ struct timespec a;
+ a.tv_sec = 0;
+ a.tv_nsec = 1000;
+ nanosleep(&a, NULL);
+ }
+ }
+
+ // auf ACK = RS Lesesignal warten um Daten
+ // abzuholen.
+
+ /*
+ for(;;) {
+ ioctl(fd, PPRSTATUS, &status);
+ if((status & PARPORT_STATUS_ACK) == PARPORT_STATUS_ACK) {
+ if(mtime(time) > 4) {
+ DPRINTF("Waiting over 4ms for ACK!\n");
+ sleep(2);
+ } else {
+ usleep(10);
+ }
+ } else break;
+ }*/
+
+ // warten bis Busy verschwindet.
+ /*
+ for(;;) {
+ ioctl(fd, PPRSTATUS, &status);
+ if(status & PARPORT_STATUS_BUSY) {
+ if(mtime(time) > 5) {
+ DPRINTF("Still busy =(\n");
+ break;
+ } else
+ usleep(10);
+ } else break;
+ }*/
+
+ return 0;
+}
+
+
+
+
Index: /schriften/Neue schrift.svg
===================================================================
--- /schriften/Neue schrift.svg (revision 1)
+++ /schriften/Neue schrift.svg (revision 1)
@@ -0,0 +1,16995 @@
+
+
Index: /schriften/neue-schrift.pl
===================================================================
--- /schriften/neue-schrift.pl (revision 1)
+++ /schriften/neue-schrift.pl (revision 1)
@@ -0,0 +1,274 @@
+#!/usr/bin/perl
+#
+# Neue Schrift. Besseres Programm ;)
+# 05.04.2008
+#
+# nimmt Zeichen per Parameter oder (wenn keine angegeben sind)
+# per STDIN an (NLs werden dann zu Leerzeichen).
+#
+# Wenn eingebunden von anderem Perl-Script, dann laeuft das Script
+# nicht sofort los, sondern stellt die Funktion
+#
+# check_string($string);
+# checkt $string auf nicht-druckbare Zeichen und gibt, wenn es
+# welche gibt false zurück, sonst true.
+#
+# label($string);
+# Gibt einen Byte-String (Bytearray) mit dem "kompilierten"
+# $string als Zeichenkette zurueck.
+#
+
+use strict;
+
+my $run_as_library = ($0 ne __FILE__);
+my $debug = 0;
+
+my %letters = (# 12345
+ ' ' => [' ',
+ ' ',
+ ' '],
+
+ 'a' => ['++++ ',
+ ' + +',
+ ' + +',
+ '++++ '],
+ 'b' => ['+++++',
+ '+ + +',
+ '+ + +',
+ ' +++ '],
+ 'c' => [' +++ ',
+ '+ +',
+ '+ +',
+ '+ +'],
+ 'd' => ['+++++',
+ '+ +',
+ '+ +',
+ ' +++ '],
+ 'e' => ['+++++',
+ '+ + +',
+ '+ + +',
+ '+ + +'],
+ 'f' => ['+++++',
+ ' + +',
+ ' + +',
+ ' + +'],
+ 'g' => [' +++ ',
+ '+ +',
+ '+ + +',
+ ' ++ +'],
+ 'h' => ['+++++',
+ ' + ',
+ ' + ',
+ '+++++'],
+ 'i' => ['+ +',
+ '+++++',
+ '+ +'],
+ 'j' => [' + +',
+ '+ +',
+ '+ +',
+ ' ++++'],
+ 'k' => ['+++++',
+ ' + ',
+ ' + + ',
+ '+ +'],
+ 'l' => ['+++++',
+ '+ ',
+ '+ ',
+ '+ '],
+ 'm' => ['+++++',
+ ' + ',
+ ' + ',
+ ' + ',
+ '+++++'],
+ 'n' => ['+++++',
+ ' + ',
+ ' + ',
+ ' + ',
+ '+++++'],
+ 'o' => [' +++ ',
+ '+ +',
+ '+ +',
+ ' +++ '],
+ 'p' => ['+++++',
+ ' + +',
+ ' + +',
+ ' ++ '],
+ 'q' => [' +++ ',
+ '+ +',
+ '++ +',
+ '++++ '],
+ 'r' => ['+++++',
+ ' + +',
+ ' ++ +',
+ '+ + '],
+ 's' => ['+ + ',
+ '+ + +',
+ ' + +'],
+ 't' => [' +',
+ '+++++',
+ ' +'],
+ 'u' => [' ++++',
+ '+ ',
+ '+ ',
+ ' ++++'],
+ 'v' => [' ++++',
+ '+ ',
+ ' ++++'],
+ 'w' => [' ++++',
+ '+ ',
+ ' + ',
+ '+ ',
+ ' ++++'],
+ 'x' => ['+ +',
+ ' + + ',
+ ' + ',
+ ' + + ',
+ '+ +'],
+ 'y' => [' +',
+ ' + ',
+ '+++ ',
+ ' + ',
+ ' +'],
+ 'z' => ['+ +',
+ '++ +',
+ '+ + +',
+ '+ ++',
+ '+ +'],
+
+ '0' => ['+++++',
+ '+ +',
+ '+++++'],
+ '1' => [' ',
+ ' ',
+ '+++++'],
+ '2' => ['+++ +',
+ '+ + +',
+ '+ +++'],
+ '3' => ['+ + +',
+ '+ + +',
+ '+++++'],
+ '4' => [' +++',
+ ' + ',
+ '+++++'],
+ '5' => ['+ +++',
+ '+ + +',
+ '+++ +'],
+ '6' => ['+++++',
+ '+ + +',
+ '+++ +'],
+ '7' => [' +',
+ ' +',
+ '+++++'],
+ '8' => ['+++++',
+ '+ + +',
+ '+++++'],
+ '9' => ['+ +++',
+ '+ + +',
+ '+++++'],
+ '(' => [' + ',
+ ' + + ',
+ '+ +'],
+ '<' => [' + ',
+ ' + + ',
+ '+ +'],
+ ')' => ['+ +',
+ ' + + ',
+ ' + '],
+ '>' => ['+ +',
+ ' + + ',
+ ' + '],
+ '.' => ['++ ',
+ '++ '],
+ '!' => [' ++',
+ '+ +++',
+ ' ++'],
+ '?' => [' +',
+ '+ + +',
+ ' ++'],
+ ':' => ['++ ++',
+ '++ ++'],
+ '-' => [' + ',
+ ' + ',
+ ' + ']
+);
+
+# String kriegen
+my $string; # gut, eigentlich nur fuer !$run_as_library, aber use strict will's so.
+unless($run_as_library) {
+ if(@ARGV) {
+ my $x=0; # ARGV-Counter
+ $string .= ($x++ == 0 ? '' : ' ').$_ for(@ARGV);
+ } else {
+ $string = join(' ', );
+ }
+ $string =~ s/\s+|\n+/ /g; # immer nur ein Leerzeichen!
+ chomp $string;
+}
+
+# Funktion fuer Library, benutzen wir hier so nicht.
+sub check_string {
+ #my $string = lc shift;
+ #$string =~ s/\s+|\n+/ /g; # immer nur ein Leerzeichen!
+ # durchgehen und Zeicen checken
+ #my $out;
+ my $r = 1;
+ for (split //, $string) {
+ unless(exists $letters{$_}) {
+ print STDERR "Buchstabe $_ kann nicht gedruckt werden!\n";
+ $r = 0;
+ }# else {
+ # $out .= $_;
+ #}
+ }
+ return $r;
+ #return $out;
+}
+
+unless($run_as_library) {
+ print STDERR "String: $string\n" if $debug;
+ print label($string);
+}
+
+sub label {
+ my $string = shift;
+ my $bytes = '';
+
+ # Zeichen durchgehen.
+ my @s = map(lc, split(//, $string));
+ #for(my $x=0, my $c; $c = $s[x], $x < length(@s); $x++) { # sowas wie foreach(@s)
+ my $x=0;
+ for (@s) {
+ print STDERR "Zeichen $_ ($x/",scalar(@s)-1,")\n" if $debug;
+
+ unless(exists $letters{$_}) {
+ print STDERR "Buchstabe $_ kann nicht gedruckt werden!\n";
+ next;
+ }
+
+ # schauen was wir vor dem Zeichen tun
+ if($x) { # beim ersten noch nichts
+ $bytes .= pack("C", 0); # eine Reihe Abstand.
+ }
+
+ # Byte generieren:
+ # anonymes Array einlesen und jeweils string zu octett formen
+ for (@{$letters{$_}}) {
+ my $byte = 0;
+ #$byte += 1 if(isPunched($_, 0)); # die ersten drei
+ #$byte += 2 if(isPunched($_, 1)); # Bit sind bei dieser
+ #$byte += 4 if(isPunched($_, 2)); # Schrift immer 0
+ $byte += 8 if(isPunched($_, 0));
+ $byte += 16 if(isPunched($_, 1));
+ $byte += 32 if(isPunched($_, 2));
+ $byte += 64 if(isPunched($_, 3));
+ $byte += 128 if(isPunched($_, 4));
+ my $pack = pack("C", $byte);
+ #printf STDERR "$_: Zahl = $byte = $pack = %d\n", $pack if $debug;
+ $bytes .= $pack;
+ } # for octett
+ } continue { $x++ } # for @s
+ return $bytes;
+} # sub label
+
+sub isPunched { return substr($_[0], $_[1], 1) ne ' '; }
+
Index: /userspace-driver/Makefile
===================================================================
--- /userspace-driver/Makefile (revision 1)
+++ /userspace-driver/Makefile (revision 1)
@@ -0,0 +1,4 @@
+
+all:
+ gcc -o setoff-strobe setoff-strobe.c
+ gcc -o puncher puncher.c -lm
Index: /userspace-driver/puncher-frontend.pl
===================================================================
--- /userspace-driver/puncher-frontend.pl (revision 1)
+++ /userspace-driver/puncher-frontend.pl (revision 1)
@@ -0,0 +1,81 @@
+#!/usr/bin/perl
+#
+# kleines Frontend für puncher.c, welches
+# folgende Funktionen bereitstellt:
+#
+# * Beschriftung des Lochstreifens mittels Programms
+# * Nullbytes vor Beschriftung (zum Warmlaufen des Punchers)
+# und vor Daten (Trennung Beschriftung/Programm)
+# * Aufruf von ./puncher[.c]
+#
+# Aufrufparameter: Siehe --help.
+#
+
+use strict;
+
+# Konstanten:
+require "../schriften/neue-schrift.pl";
+my $userspace_driver = "./puncher"; #../perl-tools/punch-simulator"; # vollstaendiges Kommando
+my $debug = 0; # per Parameter -d setzbar.
+
+# wie viel Nullbytes an welcher Stelle?
+my $null_before_label = 2;
+my $null_before_data = 40;
+
+# hier gehts los.
+sub HELP_MESSAGE {
+ print STDERR <<"HELP";
+Usage: $0 [params] [dateiname(n)]
+
+Puncher-Frontend mit Labelfunktion und Nullbytes. Parameter:
+
+-n \t*Kein* Label drucken
+-d \tDebuggen (Puncherprogramm, ...)
+
+Wenn -n nicht gesetzt ist, wird zunaechst ein Label per STDIN
+abgefragt. Wenn keine Datei angegeben ist, wird anschliessend
+die zu punchende Datei ueber STDIN erwartet.
+HELP
+}
+
+use Getopt::Std;
+our($opt_n, $opt_d);
+getopts('nd');
+
+$debug = $opt_d;
+
+my $bytes = ''; # der große Byte-Array/string.
+
+# Label:
+unless($opt_n) {
+ # Label drucken.
+ $bytes .= pack("C", 0) x $null_before_label;
+
+ print STDERR "Gewuensches Label eintippen und mit NL beenden:\n";
+ chomp(my $label = );
+ unless(check_string($label)) {
+ die "Schlechtes Label! Beende.\n";
+ exit 1;
+ }
+
+ # Label machen.
+ $bytes .= label($label);
+}
+
+# Nullbytes
+$bytes .= pack("C",0) x $null_before_data;
+
+# Daten einlesen.
+print STDERR (@ARGV ? "Reading from @ARGV...\n" : "Reading from STDIN...\n");
+$bytes .= $_ while(<>);
+
+# Puncher ausfuehren
+open(PUNCHER, "|$userspace_driver ".($debug?'-d':'').' -l'.(length($bytes))) or die "Konnte $userspace_driver nicht starten: $!";
+print PUNCHER $bytes;
+close(PUNCHER);
+
+print "\n", $? ? "Fehler beim Puncheln (Statuscode $?)" : "Erfolgreich fertiggepunscht.", "\n";
+
+exit $?;
+
+
Index: /userspace-driver/puncher.c
===================================================================
--- /userspace-driver/puncher.c (revision 1)
+++ /userspace-driver/puncher.c (revision 1)
@@ -0,0 +1,358 @@
+/**
+ * FACIT 4070 Tape punch-75 CPS
+ * Linux parallel port userspace driver (ppdev)
+ *
+ * Reads bytes from stdin and transfers them to
+ * the puncher.
+ * Verbose output will be on stderr, standard on
+ * stdout.
+ *
+ * CHANGELOG:
+ * Feb 2007 initially written
+ * 16.11.07 kleinigkeiten geaendert.
+ * 31.03.08 Endlich mal funktionsfaehig gemacht, ohne
+ * unnoetigen Debugausgaben
+ * bis 06.04.08 Komplett umgeschrieben, sodass jetzt
+ * der Zyklus nachempfunden wird, weil die
+ * busy-Leitung sowieso tut, was sie will.
+ * Ordentliche Ausgaben auf stdout, Debug
+ * Flag (-d)
+ *
+ * Dieses Programm soll sich nur aufs Punchen beschraenken,
+ * eine luxerioesere Variante (mit Beschriftung, Nullbytes
+ * vorne dran) gibt es mit einem Perl-Tool.
+ *
+ *
+ **/
+
+#include
+#include
+#include
+#include /* lowlevel io */
+#include
+#include /* var argument list */
+#include
+
+#include
+#include
+#include
+
+#include // debugging
+
+#define PARPORT_DEVICE "/dev/parport0"
+
+/*#ifdef DEBUG
+#define DPRINTF(bla...) fprintf(stderr,bla)
+#else
+#define DPRINTF(bla...)
+#endif*/
+
+#define DPRINTF(bla...) { if(debug_flag) fprintf(stderr,bla); }
+
+
+unsigned char debug_flag; /* switch: Debug an/aus? */
+size_t write_puncher(int fd, unsigned char buf);
+void visualize_byte(unsigned char buf);
+void calculate_time(int already_punched_bytes, int estimated_punch_length, int mtime_since_beginning);
+
+
+int mtime(long long since) {
+ /* gibt millisekunden zurueck seit since. since sind dabei die
+ Millisekunden seit der Unix-Epoche. Ein initiales since kann
+ per mtime(0) gefunden werden. */
+ struct timeval time;
+ gettimeofday(&time, NULL);
+ // Sec*10^6
+ return (time.tv_sec * 1000000 + time.tv_usec) - since;
+}
+
+int main(int argc, char **argv) {
+ int parport_fd;
+ int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
+ long long time_since_beginning; // etwas lustige Zeitmessung
+ int already_punched = 0; // Anzahl bereits gepunchte bytes
+ int estimated_data_length = 0; // per Schalter -l angegebbare Datenlaenge
+
+ printf("FACIT 4070 Tape punch-75 CPS userspace driver\n");
+ printf("time ms |123.45678| hex=dec status: =) punch successful / :-( still busy\n");
+
+ // Aufrufparameter analsyieren
+ debug_flag = 0;
+ opterr = 0;
+ int c;
+ while( (c = getopt(argc, argv, "dhl:s:")) != -1)
+ switch(c) {
+ case 'd':
+ debug_flag = 1;
+ break;
+ case 'h':
+ fprintf(stderr, "Usage: %s [-d] [-h] [-lNUM]\n"
+ " optional parameters:\n"
+ " -d debug mode, print out verbose informations about signals\n"
+ " if not set, only normal verbosity will be printed out on\n"
+ " stdout, painting an ASCII paper tape which visualizes the\n"
+ " bytes (see above for the caption)\n\n"
+ " -h display this help message\n\n"
+ " -s same as -l\n"
+ " -l sets the NUMBER OF BYTES which are expected on stdin.\n"
+ " with this information we can complete the status information\n"
+ " with useful informations about the estimated remaining time\n"
+ " to punch (useful for longer data)\n"
+ " example: cat 2k-data-file | %s -l2000\n",
+ argv[0], argv[0]);
+ return 0;
+ case 'l':
+ case 's':
+ c = atoi(optarg);
+ if( c > 0 ) {
+ estimated_data_length = c;
+ break;
+ }
+ printf("%s: data length must be a positive integer, like '123', not %s\n", argv[0], optarg);
+ case '?': break;
+ }
+
+ //DPRINTF("opening device...\n");
+ parport_fd = open(PARPORT_DEVICE, O_RDWR);
+ if(parport_fd == -1) {
+ perror("opening device failed");
+ return 1;
+ }
+
+ /* Claim the port */
+ //DPRINTF("claiming port...\n");
+ if(ioctl(parport_fd, PPCLAIM)) {
+ perror ("claiming port (PPCLAIM)");
+ close (parport_fd);
+ return 1;
+ }
+
+ /* Go straight into compatibility mode: */
+ //DPRINTF("Setting compatibility mode...\n");
+ mode = IEEE1284_MODE_COMPAT;
+ if(ioctl(parport_fd, PPNEGOT, &mode)) {
+ perror ("Setting compatibilty mode (PPNEGOT)");
+ close (parport_fd);
+ return 1;
+ }
+
+ DPRINTF("Waiting for Puncher beeing ready for signals...\n");
+ {
+ unsigned char status;
+ if(ioctl(parport_fd, PPRSTATUS, &status)) return -1;
+ if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
+ DPRINTF("Puncher is BUSY!\n");
+ usleep(8000);
+ }
+ }
+
+ /* The main loop (reading stdin and printing out) */
+ /* We will just read 1 byte at one time to handle
+ * it nicely... */
+ DPRINTF("Start reading from stdin...\n");
+ time_since_beginning = mtime(0);
+ for(;;) {
+ unsigned char buf; /* stdin 1 byte buffer */
+ size_t ret; /* multipurpose return value */
+
+ ret = read(0, &buf, 1); /* 1 byte from stdin */
+ if(ret < 0) {
+ perror("read stdin");
+ close(parport_fd);
+ return 1;
+ }
+
+ if(ret == 0) {/* EOF, end of input, etc. */
+ DPRINTF("stdin EOF\n");
+ break;
+ }
+
+ /* Visualisierung der Zeile */
+ printf("%5ims ", (int)(mtime(time_since_beginning)/1000));
+ visualize_byte(buf);
+ printf(" 0x%02x=%03i ", buf, buf);
+ calculate_time(++already_punched, estimated_data_length, (int)(mtime(time_since_beginning)/1000));
+
+ /* und Ausdrucken */
+ ret = write_puncher(parport_fd, buf);
+ if(ret < 0) {
+ perror("write puncher");
+ close(parport_fd);
+ return 1;
+ } else if(ret == 0) {
+ printf("=)\n"); // Smiley freut sich
+ } else if(ret == 1) {
+ printf(":-(\n"); // Smile traurig
+ }
+ } /* for stdin */
+
+ DPRINTF("Transmission finished\n");
+ ioctl(parport_fd, PPRELEASE);
+ close(parport_fd);
+ return 0;
+}
+
+void visualize_byte(unsigned char buf) {
+ /* Zeichnet Lochstreifen-Byte (wie das Perl-Proggi) */
+ unsigned char against = 0x01;
+ unsigned char check;
+ int pos;
+
+ printf("|");
+ for(pos=0; pos < 8; pos++) {
+ if(pos == 3) /* Streifenfuehrung */
+ printf(".");
+ check = buf;
+ check >>= pos;
+
+ if((check & against) == 0)
+ printf(" "); /* bit nicht gesetzt */
+ else
+ printf("*"); /* bit gesetzt */
+ } /*for */
+ printf("|");
+}
+
+void calculate_time(int already_punched_bytes, int estimated_punch_length, int mtime_since_beginning) {
+ /* In jeder Zeile berechnen, wie lange noch gepuncht wird,
+ * und ausgeben. Nur wenn Laenge per "-l" oder "-s" angegeben
+ * wird. In Bytes.
+ *
+ * Irgendwie ist der Berechnungsalgorithmus etwas schrottig und
+ * produziert in den ersten Sekunden nur Müll, aber ansonsten
+ * ist er ganz okay.
+ */
+ int percentage, remaining_sec = 0;
+
+ if(!estimated_punch_length) return; // wenn es gar nicht abgegeben wurde
+
+ //printf("%i %i ", already_punched_bytes, estimated_punch_length, mtime_since_beginning);
+
+ percentage = (int)rint(((float)already_punched_bytes / (float)estimated_punch_length) * 100);
+ if(mtime_since_beginning != 0) // erst nach dem ersten Zyklus berechenbar
+ remaining_sec = (int)rint(((float)mtime_since_beginning / ((float)already_punched_bytes / (float)estimated_punch_length) - mtime_since_beginning)/1000);
+
+ if(already_punched_bytes <= estimated_punch_length) {
+ printf("| %i%% (%i sec remaining) ", percentage, remaining_sec);
+ }
+}
+
+size_t write_puncher(int fd, unsigned char buf) {
+ /* Der eigentliche, Geraetespezifische Treiber
+ * befindet sich erst in dieser Schreib-Funktion
+ *
+ * return: <0 => Fehler; ==0 => Alles perfekt; 1 => Am Ende noch busy
+ *
+ */
+ //DPRINTF("\n");
+ static unsigned char strobe_on = (PARPORT_CONTROL_STROBE);
+ static unsigned char null_mask = 0x00;
+ unsigned char status;
+ long long time;
+
+ /* (falls nötig) warten bis PR (Punch ready == busy) kommt */
+ /*for(;;) *///{
+ /*int x;
+ for(x=0;x<5;x++) {
+ if(ioctl(fd, PPRSTATUS, &status))
+ return -1;
+
+ if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
+ DPRINTF("Puncher ready to recieve (%x)\n", status);
+ x=-1;
+ break;
+ }
+ usleep(10);
+ }*/
+
+ /* Puncher hatte noch kein PR gesetzt. */
+ //if(x<0)
+ // DPRINTF("Waited for Puncher ready (status=%x)... ", status);
+
+ //usleep(8000);
+ /* 1/2 Sekunde ist fuer debugzwecke besser als die vorherigen 8000. */
+ //}
+
+ /* set data pins */
+ if(ioctl(fd, PPWDATA, &buf))
+ return -2;
+ time = mtime(0);
+
+ usleep(10); // take some time...
+
+ /* "pulse" strobe ==> turn off strobe! (strange behaviour) */
+ if(ioctl(fd, PPWCONTROL, &null_mask))
+ return -3;
+ DPRINTF("data set; strobe pulsed...\n");
+
+ /* Puncher: PI (=strobe) minimum == 100us */
+ usleep(220); // DTL TRY
+ // was: 220 => wir gehen jetzt auf 2ms
+
+ /* check if Punch Ready has fallen */
+ if(ioctl(fd, PPRSTATUS, &status))
+ return -4;
+ // bringts ja eh nicht -- also lassen.
+
+ /*for(;;) {
+ if(ioctl(fd, PPRSTATUS, &status))
+ return -4;
+ if((status & PARPORT_STATUS_BUSY) != PARPORT_STATUS_BUSY) {
+ * it has not - quite bad, but we will continue *
+ DPRINTF("ERROR: Punch Ready has NOT FALLEN (%x)\n",status);
+ usleep(5*1000); // noch mal 5ms warten.
+ } else break;
+ }*/
+
+ /* end strobe + data pins */
+ DPRINTF("Control is %x. Ending data pins... ",status);
+ if(ioctl(fd, PPWDATA, &null_mask)) return -5;
+ DPRINTF("+ strobe... ");
+ if(ioctl(fd, PPWCONTROL, &strobe_on)) return -5;
+
+ /* wait untill Puncher is ready to success */
+ {
+ int wait = 40*1000-mtime(time); // war 13*1000
+ DPRINTF("\nWaiting for Puncher Ready (%i usec)...", wait);
+ if(wait>0) usleep(wait);
+ }
+
+ if(ioctl(fd, PPRSTATUS, &status)) return -6;
+ if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
+ DPRINTF("Still busy (%x).\n", status);
+ return 1;
+ } else {
+ DPRINTF("Finished successfully (%x)\n", status);
+ return 0;
+ }
+
+
+ //for(;;) {
+ /*
+ int x;
+ unsigned char status1,status2;
+ for(x=0;x<(100);x++) {
+ if(ioctl(fd, PPRSTATUS, &status1)) return -6;
+ usleep(15);
+ if(ioctl(fd, PPRSTATUS, &status2)) return -6;
+ if(status1 == status2) {
+ //DPRINTF("%x=%x ",status1,status2);
+ status = status2;
+
+ if((status & PARPORT_STATUS_BUSY) == PARPORT_STATUS_BUSY) {
+ DPRINTF("- Puncher finished successfully (%x)\n",status);
+ return 0;
+ }
+ }
+ usleep(10);
+ }//for
+
+ DPRINTF("Cycle passed. Still busy (%x/%x). Going on.\n",status1,status2);
+
+ //usleep(10000); // 20ms was
+ /* Der Komplettintervall betraegt 13.33 Microsekunden -
+ * 10ms ist vielleicht angemessen
+ * */
+ //}
+ //return 0;
+} /* write_puncher */
Index: /userspace-driver/setoff-strobe.c
===================================================================
--- /userspace-driver/setoff-strobe.c (revision 1)
+++ /userspace-driver/setoff-strobe.c (revision 1)
@@ -0,0 +1,52 @@
+/* This will stop the strobe signal */
+
+#include
+#include
+#include
+#include /* lowlevel io */
+#include
+
+#include
+#include
+#include
+
+#define DEBUG
+#define PARPORT_DEVICE "/dev/parport0"
+
+int main(int argc, char **argv) {
+ int parport_fd;
+ int mode; /* IEEE1284_MODE_COMAT == compatibility mode */
+
+ parport_fd = open(PARPORT_DEVICE, O_RDWR);
+ if(parport_fd == -1) {
+ perror("open device failed");
+ return 1;
+ }
+
+ if(ioctl(parport_fd, PPCLAIM)) {
+ perror ("claiming port (PPCLAIM)");
+ close (parport_fd);
+ return 1;
+ }
+
+ mode = IEEE1284_MODE_COMPAT;
+ if(ioctl(parport_fd, PPNEGOT, &mode)) {
+ perror ("Setting compatibilty mode (PPNEGOT)");
+ close (parport_fd);
+ return 1;
+ }
+
+ {
+ static unsigned char mask = PARPORT_CONTROL_STROBE;
+ printf("Setting null mask to control pins (strobe,etc.)...\n");
+ if(ioctl(parport_fd, PPWCONTROL, &mask)) {
+ perror("null mask");
+ close(parport_fd);
+ return 1;
+ }
+ }
+
+ ioctl(parport_fd, PPRELEASE);
+ close(parport_fd);
+ return 0;
+}
Index: /visualisator/Makefile
===================================================================
--- /visualisator/Makefile (revision 1)
+++ /visualisator/Makefile (revision 1)
@@ -0,0 +1,17 @@
+
+CAIROFLAGS=`pkg-config --cflags --libs cairo`
+GTKFLAGS=`pkg-config --cflags --libs gtk+-2.0`
+# GTK nutzt Cairo, daher brauchts nicht $(CAIROFLAGS) $(GTKFLAGS) in
+# einem gcc-Aufruf
+
+BACKEND=lochstreifen.c
+
+all: cmd gtk
+
+cmd: create-image.c $(BACKEND)
+ gcc -o binary $(CAIROFLAGS) create-image.c $(BACKEND)
+
+gtk: gtkprogram.c $(BACKEND)
+ gcc -o gtkprogram $(GTKFLAGS) gtkprogram.c $(BACKEND)
+
+
Index: /visualisator/create-image.c
===================================================================
--- /visualisator/create-image.c (revision 1)
+++ /visualisator/create-image.c (revision 1)
@@ -0,0 +1,332 @@
+/**
+ * Vollstaendig konfigurierbares Kommandozeilenfrontend fuer die
+ * Lochstreifenzeichenroutine (Cairo verwendend).
+ * siehe ./programm --help fuer Uebersicht der selbsterklaerenden
+ * Parameter.
+ *
+ * Default ist Einlesen ueber stdin und Ausgabe auf stdout in PNG.
+ *
+ **/
+
+#include
+#include
+#include
+#include
+
+#include "lochstreifen.h"
+
+LOCHSTREIFEN *l;
+int surface_type = 0; // 0 = PNG, 1 = SVG
+char *output_file;
+int verbosity = 0;
+
+#define DPRINTF(msg...) if(verbosity!=0) fprintf(stderr,msg);
+
+const char *argp_program_version = "Punch card visualisator - CLI frontend";
+
+static struct argp_option options[] = {
+ {"verbose", 'v', 0, 0, "Produce verbose output on stderr" },
+ //{"quiet", 'q', 0, 0, "Don't produce any output" },
+ //{"silent", 's', 0, OPTION_ALIAS },
+
+ {"output", 'o', "FILE", 0, "Output to FILE (instead of standard output)" },
+ {"image", 'i', 0, OPTION_ALIAS },
+ {"format", 'f', "SVG|PNG",0, "Set desired output image format (PNG or SVG)" },
+ {"", 0, 0, OPTION_DOC, ""},
+
+ {"Dimensions", 0, 0, OPTION_DOC, "Dimensions are integers without units"},
+ {"width", 'w', "NUM", 0, "Set desired width for output image (in px or points, according to output format)", 1 },
+ {"height", 'h', "NUM", 0, "Set desired height for output image (unit like width argument)", 1 },
+ {"diameter", 'd', "NUM", 0, "Set dimensions for output image by punched hole diameter (pixel)", 1 },
+ {"", 0, 0, OPTION_DOC, "",1},
+
+ {"Empty bytes", 1, 0, OPTION_DOC, "Bytes with value=0 which are not content of files", 1},
+ {"empty-start", -1, "NUM", 0, "Set number of empty bytes at beginning (default=0)", 2 },
+ {"empty-end", -2, "NUM", 0, "Set number of empty bytes at end (default=0)", 2 },
+ {"", 0, 0, OPTION_DOC, "",2},
+
+ {"Colors", 0, 0, OPTION_DOC, "Color format: #RGB[A], #RRGGBB[AA]", 2 },
+ {"hide-imagebg", -3, 0, 0, "Make the image background (space around paper tape) transparent", 3 },
+ {"color-imagebg", -4, "#RGBA", 0, "Set image background color", 3 },
+ {"hide-tapebg", -5, 0, 0, "Hide the paper tape background", 3 },
+ {"color-tapebg", -6, "#RGBA", 0, "Set tape background color", 3 },
+ {"hide-punched", -7, 0, 0, "Hide the holes (only the punched ones)", 3 },
+ {"color-punched", -8, "#RGBA", 0, "Set color of holes (punched bits)", 3 },
+ {"hide-notpunched", -9, 0, 0, "Hide the holes which aren't punched on real tapes", 3 },
+ {"color-notpunched",-10, "#RGBA", 0, "Set color of bits with boolean value \"false\"", 3 },
+ {"hide-feedholes", -11, 0, 0, "Hide the feed holes (which means they wouldn't be punched)", 3 },
+ {"color-feedholes", -12, "#RGBA", 0, "Set color of feed holes (the small ones)", 3 },
+ {"", 0, 0, OPTION_DOC, "",3},
+
+ {"Transformations and Rotations", 0, 0, OPTION_DOC, "", 3},
+ {"rotation", -13, "right|bottom|left|top", 0, "Rotation of punched tape (alternative short notation: 0=right, 1=bottom, 2=left, 3=top)", 4 },
+ {"reflection-byte-direction", -14, 0, 0, "Enables horizontal reflecion on the data axis (inverts data direction)", 4 },
+ {"reflection-bit-direction", -15, 0, 0, "Enables vertical reflection on the other axis (inverts bit direction)", 4 },
+ {"", 0, 0, OPTION_DOC, "",-2},
+
+ { 0 }
+};
+
+char *strtolower(char *string) {
+ // komisch, ich dachte echt, es gaebe dafuer eine Funktion in C...
+ int x=0;
+ for(;string[x];x++) string[x] = tolower(string[x]);
+
+ return string; // ja, ich veraenderte den Ursprungsstring. Egal ;-)
+}
+
+cairo_pattern_t *hex2cairo_pattern(const char *string) {
+ /** Kriegt aus #RRGGBBAA oder #RGBA eine Cairo-Surface */
+ char buf[2]; // zum temporaeren Speichern der einzelnen umzuwandelnden Zeichen
+ buf[1] = '\0'; // nur ein Ein-Zeichen-String also
+ int len = strlen(string);
+ unsigned char numbers[8]; // rausgefundende Ziffern
+ int numbers_count; // wie viele Ziffern rausgefunden
+ cairo_pattern_t *pattern;
+
+ // erst mal schauen, ob ne schoene Raute da ist und auf Laenge (entsprechendes Format)
+ if(string[0] != '#' || (len != 4 && len != 5 && len != 7 && len != 9)) {
+ fprintf(stderr, "Bad color: %s -- colors shall have format #RGB or #RRGGBB or #RGBA or #RRGGBBAA\n", string, len);
+ exit(1);
+ }
+ string++; // das "#"-Zeichen braucht keiner mehr
+
+ for(numbers_count=0; numbers_count < len-1; numbers_count++) {
+ buf[0] = string[numbers_count];
+ numbers[numbers_count] = strtol(buf, NULL, 16);
+ //printf("Read digit %s = 0x%x\n", buf, numbers[numbers_count]);
+ }
+ //numbers_count++; // wir zaehlen ab 1 -- komisch, tud er sowieso schon.
+
+ if(numbers_count == 3 || numbers_count == 4) {
+ // #RGB oder #RGBA
+ pattern = cairo_pattern_create_rgba(
+ (double)numbers[0] / (double)0xF,
+ (double)numbers[1] / (double)0xF,
+ (double)numbers[2] / (double)0xF,
+ (numbers_count == 4) ? (double)numbers[3] / (double)0xF : 1
+ );
+ } else {
+ // #RRGGBB oder #RRGGBBAA
+ pattern = cairo_pattern_create_rgba(
+ (double)(numbers[1] + numbers[0]*0x10) / (double)0xFF,
+ (double)(numbers[3] + numbers[2]*0x10) / (double)0xFF,
+ (double)(numbers[5] + numbers[4]*0x10) / (double)0xFF,
+ (numbers_count == 8) ? (double)(numbers[7] + numbers[6]*0x10) / (double)0xFF : 1
+ );
+ }
+ // Fuer Debug-Ausgaben:
+ { double r,g,b,a; cairo_pattern_get_rgba(pattern, &r, &g, &b, &a);
+ printf("Allocated color #%s as #%x%x%x, opacity %x\n", string, (unsigned int)(r*256), (unsigned int)(g*256), (unsigned int)(b*256), (unsigned int)(a*256)); }
+ printf("Farbe fertig.\n");
+ return pattern;
+}
+
+error_t parse_option (int key, char *arg, struct argp_state *state) {
+ //printf("OPTION %x (%c = %i)...\n", key, key, key);
+ switch(key) {
+ case 'v':
+ verbosity = 1;
+ break;
+ case 'o': case 'i':
+ // Ausgabedatei setzen.
+ output_file = arg;
+ break;
+ case 'w':
+ // Breite setzen.
+ lochstreifen_set_d_by_width(l, atoi(arg));
+ break;
+ case 'h':
+ // Hoehe setzen.
+ lochstreifen_set_d_by_height(l, atoi(arg));
+ break;
+ case 'd':
+ // Durchmesser setzen
+ lochstreifen_set_d(l, atoi(arg));
+ break;
+ case 'f':
+ // Dateiformat setzen
+ // keine Lust auf enums
+ if(strcmp(strtolower(arg), "png") == 0) surface_type = 0;
+ else if(strcmp(strtolower(arg), "svg") == 0) surface_type = 1;
+ else argp_error(state, "Only PNG and SVG are supported as file formats.\n");
+ break;
+ case -1:
+ // Emptystart-Bytes
+ l->empty_start = atoi(arg);
+ break;
+ case -2:
+ // Emptyend-Bytes
+ l->empty_end = atoi(arg);
+ break;
+ case -3:
+ // hide imagebg
+ l->hintergrund = NULL;
+ break;
+ case -4:
+ // color imagebg
+ l->hintergrund = hex2cairo_pattern(arg);
+ break;
+ case -5:
+ // hide tape
+ l->streifenbg = NULL;
+ break;
+ case -6:
+ // color tapebg
+ l->streifenbg = hex2cairo_pattern(arg);
+ break;
+ case -7:
+ // hide punched
+ l->punched = NULL;
+ break;
+ case -8:
+ // color punched
+ l->punched = hex2cairo_pattern(arg);
+ break;
+ case -9:
+ // hide notpunched
+ l->notpunched = NULL;
+ break;
+ case -10:
+ // color notpunched
+ l->notpunched = hex2cairo_pattern(arg);
+ break;
+ case -11:
+ // hide feedholes
+ l->fuehrung = NULL;
+ break;
+ case -12:
+ // color fuerhung
+ l->fuehrung = hex2cairo_pattern(arg);
+ break;
+ case -13:
+ // rotation
+ if(strcmp(arg, "right") == 0) arg = "0";
+ else if(strcmp(arg, "bottom") == 0) arg = "1";
+ else if(strcmp(arg, "left") == 0) arg = "2";
+ else if(strcmp(arg, "top") == 0) arg = "3";
+ arg[1] = '\0'; // String ist jetzt auf jeden Fall nur ein zeichen lang
+ lochstreifen_set_direction(l, atoi(arg), -1, -1);
+ break;
+ case -14:
+ // horizontal spiegeln
+ lochstreifen_set_direction(l, -1, 1, -1);
+ break;
+ case -15:
+ // vertikal spiegeln
+ lochstreifen_set_direction(l, -1, -1, 1);
+ break;
+ //case ARGP_KEY_END:
+ //printf("bla...");
+ default:
+ return ARGP_ERR_UNKNOWN;
+ } // switch
+ return 0; // success
+}
+
+static struct argp argp = { options, parse_option, "[FILE TO READ FROM]", // Als Argument in der ersten Zeile
+ "This program uses cairo to draw a punched tape as a PNG or SVG file. Any binary " // Hilfe oben
+ "data are accepted via stdin or read in from the file given as argument. "
+ "The produced image is written into stdout or in the filename given by -o."
+ // mit \v danach koennte man ausfuehrliche Hilfe unten anzeigen.
+}; // static struct argp
+
+cairo_status_t* lochstreifen_out_closure(void *closure, unsigned char *data, unsigned int length) {
+ // einfach nur in das uebergebene Dateihandle schreiben
+ fwrite(data, length, 1, (FILE *)closure);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+int main(int argc, char *argv[]) {
+ //unsigned char data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+ /*int x;
+ unsigned char data[256];
+ for(x=0;x<256;x++) {
+ data[x] = (unsigned char) x;
+ }
+ draw_lochstreifen(256, data);
+ return 0;*/
+ LOCHSTREIFEN *lochstreifen;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ byte_t *data;
+ int length; // laenge des *data-Arrays
+ FILE *out;
+ int input_argc; // Index der argv-Option, wo die zu handelnden Dateien stehen.
+ l = lochstreifen_new();
+ lochstreifen = l;
+
+ // Argumente parsen
+ argp_parse(&argp, argc, argv, 0, &input_argc, NULL);
+
+ //DPRINTF("Stop.\n");
+ //return 0;
+
+ // Daten einlesen
+ if(input_argc < argc) {
+ FILE *fh;
+ DPRINTF("Reading from file %s\n", argv[input_argc]);
+ fh = fopen(argv[input_argc], "r");
+
+ if(fh == NULL) {
+ perror("opening input file");
+ exit(1);
+ }
+
+ length = file_get_contents(fh, &data);
+ fclose(fh);
+ } else {
+ DPRINTF("Reading from stdin, type [STRG]+[D] to generate paper tape from data\n");
+ length = file_get_contents(stdin, &data);
+ }
+ DPRINTF("Read in %d bytes\n", length);
+
+ // Ausgabestream oeffnen
+ if(output_file != NULL) {
+ out = fopen(output_file, "w");
+
+ if(out == NULL) {
+ perror("opening output file");
+ exit(1);
+ }
+ DPRINTF("File %s successfully opened for writing\n", output_file);
+ } else {
+ DPRINTF("Writing image data to stdout\n");
+ out = stdout;
+ }
+
+ /*int x;
+ for(x=0; x
+#include
+#include // rint()
+#include // strlen()
+#include
+#include "lochstreifen.h"
+
+#include // NUR WAEHREND DEBUGGING
+
+#define WINDOW_TITLE "Lochstreifen-Visualisierung" /* Standardtitel */
+
+// Muss leider global sein, damit ein Zugriff von mehreren Funktionen moeglich ist
+GtkWidget *window; // Hauptfenster
+GtkWidget *lochstreifen_widget, *lochstreifen_statusbar; // Widget, das Lochstreifen haelt, Statusleiste
+LOCHSTREIFEN *lochstreifen; // das Lochstreifen-Objekt
+GTimer *last_statusbar_update; // fuer Statusbar-Prioritaetenbehandlung
+GtkWidget *fit_screen_toggle; // Auswahlbox im Ansichtmenue, um Autozoom umzuschalten.
+gboolean startsequence_running = FALSE; // Ist TRUE, wenn die Startanimation laeuft
+
+// Die Daten, die bei der Startsequenz angezeigt werden, liegen hier als Bytearray
+// vor. Generierung mit
+// $ [generatorprogramm] | hexdump -e '11/1 "0x%02x, " "\n"'
+// "0x , "-Zeichen wegschneiden.
+// Laenge feststellen mit wc -c
+
+int startsequence_length = 205;
+byte_t startsequence_data[] = {
+0xfc, 0x01, 0x02, 0x01, 0xfc, 0x00, 0x81, 0xff, 0x81, 0x00, 0xff,
+0x01, 0x01, 0x00, 0xff, 0x01, 0x01, 0x00, 0xff, 0x18, 0xc7, 0x00,
+0xff, 0x81, 0xff, 0x00, 0xff, 0x80, 0x60, 0x80, 0xff, 0x00, 0xff,
+0x80, 0x60, 0x80, 0xff, 0x00, 0xff, 0x91, 0x91, 0x00, 0xff, 0x40,
+0x3c, 0x02, 0xff, 0x00, 0x00, 0x00, 0x83, 0xb9, 0xc1, 0x00, 0xff,
+0x01, 0xff, 0x00, 0xff, 0x80, 0x60, 0x80, 0xff, 0x00, 0x00, 0x00,
+0x81, 0xff, 0x81, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x80,
+0xff, 0x80, 0x00, 0xff, 0x91, 0x91, 0x00, 0xff, 0x88, 0xf7, 0x00,
+0xff, 0x88, 0x88, 0xff, 0x00, 0xff, 0x18, 0xc7, 0x00, 0x80, 0xff,
+0x80, 0x00, 0x81, 0xff, 0x81, 0x00, 0xfc, 0x01, 0xfc, 0x00, 0xff,
+0x91, 0x91, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x00, 0x00,
+0xff, 0x01, 0x01, 0x00, 0xff, 0x81, 0xff, 0x00, 0xff, 0x81, 0x81,
+0x00, 0xff, 0x10, 0xff, 0x00, 0xf0, 0x91, 0x9f, 0x00, 0x80, 0xff,
+0x80, 0x00, 0xff, 0x88, 0xf7, 0x00, 0xff, 0x91, 0x91, 0x00, 0x81,
+0xff, 0x81, 0x00, 0xff, 0x90, 0x90, 0x00, 0xff, 0x91, 0x91, 0x00,
+0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0x83, 0xb9, 0xc1, 0x00, 0xff,
+0x91, 0x91, 0x00, 0x81, 0xff, 0x81, 0x00, 0xff, 0x81, 0x81, 0x00,
+0xff, 0x10, 0xff, 0x00, 0xff, 0x40, 0x3c, 0x02, 0xff, 0x00, 0xff,
+0x91, 0x91, 0x00, 0xff, 0x88, 0xf7, 0x00
+};
+
+// zum Testen:
+/*int startsequence_length = 4;
+byte_t startsequence_data[] = { 0x00, 0x01, 0x02, 0x03 };*/
+
+void message_statusbar(char *msg);
+void message_error(gchar *heading, gchar *text);
+
+GtkWidget *fast_stock_menuitem(const GtkWidget *parentmenu, const gchar *stock_id) {
+ /* erzeugt schnell mal ein menuitem mit dem entsprechenden Stock-Dingsda
+ und gibt es zurueck */
+ GtkWidget *menuitem;
+ menuitem = gtk_image_menu_item_new_from_stock(stock_id, NULL);
+ gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);
+ gtk_widget_show (menuitem);
+ return menuitem;
+}
+
+GtkWidget *fast_menuitem(const GtkWidget *parentmenu, const gchar *label) {
+ /* erzeugt schnell mal ein menuitem mit der entsprechenden Beschriftung und gibts
+ zurueck */
+ GtkWidget *menuitem;
+ menuitem = gtk_menu_item_new_with_label(label);
+ gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);
+ gtk_widget_show (menuitem);
+ return menuitem;
+}
+
+
+GtkWidget *fast_menu_tearoff(const GtkWidget *parentmenu) {
+ /* Schnell mal ein Abreissitem hinzufuegen */
+ GtkWidget *menuitem;
+ menuitem = gtk_tearoff_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);
+ gtk_widget_show (menuitem);
+ return menuitem;
+}
+
+GtkWidget *fast_menu_seperator(const GtkWidget *parentmenu) {
+ /* Schnell einen Seperator */
+ GtkWidget *menuitem;
+ menuitem = gtk_separator_menu_item_new();
+ gtk_menu_shell_append(GTK_MENU_SHELL(parentmenu), menuitem);
+ gtk_widget_show(menuitem);
+ return menuitem;
+}
+
+void redraw_lochstreifen(gboolean i_have_resized_the_lochstreifen) {
+ /**
+ * Zentrale Funktion zum Aufrufen um den Lochstreifen manuell neu
+ * zu zeichnen. Wenn der Parameter TRUE ist, wird signalisiert,
+ * dass die Groesse des Lochstreifens sich (wie auch immer) geaendert
+ * hat (neue Daten, Zoom, etc. pp) -- also wird ggf. ein neues
+ * size request abgesetzt, je nach Zoomeinstellungen (Autozoom!)
+ **/
+ if(i_have_resized_the_lochstreifen) {
+ if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle))) {
+ // Lochstreifengroesse wird automatisch dem Fenster angepasst,
+ // dafuer werden die size requests anders gestellt, damit kein nervender
+ // Scrollbalken fuer die angepasste Dimension kommt.
+ // siehe transform_fit_lochstreifen
+ if(lochstreifen_get_orientation(lochstreifen) == 1)
+ // Mindestdimensionen: Breite festgelegt durch Daten, Hoehe variabel
+ gtk_widget_set_size_request(lochstreifen_widget, lochstreifen_get_width(lochstreifen), -1);
+ else
+ gtk_widget_set_size_request(lochstreifen_widget, -1, lochstreifen_get_height(lochstreifen));
+ } else {
+ // Lochstreifengroesse wird nicht automatisch dem Fenster angepasst.
+ // Ganz normal Breite und Hoehe wuenschen.
+ gtk_widget_set_size_request(lochstreifen_widget, // neue Groesse erfordern.
+ lochstreifen_get_width(lochstreifen),
+ lochstreifen_get_height(lochstreifen));
+ }
+ } // i have resized...
+ gtk_widget_queue_draw(lochstreifen_widget); // neuzeichnen.
+}
+
+gboolean export_lochstreifen(GtkWidget *widget, gchar *format) {
+ cairo_surface_t *surface;
+ cairo_t *cr;
+ cairo_status_t status;
+ GtkWidget *chooser;
+ char *filename;
+
+ // gewuenschten Dateinamen kriegen
+ chooser = gtk_file_chooser_dialog_new(
+ g_strdup_printf("Dateiname fuer %s-Export auswaehlen", format),
+ GTK_WINDOW(window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE);
+
+ if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) {
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
+ }
+ gtk_widget_destroy(chooser);
+
+ lochstreifen_flush_only_start_area(lochstreifen); // damit der ganze Lochstreifen gezeichnet wird, vgl. expose_lochstreifen
+ if(strcmp(format, "PNG") == 0) {
+ // PNG erstellen
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ lochstreifen_get_width(lochstreifen),
+ lochstreifen_get_height(lochstreifen)
+ );
+ cr = cairo_create(surface);
+ lochstreifen_draw(lochstreifen, cr);
+ status = cairo_surface_write_to_png (surface, filename);
+ message_statusbar(
+ g_strdup_printf("PNG-Datei (%d x %d Pixel, 24bit) wurde exportiert: %s",
+ lochstreifen_get_width(lochstreifen),
+ lochstreifen_get_height(lochstreifen),
+ cairo_status_to_string(status))
+ );
+ } else if(strcmp(format, "SVG") == 0) {
+ // SVG erstellen
+ double width,height;
+ // SVG-Surface erwartet Breite in Punkt, 1pt = 1/72 inch
+ width = 72 * lochstreifen_get_width(lochstreifen) / (double)fast_get_dpi();
+ height = 72 * lochstreifen_get_height(lochstreifen) / (double)fast_get_dpi();
+ // irgendwie spinnt der Compiler und meint ohne den folgenden unsinnigen
+ // exipliten Typcastings "Warnung: Zuweisung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung"
+ surface = (cairo_surface_t *)cairo_svg_surface_create((char*)filename, (double)width, (double)height);
+
+ cr = cairo_create(surface);
+ lochstreifen_draw(lochstreifen, cr);
+
+ message_statusbar(
+ g_strdup_printf("SVG-Datei (%.2f x %.2f Punkt) wurde exportiert: %s",
+ width, height,
+ cairo_status_to_string(cairo_surface_status(surface))
+ )
+ );
+ } else {
+ message_statusbar("Gewuenschter Exporttyp nicht feststellbar!");
+ }
+
+ cairo_surface_destroy(surface);
+ cairo_destroy(cr);
+ g_free(filename);
+}
+
+gboolean null_bytes_dialog (GtkWidget *widget, gpointer data) {
+ GtkWidget *dialog, *table, *input_start, *input_end, *label;
+ GtkWidget *box;
+
+ dialog = gtk_message_dialog_new(GTK_WINDOW(window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_OK_CANCEL,
+ "Nullbytes");
+ gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+ "Am Anfang und am Ende der angezeigten Datei koennen\n"
+ "zusaetzliche \"virtuelle\" Nullbytes angezeigt werden,\n"
+ "die in der Datei nicht gespeichert sind. Je nach Farbeinstellung\n"
+ "sieht man nur Fuehrungsloecher - damit sieht der\n"
+ "Lochstreifen realistischer aus.");
+
+ input_start = gtk_spin_button_new_with_range(0., 10000., 1.);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(input_start), (gdouble)lochstreifen->empty_start);
+ input_end = gtk_spin_button_new_with_range(0., 10000., 1.);
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(input_end), (gdouble)lochstreifen->empty_end);
+
+ box = gtk_table_new(2, 2, FALSE);
+ gtk_table_set_row_spacings(GTK_TABLE(box), 5);
+ label = gtk_label_new("Nullbytes am Anfang: ");
+ gtk_table_attach_defaults(GTK_TABLE(box), label,
+ 0, 1, 0, 1);
+ gtk_table_attach_defaults(GTK_TABLE(box), input_start,
+ 1, 2, 0, 1);
+ label = gtk_label_new("Nullbytes am Ende: ");
+ gtk_table_attach_defaults(GTK_TABLE(box), label,
+ 0, 1, 1, 2);
+ gtk_table_attach_defaults(GTK_TABLE(box), input_end,
+ 1, 2, 1, 2);
+
+ gtk_container_add(GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+ box);
+ gtk_widget_show_all (dialog);
+
+ if(gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ lochstreifen->empty_start = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(input_start));
+ lochstreifen->empty_end = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(input_end));
+ message_statusbar(
+ g_strdup_printf("Vorne werden nun %d Nullbytes angezeigt, hinten %d.",
+ lochstreifen->empty_start, lochstreifen->empty_end)
+ );
+
+ redraw_lochstreifen(TRUE);
+ } else
+ message_statusbar("Anzahl der Nullbytes wurde nicht veraendert.");
+ gtk_widget_destroy (dialog);
+}
+
+gboolean expose_lochstreifen(GtkWidget *widget, GdkEventExpose *event, gpointer data) {
+ /* Calllback für das "expose_event" - Zeichenevent */
+ cairo_t *cr;
+ time_t TIME;
+ time(&TIME);
+ //LOCHSTREIFEN *l;
+
+ // mal testen:
+ gdk_window_clear_area(widget->window,
+ event->area.x, event->area.y, event->area.width, event->area.height);
+
+ cr = gdk_cairo_create(widget->window);
+ //l = (LOCHSTREIFEN *)data;
+
+ printf("%d Neuzeichnen: x|y = (%d|%d), width*height = %d * %d\n", TIME,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ // Clipping, um das Neuzeichnen zu beschleunigen. Ist das sinnvoll?
+ /*cairo_rectangle (cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_clip (cr);*/
+
+
+ lochstreifen_set_only_start_area(lochstreifen,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ lochstreifen_draw(lochstreifen, cr);
+ /*printf("Fertig (real width*height = %d * %d)\n", lochstreifen_get_width(lochstreifen),
+ lochstreifen_get_height(lochstreifen));
+ */
+ cairo_destroy(cr);
+ return FALSE;
+}
+
+int fast_get_dpi() {
+ /**
+ * Mal schnell die Aufloesung als Ganzzahl zurueckgeben.
+ * Der Rueckgabewert gibt also die Anzahl der Pixel an, die auf dem Monitor
+ * einen Zoll breit sein sollten...
+ **/
+ GdkScreen *screen = gdk_screen_get_default();
+ if(screen == NULL) {
+ printf("Konnte GdkScreen zwecks DPI-Auslesung nicht erkennen!\n");
+ return;
+ }
+
+ gdouble dpi = gdk_screen_get_resolution(screen);
+ if(dpi < 0) {
+ printf("Screenresolution (%f) nicht feststellbar\n", dpi);
+ return;
+ }
+ return (int)rint(dpi); // noch sauber runden.
+}
+
+gboolean transform_fit_lochstreifen(GtkWidget *widget, GdkEventConfigure *event, gpointer data) {
+ // Bei Groessenveraenderungen des Lochstreifenwidgets wird dies
+ // aufgerufen, wenn "an Bildschirmgroesse anpassen" gewuenscht ist
+
+ // Das Scrollwidget davon unterrichten, nur noch in einer Richtung zu scrollen, damit
+ // es beim Verkleinern des Fensters nicht meint, genug Platz zu haben und sich die Lochstreifen-
+ // groesse gar nicht anpasst.
+ // muss bloederweise hier gemacht werden, weil man ja nachtraeglich die Ausrichtung des
+ // Lochstreifens aendern koennte.
+ int orientation = lochstreifen_get_orientation(lochstreifen); // 1 = horizontal
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk_widget_get_parent(gtk_widget_get_parent(lochstreifen_widget))),
+ orientation == 1 ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER,
+ orientation == 1 ? GTK_POLICY_NEVER : GTK_POLICY_AUTOMATIC);
+
+ // Mindestgroessenberechnungen nach redraw_lochstreifen verlagert.
+ if(lochstreifen_get_orientation(lochstreifen) == 1) {
+ // horizontal ausgerichteter Lochstreifen => Hoehe fixieren.
+ lochstreifen_set_d_by_height(lochstreifen, event->height);
+ // Mindestdimensionssetzen verlagert nach redraw_lochstreifen,
+ // damit nicht Datengroessenaenderung die Sachen wieder kaputtmachen
+ // Mindestdimensionen: Breite festgelegt durch Daten, Hoehe variabel
+ } else {
+ // vertikal ausgerichtet => Breite fixieren
+ lochstreifen_set_d_by_width(lochstreifen, event->width);
+ // set size request verschoben nach redraw_lochstreifen, siehe oben
+ }
+
+ redraw_lochstreifen(TRUE);
+ return FALSE;
+}
+
+void transform_lochstreifen(GtkWidget *widget, gpointer data) {
+ char action = *((char *)data);
+ char *status_comment;
+ byte_t status_type = 0; // 0 = nix ersetzen, 1 = Ansicht in % einsetzen, 2 = Drehausrichtung einsetzen
+ if(action == '+') {
+ lochstreifen_set_d(lochstreifen, lochstreifen->d + 3); // vergroessern
+ status_comment = "Ansicht vergroessert auf %d%%";
+ status_type = 1;
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen
+ } else if(action == '-') {
+ if(lochstreifen->d - 3 < 1) {
+ message_statusbar("Der Lochstreifen kann nicht kleiner gezeichnet werden!");
+ return;
+ }
+ lochstreifen_set_d(lochstreifen, lochstreifen->d - 3); // verkleinern
+ status_comment = "Ansicht verkleinert auf %d%%";
+ status_type = 1;
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen
+ } else if(action == '=') { // 100% = "Lebensgroesse2
+ lochstreifen_set_d(lochstreifen, (int)rint((float)fast_get_dpi()/(float)16)); // ein Loch ist etwa 1/16 Zoll breit
+ status_comment = "Wirkliche Lebensgroesse eingestellt (kann bei falscher Monitoreinstellung abweichen)";
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(fit_screen_toggle), FALSE); // nicht automatisch anpassen
+ } else if(action == '[') { // an Bildschirmgroesse anpassen
+ if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
+ // Checkbox wurde aktiviert
+ g_signal_connect(G_OBJECT(lochstreifen_widget), "configure_event", G_CALLBACK(transform_fit_lochstreifen), NULL);
+ // den Container resizen damit die erste Anpassung inkraft tritt
+ gtk_widget_queue_resize_no_redraw(lochstreifen_widget); // neugezeichnet wird unten.
+ status_comment = "Lochstreifen passt sich nun stets dem Anzeigebereich an";
+ } else {
+ // Checkbox wurde deaktiviert
+ g_signal_handlers_disconnect_by_func(G_OBJECT(lochstreifen_widget), G_CALLBACK(transform_fit_lochstreifen), NULL);
+ // Scrollwidget wieder zuruecksetzen.
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtk_widget_get_parent(gtk_widget_get_parent(lochstreifen_widget))),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ return;
+ // nichts ausgeben, weil auch durch andere Sachen aufgerufen
+ }
+ } else if(action == 'S') { // Statusleiste einblenden/ausblenden
+ if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
+ // Checkbox wurde aktiviert
+ gtk_widget_show(lochstreifen_statusbar);
+ status_comment = "Statusleiste wird (wieder) angezeigt.";
+ } else gtk_widget_hide(lochstreifen_statusbar);
+ } else if(action == '>') { // Drehen mit Uhrzeigersinn
+ //lochstreifen_rotate(lochstreifen);
+ lochstreifen_set_direction(lochstreifen, 4, -1,-1);
+ status_comment = "Lochstreifen im Uhrzeigersinn gedreht (%s)";
+ status_type = 2;
+ } else if(action == '<') { // Drehen gegen Uhrzeigersinn
+ lochstreifen_set_direction(lochstreifen, 5, -1,-1);
+ status_comment = "Lochstreifen gegen Uhrzeigersinn gedreht (%s)";
+ status_type = 2;
+ } else if(action == '_') { // horizontal Spiegeln
+ lochstreifen_set_direction(lochstreifen, -1, 2, -1);
+ status_comment = "Lochstreifen wurde vertikal gespiegelt (Datenreihenfolge umgedreht, d.h. links und rechts vertauscht)";
+ } else if(action == '|') { // vertikal spiegeln
+ lochstreifen_set_direction(lochstreifen, -1, -1, 2);
+ status_comment = "Lochstreifen wurde horizontal gespiegelt (unten und oben vertauscht)";
+ }
+ redraw_lochstreifen(TRUE);
+
+ // Ausgaben fuer Statuszeile vorbereiten
+ if(status_comment == NULL || strlen(status_comment) == 0) return; // gibt nichts zu sagen
+ if(status_type == 1) {
+ // % von realer Groesse angeben.
+ message_statusbar(
+ g_strdup_printf(status_comment, (int)((float)lochstreifen->d / ((float)fast_get_dpi()/(float)16) * 100)) // siehe action=='='
+ );
+ } else if(status_type == 2) {
+ // Ausrichtung angeben als String
+ char *ausrichtung;
+ switch(lochstreifen->drehung) {
+ case 0: ausrichtung = "horizontal, von links nach rechts"; break;
+ case 1: ausrichtung = "vertikal, von oben nach unten"; break;
+ case 2: ausrichtung = "horizontal, von rechts nach links"; break;
+ case 3: ausrichtung = "vertikal, von unten nach oben"; break;
+ default: ausrichtung = "*** ERROR - ungueltige Ausrichtung";
+ }
+ message_statusbar(
+ g_strdup_printf(status_comment, ausrichtung)
+ );
+ } else // status_type == 0
+ message_statusbar(status_comment);
+}
+
+void change_constant_gui(GtkWidget *widget, gpointer data) {
+ // GUI zur Aenderung der Konstanten anzeigen...
+ printf("Pending...\n");
+}
+
+GdkColor *color_cairo2gdk(cairo_pattern_t *pattern);
+
+gboolean open_lochstreifen_file(char *filename) {
+ /**
+ * Oeffnet die gewuenschte Datei.
+ * Bei Fehler wird FALSE zurueckgegeben
+ **/
+ int length; gchar *data;
+ gboolean ret;
+ GError *err;
+
+ ret = g_file_get_contents(filename, &data, &length, &err);
+
+ if(ret == FALSE) {
+ message_error("Fehler beim Oeffnen",
+ g_strdup_printf("Konnte die Datei '%s' nicht oeffnen: %s", filename,
+ err->message)
+ );
+ return;
+ }
+
+ if(startsequence_running) {
+ // Startsequenz (wenn Programm ohne Lochstreifendatei gestartet wird) laeuft noch
+ // beenden, in dem startsequence_running auf FALSE gesetzt wird.
+ startsequence_running = FALSE;
+ }
+
+ lochstreifen_set_data(lochstreifen, length, (byte_t *)data, -1, -1);
+ message_statusbar("Die Datei wurde geoeffnet.");
+ gtk_window_set_title(GTK_WINDOW (window),
+ g_strdup_printf("%s - %s", basename(filename), WINDOW_TITLE)
+ );
+
+ // Neuzeichnen, usw.
+ redraw_lochstreifen(TRUE);
+}
+
+gboolean open_lochstreifen_file_dialog(GtkWidget *widget, GtkWidget *parentWindow) {
+ /**
+ * Zeigt den Datei-Oeffnen-Dialog an (als Callback-Funktion fuer das Datei-Menue)
+ *
+ *
+ **/
+ GtkWidget *chooser;
+ chooser = gtk_file_chooser_dialog_new(
+ "(Binaer-)datei zur Darstellung als Lochstreifen auswaehlen",
+ GTK_WINDOW(parentWindow),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+ if(gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_OK) {
+ char *filename;
+ FILE *file;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser));
+ if(filename == NULL) {
+ message_error("Keine Datei geoeffnet.", NULL);
+ gtk_widget_destroy(GTK_WIDGET(chooser));
+ return FALSE;
+ }
+
+ /*file = fopen(filename, "r");
+ if(file == NULL) {
+ message_error("Fehler beim Oeffnen",
+ g_strdup_printf("Konnte die Datei '%s' nicht oeffnen: %s", filename,
+ g_strerror (errno))
+ );
+ return;
+ }
+ open_lochstreifen_file(file);*/
+ open_lochstreifen_file(filename);
+ g_free(filename);
+ }
+ gtk_widget_destroy(chooser);
+ return FALSE;
+}
+
+void message_error(gchar *heading, gchar *text) {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new(GTK_WINDOW(window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ heading);
+ if(text != NULL) gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), text);
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(GTK_WIDGET(dialog));
+}
+
+void colorize_lochstreifen(GtkWidget *widget, gpointer data) {
+ cairo_pattern_t **target = (cairo_pattern_t **)data; // Doppellink noetig weil Adressaenderung
+ GdkColor color;
+ gtk_color_button_get_color(GTK_COLOR_BUTTON(widget), &color);
+ /*double red, green, blue;
+ printf("Farben gewaehlt: R=%i G=%i B=%i\n",color.red, color.green, color.blue);
+ red = ((double)color.red / (double)G_MAXUINT16); // G_MAXUINT16 = 2^16 weil Farben = guint16
+ green = ((double)color.green / (double)G_MAXUINT16);
+ blue = ((double)color.blue / (double)G_MAXUINT16);
+
+ printf("Farben == R=%f G=%f B=%f\n",
+ red,green,blue);*/
+
+ //if(*target != NULL) cairo_pattern_destroy(*target); // damit nicht sinnlos Speicher zugemuellt wird
+ *target = cairo_pattern_create_rgb(
+ // darauf muss man erst mal kommen: Vorher in double casten, denn sonst
+ // berechnet er einen unsigned short (=guint16), der einfach auf 0 ab oder
+ // auf 1 hochrundet. (double)(guint16/G_MAXUNIT16) gibt also stets 0,000 oder 1,000.
+ (double)((double)color.red / (double)G_MAXUINT16), // G_MAXUINT16 = 2^16 weil Farben = guint16
+ (double)((double)color.green / (double)G_MAXUINT16),
+ (double)((double)color.blue / (double)G_MAXUINT16));
+ //printf("%s\n", cairo_status_to_string(cairo_pattern_status(*target)));
+
+ GdkColor *g = color_cairo2gdk(*target);
+ //printf("Farben zurueck: R=%d G=%d B=%d\n", g->red, g->green, g->blue);
+ //gtk_color_button_get_alpha(GTK_COLOR_BUTTON(widget)) / 65535);
+ redraw_lochstreifen(FALSE);
+ // gtk_color_button_get_alpha(GTK_COLOR_BUTTON(widget)) / 65535);
+
+ // noch mal schnell RGB-Wert fuer Statuszeile ausgeben
+ message_statusbar(
+ g_strdup_printf("Farbe geaendert auf RGB (%d|%d|%d)",
+ (int)((double)color.red / (double)G_MAXUINT16 * 255),
+ (int)((double)color.red / (double)G_MAXUINT16 * 255),
+ (int)((double)color.red / (double)G_MAXUINT16 * 255)
+ )
+ );
+}
+
+
+GtkWidget *fast_color_menuitem(const GtkWidget *parentmenu, const char *dialog_title, const char *labeltext, GdkColor *initialColor, GtkSizeGroup *label_nice_sizegroup) {
+ /* Schnell ein Colorchooser-Button inklusive Richtextlabel in einem
+ Menuitem einbauen. Gibt das Colorchooserbutton-Widget zurück,
+ initialColor kann NULL sein. GtkSizeGroup auch. */
+ GtkWidget *menuitem, *menubox, *colorbutton, *label;
+ menuitem = gtk_menu_item_new();
+ menubox = gtk_hbox_new(FALSE, 4);
+ gtk_container_add(GTK_CONTAINER(menuitem), menubox);
+ gtk_widget_show(menubox);
+
+ colorbutton = gtk_color_button_new();
+ //gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(colorbutton), TRUE); // doch kein Alpha, das bringt nichts.
+ gtk_color_button_set_title(GTK_COLOR_BUTTON(colorbutton), dialog_title);
+ gtk_box_pack_start(GTK_BOX(menubox), colorbutton, FALSE, FALSE, 0);
+ gtk_widget_show(colorbutton);
+
+ label = gtk_label_new(NULL);
+ gtk_label_set_markup(GTK_LABEL(label), labeltext);
+ gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
+ gtk_box_pack_start(GTK_BOX(menubox), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ g_signal_connect_swapped(menuitem, "activate", G_CALLBACK(gtk_button_clicked), colorbutton);
+
+ if(initialColor != NULL) {
+ //printf("Farben:\n");
+ //printf("\tr%i g%i b%i\n", initialColor->red, initialColor->green, initialColor->blue);
+ gtk_color_button_set_color(GTK_COLOR_BUTTON(colorbutton), initialColor);
+ }
+ if(label_nice_sizegroup != NULL) {
+ gtk_size_group_add_widget(label_nice_sizegroup, label);
+ }
+
+ gtk_widget_show (menuitem);
+ gtk_menu_shell_append (GTK_MENU_SHELL (parentmenu), menuitem);
+ return colorbutton;
+}
+
+GdkColor *color_cairo2gdk(cairo_pattern_t *pattern) {
+ /** Kleine Behelfsfunktion, um von einem Cairopattern die Farbe im GDK-format zu ziehen
+ ALPHA wird ganz nett ignoriert :) */
+ GdkColor *c = malloc(sizeof(GdkColor));
+ double red, green, blue, alpha;
+ if(pattern != NULL)
+ cairo_pattern_get_rgba(pattern, &red, &green, &blue, &alpha);
+ else
+ { red=1; green=1; blue=1; } // pattern ist NULL => nehmen mir mal weiss ;-)
+ c->red = red * 65535; // 2^16
+ c->green = green * 65535;
+ c->blue = blue * 65535;
+ return c;
+}
+
+gboolean startup_sequence_loop(gpointer state) { //real_data_length) {
+ // siehe startup_sequence
+ //int state = *((int *)state_pointer);
+
+ // Schleife wird deaktiviert, in dem startsequence_running auf false gesetzt wird.
+ if(!startsequence_running)
+ return FALSE;
+
+ if(*((int*)state) <= startsequence_length) {
+ lochstreifen->data++; // Zeiger zeigt aufs naechse Byte
+ *((int*)state) += 1;
+ } else {
+ lochstreifen->data -= startsequence_length;
+ *((int*)state) = 0;
+ }
+
+
+ // einfach erst mal die Lochstreifendaten um eins verschieben.
+ /*if(lochstreifen->data_length < length) {
+ lochstreifen->data_length++;
+ }*/
+ /*
+ byte_t buf;
+ int x;
+ for(x = 1; x < lochstreifen->data_length;x++) {
+ buf = lochstreifen->data[x-1];
+ lochstreifen->data[x-1] = lochstreifen->data[x];
+ lochstreifen->data[x] = buf;
+ }*/
+
+ // neuzeichnen.
+ redraw_lochstreifen(TRUE);
+ printf("Neugezeichnet.\n");
+
+ return TRUE;
+ // true zurueckgeben, wenns weitergehen soll.
+}
+
+gboolean startup_sequence(GtkWidget *widget, gpointer datas) {
+ /**
+ * Die kleine "Startup-Sequenz" wird gezeigt, wenn es keine Daten anzuzeigen gibt.
+ * Dabei scrollt ein Text (eigene Darstellung) als Lochstreifen durch die Gegend.
+ *
+ **/
+ // Integer, um aktuelle Position zu speichern
+ int *state = malloc(sizeof(int));
+ *state = 0;
+ // Array mit gerade 2x Datenarray hintereinander erstellen.
+ byte_t *bufdata = malloc(startsequence_length*2); // Buffer mit doppelter Laenge erstellen
+ memcpy(bufdata, startsequence_data, startsequence_length); // Bufarray fuellen
+ memcpy(bufdata+startsequence_length, startsequence_data, startsequence_length); // und ein zweites mal
+ /*int x;
+ byte_t *data = malloc(sizeof(byte_t)*256);
+ for(x=0;x<256;x++) {
+ data[x] = (byte_t) (255-x);
+ }
+ */
+
+ /*int length_ = 256;
+ for(x=0; xx, (int)event->y);
+ if(byte > 0) {
+ gchar *msg; byte_t value,bit;
+ value = lochstreifen->data[byte-1]; // weil ab 1 zaehlen => -1 weil array ab 0 zaehlt
+
+ // Bitdarstellung selbst machen (printf hat sowas wohl nicht)
+ char bitdarstellung[9]; bitdarstellung[8] = '\0'; // Nullterminierung
+ for(bit=0; bit<8; bit++) {bitdarstellung[bit] = (((value >> bit) & 0x01) == 0x01) ? '1':'0';}
+
+ msg = g_strdup_printf("Byte %03d von %03d: Wert dez=%03d bin=%s okt=%03o hex=%02X",
+ byte, lochstreifen->data_length,
+ value, bitdarstellung, value, value);
+ gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0, msg);
+ g_free(msg);
+ } else if(byte == 0) {
+ //gtk_statusbar_push(statusbar, 0, "Zeiger befindet sich außerhalb");
+ // Zeiger befindet sich ausserhalb. Nichts hier ausgeben.
+ // d.h. Statusbar wurde exiplit geleert und bleibt leer.
+ } else if(byte == -1) {
+ gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0,
+ "Mauszeiger befindet sich auf den zusaetzlichen Nullbytes.");
+ }
+
+ return FALSE;
+}
+
+void message_statusbar(char *msg) {
+ /**
+ * Kurze Nachrichten in der Statuszeile anzeigen.
+ * Diese Nachrichten bleiben mindestens 4 Sekunden lang sichtbar, bevor z.B.
+ * die Position des Mauscursors wieder erscheint. Dafuer dient der Timer.
+ **/
+ gtk_statusbar_pop(GTK_STATUSBAR(lochstreifen_statusbar), 0);
+ gtk_statusbar_push(GTK_STATUSBAR(lochstreifen_statusbar), 0, msg);
+ // Statusbar-Timer erst hier einrichten, damit nach Programmstart man nicht
+ // erst 4 Sekunden warten muss.
+ if(last_statusbar_update == NULL)
+ last_statusbar_update = g_timer_new(); // wird automatisch gestartet
+ else
+ g_timer_start(last_statusbar_update); // Timer zuruecksetzen
+}
+
+gboolean scroll_lochstreifen(GtkWidget *lochstreifenwidget, GdkEventScroll *event, gpointer user_data) {
+ /**
+ Beim Scrollen auf dem Widget wird das GTK_SCROLLED_WINDOW (user_data) gescrollt, je nach
+ Ausrichtung des Streifens. Nur eindimensionales Scrolling, nicht 2d. (wer hat schon eine
+ Apple Mighty Mouse ;-) )
+ **/
+ GtkAdjustment* adjustment;
+ gdouble t;
+ if(lochstreifen->drehung % 2 == 0) {
+ // Lochstreifen ist horizontal ausgreichtet
+ adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(user_data));
+ if(adjustment == NULL) { printf("hadjustment = NULL!\n"); return FALSE; }
+ t = gtk_adjustment_get_value(adjustment) + lochstreifen->d * // um eine Lochbreite scrollen
+ ((event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? -1 : 1);
+ // nach rechts oder links scrollen
+/* );
+ printf("Set to %f\n", gtk_adjustment_get_value(adjustment) + (gdouble)adjustment->step_increment *
+ (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? (gdouble)1 : (gdouble)-1);*/
+ } else {
+ // nach oben bzw. unten scrollen
+ adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(user_data));
+ if(adjustment == NULL) { printf("vadjustment = NULL!\n"); return FALSE; }
+ t = gtk_adjustment_get_value(adjustment) + lochstreifen->d *
+ ((event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_RIGHT) ? -1 : 1);
+ // nach oben oder unten scrollen
+ }
+ printf("Scroll Is: %f | up: %f | down: %f | shall be: %f\n", gtk_adjustment_get_value(adjustment), adjustment->lower, adjustment->upper, t);
+
+ if(t < adjustment->lower) t = adjustment->lower;
+ if(t > adjustment->upper) t = adjustment->upper;
+ gtk_adjustment_set_value(adjustment, t);
+ // geht nicht:
+ //g_signal_emit_by_name(lochstreifen_widget, "motion-notify-event"); // Mauszeigerbewegung simulieren => Statuszeile updaten
+}
+
+int main(int argc, char *argv[]) {
+ GtkWidget *mainbox;
+ GtkWidget *menubar, *menuitem, *menu;
+ GtkSizeGroup *color_sizes; // Damit Farbmenue einheitlich aussieht
+ GtkWidget *scroll;
+ GtkWidget *statusbar;
+ lochstreifen = lochstreifen_new(); // muss hier bereit zugewiesen werden weil benutzt
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
+ gtk_window_set_title(GTK_WINDOW (window), WINDOW_TITLE);
+ g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ mainbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER (window), mainbox);
+ gtk_widget_show(mainbox);
+
+ statusbar = gtk_statusbar_new(); // erst nach Inhaltswidget hinzufuegen
+ lochstreifen_statusbar = statusbar; // quick & dirty global machen...
+
+ /* Menü */
+ menubar = gtk_menu_bar_new();
+ gtk_box_pack_start (GTK_BOX (mainbox), menubar, FALSE, TRUE, 0);
+ gtk_widget_show(menubar);
+
+ // Erstes Menue: Datei
+ menu = gtk_menu_new();
+ // Oeffnen
+ g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_OPEN)),
+ "activate", G_CALLBACK(open_lochstreifen_file_dialog), window);
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Grafik als PNG exportieren...")),
+ "activate", G_CALLBACK(export_lochstreifen), "PNG");
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Grafik als SVG exportieren...")),
+ "activate", G_CALLBACK(export_lochstreifen), "SVG");
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_QUIT)),
+ "activate", G_CALLBACK(gtk_main_quit), NULL);
+
+ menuitem = gtk_menu_item_new_with_mnemonic("_Datei");
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
+ gtk_widget_show (menuitem);
+
+ // Zweites Menue: Ansicht
+ menu = gtk_menu_new();
+ fast_menu_tearoff(menu);
+ g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_IN)),
+ "activate", G_CALLBACK(transform_lochstreifen), "+");
+ g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_OUT)),
+ "activate", G_CALLBACK(transform_lochstreifen), "-");
+ g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_100)),
+ "activate", G_CALLBACK(transform_lochstreifen), "=");
+ //g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_ZOOM_FIT)),
+ // "activate", G_CALLBACK(transform_lochstreifen), "[");
+ menuitem = gtk_check_menu_item_new_with_mnemonic("Groesse dem Fenster _anpassen");
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), FALSE);
+ g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(transform_lochstreifen), "[");
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ gtk_widget_show (menuitem);
+ fit_screen_toggle = menuitem; // auch hier global speichern, weil es in einer Funktion gebraucht wird.
+
+ g_signal_connect(G_OBJECT(fast_stock_menuitem(menu, GTK_STOCK_PROPERTIES)), //"Groessenverhaeltnisse aendern...")),
+ "activate", G_CALLBACK(change_constant_gui), NULL);
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Drehen im Uhrzeigersinn")),
+ "activate", G_CALLBACK(transform_lochstreifen), ">");
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Drehen gegen den Uhrzeigersinn")),
+ "activate", G_CALLBACK(transform_lochstreifen), "<");
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Horizontal spiegeln (Datenreihenfolge umkehren)")),
+ "activate", G_CALLBACK(transform_lochstreifen), "|");
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Vertikal spiegeln (Bitpositionen drehen)")),
+ "activate", G_CALLBACK(transform_lochstreifen), "_");
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_menuitem(menu, "Anzahl Nullbytes einstellen...")),
+ "activate", G_CALLBACK(null_bytes_dialog), NULL);
+ menuitem = gtk_check_menu_item_new_with_mnemonic("_Statusleiste anzeigen");
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
+ g_signal_connect(G_OBJECT(menuitem), "toggled", G_CALLBACK(transform_lochstreifen), "S");
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
+ gtk_widget_show (menuitem);
+
+ menuitem = gtk_menu_item_new_with_mnemonic("_Ansicht");
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
+ gtk_widget_show (menuitem);
+
+ // Drittes Menue: Farben
+ menu = gtk_menu_new();
+ color_sizes = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+ fast_menu_tearoff(menu);
+ g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe des Lochstreifens waehlen",
+ "Farbe des Lochstreifens", color_cairo2gdk(lochstreifen->streifenbg), color_sizes)),
+ "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->streifenbg));
+ //gtk_color_button_set_color(GTK_COLOR_BUTTON(menuitem), color_cairo2gdk(lochstreifen->streifenbg));
+
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Loecher waehlen",
+ "Farbe der Loecher waehlen\n(binaere einsen)", color_cairo2gdk(lochstreifen->punched), color_sizes)),
+ "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->punched));
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Nicht-Loecher waehlen",
+ "Farbe der Nullen waehlen\n(nicht gelochte Bits)", color_cairo2gdk(lochstreifen->notpunched), color_sizes)),
+ "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->notpunched));
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Lochstreifen-Fuehrungsloecher waehlen",
+ "Farbe der Fuehrungs-loecher\nwaehlen (kleine Loecher)", color_cairo2gdk(lochstreifen->fuehrung), color_sizes)),
+ "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->fuehrung));
+ fast_menu_seperator(menu);
+ g_signal_connect(G_OBJECT(fast_color_menuitem(menu, "Farbe der Hintergrund waehlen",
+ "Hintergrundfarbe waehlen\n(um dem Streifen rum)", color_cairo2gdk(lochstreifen->hintergrund), color_sizes)),
+ "color-set", G_CALLBACK(colorize_lochstreifen), &(lochstreifen->hintergrund));
+
+ menuitem = gtk_menu_item_new_with_mnemonic("_Farben");
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM (menuitem), menu);
+ gtk_menu_shell_append(GTK_MENU_SHELL (menubar), menuitem);
+ gtk_widget_show (menuitem);
+
+ // So jetzt aber Inhalt: Das Hauptwidget.
+ lochstreifen_set_d(lochstreifen, 20);
+
+ // Daten einlesen.
+ {
+ char *filename = NULL;
+ gboolean read_from_stdin = FALSE;
+ gboolean no_splash = FALSE;
+ GError *error = NULL;
+ GOptionContext *context;
+ byte_t show_mystart = 0; // eigene Startprozedur anzeigen?
+ GOptionEntry option_entries[] = {
+ { "filename", 'f', 0, G_OPTION_ARG_FILENAME, &filename, "Datei zu oeffnen", NULL },
+ { "stdin", 's', 0, G_OPTION_ARG_NONE, &read_from_stdin, "Von Standardeingabe lesen", NULL },
+ { "no-splash", 'n', 0, G_OPTION_ARG_NONE, &no_splash, "Keine Startanimation anzeigen, wenn ohne Datei gestartet", NULL },
+ { NULL }
+ };
+
+ context = g_option_context_new(" - Lochstreifenvisualisierung");
+ g_option_context_add_main_entries(context, option_entries, NULL);
+ g_option_context_add_group(context, gtk_get_option_group(TRUE));
+ g_option_context_parse(context, &argc, &argv, &error);
+
+ if(read_from_stdin) {
+ printf("%s: Lese Daten von Standardeingabe, erst nach EOF wird Fenster geoeffnet.\n",argv[0]);
+ byte_t *data;
+ int length = file_get_contents(stdin, &data);
+ lochstreifen_set_data(lochstreifen, length, data, 6, 6);
+ } else if(filename != NULL) {
+ // eine Datei einlesen
+ printf("Von Datei %s lesen\n", filename);
+ if(!open_lochstreifen_file(argv[1]))
+ show_mystart = 1;
+ } else if(!no_splash) {
+ // Splash (=Start)-Sequenz anzeigen
+ show_mystart = 1;
+ }
+
+ // Daten wurde eingelesen -- oder auch nicht:
+ if(show_mystart != 0) {
+ g_signal_connect_after(G_OBJECT(window), "show", G_CALLBACK(startup_sequence), NULL);
+ startsequence_running = show_mystart;
+ } else startsequence_running = FALSE;
+ }
+
+ lochstreifen_widget = gtk_drawing_area_new();
+ gtk_widget_set_size_request (GTK_WIDGET (lochstreifen_widget),
+ lochstreifen_get_width(lochstreifen),
+ lochstreifen_get_height(lochstreifen)); // erst mal spasseshalber
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scroll), lochstreifen_widget); // weil nicht scrollable
+ // Scrollbalken nur anzeigen wenn benoetigt
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_NONE);
+ gtk_box_pack_start(GTK_BOX(mainbox), scroll, TRUE, TRUE, 0);
+ gtk_widget_show(scroll);
+
+ gtk_widget_show(lochstreifen_widget);
+ g_signal_connect(G_OBJECT(lochstreifen_widget), "expose_event", G_CALLBACK(expose_lochstreifen), NULL);
+ gtk_widget_add_events(lochstreifen_widget, GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK); // Mauscursor kriegen, Mausscrolling kriegen
+ g_signal_connect(G_OBJECT(lochstreifen_widget), "motion-notify-event", G_CALLBACK(update_statusbar), NULL);
+ g_signal_connect(G_OBJECT(lochstreifen_widget), "scroll-event", G_CALLBACK(scroll_lochstreifen), scroll);
+
+ // Statusbar hinzufuegen.
+ // Ich haette ja gerne eine maechtigere Statusbar, aber das geht wohl
+ // leider nicht. Ein paar Versuche, das Label dort wenigstens Pango-Formatierungs-Faehig
+ // zu machen:
+ /*gtk_container_forall(GTK_CONTAINER(statusbar), G_CALLBACK(fast_nicer_statusbar), NULL);
+ gboolean fast_nicer_statusbar(GtkWidget *statusbar_child, gpointer egal) {
+ GList *children;
+ gpointer child;
+ children = gtk_container_get_children(GTK_CONTAINER(statusbar));
+
+ gtk_container_forall (GtkContainer *container,
+ GtkCallback callback,
+ gpointer callback_data);
+
+ //printf("Checke Kindelement von statusbar (%d)\n", g_list_length(children));
+ //while((child = g_list_next(children)) != NULL) {
+ if(GTK_IS_LABEL(statusbar_child)) {
+ printf("LABEL GEFUNDEN!\n");
+ gtk_label_set_use_markup(GTK_LABEL(statusbar_child), TRUE); // :-)
+ }
+ printf("Fand ein %s-Objekt.\n", G_OBJECT_TYPE_NAME(statusbar_child));
+ //}
+ //printf("Fertig.\n");
+ } */
+ gtk_box_pack_start(GTK_BOX(mainbox), statusbar, FALSE, TRUE, 0);
+ gtk_widget_show(statusbar);
+
+ // TEST DEBUG:
+ //gtk_widget_set_redraw_on_allocate(lochstreifen_widget, TRUE);
+ //gtk_widget_set_double_buffered(lochstreifen_widget, FALSE);
+
+ gtk_widget_show(window);
+ gtk_main();
+ return 0;
+}
Index: /visualisator/lochstreifen.c
===================================================================
--- /visualisator/lochstreifen.c (revision 1)
+++ /visualisator/lochstreifen.c (revision 1)
@@ -0,0 +1,574 @@
+/**
+ * Lochstreifen mit Cairo zeichnen
+ *
+ * Diese Datei stellt ein Objekt (LOCHSTREIFEN) zur Verfuegung,
+ * welches mit Cairo Lochstreifen auf vielfaeltige Weise rendern
+ * kann. Ueber die zahlreichen Funktionen koennen die Variablen
+ * eingestellt werden.
+ *
+ * Diese Lochstreifenroutinen sind bewusst nur mit Cairo programmiert
+ * worden (kompilieren mit `pkg-config --cflags --libs cairo`), sie
+ * benoetigen kein installiertes GTK oder Glib.
+ *
+ * Die Variationsmoeglichkeiten fuer die gezeichneten Lochstreifen
+ * sind sehr vielfaeltig und koennen einzeln voellig frei miteinander
+ * kombiniert werden. So kann man saemtliche geometrischen Abstaende
+ * aendern (Abstand der Lochreihen, Lochspalten, Fuehrungloecher,
+ * Durchmesser der unterschiedlichen Loecher, Abstaende in und um
+ * den Lochstreifen, usw.) oder verhaeltnissmaessig angeben.
+ * Ausserdem laesst sich der Lochstreifen sehr leicht in 45°-Schritten
+ * drehen oder um beide Achsen spiegeln. Saemtliche Farben sind frei
+ * einstellbar, einzelne Objekte koennen auf Wunsch auch nicht
+ * gezeichnet werden.
+ *
+ * Anzumerken sei auch, dass diese Routinen nur die Zeichenarbeit
+ * uebernehmen -- das Cairoobjekt muss das Programm stellen. Damit sind
+ * voellige Freiheiten zur Wahl der Cairo-Surface gegeben (SVG, PNG,
+ * PDF, ... -- alles moeglich, Cairo eben). Da man bei der Erstellung
+ * einer Cairosurface ueblicherweise Groessenangaben braucht, kriegt
+ * man diese aus den aktuellen Parametern berechnet mit
+ * lochstreifen_get_width und lochstreifen_get_height.
+ *
+ * Fuer die Bedeutung der einzelnen Felder der LOCHSTREIFEN-Struktur
+ * siehe Header-File, fuer genauere Erklaerungen zu den Funktionen
+ * siehe direkt bei deren Implementierungen (diese Datei).
+ *
+ * sven, im November 2007.
+ *
+ **/
+#include
+#include
+#include
+#include
+
+#include "lochstreifen.h"
+
+#define DEBUG 1
+
+int file_get_contents(FILE *stream, byte_t **content) {
+ /**
+ * Kleine Behelfsfunktion, die den stream (z.B. stdin, eine Datei) als Bytes
+ * komplett einliest.
+ * Erwartet: Stream, Zeiger auf Zeiger (für Array)
+ * Gibt zurück: Return-value: Laenge von content, rechnend ab 1
+ * Call-by-reference: Content wird alloziiert als Array mit Inhalt
+ *
+ * Erzeugt seltsamerweise manchmal komische Fehler,
+ * g_file_get_contents von Glib funktioniert zuverlaessiger.
+ **/
+ // das war meine Version, bevor ich mir alles von g_file_get_contents
+ // abgeschaut habe. Einen Fehler hab ich zumindest gerade entdeckt:
+ // realloc gibt ggf. einen neuen Pointer zurück. Das würde erklären, warum auch
+ // das ganze *mal* ging und *mal* nicht. Offensichtlich kopiert realloc dann auch
+ // die Daten, wenn es entscheidet, sie woanders auf dem heap abzusieldeln...
+ /*
+ // um wie viel Zeichen das dynamische Array jeweils erhoeht werden soll
+ // ein Kompromiss zwischen Platzverschwendung (zuviel allokatierter aber ungenutzter
+ // Speicher) und Perfomance beim Einlesen (zu oft das Array erweitern)
+ #define FILE_GET_CONTENT_STEPSIZE 20
+
+ int length;
+ int extended = 1; // wie oft bereits erweitert
+ *content = (byte_t*) malloc(sizeof(byte_t) * FILE_GET_CONTENT_STEPSIZE);
+ if(*content == NULL) return 0; // schlecht.
+
+ for(length=0;;) {
+ (*content)[length] = (byte_t)fgetc(stream);
+ if(feof(stream) != 0) break; // EOF vor dem Einlesen!
+ printf("%03d. Zeichen eingelesen: 0x%02X (=%c)\n", length+1, (*content)[length], (*content)[length]);
+ if(extended*FILE_GET_CONTENT_STEPSIZE == ++length) {// Speicherende erreicht?
+ printf("=> Bereits %d mal den %d-Puffer verwendet, erweitere auf %d...\n", extended, FILE_GET_CONTENT_STEPSIZE, (extended+1)*FILE_GET_CONTENT_STEPSIZE);
+ if(realloc(*content, sizeof(byte_t)*(++extended)*FILE_GET_CONTENT_STEPSIZE) == NULL) // Speicher vergroessern
+ return length; // Fehler - das eingelesene zumindest zurueckgeben.
+ }
+ }
+
+ return length; // wir wollen ab 1 zaehlen, das wurde indirekt durch den letzten unnoetigen ++inkrement gemacht
+ }
+ int file_get_contents(FILE *stream, byte_t **content) {
+ */
+ /**
+ * Neugeschrieben nach etwas Inspiration von der glib am 05.04.2008.
+ * Funktion get_contents_stdio, gfileutils.c im Sourcecode von glib-2.14.3.
+ * Router natürlich aus (03:11!), aber da sieht man mal wieder den Vorteil von Gentoo:
+ * Gleich alle Sourcecodes auf der Platte =)
+ *
+ *
+ *
+ **/
+ // *stream = *f
+ // *content = **contents
+ // gsize *length
+
+ char buf[4096];
+ size_t bytes; // gerade eben eingelesene bytes
+ char *str = NULL;
+ size_t total_bytes = 0; // alle bis jetzt eingelesenen bytes
+ size_t total_allocated = 0;
+ char *tmp; // fuers realloc
+
+ while(!feof(stream)) {
+ bytes = fread(buf, 1, sizeof(buf), stream);
+
+ while( (total_bytes + bytes) > total_allocated) {
+ if(str)
+ total_allocated *= 2;
+ else
+ total_allocated = bytes > sizeof(buf) ? bytes : sizeof(buf);
+
+ tmp = realloc(str, total_allocated);
+
+ if(tmp == NULL) {
+ fprintf(stderr, "*** file_get_contents ERROR*** Could not reallocate\n");
+ //return length; // Fehler - das eingelesene zumindest zurueckgeben.
+ // nee, gar nichts zurückgeben. Das geht so nicht.
+ return 0;
+ }
+
+ str = tmp;
+ } // while innen
+
+ memcpy(str + total_bytes, buf, bytes);
+ total_bytes += bytes;
+ } // while
+
+ if(total_allocated == 0)
+ str = malloc(1); // ein leerer String halt.
+
+ //str[total_bytes] = '\0'; // wenns ein string wäre.
+
+ *content = str;
+
+ return total_bytes;
+}
+
+void lochstreifen_set_color(cairo_pattern_t *color, byte_t red, byte_t green, byte_t blue, byte_t alpha) {
+ /** Kleine Befehlsfunktion, die ein Cairopattern erzeugt. Farbwerte zwischen 0 und 255.
+ alpha = 255 ist unnoetig => einfach das Patternobjekt auf NULL setzen und die Zeichenfunktion
+ wird es nicht zeichnen. */
+ color = cairo_pattern_create_rgba(red/255, green/255, blue/255, alpha/255);
+}
+
+
+LOCHSTREIFEN *lochstreifen_new() {
+ /** Neues Lochstreifenobjekt erzeugen */
+ LOCHSTREIFEN *l = malloc(sizeof(LOCHSTREIFEN));
+ // Defaultwerte setzen:
+ l->d = 10;
+ l->data_length = 0;
+ l->debug = 0;
+ l->hintergrund = NULL; // nicht zeichnen
+ l->streifenbg = cairo_pattern_create_rgb(0.7,0.7,0.7);
+ l->punched = cairo_pattern_create_rgb(0,0,0);
+ l->notpunched = cairo_pattern_create_rgb(0.827, 0.827, 0.827); //220/255, 220/255, 220/255);
+ l->fuehrung = cairo_pattern_create_rgb(143/255, 175/255, 255/255);
+ //cairo_matrix_init_identity(&(l->transformation));
+ //, 1, 0, 0, 1, 0, 0); // Standardmatrix einrichten (keine Drehung)
+ l->drehung = 0;
+ l->spiegelung_hor = 0;
+ l->spiegelung_ver = 0;
+ lochstreifen_flush_only_start_area(l);
+ return l;
+}
+
+void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data, int empty_start, int empty_end) {
+ /** Zu druckende Daten eingeben, Anzahl gewuenschter Leerbytes vorne/hinten eingeben,
+ ist empty_start/empty_end < 0, wird das entsprechende nicht gesetzt */
+ l->data_length = data_length;
+ if(l->data != NULL) // unbenutzten Speicher freigeben!
+ free(l->data);
+ l->data = data;
+ if(empty_start >= 0) l->empty_start = empty_start;
+ if(empty_end >= 0) l->empty_end = empty_end;
+}
+
+int lochstreifen_set_only_start_area(LOCHSTREIFEN *l, int x, int y, int width, int height) {
+ /** Clipping-Rechteck setzen. Damit wird beim naechsten Zeichnen nur in diesem
+ Bereich gezeichnet. Es handelt sich jedoch um kein exiplites ordentliches
+ cairo_clipping, sondern eine grobe Naehrung zwecks Perfomance.
+ Die Koordinaten beziehen sich auf die entgueltige Form (inkl. Drehung, ...)
+ */
+ l->only_start_x = x;
+ l->only_start_y = y;
+ l->only_width = width;
+ l->only_height = height;
+}
+
+int lochstreifen_flush_only_start_area(LOCHSTREIFEN *l) {
+ /** Clipping-Rechteck loeschen -- beim naechsten Zeichnen alles zeichnen */
+ l->only_start_x = 0;
+ l->only_start_y = 0;
+ l->only_width = 0;
+ l->only_height = 0;
+}
+
+void lochstreifen_set_d(LOCHSTREIFEN *l, int d) {
+ /** Durchmesser eines Loches uebergeben (allgemeine Referenzeinheit fuer Dimensionen) */
+ l->d = d;
+ l->bspace = d*0.7/1.9; // Abstand der Bytes voneinander (Reihen)
+ l->hspace = d/2; // Abstand der Loecher in der Bytereihe
+ l->padding = d; // Abstand Löcher <=> Lochstreifenrand
+ l->df = d/2; // Durchmesser Lochfuehrungsloch
+ l->fspace = 1.1*(d+ l->hspace); // Breite der Lochfuehrungs"nut"
+ l->margin = d*2; // Abstand um Lochstreifen herum (an allen Seiten)
+ l->abriss = (8*d+6* l->hspace + l->fspace)/2; // Länge der Abrisse an Start/Ende (halbe Höhe vom Lochstreifen)
+}
+
+int lochstreifen_get_orientation(LOCHSTREIFEN *l) {
+ /** Gibt die Orientierung des Lochstreifens zurueck; 1 = horizontal, 0 = vertikal */
+ return (l->drehung % 2 == 0) ? 1 : 0;
+}
+
+int lochstreifen_get_width(LOCHSTREIFEN *l) {
+ /** Berechnet aktuelle Breite aus Lochstreifenkonstanten */
+ // interne Ersetzungen...
+ #define LOCHSTREIFEN_WIDTH 2*l->abriss + 2*l->margin + \
+ (l->data_length + l->empty_start + l->empty_end) * (l->d + l->bspace) - l->bspace // ein bspace zuviel am Ende
+ #define LOCHSTREIFEN_HEIGHT 8*l->d + 6*l->hspace + l->fspace + l->margin*2 + l->padding*2 \
+ // ^ weil letztes hspace + hspace über fspace unnötig
+ return (l->drehung % 2 == 0) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
+}
+
+int lochstreifen_get_height(LOCHSTREIFEN *l) {
+ /** Berechnet aktuelle Hoehe aus Lochstreifenkonstanten */
+ return (l->drehung % 2 == 1) ? LOCHSTREIFEN_WIDTH : LOCHSTREIFEN_HEIGHT;
+}
+
+void lochstreifen_set_d_by_width(LOCHSTREIFEN *l, int width) {
+ /**
+ * Umkehrfunktion zu set_d (dort wird die Breite/Hoehe durch d berechnet),
+ * hier wird d durch die vorgegebene Breite berechnet. Die Hoehe ergibt
+ * sich dann natuerlich auch automatisch.
+ * Evventuelle Drehungen werden miteinberechnet, d.h. wenn der Lochstreifen
+ * z.B. nach oben/unten zeigt, bezieht sich width auf die "echte" Hoehe.
+ **/
+ // Gleichung zum Berechnen von LOCHSTREIFEN_WIDTH nach
+ // d aufgeloest mit MuPad Pro 3.2 ( ;-) )
+ #define LOCHSTREIFEN_INV_WIDTH (double) (1 / (6187./380. + 26./19. * (double)(l->data_length + l->empty_start + l->empty_end)))
+ #define LOCHSTREIFEN_INV_HEIGHT (double) (1 * 20./373.)
+ lochstreifen_set_d(l,
+ (int)rint((double)width * ((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
+ );
+ //printf("Width soll %d ==> %d | %d\n", width, lochstreifen_get_width(l), lochstreifen_get_height(l));
+}
+
+void lochstreifen_set_d_by_height(LOCHSTREIFEN *l, int height) {
+ /**
+ * Siehe set_d_by_width, nur wird hier d abhaengig von der gewuenschten Hoehe
+ * berechnet.
+ **/
+ lochstreifen_set_d(l,
+ (int)rint((double) height * LOCHSTREIFEN_INV_HEIGHT) //((l->drehung % 2 == 0) ? LOCHSTREIFEN_INV_WIDTH : LOCHSTREIFEN_INV_HEIGHT))
+ );
+ //printf("Height soll %03d ==> d=%02d | %f, w/h = %03d | %03d\n", height, l->d,
+ // (double)height*LOCHSTREIFEN_INV_HEIGHT
+ // , lochstreifen_get_width(l), lochstreifen_get_height(l));
+}
+
+void lochstreifen_set_direction(LOCHSTREIFEN *l, int drehung, int spiegelung_hor, int spiegelung_ver) {
+ /**
+ * Transformationen der Lochstreifenausrichtung
+ * drehung: 0 = Kopf nach links
+ * 1 = oben
+ * 2 = rechts
+ * 3 = unten
+ * -1 = nicht aendern
+ * 4 = um 90° im Uhrzeigersinn drehen
+ * 5 = um 90° gegen Uhrzeigersinn drehen
+ * Spiegelung horizontal/vertikal: 0 = nein
+ * 1 = ja
+ * 2 = vertauschen
+ * -1 = nicht aendern
+ **/
+ if(drehung >= 0) {
+ // Das "Ausprobieren" zwecks "Autodrehung" mit Aufruf wie
+ // lochstreifen_set_direction(l, l->drehung++, -1, -1);
+ //if(drehung > 4) drehung -= 4; // bei zu grossen Werten mal ausprobieren
+ //if(drehung < 0) drehung += 4; // bei zu kleinen Werten mal ausprobieren
+ //if(drehung % 4 == 0) drehung = 0; // quasi keine Drehung
+ if(drehung >= 4) {
+ if(drehung == 4) l->drehung++;
+ else if(drehung == 5) l->drehung--;
+ if(l->drehung >= 4) l->drehung -= 4; // bei zu grossen Werten
+ if(l->drehung < 0) l->drehung += 4; // bei zu kleinen Werten
+ } else {
+ //if(drehung > 0 && drehung < 4) // gute Werte
+ // normale Drehung mit festem Zielwert
+ l->drehung = drehung;
+ }
+ }
+ if(spiegelung_hor > -1) {
+ if(spiegelung_hor == 2) l->spiegelung_hor = l->spiegelung_hor == 0 ? 1 : 0; // negotieren
+ else l->spiegelung_hor = spiegelung_hor; // normal
+ }
+ if(spiegelung_ver > -1) {
+ if(spiegelung_ver == 2) l->spiegelung_ver = l->spiegelung_ver == 0 ? 1 : 0; // negotieren
+ else l->spiegelung_ver = spiegelung_ver; // normal
+ }
+}
+
+/*
+void lochstreifen_rotate(LOCHSTREIFEN *l) {
+ **
+ * Wird den Lochstreifen beim naechsten Zeichnen um 45° mit dem
+ * Uhrzeigersinn rotiert anzeigen. Nur mit diesen Funktionen wird
+ * die Hoehen/Breitenberechnung im Vorhinein noch funktionieren!
+ **
+ cairo_matrix_rotate(&(l->transformation), M_PI);
+ cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0),
+ l->drehung++; // ...
+}
+
+void lochstreifen_spiegel(LOCHSTREIFEN *l, byte_t horizontal) {
+ **
+ * Spiegelt den Lochstreifen, ist horizontal = 1 dann horizontal,
+ * sonst vertikal (oder so aehnlich)
+ **
+ if(horizontal != 0) { // vertikal
+ cairo_matrix_scale(&(l->transformation), -1, 1);
+ cairo_matrix_translate((&l->transformation), 0, lochstreifen_get_height(l));
+ } else {
+ cairo_matrix_scale(&(l->transformation), 1, -1);
+ cairo_matrix_translate((&l->transformation), lochstreifen_get_width(l), 0);
+ }
+}
+*/
+
+int lochstreifen_byte_by_coordinate(LOCHSTREIFEN *l, int x, int y) {
+ /**
+ * Anhand der Koordinaten (x|y) wird der Index des Bytes (fuers Datenarray, ab 1 zaehlend),
+ * welches damit "erfasst" wird, zurueckgegeben.
+ * Befindet sich (x|y) nicht im Bereich eines Bytes, dann wird je nach Fall zurueckgegeben:
+ * 0 = ausserhalb Lochstreifens
+ * -1 = in Emptystart/Emptyend-Bytes (die nicht in der Datei existieren)
+ * oder in Abrissbereichen
+ **/
+ int byte;
+ // BETRACHTUNG HORIZONTALE AUSRICHTUNG
+
+ if(y <= l->margin || y >= LOCHSTREIFEN_HEIGHT - l->margin) return 0; // ueber/unter Lochstreifen
+ x -= l->margin; // erst mal Rand abziehen
+ if(x <= 0) return 0; // links neben dem Lochstreifen.
+ x -= l->abriss + (l->empty_start)*(l->d + l->bspace); // Emptystart+Abrissbereich
+ if(x <= 0) return -1; // in diesem Bereich gewesen
+ // jetzt sind wir im Bytebereich
+ byte = (int) (x / (l->d + l->bspace)) + 1; // Abrunden: Auf welchem Byte man ist + ab 1 zaehlen.
+ if(byte > l->data_length + l->empty_start) return 0; // komplett ausserhalb Lochstreifens
+ else if(byte > l->data_length) return -1; // im Emptyendbereich
+ else return byte; // im gueltigen Bereich -- Byte gefunden!
+
+}
+
+void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr) {
+ /**
+ * Den Lochstreifen auf das uebergebene Cairoobjekt zeichnen.
+ * Die Funktion zeichnet nach den aktuellen Lochstreifenobjekt-Angaben
+ * (Groesse/Breite) -- wenn die cairo_image_surface nicht diesen Dimensionen
+ * entspricht, ist das alt schlecht.
+ *
+ **/
+ int byte,loch,x,y; // temp fuer Schleifen
+ int height = lochstreifen_get_height(l);
+ int width = lochstreifen_get_width(l);
+ // 4 Eckpunkte des Zeichenbereichs bestimmen...
+ int x1,x2,y1,y2;
+ x1 = l->only_start_x; y1 = l->only_start_y;
+ x2 = x1 + width; y2 = y1 + height;
+
+ /*int x1,y1,x2,y2,x3,y3,x4,y4;
+ x1 = l->only_start_x; y1 = l->only_start_y;
+ x2 = x1+width; y2 = y1;
+ x3 = x2; y3 = y2+height;
+ x4 = x1; y4 = y3;*/
+
+ // Verschiebungsmatrix erst hier berechnen, weil Verschiebungen vorher unklar
+ // wunderbare affine Abbildungen ;-)
+ cairo_matrix_t matrix, temp; // temp: Temporaere Matrix zur Matrizenmulitiplikation
+ cairo_matrix_init_identity(&matrix);
+ if(l->drehung > 0) {
+ if(l->drehung == 1) {
+ cairo_matrix_init(&temp, 0, -1, 1, 0, 0, height);
+ x = width; width = height; height = x; // Breiten und Hoehen
+ x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
+ } else if(l->drehung == 2) {
+ cairo_matrix_init(&temp, -1, 0, 0, -1, width, height);
+ } else if(l->drehung == 3) {
+ cairo_matrix_init(&temp, 0, 1, -1, 0, width, 0);
+ x = width; width = height; height = x; // Breiten und Hoehen
+ x = l->only_width; l->only_width = l->only_height; l->only_height = x; // gerade vertauschen
+ }
+ cairo_matrix_multiply(&matrix, &matrix, &temp);
+ }
+
+ if(l->spiegelung_hor != 0) {
+ cairo_matrix_init(&temp, -1, 0, 0, 1,
+ l->drehung % 2 == 0 ? width : height, // Default bei Nicht-Drehung: width
+ 0);
+ cairo_matrix_multiply(&matrix, &matrix, &temp);
+ }
+ if(l->spiegelung_ver != 0) {
+ cairo_matrix_init(&temp, 1, 0, 0, -1, 0,
+ l->drehung % 2 == 0 ? height: width); // Default bei Nicht-Drehung: height
+ cairo_matrix_multiply(&matrix, &matrix, &temp);
+ }
+
+ //if(l->drehung > 0) {
+ /*cairo_matrix_rotate(&matrix, l->drehung/2 *M_PI);
+ if(l->drehung == 1) { // 90°, im III. Sektor
+ //x = width; width = height; height = x;
+ //cairo_matrix_translate(&matrix, 0, 0);
+ } else if(l->drehung == 2) { // 180°, im IV Sektor
+ cairo_matrix_translate(&matrix, width, height);
+ } else if(l->drehung == 3) { // 270°, im I. Sektor
+ //x = width; width = height; height = x;
+ cairo_matrix_translate(&matrix, width, height);
+ }*/
+ // 4. Sektor kommt nicht vor
+ //}
+ cairo_set_matrix(cr, &matrix);
+ // -1, 0, 0, 1, width, 0 = spiegelung x-achse
+
+ //cairo_device_to_user(cr, (double*)&(l->only_start_x), (double*)&(l->only_start_y));
+ cairo_device_to_user(cr, (double*)&(x1), (double*)&(y1));
+ cairo_device_to_user(cr, (double*)&(x2), (double*)&(y2));
+
+ l->only_start_x = x2 < x1 ? x2 : x1;
+ l->only_start_y = y2 < y1 ? y2 : y1;
+
+ cairo_set_source(cr, l->fuehrung);
+ cairo_rectangle(cr, l->only_start_x, l->only_start_y, l->only_width, l->only_height);
+ //printf("Only: %d|%d, %d * %d\n", l->only_start_x, l->only_start_y, l->only_width, l->only_height);
+ cairo_paint(cr);
+
+ // Hintergrundfarbe zeichnen.
+ if(0||l->hintergrund != NULL) {
+ //l->hintergrund = cairo_pattern_create_rgb(1,1,1);
+ cairo_set_source(cr, l->hintergrund);
+ cairo_paint(cr);
+ }
+
+ // sache zeichnen
+ cairo_set_source(cr, l->streifenbg);
+ cairo_rectangle(cr, -10, -10, width+20, height+20);
+ cairo_stroke(cr);
+ if(0==1){
+ double x,y, a,b;
+ int xx,yy,aa,bb;
+ x=0;y=0; a=width;b=height;
+ cairo_matrix_transform_point(&matrix, &x, &y);
+ cairo_matrix_transform_point(&matrix, &a, &b);
+ xx=(int)x;yy=(int)y;aa=(int)a;bb=(int)b;
+ printf("Punkt (0/0)=(%i|%i) und (%i|%i)=(%i/%i)\n", xx, yy, width, height, aa, bb);
+ }
+
+ // Lochstreifenhintergrund inklusive Abriss vorne/hinten malen
+ if(l->streifenbg != NULL) {
+ cairo_set_source(cr, l->streifenbg);
+
+ // Abriss vorne
+ cairo_move_to(cr, l->margin + l->abriss*0.8, l->margin); // oben rechts
+ cairo_line_to(cr, l->margin, l->margin + l->padding+ 3*l->d + 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
+ cairo_line_to(cr, l->margin + l->abriss, height - l->margin); // unten ganz rechts
+ cairo_line_to(cr, l->margin + l->abriss, l->margin); // nach oben ganz rechts...
+ cairo_close_path(cr); // schliessen
+ // normaler Bereich
+ cairo_rectangle(cr, l->margin + l->abriss, l->margin,
+ width - 2*l->margin - 2*l->abriss, height - 2*l->margin);
+ /*printf("Zeichne Rechteck x|y = (%d|%d) width*height = %d * %d\n",
+ l->margin + l->abriss, l->margin,
+ width - 2*l->margin - 2*l->abriss, height - 2*l->margin
+ );*/
+ // Abriss hinten...
+ cairo_move_to(cr, width - l->margin - l->abriss*0.2, l->margin); // oben mitte
+ cairo_line_to(cr, width - l->margin - l->abriss,
+ l->margin + l->padding + 3*l->d+ 2*l->hspace + l->fspace/2); // genau die fspace-Mitte
+ cairo_line_to(cr, width - l->margin, height - l->margin); // unten ganz rechts
+ cairo_line_to(cr, width - l->margin - l->abriss, height - l->margin); // unten ganz links
+ cairo_line_to(cr, width - l->margin - l->abriss, l->margin); // nach oben zum schliessen
+ cairo_close_path(cr);
+
+ cairo_fill(cr);
+ }
+
+
+ // Lochstreifenlöcher malen
+
+ /*if(l->only_start_x > 0) {
+ // nur in bestimmten Bereich zeichnen
+ int start_byte = l->empty_start + lochstreifen_byte_by_coordinate(l, l->only_start_x, l->only_start_y); // absolut inkl. empty bytes
+
+ } else byte = -l->empty_start; // leere Bytes vorne eingeschlossen
+ }*/
+
+ // Bytes durchgehen, leere Bytes vorne/hinten mit eingeschlossen
+ for(byte = -l->empty_start, x=l->margin + l->abriss; byte < l->data_length + l->empty_end; x += l->d + l->bspace, byte++) {
+ // Clipping: Um unnoetiges Zeichnen zu ersparen, erst ab X-Koordinate zeichnen
+ if(x < l->only_start_x - (l->d + l->bspace)) continue; // - 1x Loch weniger, damit nicht ein gerade abgeschnittenes nichtgezeichnet wird
+ // und nur bis zur rechten Begrenzung zeichnen -- dannach genuegt Abbruch.
+ if(l->only_width != 0 && x > l->only_start_x + l->only_width) break;
+
+ // Bits des entsprechenden Bytes durchgehen
+ for(loch=0, y = l->margin + l->padding; loch < 8; y += l->d + l->hspace, loch++) {
+ // Clipping: Erst ab Y-Koordinate zeichnen (-1xLoch-Korrektur gegen Abschnitt)
+ if(y < l->only_start_y - (l->d - l->hspace)) continue;
+ // bis zur unteren Begrenzung -- anschliessend Abbruch
+ if(l->only_height != 0 && y > l->only_start_y + l->only_height) break;
+
+ // Ggf. Lochstreifenfuehrung zeichnen
+ if(loch==3 && l->fuehrung != NULL) {
+ // Nur vor dem 3. Loch (wenn ueberhaupt)
+ y -= l->hspace; // den Abstand vom vorherigen Loch wieder wegnehmen
+ cairo_set_source(cr, l->fuehrung);
+ cairo_arc(cr, x+l->d/2, y+l->fspace/2, l->df/2, 0., 2*M_PI);
+ cairo_fill(cr);
+ y += l->fspace;
+ } else if(loch == 3) // 3. Loch, aber keine Fuehrung zeichnen => Platz freilassen!
+ y += l->fspace - l->hspace;
+
+ // Debugausgaben machen?
+ if(l->debug != 0 && byte >= 0 && byte < l->data_length) {
+ if(loch == 0) printf("byte %3i von %3i: 0x%2x = ", byte, l->data_length, l->data[byte]);
+ fprintf(stderr, "%c", (((l->data[byte] >> loch) & 0x01) == 0x01) ? '#' : ' ');
+ if(loch == 7) printf("\n");
+ }
+
+ if((byte < 0 || byte >= l->data_length) || // wenn ein Nullbyte gezeichnet wird
+ (((l->data[byte] >> loch) & 0x01) != 0x01) // oder das Bit an der Stelle nicht gesetzt ist
+ ) { // ist es not-Punched
+ if(l->notpunched != NULL) { // notpunched zeichnen? (muss subif sein)
+ cairo_set_source(cr, l->notpunched);
+ cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
+ cairo_fill(cr);
+ }
+ } else if(l->punched != NULL) { // es ist Punched. Zeichnen?
+ cairo_set_source(cr, l->punched);
+ cairo_arc(cr, x+l->d/2, y+l->d/2, l->d/2, 0., 2*M_PI);
+ cairo_fill(cr);
+ }
+ // Die Routine wegen dem Zeichnen?-Ding hervorgehoben.
+ /*cairo_set_source(cr,
+ (byte < 0 || byte >= data_length) || // wenn ein Nullbyte gezeichnet wird
+ (((data[byte] >> loch) & 0x01) != 0x01) ? // oder das Bit an der Stelle nicht gesetzt ist
+ notpunched : punched); // dann dies farbig kennzeichnen
+ cairo_arc(cr, x+d/2, y+d/2, d/2, 0., 2*M_PI);
+ cairo_fill(cr);*/
+
+ // y+= war hier.
+ } // for bits (loecher)
+ // x += war hier.
+ } // for bytes
+
+ // Lochstreifenfuehrung im vorderen Abriss malen
+ if(l->fuehrung != NULL) {
+ cairo_set_source(cr, l->fuehrung);
+ y = l->margin + l->padding + 3*l->d + 2*l->hspace + l->fspace/2; // fspace-Mitte
+ x = l->margin + l->abriss - l->d - l->bspace; // Start-x
+ for(; x > l->margin;) {
+ cairo_arc(cr, x + l->d/2, y, l->df/2, 0., 2*M_PI);
+ x -= l->d + l->bspace;
+ }
+ cairo_fill(cr);
+ }
+
+ // fertig mit dem Lochstreifenzeichnen.
+} // function draw_lochstreifen
Index: /visualisator/lochstreifen.h
===================================================================
--- /visualisator/lochstreifen.h (revision 1)
+++ /visualisator/lochstreifen.h (revision 1)
@@ -0,0 +1,77 @@
+/*
+** Allgemeine Headerfile fuer das
+** Lochstreifen-Visualisieren-Projekt
+*/
+#include // cairo_t unten
+
+#define byte_t unsigned char
+#define LOCHSTREIFEN struct lochstreifen
+
+// Die Lochstreifenstruktur, die alle relevanten Daten enthaelt
+struct lochstreifen {
+ /* Daten, die der Lochstreifen enthaelt: */
+ int data_length; // Länge des Datenarrays, rechnend ab 1 (wie argc)
+ byte_t *data; // Datenarray
+
+ int empty_start; // wie viele 0bytes vorne
+ int empty_end; // wie viele 0bytes hinten
+
+ /* Konstanten zum Aussehen des Lochstreifens
+ Referenzeinheit ist d, daraus wird alles berechnet,
+ siehe lochstreifen_set_d
+ */
+ int d; // Durchmesser eines Loches
+ int bspace; // Abstand der Bytes voneinander (Reihen)
+ int hspace; // Abstand der Loecher in der Bytereihe
+ int padding; // Abstand Löcher <=> Lochstreifenrand
+ int df; // Durchmesser Lochfuehrungsloch
+ int fspace; // Breite der Lochfuehrungs"nut"
+ int margin; // Abstand um Lochstreifen herum (an allen Seiten)
+ int abriss; // Länge der Abrisse an Start/Ende (halbe Höhe vom Lochstreifen)
+
+ /* Farben, in denen der Lochstreifen gehalten ist */
+ cairo_pattern_t *hintergrund, *streifenbg, *punched, *notpunched, *fuehrung;
+ // Farben um Lochstreifen, Lochstreifen, Loecher, Nicht-Loecher, Fuehrung
+ // siehe zum Setzen: lochstreifen_set_color oder per Cairo-Funktion fuer
+ // komplexere Loesungen. Bei NULL wird die Komponente nicht gezeichnet!
+
+ /* Drehungen und co, nicht direkt veraendern, sonst stimmt die vorberechnete
+ Hoehe/Breite nicht mehr mit den realen Werten ueberein. */
+ //cairo_matrix_t transformation;
+ // Das folgende koennte man natuerlich effizienter Speichern, aber egal.
+ int drehung; // 0-3, jeweils 45°-Schritte im Uhrzeigersinn
+ int spiegelung_hor; // horizontale Spiegelung != 0 == ja
+ int spiegelung_ver; // vertikale Spiegelung != 0 == ja
+
+ /* Nur bestimmte rechteckige Bereiche zeichnen -- dies wird massgeblich vom
+ GTK-Interface benutzt */
+ int only_start_x; // Die angegebenen Punkte
+ int only_start_y; // spannen ein Rechteck auf. In grober
+ int only_width; // Naeherung wird nur in diesem Bereich
+ int only_height; // gezeichnet.
+
+ /* Debugausgaben machen => wenn debug != 0 ist! */
+ byte_t debug;
+};
+
+/* lochstreifen.c */
+// allgemeine Zusatzfunktion, kein Bezug
+int file_get_contents(FILE *stream, byte_t **content);
+
+// Lochstreifenfunktionen, siehe Dokumentation in c-File
+LOCHSTREIFEN *lochstreifen_new();
+void lochstreifen_set_data(LOCHSTREIFEN *l, int data_length, byte_t *data, int empty_start, int empty_end);
+void lochstreifen_set_d(LOCHSTREIFEN *l, int d);
+void lochstreifen_set_d_by_width(LOCHSTREIFEN *l, int width);
+void lochstreifen_set_d_by_height(LOCHSTREIFEN *l, int height);
+int lochstreifen_get_width(LOCHSTREIFEN *l);
+int lochstreifen_get_height(LOCHSTREIFEN *l);
+int lochstreifen_set_draw_only_area(LOCHSTREIFEN *l, int x, int y, int width, int height);
+int lochstreifen_flush_draw_only_area(LOCHSTREIFEN *l);
+void lochstreifen_set_color(cairo_pattern_t *color, byte_t red, byte_t green, byte_t blue, byte_t alpha);
+//void lochstreifen_rotate(LOCHSTREIFEN *l);
+//void lochstreifen_spiegel(LOCHSTREIFEN *l, byte_t horizontal);
+void lochstreifen_set_direction(LOCHSTREIFEN *l, int drehung, int spiegelung_hor, int spiegelung_ver);
+void lochstreifen_draw(LOCHSTREIFEN *l, cairo_t *cr);
+int lochstreifen_get_orientation(LOCHSTREIFEN *l);
+int lochstreifen_byte_by_coordinate(LOCHSTREIFEN *l, int x, int y);
Index: /web-frontend/design/ausrichtung-vorlage.svg
===================================================================
--- /web-frontend/design/ausrichtung-vorlage.svg (revision 1)
+++ /web-frontend/design/ausrichtung-vorlage.svg (revision 1)
@@ -0,0 +1,744 @@
+
+
+
Index: /web-frontend/design/formular.css
===================================================================
--- /web-frontend/design/formular.css (revision 1)
+++ /web-frontend/design/formular.css (revision 1)
@@ -0,0 +1,142 @@
+/* Ergaenzungsstyle fuer das komplexe Formular,
+ nutzt ansonsten private.design */
+
+.clear {
+ clear: both;
+ height: 1px;
+ overflow: hidden;
+}
+
+fieldset {
+ margin: 2em 0;
+ border: 4px solid #E7E7E7;
+ border-bottom: none;
+ padding: 0;
+
+ background-image: url(http://privat.technikum29.de/src/private.design/body.bg.png);
+ background-repeat: repeat-x;
+ background-position: bottom left;
+}
+
+fieldset .abstract {
+ /* Die Kurzzusammenfassung nur zusammengeklappt anzeigen */
+ display: none;
+}
+
+fieldset.shown h3 {
+ display: block;
+ border-bottom: 4px solid #E7E7E7;
+ padding: 8px;
+
+ font-weight: bold;
+ font-size: 130%;
+ margin: 0;
+ background-color: #E7E7E7;
+}
+
+fieldset .content {
+ margin: 30px;
+}
+
+.box {
+ margin: 15px 0;
+ padding: 10px;
+ border: 1px solid #aaa;
+ background-color: #fff;
+}
+
+table.box {
+ border: none;
+ background: none;
+
+ border-spacing: 10px;
+}
+
+table.box td {
+ border: 1px solid #aaa;
+ background-color: #fff;
+ vertical-align: center;
+ text-align: center;
+ padding: 10px;
+}
+
+/* Ein/Ausklappeffekt, durch JS eingeleitet */
+
+fieldset.hidden {
+ border: none;
+ background: transparent;
+ margin: 0.1em 0;
+ padding: 0;
+ border-bottom: 4px solid #e7e7e7;
+ cursor: pointer;
+}
+
+fieldset.hidden:hover {
+ background-color: yellow;
+ border-color: blue;
+}
+
+fieldset.hidden .content {
+ display: none;
+}
+
+fieldset.hidden h3 {
+ display: inline;
+ float: left;
+ margin: 0;
+ font-size: 100%;
+ font-weight: bold;
+ text-align: right;
+ width: 30%;
+ padding-right: 1.4em;
+ border: none;
+}
+
+fieldset.hidden .abstract {
+ display: inline;
+}
+
+#ausklapp-info p {
+ clear: both;
+ text-align: center;
+}
+
+/* Formularelemente */
+textarea {
+ width: 100%;
+}
+
+.color-tester {
+ /* armes Opferelement, welches die eingegebenen Farben anzeigen darf. */
+ width: 5em;
+ border: 1px solid black;
+ display: inline;
+ margin-left: 1em;
+ padding: 0 3em;
+}
+
+input.submit {
+ padding: 10px;
+ font-weight: bold;
+ background-color: yellow;
+}
+
+
+/* Und noch auf der ausgebenden Seite */
+.big-error, .big-warning, .big-okay {
+ padding: 2em;
+ margin: 1em 0;
+ font-weight: bold;
+ background-color: #FFD3D3;
+ border: 1.3em solid #f00;
+}
+
+.big-warning {
+ border: 1.3em solid #fd0;
+ background-color: #FFF5B4;
+}
+
+.big-okay {
+ border: 1.3em solid #15FF00;
+ background-color: #ACFFAD;
+}
Index: /web-frontend/design/formular.js
===================================================================
--- /web-frontend/design/formular.js (revision 1)
+++ /web-frontend/design/formular.js (revision 1)
@@ -0,0 +1,86 @@
+var oldaction; // alte action von form, bevor ajaxifiziert
+
+function init() {
+ // beim Laden der Seite Fieldsets verstecken
+ var f = document.getElementsByTagName("fieldset");
+ for(var x=0; x < f.length; x++) {
+ if(f[x].className == "initially-hidden") {
+ f[x].className = "hidden";
+ f[x].onclick = function() { this.className = "shown"; };
+ }
+ }
+
+ /// außerdem Formularelemente ausgrauen
+ // checked: data-src-file
+ en('data-file');dis('data-form data-input data-text');
+ // checked: dimension-src-diameter
+ en('dimension-diameter');dis('dimension-width dimension-height')
+ // Farbfelder:
+ var k = new Array('imagebg', 'tapebg', 'punched', 'notpunched', 'feedholes');
+ for(var x=0; x < k.length; x++) {
+ color(document.forms[0].elements['color-'+k[x]], 'color-'+k[x]);
+ }
+
+ // und das AJAX-Zeug laden:
+ // 1. Formular abändern
+ oldaction = document.forms[0].getAttribute("action");
+ document.forms[0].setAttribute("action", oldaction+"?ajax");
+
+ // 2. Submit abänder
+ var button = document.getElementById("submit-button");
+ button.setAttribute("type", "button");
+ button.setAttribute("onclick", "new POST().submitForm(document.forms[0], getHttpRes);");
+
+ // 3. und dieses Teleport-Teil starten
+ Init.run('BODY');
+}
+
+function en(names) {
+ /* enables name */
+ var n = names.split(" ");
+ for(var x=0; x < n.length; x++) {
+ document.forms[0].elements[n[x]].removeAttribute("disabled");
+ }
+}
+
+function dis(names) {
+ /* disable names */
+ var n = names.split(" ");
+ for(var x=0; x < n.length; x++) {
+ document.forms[0].elements[n[x]].setAttribute("disabled", "disabled");
+ }
+}
+
+function color(e, id) {
+ /* colorizes testfield */
+ document.getElementById(id+"-field").style.backgroundColor = e.value;
+}
+
+
+function getHttpRes(msg, state, extra){
+ // Ajax-Antwort kriegen, mit diesem Teleport-Teil
+ if(state != __RPC_SUCCESS__) return alert("Konnte nicht zu Server verbinden!");
+
+ // nachricht checken:
+ if(msg == "ok") {
+ // weitermachen. Formular abschicken!
+ document.getElementById('ajax-output').innerHTML = "
Alle Eingaben richtig, Lochstreifen wird erstellt...
";
+ // Formular wieder auf alte Zieladresse setzen (GET?ajax weg)
+ document.forms[0].setAttribute("action", oldaction);
+ // damit das Button seine FUnktion wieder hat, falls jemand zurückgeht
+ document.getElementById("submit-button").setAttribute("type", "submit");
+ // und damit nicht vor dem submit dummerweise die Ergebnisseite von dem Ajaxding
+ // geladen wird, was zur Folge hat, dass das Bild doppelt generiert würde
+ // keine Ahung ob das was bringt...
+ document.getElementById("submit-button").removeAttribute("onclick");
+ document.forms[0].submit();
+ } else {
+ var forword = "
Es sind Fehler in den Eingaben aufgetreten, daher kann der Lochstreifen noch nicht erstellt werden. Bitte berichtigen sie diese Fehler und klicken sie dann nochmals auf \"Lochstreifen generieren\"
';
+ }
+ exit;
+}
+
+// Schritt 1: Eingaben entgegennehmen und validieren
+
+// 1/6: Punch-Daten
+$input_source = get('data-src');
+switch($input_source) {
+ case 'file': // Dateiupload. Tja. Datei direkt dem Programm übergeben. Vorher
+ // Größe checken. Also mal los:
+ if($ajax) {
+ // wenn Ajax benutzt wird, wird die Datei noch nicht hochgeladen.
+ break; // also erst anschließend machbar.
+ }
+ if(!isset($_FILES['data-file'])) {
+ $errors[] = "Keine Datei hochgeladen, obwohl Dateiupload als Datenquelle ausgewählt war!";
+ } elseif($_FILES['data-file']['size'] > 500*1024) {
+ $errors[] = "Die hochgeladene Datei ist größer als ein 500kb. Derart große
+ Lochstreifen sind aus Perfomancegründen nicht erlaubt. Laden sie
+ sich das Visualisierungsprogramm runter und erstellen sie lokal
+ ihre Mammutlochstreifen.";
+ } elseif($_FILES['data-file']['size'] == 0) {
+ $warnings[] = "Die hochgeladene Datei ist leer (0 Bytes Inhalt). Das gibt keinen sonderlich
+ spannenden Lochstreifen...";
+ }
+ $original_filename = $_FILES['data-file']['name']; // fuer den Report weiter unten
+ $input_filename = $_FILES['data-file']['tmp_name'];
+ // usw.
+ break;
+ case 'input': // Daten direkt eingetippt. Na dann...
+ $text = get('data-input');
+ $form = get('data-form');
+ $input_binary = 'abc';
+ $parts = preg_split("/\s+|\n+/", $text);
+ foreach($parts as $x => $byte) {
+ if(!strlen($byte)) continue; // nur whitespace, Abfall durch das preg_split.
+
+ // Alle Formen zu dezimal umwandeln.
+ if($form == 'bin')
+ $byte = bindec($byte);
+ elseif($form == 'hex')
+ $byte = hexdec($byte);
+ elseif($form == 'oct')
+ $byte = octdec($byte);
+ elseif($form == 'hex0')
+ $byte = hexdec(substr($byte,2)); // 0x wegschneiden.
+ elseif($form != 'dec') {
+ $errors[] = "Fehler: Ungültige Datenform $form!";
+ break;
+ }
+
+ if(!is_numeric($byte)) {
+ $errors[] = "Fehler: Byte $x mit dem Wert $byte ist keine entsprechende
+ Zahl des Types $form. Vielleicht haben sie nicht das
+ passende Format eingestellt, in dem sie ihre Daten eingegeben haben?";
+ break;
+ }
+
+ $input_binary .= chr($byte); // <- the PHP way | the Perl way -> pack('C', $byte);
+ } // foreach
+ if(strlen($input_binary) > 1024*1024) {
+ $errors[] = 'Sie haben über eine Millionen Bytes eingetippt! Derart große
+ Lochstreifen sind aus Perfomancegründen nicht erlaubt. Laden sie
+ sich das Visualisieurngsprogramm runter und erstellen sie ihren
+ Monsterstreifen lokal.';
+ break;
+ } elseif(strlen($input_binary) == 0) {
+ $errors[] = 'Sie haben keine Daten eingegeben, obwohl direkte Byteeingabe als
+ Datenquelle ausgewählt wurde!';
+ break;
+ }
+ // so, jetzt liegts als $input_binary vor.
+ break;
+ case 'font': // Text, der gepuncht werden soll
+ $text = get('data-text');
+ if(!preg_match('/^[a-zA-Z0-9 ]+$/', $text)) {
+ $warnings[] = 'Im Text befinden sich nichtdruckbare Zeichen. Nur Buchstaben und Zahlen
+ können dargestellt werden, keine anderen Zeichen.';
+ }
+ if(strlen($text) == 0) {
+ $errors[] = 'Sie haben keinen Text eingegeben, obwohl Textgenerierung als Datenquelle
+ ausgewählt wurde!';
+ }
+ if(strlen($text) > 1000) {
+ $errors[] = 'Der Text ist mit über 1000 Zeichen eindeutig zu lang.
+ Aus Perfomancegründen ist das nicht erlaubt. Laden sie sich die
+ entsprechenden Programme runter und erstellen sie ihren Streifen lokal.';
+ }
+ // irgendwas mit dem Text machen.
+ // und als $input_binary fertig machen.
+ $input_binary = 'abc';
+ break;
+ default: $errors[] = "Ungültige Datenquelle! Es konnten keine Daten entgegengenommen werden!";
+}
+
+// 2/6: Formatfragen.
+$format = strtolower(get('format'));
+if($format != 'png' && $format != 'svg') {
+ $errors[] = "Ungültiges Ausgabeformat $format! Erlaubt sind nur PNG und SVG!";
+}
+
+// 3/6: Dimensionen
+$dsrc = get('dimension-src');
+if($dsrc == 'width' || $dsrc == 'height' || $dsrc == 'diameter') {
+ $size = get("dimension-$dsrc");
+ if(!my_ctype_digit($size)) {
+ $errors[] = "Die Größenangabe zu den Dimensionen, die der Lochstreifen annehmen soll,
+ ist fehlerhaft: $size ist keine positive ganze Dezimazahl!";
+ } elseif($dsrc == 'diameter' && $size > 100) {
+ $errors[] = "Der Durchmesser eines Loches ist mit 100 pxieln zu groß, ein so großes Bild
+ darf aus Perfomancegründen nicht generiert werden. Bitte kleineren Wert
+ einstellen.";
+ } elseif($size > 1000*100) {
+ $errors[] = "Die Größenangabe von über 100.000 Pixel ist viel zu groß. Bitte kleineren Wert
+ einstellen.";
+ }
+ // alles klar. $size und $dsrc
+} else
+ $errors[] = "Es wurde keine Größenangabe zum Lochstreifen gemacht!";
+
+
+// 4/6: Ausrichtung des Lochstreifens
+$alignment = get('alignment');
+if(preg_match('/^(hor)-(rtl|ltr)-([ou])$|^(ver)-(btt|ttb)-([lr])$/', $alignment, $m)) {
+ // so, jetzt mal zusammenpuzzeln...
+} else
+ $errors[] = "Ungültige Ausrichtung des Lochstreifens: $alignment war nicht in der Auswahl!";
+
+
+// 5/6: Den ganzen komponentenweiten Kram
+$comp = array('imagebg', 'tapebg', 'punched', 'notpunched', 'feedholes');
+$comp_visibility = array(); $comp_color = array();
+$comp_translation = array('Bildhintergrund', 'Lochstreifen', 'Löcher', 'Nicht-Löcher', 'Führungslöcher');
+
+foreach($comp as $x => $component) {
+ $comp_visibility[$x] = get("show-$component") ? 1 : 0;
+ $color = substr(get("color-$component"), 1); // das "#" wegstrippen
+ $lucency = get("lucency-$component");
+ if(!preg_match('/^[0-9a-fA-F]{6}$/', $color)) {
+ $errors[] = "Die Farbangabe $color für den Komponenten $component ist keine korrekte Hexadezimalfarbangabe.";
+ continue;
+ } elseif(!preg_match('/^[0-9a-fA-F]{2}$/', $lucency)) {
+ $errors[] = "Die Transparenzangabe $lucency für den Komponenten $component ist nicht korrekt.";
+ continue;
+ }
+ $comp_color[$x] = "#${color}${lucency}";
+}
+
+// 6/6: Empty-start, Empty-End
+$empty_start = get('empty-start');
+$empty_end = get('empty-end');
+if(!my_ctype_digit($empty_start))
+ $errors[] = "Die Anzahl leerer Startbytes ist keine positive ganze Zahl ($empty_start)";
+if(!my_ctype_digit($empty_end))
+ $errors[] = "Die Anzahl leerer Endbytes ist keine positive ganze Zahl ($empty_end)";
+
+// fertig.
+
+// Fehler ausgeben und beenden.
+if(!empty($errors)) {
+ exit_errors();
+}
+
+// keine Fehler aufgetreten und in Ajax-Mode: "ok" zurückgeben
+if($ajax) {
+ echo "ok";
+ exit;
+}
+
+// Wenn wir hier sind, gehts schon mal weiter.
+
+echo '
Lochstreifengenerator
';
+
+if(!empty($warnings)) {
+ // es gibt Warnungen...
+ echo '
Es sind Probleme aufgetaucht, die allerdings nicht wirklich schlimm sind, der
+ Lochstreifen wurde trotzdem generiert:
";
+ print "\nReturn Value $return_value\n";
+
+ }
+
+ // checken ob was gemacht wurde.
+ if(!is_file($image_filename)) {
+ print "
Gewünschtes Bild konnte nicht erstellt werden!
";
+ exit; // dann brauchts auch kein Report und so. Der braucht nämlich die Datei.
+ }
+} else
+ print '
Konnte Generatorprozess nicht starten!
';
+
+// + Übersichtsseite machen, erst mal in String, und ausgeben.
+$dir_url = dirname($_SERVER['PHP_SELF']);
+$image_url = "$dir_url/$image_filename";
+$report_file = $output_dir.'/'.$output_hash.'.htm';
+$report_url = "$dir_url/$report_file";
+$filesize = DataSizeFormat(filesize($image_filename));
+
+$report = "
Der folgende Lochstreifen wurde am ".date('m.d.Y')." um ".date('H:i:s')." Uhr von dem
+ Besucher mit der IP-Adresse $_SERVER[REMOTE_ADDR] generiert. Die erstellte Datei vom
+ Typ ".strtoupper($format)." ist $filesize groß";
+
+if($format == 'png') {
+ $imagesize = GetImageSize($image_filename);
+ $report .= ", sie hat die Ausmaße von $imagesize[0] x $imagesize[1] Pixel.
\n";
+ $report .= "
Das Bild wurde gespeichert unter der Adresse $image_url
+ und kann z.B. zur Weiterverwendung runtergeladen werden. Es sieht so aus:
+ ";
+} else {
+ $report .= ".
Das Bild wurde unter der Adresse $image_url gespeichert.
+ Mit einem modernen Browser (Nicht Internet Explorer) können sie sich die SVG-Datei durch
+ Anklicken des Linkes anschauen. Laden sie sich (ansonten) die Datei runter und öffnen sie
+ es mit einem Vektorgrafikprogramm, z.B. mit dem frei erhältlichen Inkscape.
";
+}
+
+// Discmailer ;-)
+$report .= "
Bitte beachten sie: Die Verfügbarkeit des Bildes auf diesem Server gehört nicht in den
+ \"Dienstleistungsumfang\" des Generierungsprogramms. Das heißt, dass sie durch Eingeben ihrer
+ Daten zugestimmt haben, dass diese mit dem Bild nach freiem Ermessen des Administrators gespeichert
+ werden und willkürlich gelöscht werden können. Es besteht kein Anspruch auf selbst zeitlich
+ begrenztes Hosting! Wenn sie das Bild im Internet verfügbar machen wollen, können sie es z.B.
+ auf kostenlosen Bilderhostern hochladen. Suchen sie dazu mit der Suchmaschine ihres Vertrauens
+ nach so etwas wie z.B. \"image hosting\"
";
+
+$report .= "
Die Daten
";
+
+// Daten als HEX aufbereiten
+if($input_source == 'file')
+ $input_binary = file_get_contents($input_filename);
+$report_input_source = array(
+ 'file' => "als eine Datei mit dem Namen $original_filename hochgeladen",
+ 'input' => "$form-kodiert eingetippt",
+ 'font' => "als zu generierende Schrift eingetippt, zugrunde lag der Text $text"
+);
+
+$report .= "
Die Daten, die dem generierten Lochstreifen zugrundeliegen, wurden vom Benutzer
+ $report_input_source[$input_source]. Im folgenden wird ein Hexdump der ".strlen($input_binary)."
+ Bytes angegeben, mit denen letztendlich der Lochstreifen generiert wurde. Mit geeigneten
+ Hilfmitteln (z.B. einem Hexeditor) können sie aus den Daten eine Binärdatei erstellen.";
+
+$report .= "
";
+for($x=0; $x $c) {
+ $report .= "
$comp_translation[$x] ($c): ".
+ ($comp_visibility[$x] ? "sichtbar, und zwar mit der Farbe $comp_color[$x] (Format #RRGGBBAA)"
+ : "nicht sichtbar (deaktiviert)");
+}
+
+$report .= "";
+
+$report .= "
Außerdem wurden $empty_start leere Startbytes und $empty_end leere Endbytes eingestellt.
+ Die eingestellte Rotation des Lochstreifens wird durch das folgende Bild verdeutlicht:
+
+
Die Größe des Lochstreifens wurde von der Dimension $dsrc abhängig gemacht und auf
+ $size eingestellt.
";
+
+$report .= "
Generierung
";
+
+$report .= "
Mit dem Kommandozeilentool führ(t)en folgende Parameter zu der Generierung eines derart
+ gewünschten Lochstreifens:
+ $exec_params
+ Durch Eingabe dieser Parameter mit den oben angezeigten Eingabedaten müsste jederzeit
+ das gleiche Bild reproduzierbar sein.
Das Generieren des Lochstreifens nahm die folgende Zeit in Anspruch:
$stderr
+
Dabei steht real für die wirklich vergangene Zeit, die der Benutzer warten musste,
+ bevor er seinen Lochstreifen bekam, user für die tatsächliche Zeit, die das Programm
+ aktiv war (Abweichungen zu real können dadurch begründet sein, dass der Server noch
+ andere Sachen gleichzeit machte) und system für die Zeit, in der der Server wirklich
+ ernsthaft über den Lochstreifen nachgedacht hat ;-)
";
+
+//// REPORT zuende. Jetzt erst mal ausdrucken.
+
+if(!$verbose) echo "fertig
\n"; // als Antwort auf die "wird nun generiert..."-Ausgaben weit oben.
+echo "
Mit dem generierten Bild wurde eine Urkunde erstellt, in der alle Parameter, Daten und sonstige
+ interessante Dinge festgehalten sind. Es folgt nur dessen Inhalt:
";
+
+echo "
"; // ;)
+echo $report;
+echo "
";
+
+echo "
Diese \"Urkunde\" wurde mit dem Bild zusammen gespeichert. Sie ist unter einer ähnlichen Adresse
+ wie das Bild erreichbar, und zwar unter $report_url.