From: Pekka Riikonen Date: Sat, 2 Feb 2008 18:54:01 +0000 (+0100) Subject: Imported Robodoc. X-Git-Url: http://git.silcnet.org/gitweb/?p=robodoc.git;a=commitdiff_plain;h=813ffbb077c8f96dc1f8cc69d78c78fb807bdad9 Imported Robodoc. --- 813ffbb077c8f96dc1f8cc69d78c78fb807bdad9 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..140e293 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,23 @@ +# vi: ff=unix +Frans Slothouber +Jacco van Weert +Petteri Kettunen +Bernd Koesling +Anthon Pang +Thomas Aglassinger +Stefan Kost +David Druffner +Nathan Prewitt +Sasha Vasko +Dennis Stampfer +Je'rome Laheurte +Janusz Piwowarski +Andreas Signer +Kai Hofmann +Brian P. Hanley +Gian Paolo Ciceri +David White +John P. Rouillard +Jeremy Cowgar +Gergely Budai + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/CVS.adm/MstData.stp b/CVS.adm/MstData.stp new file mode 100644 index 0000000..2572ee1 --- /dev/null +++ b/CVS.adm/MstData.stp @@ -0,0 +1,4 @@ + + + + diff --git a/CVS.adm/UsgData.stp b/CVS.adm/UsgData.stp new file mode 100644 index 0000000..1071ef3 --- /dev/null +++ b/CVS.adm/UsgData.stp @@ -0,0 +1,60 @@ + + + + ff7N€p~†}}upfYiuNPKM]]> + + + DFnvfFI2P<]]> + + + + + + >^0: +MBP21U + + + + + + + + + + + + + + + + + + + + + + + >Nmt]]> + + + + + + + + + + + + + + + + + + diff --git a/CVS.adm/prjprm.stp b/CVS.adm/prjprm.stp new file mode 100644 index 0000000..1b0d3cb --- /dev/null +++ b/CVS.adm/prjprm.stp @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..08de285 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,710 @@ +# vi: spell ff=unix + +Jun 2007 - V4.99.34 + Gergely Budai + added option --header_breaks, which allows ROBODoc to insert line breaks + after every specified number of header names to improve readability. + + Frans Slothouber + o Merged path by Tom Keal that Fixes bug in parsing of the robodoc.rc file. + (The wrong number of items is recorded for the preformatted_items and + format_items block.) + +Apr 2007 - V4.99.32 + o Fixed bug 1706446, --sectionnameonly and --rtf format problem + o Fixed bug 1679101, "robodoc crashed on a faulty header". + o Added the option --no_subdirectories. + o output mode pipes at the end of an item don't result in broken + formatting anymore. + o Items that start with non-ascii characters are now recognized. + o makefile.plain works again + o the item names in the 'item order', 'ignore items', and other items blocks + in the robodoc.rc file are checked against the list of allowed item names. + o the options --sections and --toc do no longer lead + to an assert() with --ascii + o Added item sorting. The order in which items are to + appear in the documentation can be specified in the + robodoc.rc file. + +Feb 2007 - V4.99.30 + Frans Slothouber + o Removed form-feed from ASCII output + o Applied patch from Christian Vigh to make ROBODoc compile + under MSVC++ V7 + o Applied patch from Wim van Hoydonck to fix a bug + in the escaping of '_' in the names internal artifacts + for LaTeX output. + o Fixed makefile.plain + o ROBODoc compiles without warnings using + make -f makefile.plain + + Gergely Budai + o Using bitfields in stead of and-ing with a define. + o Function name separator can be configured to be something + different than ',' + o Added a configuration block that allows the used to + specify which items are pre-formatted by default. + +Sep 2006 + Frans Slothouber + o Corrected return value of main() + +Sep 2006 - V4.99.28 + Michèle Garoche + o Improved Mac support (for FINK) + +Aug 2006 - V4.99.28 + Gergely Budai + o Fixed many compiler warnings. + o More readable .css file + o makefile for mingw under cygwin + o Better syntax colouring support + + Frans Slothouber + o Moved most of the HTML formatting to the .css file + o Fixed a bug that caused the second list in a paragraph not + to be recognized. + o Added more documentation to the source. + o Removed code for SGML docbook + o Removed makefile and project file for MS VC++ + o Added functions to check for duplicate and + mutual exclusive options. + +Jun 2006 - V4.99.26 + o Merged patch from Gergely Budai. (Adds syntax colouring, better + Latex output, and better tab control). + o changed output of --test format to xml. (Easier to parse). + o Masterindex no longer contains links to source files when + --one_file_per_header is used. + +Jun 2006 - V4.99.24 + o Added option --one_file_per_header (experimental: this splits + the documentation into many files, one per header). + o Added header examples to documentation. + +Dec 2005 - V4.99.23 + o Made it compile again under MingW + o Fixed a bug in the reporting of a missing robodoc.rc file + +Dec 2005 - V4.99.21 + o Fixed crash on empty source items. + o Merged patch from cdumke for handling long lines + +Dec 2005 - V4.99.19 + o Merged a patch from Friedrich Haase that allows '--src .' + and adds the options --sectionnameonly + o Merged a patch from Andreas Weder for better LaTeX output + o Added configuration options to allow some items + to work in the same way as a SOURCE item. + o ROBODoc now allows module and function names + that include white space. + +Frans Slothouber +Apr 2005 - V4.99.17 + o Added patch by Thierry Pierron for troff output. + +Feb 2005 - V4.99.15 + o Documented more tests. + o Changed timestamp format. + o Added check on fork(). If fork() is not found only a stub for robohdrs + is compiled. + o Added patch by Thierry Pierron for aliasses. A single + header can now be used to documents several similar functions/ + classes/variables etc. + +Frans Slothouber +Feb 2005 - V4.99.10 + o Fixed a bug in the compilation under mingw + +Jan 2005 - V4.99.8 +Frans Slothouber + o ROBODoc will look in different locations for the robodoc.rc file. + ( $HOME/robodoc.rc, $HOMEDRIVE$HOMEPATH/robodoc.rc, and + /usr/share/robodoc/robodoc.rc ) + o Added option --nogeneratedwith to enable users to remove the + generated with robodoc line for the generated documentation. + o Fixed the makefile for mingw (thanks to Brian Elmegaard) + o Fixed a bug that caused robodoc to find headers even if + there were none. [1055886] + o Fixed a bug that caused robodoc to crash if single line source + item was found. [1056681] + +Sep 2004 - V4.99.6 + o Fixed a bug that caused robodoc to crash when no files + are found. [1033913] + +Sep 2004 - V4.99.4 +Frans Slothouber + o Fixed a bug that caused robodoc to die with an assert + when an absolute path is used under windows. [1033644] + o Updated the man page. + o Fixed a bug that caused links to be created for 'Foo' in + Bar_Foo. + +Aug 2004 - V4.99.3 +Frans Slothouber +o If paths such as c:\doc\foo\bar are used as parameters + they are first translated to c:/doc/foo/bar before + they are further processed. +o Added patch send in by Ernst Bokkelkamp that adds + the header type to each headers documentation. +o Updated documentation. + +May 2004 - V4.99.1 + o Merged a patch by Bernhard Schoenhammer that adds a + accept files: + block to the robodoc.rc file. + o Solved bug [972456] Case problem with creating links. + o Fixed a bug [975543] that caused the Doc dir to be included when it was + a subdir of the sourcedir and the sourcedir was specified to + be '.' + +May 2004 - V4.99.0 + o Fixed XML DocBook output, it appears that 4.0.24 created + invalid XML files. + o Added smart formatting. Instead of using preformatted text, + that is copying the header text verbatim into the output document, + ROBODoc tries to determine the structure of the text from + the indentation and use of special characters. + + For instance + This is a list: + o list item 1, + o list item 2. + + Will be translated into the appropriate commands to create a similar + list in the output format. + +May 2004 - V4.0.25 + Frans Slothouber + o Added --headless and --footless option to create documents that can be + included into large documents. (Works for LaTeX and HTML). + +May 2004 - V4.0.24 + Frans Slothouber + o Added --nosort option + o With the define IGNORE_CASE_FILENAMES one can make robodoc case-insensitve + when it comes to filenames. + o Fixed bug [924530] False warning with empty lines + o Fixed bug [925920] broken robodoc.rc file; robodoc ignored end markers or + remark markers if there was no header marker block. + +March 2004 - V4.0.23 + Frans Slothouber + o When sorting module headers come before headers + of other types. + o Fixes a bug in the sorting of headers. + o Fixes a bug in linking + o Sourcefiles that do not contain headers are not shown. + +February 2004 - V4.0.21 + Frans Slothouber + o Added navigation bar for every header. It allows one to jump + to the parent header, the top of the document, and the index + when available. + o ROBODoc will continue parsing the other headers if it finds + a header it can not parse. + o Better formatted warnings. + o The sourcefile index is now always sorted + o Everything is sorted according to a non case sensitive string + compare. + +January 2004 - V4.0.19 + Frans Slothouber + o Fixed bug 874567 No crosslinks for names that start with '-' + o Fixed bug 875533 No bolding for names starting with :: + o Added configurable header markers, remark markers, + and end markers. ROBODoc is now usable with + _any_ language. + + Hermann Hueni + o Fixed broken configure on Solaris. + +January 2004 - V4.0.18 + Frans Slothouber + o Update of the user manual and documentation + o Note that: + If you were using an 'extensions:' block in your robodoc.rc file, + you have to replace this with an 'ignore files:' block with all + extensions prefixed with '*'. So, if you were using + + extensions: + .txt + .obj + + replace this with + + ignore files: + *.txt + *.obj + +December 2003 - V4.0.17 + Frans Slothouber + o Added directory tree shaped master index for the sourcefiles. + o Added filtering of files and directories based on wildcard + expressions. + Michael Felke + o Support for lotus script, clean-up of headers.c and headers.h + +December 2003 - V4.0.15 + Frans Slothouber + o Added support for DB/C + +December 2003 - V4.0.14 + John Rouillard + o Bug fix. no index file was generated for headertypes of which + there were only internal headers. + Frans Slothouber + o More tests + +December 2003 - V4.0.13 + Skipped + +December 2003 - V4.0.12 + David White + o Updated makefile for borland C + o Added marker for Aspen Custom Modeller (ACM) + Frans Slothouber + o Added more documentation + o a .css file is now also used in singledoc mode + o each header in the html documentation now has a permanent + "a name" based on the full name of a header. + o fixed the title of singledoc documents. + o files or directories specified with --src or --doc + are now automatically prefixed with a ./ + o It is now allowed to have a Doc directory that is a subdirectory + of the source directory. This Doc directory is skipped while robodoc + scans for sourcefiles. + o Added headermarker !**** for Fortran + o ROBODoc now warns if it finds something that looks like an item name but is + not in the list of item names. This catches spelling mistakes like NAEM, + IMPUTS, VALEU, etc + o Fixed bug 830868 no error message for misspelled options + o Fixed bug 767034 a slash at the end of a path confuses robodoc + o Fixed bug 772213 assert fires if header is not closed + o Added user configurable header types (section "header types" + in robodoc.rc file). + o Added lock mode (--lock). Per source file robodoc locks on the + first headermarker it finds and will recognize only that particular headermarker + for the remaining part of the file. + In addition it locks on the first remark marker in each header and + will recognize only that particular remark marker for the remaining + part of the header. + Petteri Kettunen + o First implementation of piping in generator.c + +September 2003 - V4.0.11 + Frans Slothouber + o Added a table for header types. This will allow custom + header types. + o The master index table for HTML output is split up in + several pages. One for each header type. + Petteri Kettunen + o added --version option + o fixed regex in bump.pl + +September 2003 - V4.0.10 + Skipped. + +Augustus 2003 - V4.0.9 + Frans Slothouber + o Removed some obsolete functions. + o Added project file for MSVC++ + o Merged patch from Brian P. Hanley: + + the option --rc to specify an alternate robodoc.rc file. + + the option --css to specify an alternate css file. + (The content of this file will be copied into the + robodoc.css file). + +Augustus 2003 - V4.0.8 + Skipped. + +July 2003 - V4.0.7 + Frans Slothouber + o Indented all source code with indent + o Added markers for VB + o Added a Perl example to the Examples directory (bug 779560) + o Fixed layout of the man pages. (bug 779553) + Petteri Kettunen + o signed/unsigned char changes and UTF-8 output in SGML and DBXML modes + o robohdrs/-t option, macro (#define) created as `d' type header + +July 2003 - V4.0.6 + David White + o Added a makefile for Borland C compiler + Frans Slothouber + o Fix for bug 761686, space in .rc file confuses robodoc + o Added a section on how to use robodoc under win32 to + the manual. + o Fix for bug 770251, Absolute filename causes an assertion to fail + Kai + o Added a makefile for djgpp GCC under win32. + +July 2003 - V4.0.5 + Frans Slothouber + o Fix for bug 761688, rtf output goes only 4 sections deep. + o Added the option --tabsize n + o Lines that do not start with a remark marker are skipped, + unless they are part of a source item. + o Re-enabled ascii output. + + Kai Hofmann + o Fix for many compiler warnings. + +June 2003 - V4.0.4 + Frans Slothouber + o Merged changes to the html generator from Kai. + +June 2003 - V4.0.3 + Frans Slothouber + o Fix for bug -- ./configure crashes. + o Fix for bug -- Wrong version number is shown when compiled without using + autoconfig. + + Jacco van Weert + o Added image: tag to html output. + +May 2003 - V4.0.2 + o Fix for bug -- robodoc chokes on empty lines in + the robodoc.rc file. + o Fix for bug -- Bad formatting of the 'unknown section' error. + o Fix for bug 721685 -- TOC appears twice in a RTF Doc + o Fix for bug 721690 -- TOC in mutidoc files are wrong. + o Added support for DCL. + +April 2003 - V4.0.1 + o Fix for bug 715778 -- on some machines the d_type of the + struct dirent is always DT_UNKNOWN. This caused ROBODoc + to skip all files. (Thanks to Je'rome Laheurte). + o Merged a patch by Andreas Signer that add a number of + new headr types. + o Merged a patch by Janusz Piwowarski that allows users + to specify (1) the extension of the output file and + (2) html character encoding. + +April 2003 - V4.0.0 + o Support for XML DocBook output. + o A new tool, robohdrs, is included -- it can insert empty headers + in the source code. + o Support for cascading style sheets (CSS) in HTML mode. + o Complete rework of the commandline interface. + o ROBODoc can now work with directories and subdirectories, + and does not need xref files anymore. + o All documentation can be created with a single command, you + no longer need a makefile to create your documentation. + o The manual is now in docbook format and much more extensive. + o Lots of refactoring, code should be easier to extend and understand + now. + o There is now some design documentation. + o Support for single file and multiple file documentation. + o Dropped support for Amiga Guide format. + o More unittests. + o Support for packaging under RedHat and OS-X + o C++ and C examples have been removed. + +July 2002 - V3.2.4 + o Indented headers + o 2 character header types + Modifications by Nathan Prewitt + o To allow further classification + of internal headers as internal functions, internal classes, + internal variables, etc. + o Added export into TROFF format with man macros - + suitable for Unix man pages. + o Fixed HTML generation to skip table of contents + if there were no TOC requested at command line. + o Fixed analyzer to correctly handle empty headers. + +March 2002 - Frans Slothouber (V3.2.4Beta2) + o More unittests + o Documentation update + o Added automatic detection of file:/ + o Merged back the changes by Sasha Vasko.after I had + accidently deleted them when merging the DocBook changes. + o Indented most of the sourcecode. + +March 2002 - Frans Slothouber (V3.2.4Beta1) + o Documentation updates. + o added a target docclean in the makefile in Source/ to clean + all temporary files. + o updated documentation + o added testframework + +August 2001 DCD Changes - V3.2.4 with docbook support: + o Added support for Docbook SGML - Robodoc can now produce + output in Docbook SGML using the DBSGML command line switch, + allowing standardized conversion to a host of formats + including HTML (single and multiple), RTF, ASCII, LATEX, + and PDF. Docbook also + allows you to use external style sheets in which you can + change the look of your document. See www.docbook.org for more + on DocBook + o Added -rh switch which causes Robodoc to scan for a single header + defined as *ROBODOC* (char *robo_header) instead of header_markers + and uses *ROBODOC_END* as the end marker. + This prevents problems with Robodoc becoming confused with + normal comments uing *. It is particularly helpful in scanning + PHP source. It will only work with languages that support + multiline c-style comments + o Added -nt switch. Only used in DBSGML mode when creating a master + index. This causes Robodoc to list the Master Index functions as + a section 3 level item rather than as part of a table. + o Added genrd, a Unix bash shell script which simplifies the use + of Robodoc when generating documents from multiple source files + and when creating crossreferences and a master index. + Whole directories and subdirectories of source code can be + scanned and documented with a one line statement rather than + having to construct a makefile or using multiple + robodoc statements. See genrd -h for more info. + +Sepetember 2000 - Frans Slothouber (V3.2.3) + o Added a descrip.mms file for compilation under VMS + o make install installs additional documentation. + o Fixed a bug that caused links of the type + "someword/anotherword," to be ignored, while + "someword/anotherword" was recognized. + +July 2000 - Frans Slothouber (V3.2.2) + o Documentation explains how to use ROBODoc when your sources are + in several subdirectories. + o Documentation explains master index file for LaTeX, how to view + the generated documentation, and the new options, NOSOURCE, SINGLEDOC + and TITLE. + o example makefile includes commands to view the + generated documentation. + o Updated the man page + o Added option SINGLEDOC + For LaTeX output this generates documentation without + the start and end headers. This way the generated file + can be included in a master file. + o Added master index file for LaTeX output. The documentation + gathered from several source files can now be included into + one big file. + o Added the option NOSOURCE. With this option the SOURCE item + is not included in the documentation. + o Added the TITLE option. This allows to set the title for + the master index file. + o Made the search for headermarkers case insensitve. + REM == Rem == rem + +December 1999 - v3.1f + o added RB_TimeStamp() to include time stamps in the documentation. + o Documentation is now generated in LaTeX2e format. + o added '|****' as begin marker, '|' as remark marker and '|***' as + end marker for GNU assembler support. + o ran ident on all source. Using the GNU standard now. + o Added new fold markers provided by Petteri + +December 1999 - Frans Slothouber (v3.1e) + o Moved the C example in Examples to Examples/C + o Added an C++ example in Examples/CPP + o Added empty headers for C++ in Headers/ + o More documentation. + o added markers for HTML. + o modified the RB_Find_Link() function to also words that include + "::". This is used for C++ methods. + o added a RB_Function_Name() function that correctly extracts the + function name (or the name of any other object that is documented) + from the header name. The old code used RB_FilePart which failed + on C++ method names. + o Fixed a core-dumping bug in RB_Set_Doc_Base() + +December 1999 - Frans Slothouber (v3.1d) + o Added list of possible item names to the robodoc man page. + o Added list of possible header types to the robodoc man page. + o Updated manual with information on the generation of the + master index file and new header types. + o added new header types for, classes, methods, variables, + functions, strutures and constants. (Idea of Stefan Kost) + o added a command to create a master index file that contains + sorted pointers to all classes, methods, variables, + functions, strutures and constants. + +December 1999 - Frans Slothouber (v3.1c) + o Added testheader.c for debug purposes. + o Split the source code into serveral files. + o Fixed numerous typos in the documentation. + o Using m4 to create the html documentation (for table of contents ect). + o Added cross links between the documentation and examples. + From patches that I received from Stefan Kost + o renamed BEAST METHODS -> METHODS + o renamed BEAST ATTRIBUTES -> ATTRIBUTES + o added new items useful for object oriented programming; some of + these items are already used in os3.1 autodocs + TAGS, COMMANDS, DERIVED FROM, DERIVED BY, USES, + CHILDREN, USED BY, PARENTS, USAGE, PURPOSE + o commented the item names + o changed item-type enums to end all with _ITEM + o changed RB_Find_Link to accept names ending with '...' + o changed copyright comment to be a style-guide conform version string. + o changed RB_VER[] to be a style-guide conform version string + o changed AMIGA into _AMIGA, because the first one does not exists, + when compiling with NOANSI on SAS C/C++ + +November 1999 - Frans Slothouber (v3.1b) + o Added a man page + o Cleaned-up html documentation. + o is generated at the beginning of + each document. A mention of the source code name in another + document creates a link to this name (provided you use xrefs). + o Moved most #defines and enums to robodoc.h + o Made ROBODoc more forgiving in reading the xrefs file. Empty + lines are allowed and also spaces at the end of a file name. + +August 1999 - Frans Slothouber: v3.1 + o Added GPL licence + o Added INSTALL, README, and TODO + o Converted the documentation to HTML + o Spell-checked all documentation + o More documentation and a more informative usage() function. + o robodoc -c prints licence + o removed a number of Source items from the documentation to reduce + the size of the robodoc.c.html file... no fun for people + to download a >100k file. + o removed the warning about not using a robodoc default file. + o indent -orig -i2 -nbc -ncdb -bad -bap + o Fixed the warnings. + o Fixed some occurrences of (evil cast)malloc (thou shalt not + cast malloc :) + o ROBODoc now returns EXIT_FAILURE or EXIT_SUCCESS, as defined + in + o Fixed a memory leak in RB_Analyse_Document() + +Modifications by Petteri Kettunen +August 1999 - v3.0m+ + o Support for folding in SOURCE items, HTML only. + o indent -kr + o Added options FOLD and C + +Modifications by Petteri Kettunen +Feb 1999 - v3.0m + o Changed background color to white + o Changed size of Table of Contents title. (H3 instead of H1) + o The reverse function also reversed the sorted header list, + fixed this. + +Modifications by FNC Slothouber. + Feb-1999 - v3.0l * Added function to reverse the header list. +14-Aug-1998 - v3.0k * Tcl/Tk '#' handling added; + + +Modifications by agi +15-Dec-1997 - v3.0j + o cleaned the HTML-output, so it now conforms to the DTD for HTML-3.2 + o TOC now is an ordered list (
    and
  1. ) + o added "" + o added quotes to values of some HTML-attributes + o more compatible implementation of the SGML-comment containing + copyright-info replaced all occurrences of
    .. by 
    
    +  o replaced 

    by

    + o fixed two minor warnings reported by gcc -Wall + +Modifications by FNC Slothouber. +10-July-1996 - v3.0i + o Bug Fix, Both the options INTERNAL and INTERNALONLY did not + work correctly. +01-April-1996 - v3.0h + o Added ';' to > and < so lynx also recognizes them. + o Fancied up the HTML output. + +Modifications by apang + 08-Mar-1996 - v3.0f + o Cleaner build for Borland C++ 4.52 + o Added more markers (C++, Pascal, Modula-2, COBOL) + o Added more item types/names + o Added #defines for the preamble (COMMENT_ROBODOC and + COMMENT_COPYRIGHT) + o BLANK_HEADER for detection of asterisk'd lines + o RB_Say() the GENERIC header warning instead of using printf() + o Indents SOURCE body in output + o ASCII respects the TOC flag; removed extraneous newline after + formfeed (so it's more like AutoDoc) + o HTML output fixed to handle '<', '>', and '&' + o LaTeX attributes and '%' handling added; fancied up the output a bit + o RTF support added + o Changed some fprintf()'s to fputc()'s for potentially lower overhead + o Fixed line eater bug + o More general fix to the TOC problem of including internal links + when it wasn't selected + +Modifications by FNC Slothouber. +04-Feb-1996 - v3.0e + o fixed the problem with the TOC that included links to headers that + were not selected. (i.e internal) +08-Oct-1995 - v3.0d + o Bug fixes +16-Sep-1995 - v3.0c + o Bug fixes +27-Aug-1995 - v3.0b + o Fixed a bug with the defaults file + o Improved search algorithm RoboDoc is now 5.8 times faster. +18-Aug-1995 - v3.0 + o New scanner that searches for a set default markers + that define what is a comment or what is not and that + define what or what is not a header/end marker. + o Added Beast Support + +08-Aug-1995 - Koessi - + o a lot of while instead of for + o a lot of switch() instead of ifelse + o version defined + o RB_Say, RB_Panic now useable like printf() + o new formats for nearly all output-strings + o char *whoami is global copy of argv[0] + o BOLD <- MAKE_LARGE && AMIGAGUIDE + o succesfully compiled&tested on HPUX (HP9000/800) + o optimized listfunctions + o encapsulated header- and link- allocating and freeing + o RB_Find_Function_Name() replaced with RB_FilePart() + +07-Aug-1995 - Koessi - + o automated foldmarks "\***" + o ! GoldEd's foldmarks == RoboDoc marker ! + o quoted source parsing enhanced + +01-Aug-1995 - Koessi - v2.0? + o more robust parsing, less enforcer-hits + o removed self-referencing links ! + o remarked most changes with *koessi* + o added GoldEd-foldmarks + o compiled successfully with SAS-C 6.3 + +24-May-1995 - Frans Slothouber - v2.0e + o Fixed a bug that cause the CleanUp Routine to lock up. + o Improved the HTML output, should work faster now. + +15-May-1995 - Frans Slothouber - v2.0d + o New Defaults file. + o Added Verbose option. + +12-May-1995 - Frans Slothouber - v2.0c + o Bug fixes. + +10-May-1995 - Frans Slothouber - v2.0a + o Program completely rewritten + o added SOURCE item and LaTeX output. + o added TAB converter. + +20-Apr-95 - Jacco van Weert - v1.1a: + o INTERNALONLY option added. + o Sort problem solved. + +2-Apr-95 - Jacco van Weert - v1.0b: Bug fixes + o Procedure header search bug solved. + o Print 'created procedure' text + +Mar-95 - Jacco van Weert - v1.0a: Final version + +2-Feb-95 - Jacco van Weert - v0.93: + o Mungwall hit, solved. + o When item headers, are also available in body then parts are + duplicated solved. + +26-Jan-95 - v0.92: 2nd test beta-version + +19-January-95 - Jacco van Weert (v0.8) + o First test beta-version + +December 1994 - Jacco van Weert -- creation date. + + diff --git a/Contributions/robodoc.kaptn b/Contributions/robodoc.kaptn new file mode 100644 index 0000000..f1d639b --- /dev/null +++ b/Contributions/robodoc.kaptn @@ -0,0 +1,292 @@ +#!/usr/bin/env kaptain +# $Id: robodoc.kaptn,v 1.3 2007/01/29 22:28:20 gumpu Exp $ +# NAME +# robodoc.kaptn - robodoc.rc gui composer +# COPYRIGHT +# Copyright (C) 2003 gian paolo ciceri +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# +# HISTORY +# Sep, 9th 2003: v0.1.0 - initial, tentative release (borrowed from procmail.kaptn). +# + + +############################################################# +# +# main wizard +# +start :wizard "Robodoc Configuration Wizard" -> intro setup finish; +############################################################# + +############################################################# +# +# into page +# +intro "robodoc.rc builder" -> intro1 intro2; +intro1 -> text1 introa; +text1 -> @text("This is a graphical front-end for creating robodoc.rc \ +configuration files made using Kaptain, the Universal graphical front-end."); +intro2 "" -> @; +introa "" -> workdir @fill; +workdir "Choose Working Directory" -> "\nWORKDIR=" @directory="$PWD"; +############################################################# + +############################################################# +# +# finish page, where I write the robodoc.rc file +# +finish "Finish" -> text3 other_settings; +text3 -> @text("Now press the Preview button to see the settings you have made.\ + Don't forget to press Write button in order to save the setting in the given file."); +other_settings -> filename @fill @preview(allfile)="Preview" @action(writetofile)="Write"; +writetofile-> "echo '" allfile "' > " filename ; +filename -> @outfile="$PWD/robodoc.rc"; +############################################################# + +############################################################# +# +# setup page, here's the beef! +# +setup :horizontal "Settings" -> recipe; +recipe :framed :horizontal -> recipe1 recipe2; +recipe1 :framed "Main documentation options" -> outputtype sourcedir docdir cssfile ; +recipe2 :framed "Items and misc. options" -> items ignoreitems ignoreext flags; +#recipe :framed -> outputtype sourcedir docdir cssfile items ignoreitems ignoreext flags regexp; + +outputtype :horizontal "Output Types" -> !these_output | more_output ; + these_output :beside -> "--html\n" @string="--html"; + more_output :beside -> "\n" more_output0; + +sourcedir "Sources Directory" -> "--src\n" @directory="$PWD"; + +docdir "Documents Directory" -> "--doc\n" @directory="$PWD"; + +cssfile "CSS stylesheet" -> "--css\n" @infile("*.css"); + +items :horizontal "Items" -> !these_items | more_items; + these_items :beside -> @string; + more_items :beside -> more_items0; + +ignoreitems :horizontal "Ignore Items" -> !these_iitems | more_iitems; + these_iitems :beside -> @string; + more_iitems :beside -> more_iitems0; + +ignoreext :horizontal "Ignore file Extensions" -> these_iexts | !more_iexts; + these_iexts :beside -> @string="*.bkp\n ~"; + more_iexts :beside -> more_iexts0; + +########################################################### +#@list('NAME', 'SYNOPSIS', 'INPUTS', 'OUTPUTS', 'HISTORY') ; +#ignoreitems "Ignore Items" -> "ignore items:\n" @combow('HISTORY', 'BUGS', 'AUTHORS', 'TODO', 'NEWS'); +#ignoreext "Ignore Extensions" -> "extensions:\n" @combow('*.bkp', '~'); +########################################################### + + + +flags :horizontal "Misc.Options" -> these_flags | !more_flags ; + these_flags :beside -> ":0 " @string; + more_flags :beside -> ":0 " more_flags0; +############################################################# + + +############################################################# +# +# robodoc.rc file setup, in the `allfile` variable +# +allfile -> "#This file was created by Kaptain\n\n" + "#options" "\n" + options "\n" + + "#output types" "\n" + out_options "\n" + + "#source directory" "\n" + sourcedir "\n" + + "#document directory" "\n" + docdir "\n" + + "#stylesheet" "\n" + cssfile "\n" + + "#items" "\n" + "items" "\n" + items "\n" + + "#ignore items" "\n" + "ignore items:\n" + ignoreitems "\n" + + "#ignore files by extension" "\n" + "extensions:" "\n" + ignoreext "\n" + + "#end\n" ; +############################################################# + + +############################################################# +# +# auxiliary dialog, to setup options +# +more_flags0 :dialog "Options..." -> flags_top flags_buttons; +flags_buttons -> @close="OK"; +flags_top :horizontal :framed -> options;# extras; +# extras "Extras" -> @; + options "Options" + -> index multidoc singledoc singlefile + tell folds internal internalonly + nosource nodesc sections tabsize toc; + + index "Also create a master index file" -> "--index\n"! | @; + multidoc "Generate one document per source file, and copy the directory hierarchys" -> + "--multidoc\n"! | @; + singledoc "Define the documentation directory or documentation file." -> "--singledoc\n" |!@; + singlefile "Generate a single document from a single file." -> "--singlefile\n" |!@; + tell "ROBODoc tells you what steps it is taking." -> "--tell\n" |!@; + folds "Use fold marks to split a big document into smaller ones." -> "--folds\n" |!@; + internal "Also include headers marked internal." -> "--internal\n" |!@; + internalonly "Only include headers marked internal." -> "--internalonly\n" |!@; + nosource "Do not include the SOURCE items." -> "--nosource\n" |!@; + nodesc "Do not scan any subdirectories." -> "--nodesc\n" |!@; + sections "Create sections based on the module hierarchy." -> "--sections\n" |!@; + tabsize "Lets you specify the tabsize." -> "--tabsize\n" |!@; + toc "Add a table of contents." -> "--toc\n" |!@; +############################################################# + +############################################################# +# +# auxiliary dialog, to setup output types (html, latex, rtf, docbook) +# +more_output0 :dialog "Output Types..." -> output_top output_buttons; +output_buttons -> @close="OK"; +output_top :horizontal :framed -> out_options;# extras; +# extras "Extras" -> @; + out_options "Output Types" + -> html ascii rtf latex docbook; + html "HTML" -> "--html\n"! | @; + ascii "ASCII" -> "--ascii\n"! | @; + latex "LaTeX" -> "--latex\n" | !@; + rtf "Rich Text format" -> "--rtf\n" | !@; + docbook "DocBook" -> "--dbxml\n" | !@; +############################################################# + +############################################################# +# +# auxiliary dialog, to setup items +# +more_items0 :dialog "Include Items..." -> item_top item_buttons ; +item_buttons -> @close="OK"; +item_top :horizontal :framed -> item_options;# extras; +# extras "Extras" -> @; +item_options :horizontal "Items" + -> itemleft itemright; + + itemleft -> NAME SYNOPSIS INPUTS + USAGE SOURCE COPYRIGHT FUNCTION AUTHOR RESULT EXAMPLE NOTES DIAGNOSTICS; + + itemright -> WARNINGS ERRORS BUGS SEEALSO METHODS ATTRIBUTES TAGS COMMAND DERIVEDFROM + DERIVEDBY USES USEDBY INPUTS OUTPUTS HISTORY; + + NAME "NAME, Item name + short description" -> " NAME\n"! | @; + SYNOPSIS "SYNOPSIS, how to use it" -> " SYNOPSIS\n" | !@; + USAGE "USAGE, how to use it" -> " USAGE\n" | !@; + SOURCE "SOURCE, source code inclusion" -> " SOURCE\n" | !@; + COPYRIGHT "COPYRIGHT, who own the copyright" -> " COPYRIGHT\n" | !@; + FUNCTION "FUNCTION, what does it" -> " FUNCTION\n" | !@; + AUTHOR "AUTHOR, who wrote it" -> " AUTHOR\n" | !@; + RESULT "RESULT, what do we get returned" -> " RESULT\n" | !@; + EXAMPLE "EXAMPLE, a clear example of the items use" -> " EXAMPLE\n" | !@; + NOTES "NOTES, any annotations" -> " NOTES\n" | !@; + DIAGNOSTICS "DIAGNOSTICS, diagnostical output" -> " DIAGNOSTICS\n" | !@; + WARNINGS "WARNINGS, warning messages" -> " WARNINGS\n" | !@; + ERRORS "ERRORS, error messages" -> " ERRORS\n" | !@; + BUGS "BUGS, known bugs" -> " BUGS\n" | !@; + SEEALSO "SEE ALSO, references" -> " SEE ALSO\n" | !@; + METHODS "METHODS, oop attributes" -> " METHODS\n" | !@; + ATTRIBUTES "ATTRIBUTES, oop attributes" -> " ATTRIBUTES\n" | !@; + TAGS "TAGS, tagitem description" -> " TAGS\n" | !@; + COMMAND "COMMAND, command description" -> " COMMAND\n" | !@; + DERIVEDFROM "DERIVED FROM, oop super class" -> " DERIVED FROM\n" | !@; + DERIVEDBY "DERIVED BY, oop sub class" -> " DERIVED BY\n" | !@; + USES "USES, what modules are used by this one" -> " USES\n" | !@; + USEDBY "USED BY,which modules do use this" -> " USED BY\n" | !@; + INPUTS "INPUTS, what can we feed into it" -> " INPUTS\n" | !@; + OUTPUTS "OUTPUTS, what output will be made" -> " OUTPUTS\n" | !@; + HISTORY "HISTORY, who done what changes when" -> " HISTORY\n" | !@; +############################################################# + +############################################################# +# +# auxiliary dialog, to setup ignore items +# +more_iitems0 :dialog "Ignore Items..." -> iitem_top iitem_buttons; +iitem_buttons -> @close="OK"; +iitem_top :horizontal :framed -> iitem_options;# extras; +# extras "Extras" -> @; + iitem_options :horizontal "Ignore Items" + -> iitemleft iitemright; + + iitemleft -> iNAME iSYNOPSIS iINPUTS + iUSAGE iSOURCE iCOPYRIGHT iFUNCTION iAUTHOR iRESULT iEXAMPLE iNOTES iDIAGNOSTICS; + + iitemright -> iWARNINGS iERRORS iBUGS iSEEALSO iMETHODS iATTRIBUTES iTAGS iCOMMAND iDERIVEDFROM + iDERIVEDBY iUSES iUSEDBY iOUTPUTS iHISTORY iBUGS; + + iNAME "NAME, Item name + short description" -> " NAME\n" | !@; + iSYNOPSIS "SYNOPSIS, how to use it" -> " SYNOPSIS\n" | !@; + iUSAGE "USAGE, how to use it" -> " USAGE\n" | !@; + iSOURCE "SOURCE, source code inclusion" -> " SOURCE\n" | !@; + iCOPYRIGHT "COPYRIGHT, who own the copyright" -> " COPYRIGHT\n" | !@; + iFUNCTION "FUNCTION, what does it" -> " FUNCTION\n" | !@; + iAUTHOR "AUTHOR, who wrote it" -> " AUTHOR\n" | !@; + iRESULT "RESULT, what do we get returned" -> " RESULT\n" | !@; + iEXAMPLE "EXAMPLE, a clear example of the items use" -> " EXAMPLE\n" | !@; + iNOTES "NOTES, any annotations" -> " NOTES\n" | !@; + iDIAGNOSTICS "DIAGNOSTICS, diagnostical output" -> " DIAGNOSTICS\n" | !@; + iWARNINGS "WARNINGS, warning messages" -> " WARNINGS\n" | !@; + iERRORS "ERRORS, error messages" -> " ERRORS\n" | !@; + iBUGS "BUGS, known bugs" -> " BUGS\n" | !@; + iSEEALSO "SEE ALSO, references" -> " SEE ALSO\n" | !@; + iMETHODS "METHODS, oop attributes" -> " METHODS\n" | !@; + iATTRIBUTES "ATTRIBUTES, oop attributes" -> " ATTRIBUTES\n" | !@; + iTAGS "TAGS, tagitem description" -> " TAGS\n" | !@; + iCOMMAND "COMMAND, command description" -> " COMMAND\n" | !@; + iDERIVEDFROM "DERIVED FROM, oop super class" -> " DERIVED FROM\n" | !@; + iDERIVEDBY "DERIVED BY, oop sub class" -> " DERIVED BY\n" | !@; + iUSES "USES, what modules are used by this one" -> " USES\n" | !@; + iUSEDBY "USED BY,which modules do use this" -> " USED BY\n" | !@; + iINPUTS "INPUTS, what can we feed into it" -> " INPUTS\n" | !@; + iOUTPUTS "OUTPUTS, what output will be made" -> " OUTPUTS\n" | !@; + iHISTORY "HISTORY, who done what changes when" -> " HISTORY\n" | !@; +############################################################# + +############################################################# +# +# auxiliary dialog, to setup excluded file by extension +# +more_iexts0 :dialog "Exclude Extensions..." -> iextm_top iextm_buttons; +iextm_buttons -> @close="OK"; +iextm_top :horizontal :framed -> iextm_options;# extras; +# extras "Extras" -> @; + iextm_options "Exclude files by extension" + -> BAK TILDE; + BAK "*.bak" -> " *.bak\n" | @; + TILDE "~" -> " ~\n" | @; +############################################################# + diff --git a/Contributions/robodoc2pod.pl b/Contributions/robodoc2pod.pl new file mode 100644 index 0000000..b88f4e1 --- /dev/null +++ b/Contributions/robodoc2pod.pl @@ -0,0 +1,162 @@ +#!/usr/bin/perl +################################################### +# robodoc 2 pod converter +################################################### +#****h* robodoc2pod +# NAME +# Robodoc 2 Pod +# +# FUNCTION +# Generate POD documentation from ROBODoc to allow +# use of perldoc with your Robodoc'ed code. +# +# HISTORY +# * V 0.2.1 of 06/03/14 corrected the regexps +# * V 0.2.0 of 06/03/13 rewritten with intermediate representation +# * V 0.1.0 of 06/03/10 first version +# +# BUGS +# nothing known right now. +# +# TODO +# * refactor cleanly +# * manage locales +# * manage nested lists +# * indent EXAMPLE with +# +# LICENSE +# This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. +# AUTHOR +# Emmanuel Florac ( wazoox @ free . fr ) +# COPYRIGHT +# (c) 2006 Intellique (www.intellique.com) +#*** +# always use strict et warnings. +use strict; +use warnings; + +use Data::Dumper; + +######################### +# functions +######################### + +sub usage { + return "usage : $0 [ >> ]"; +} + +######################### +# main +######################### + +# must provide a file name to work with +my $file = shift or die usage(); +open my $fh, $file or die "can't open file : $file"; + +# robodoc start and end tags (marks robodoc blocks) +my $rbd_starttag = qr(^\*\*\*\*[\w\*]\*); +my $rbdheadtype = qr(^\*\*\*\*([\w\*])\*); +my $rbd_endtag = qr(^\*\*\*); + +# robodoc general tags +my @rbdtags = ( + 'NAME', 'COPYRIGHT', 'SYNOPSIS', 'USAGE', + 'FUNCTION', 'DESCRIPTION', 'PURPOSE', 'AUTHOR', + 'CREATION DATE', 'MODIFICATION', 'HISTORY', 'INPUTS', + 'ARGUMENTS', 'OPTIONS', 'PARAMETERS', 'SWITCHES', + 'OUTPUT', 'SIDE EFFECTS', 'RESULT', 'RETURN VALUE', + 'EXAMPLE', 'NOTES', 'DIAGNOSTICS', 'WARNINGS', + 'ERRORS', 'BUGS', 'TODO', 'IDEAS', + 'PORTABILITY', 'SEE ALSO', 'METHODS', 'NEW METHODS', + 'ATTRIBUTES', 'NEW ATTRIBUTES', 'TAGS', 'COMMANDS', + 'DERIVED FROM', 'DERIVED BY', 'USES', 'CHILDREN', + 'USED BY', 'PARENTS', 'SOURCE', 'LICENSE', +); + +my %rbdheaders = ( + c => 'Class', + d => 'Constant', + f => 'Fonction', + h => 'Module', + m => 'Méthod', + s => 'Structure', + t => 'Type', + u => 'Unit Test', + v => 'Variable', + '*' => '', +); + +# to check for headers tags +my $tagmatch = join '|', @rbdtags; +$tagmatch = qr(^($tagmatch)); + +# to store the robodoc +my @robodoc; + +# flag and titles +my $inrobodoc = 0; +my $rbdtagname = ''; + +# read the file +while (<$fh>) { + + # remove leading # if any + s/^\s*# *//; + chomp; + + $inrobodoc = 0 if m/$rbd_endtag/; + + if ($inrobodoc) { + push @{ $robodoc[$#robodoc]{$rbdtagname} }, $_; + } + + if (m/$rbd_starttag/) { + $inrobodoc = 1; + my ($headertype) = (m/$rbdheadtype/); + ($rbdtagname) = (m/$rbd_starttag(.*)/); + chomp $rbdtagname; + if ($rbdtagname) { + $rbdtagname = $rbdheaders{$headertype} . $rbdtagname; + push @robodoc, { $rbdtagname => [] }; + } + } +} + +close $fh; + +# now convert robodoc to pod +my @pod; +my $items = 0; +my $podhead = 1; + +foreach (@robodoc) { + my ( $k, $v ) = each %$_; + my $currhead = $podhead; + push @pod, '', "=head$currhead $k", ''; + $currhead++; + + foreach my $line (@$v) { + # insert head if this is a managed tag + if ( $line =~ m/$tagmatch/ ) { + push @pod, ( '', "=head$currhead $line", '' ); + # insert bulleted lists + } elsif ( my ($elem) = ( $line =~ m/^\*\s+(.*)/ ) ) { + if ( $items == 0 ) { + $items++; + push @pod, "=over"; + } + push @pod, ( '', '=item *', '', $elem ); + # end bulleted list + } elsif ( $items > 0 ) { + $items = 0; + push @pod, ('', '=back', ''); + push @pod, $line; + # raw insert + } else { + push @pod, $line; + } + } +} + +print join( "\n", @pod ) . "\n"; + diff --git a/DEVELOPERS b/DEVELOPERS new file mode 100644 index 0000000..cc698fd --- /dev/null +++ b/DEVELOPERS @@ -0,0 +1,46 @@ +$Id: DEVELOPERS,v 1.10 2006/06/17 11:35:10 gumpu Exp $ + +If you get this from CVS, this is how to create a workable archive. +Run: + aclocal + automake -a + autoconf + + +To create a new release edit + bump.pl +and then run it. Then run + ./do.sh + + +To clean _everything_ + + make -f makefile.am myclean + + +To create the (g)zipfiles: + ./configure + make dist + make dist-zip + + +To check for memory leaks use: + CFLAGS="-g -Wall -DDMALLOC -DMALLOC_FUNC_CHECK" LDFLAGS="-ldmalloc" ./configure +in combination with the dmalloc library ( http://dmalloc.com/ ) + + +To cross-compile Windows binary on GNU/Linux, do: + + (cd Source && make -f makefile.plain xcompile) + +This requires mingw32 cross-compiler. On Debian GNU/Linux (and on its +derivatives) this can be installed simply by typing: + + apt-get update && apt-get install mingw32 + + +There are three modules for ROBODoc +robo -- The source code and documentation +robotest -- A test suite ( OBSOLETE ) +robowwww -- The web pages for ROBODoc. ( OBSOLETE ) + diff --git a/Design/design.txt b/Design/design.txt new file mode 100644 index 0000000..b019b97 --- /dev/null +++ b/Design/design.txt @@ -0,0 +1,198 @@ + +Some random notes about the design of robodoc. +This will later be turned into a proper docbook +document. + + + +Collections / Containers. + +For most of the containers a singly linked list is used. +The link to the next element is called "next" and is the +first field in any structure that is stored in a linked list. + +For instance + +struct S { + struct S* next; + long another_field; + char* aName; +}; + +An anchor points to the first element in the list. + +If this convention is used for all linked lists than it is +easy to remember how to iterate through the container. + + struct X* x_container; + + struct X* x_iterator; + for ( x_iterator = x_container; + x_iterator != 0; + x_iterator = x_iterator->next ) { + + } + +Inserting an element: + + x_new_element->next = x_container; + x_container = x_new_element; + + +======================================================== + +General Flow + +Sourcecode ---> [ROBODoc] ---> Document. + +The sourcecode consists of one or more sourcefiles. +The resulting document consists of one or more parts. + +For every sourcefile that is one part. +There can be additional parts. For instance +for indexfiles or to pull all parts into a single document. + + +> Can someone explain the differences internally of a single doc +> and multi doc? At first glance, it would seem that Lua scripts +> should only implement single doc because they are to be free to +> do as they please, but I may be mistaken. +> +> Please advise. + +The difference between singledoc and multidoc mode. + +The whole robodoc process consists of step 3 +(1) The scanning of the source directory tree -- this collect the names of + all the files and directories in the source directory tree. + All this information is stored in a RB_Directory structure inside + a RB_Document structure. +(2) The analysing of all the sourcefiles -- this reads the content of + all the files found in step 1 and collects all the headers found in + these files. + These are store in list of RB_Part structures stored inside a + RB_Document structure. For each sourcefile there is a RB_Part + structure. All the headers found in a single source file are + stored as a list of RB_header structures in a RB_Part structure. +(3) the generation of the documentation -- write the headers a + single documentation file or mulitiple documentation files. + + +The difference between single doc and multidoc can be found in step 3. +The difference can be seen in most clearly in the functions: +RB_Generate_SingleDoc() and RB_Generate_MultiDoc() + +If you look at the start of both functions they both call: + + RB_Document_Collect_Headers( document ); + RB_Document_Link_Headers( document ); + RB_Fill_Header_Filename( document ); + RB_Name_Headers( document->headers, document->no_headers ); + RB_CollectLinks( document, document->headers, document->no_headers ); + +However before this RB_Generate_MultiDoc() calls + + RB_Document_Determine_DocFilePaths( document ); + RB_Document_Create_DocFilePaths( document ); + RB_Document_Determine_DocFileNames( document ); + +This creates the documentation directory tree, which is a mirror image +of the source directory tree, and determines for each RB_Part +(sourcefile) the filename for the documentation file. +The information is later used in RB_Fill_Header_Filename(). + +RB_Fill_Header_Filename() stores the name of the file a header is +to be written to. In single doc mode RB_Fill_Header_Filename() this +filename is always the same (the filename specified with the +--doc option). In multidoc mode the filename can be different and is +based on the name computed in RB_Document_Determine_DocFileNames(). + +In singledoc mode a single file is now opened. For each part, +the headers in this part are written to this file. (So all +headers end up in the same file). + +In multidoc mode a new file is opened for each part, and the headers +in the part are written to this file. (So headers end up in +different files). + +In addition in multidoc mode a series of index files can be generated. + + + +===================================================================== + +General Flow + +Sourcecode ---> [ROBODoc] ---> Document. + +The whole ROBODoc process consists of three steps: scanning, +analysing, generating. + +Scanning + +ROBODoc scans the source directory tree. This collects the names of +all the source files. + +Analysing + +ROBODOc analyses all the sourcefiles. This reads the content of all +source files and collects all the headers. + +Generating + +In this step the headers are written to one or more documentation files. +In addition + +The data collected during scanning and analysing is stored in a +number of structures. + +RB_Directory, it stores the names of the sourcefiles and directories +in the source direcory tree. Files names are stored in a RB_Filename +structure, directory names in a RB_Path structure. Each RB_Filename +contains a pointer (path) a RB_Path that tells in which directory a +file is located. Each RB_Path has a pointer (parent) to another +RB_Path that tells of which directory is a directory located (of which +directory it is a subdirectory). The only exception is the root +directory. + +Besides the name of the sourcefile, the RB_Filename also stores the +name of the documentation file. + +For each sourcefile there is an RB_Part structure. It contains a +pointer (filename) to the RB_Filename and a list (headers) of +RB_Header structure containing the headers found in the sourcefile. + +Every RB_Header structure contains a pointer (owner) to the RB_Part +structure to which it belongs. Headers can form a hierarchy that is +used to create sections and subsections in the documentation. To +store this hierarchy every RB_header structure contains a pointer +(parent) to its parent header. For instance, given the following two +headers, SubModule is the parent of SubSubModule. + +/****h* TopModule/SubModule + * + ****/ + +/****h* SubModule/SubSubModule + * + ****/ + +In the documentation this creates the sections + +1.TopModule +1.1 SubModule +1.1.1 SubSubModule + + +The RB_Directory and the linked list of RB_Part structures are +stored in a RB_Document structure. + +During the generation of the documentation ROBODoc tries to create +cross links between the mention of a header's name (on object) and the +documentation generated from that header (the documentation for the +object). + +To aid this proces there is an array of RB_link structures. This +array is sorted for quick searching. + + diff --git a/Design/uml.fig b/Design/uml.fig new file mode 100644 index 0000000..53f8dbb --- /dev/null +++ b/Design/uml.fig @@ -0,0 +1,130 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +6 5400 8100 6900 9600 +6 5400 8100 6900 9600 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5400 8100 6900 8100 6900 9600 5400 9600 5400 8100 +4 1 0 50 0 12 12 0.0000 4 180 945 6150 8400 RB_Header\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 5400 8550 6900 8550 +-6 +6 5400 8100 6900 9600 +6 5400 8100 6900 9600 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5400 8100 6900 8100 6900 9600 5400 9600 5400 8100 +4 1 0 50 0 12 12 0.0000 4 180 945 6150 8400 RB_Header\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 5400 8550 6900 8550 +-6 +6 10200 900 11700 2400 +6 10200 900 11700 2400 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 10200 900 11700 900 11700 2400 10200 2400 10200 900 +4 1 0 50 0 12 12 0.0000 4 180 1260 10950 1200 RB_Directory\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 10200 1350 11700 1350 +-6 +6 3600 10500 5100 12000 +6 3600 10500 5100 12000 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 3600 10500 5100 10500 5100 12000 3600 12000 3600 10500 +4 1 0 50 0 12 12 0.0000 4 180 735 4350 10800 RB_Link\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 3600 10950 5100 10950 +-6 +6 300 10500 1800 12000 +6 300 10500 1800 12000 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 300 10500 1800 10500 1800 12000 300 12000 300 10500 +4 1 0 50 0 12 12 0.0000 4 135 735 1050 10800 Globals\001 +-6 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 300 10950 1800 10950 +-6 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 1800 4500 3300 4500 3300 6000 1800 6000 1800 4500 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 5400 4500 6900 4500 6900 6000 5400 6000 5400 4500 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 3300 4800 5400 4800 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 1 + 5100 4800 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 6900 4800 9000 4800 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 9000 4650 10500 4650 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 5400 4950 6900 4950 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 1800 4950 3300 4950 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 2 + 11700 4650 13200 4650 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 6150 6000 6150 8100 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 6150 6000 6150 8100 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 2550 6000 2550 8700 5400 8700 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 60.00 120.00 + 11700 1800 12600 1800 12600 4200 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 3 + 0 0 1.00 90.00 150.00 + 2550 4500 2550 1500 10200 1500 +2 1 0 1 0 7 50 0 -1 0.000 0 0 7 1 0 3 + 0 0 1.00 90.00 150.00 + 10200 1800 9600 1800 9600 4200 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 11700 4200 13200 4200 13200 5700 11700 5700 11700 4200 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 10500 4500 11700 4500 +2 2 0 1 0 7 50 0 -1 0.000 0 0 -1 0 0 5 + 9000 4200 10500 4200 10500 5700 9000 5700 9000 4200 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 4 + 0 0 1.00 60.00 120.00 + 6900 9300 8250 9300 8250 8400 6900 8400 +2 1 0 1 0 7 50 0 -1 0.000 0 0 -1 1 0 2 + 0 0 1.00 60.00 120.00 + 1800 11250 3600 11250 +4 1 0 50 0 12 12 0.0000 4 165 1155 2550 4800 RB_Document\001 +4 1 0 50 0 12 12 0.0000 4 165 735 6150 4800 RB_Part\001 +4 1 0 50 0 12 12 0.0000 4 165 525 4950 4650 parts\001 +4 1 0 50 0 12 12 0.0000 4 165 1155 4500 6450 RB_Document\001 +4 1 0 50 0 12 12 0.0000 4 180 1155 8250 4650 source_file\001 +4 1 0 50 0 12 12 0.0000 4 135 735 5700 7500 headers\001 +4 1 0 50 0 12 11 0.0000 4 105 360 4800 5100 0..*\001 +4 1 0 50 0 12 11 0.0000 4 105 360 5700 7800 0..*\001 +4 1 0 50 0 12 12 0.0000 4 180 1155 4650 8550 all_headers\001 +4 1 0 50 0 12 11 0.0000 4 105 360 4650 9000 0..*\001 +4 1 0 50 0 12 12 0.0000 4 135 525 9300 3300 files\001 +4 1 0 50 0 12 12 0.0000 4 180 525 12300 3300 paths\001 +4 1 0 50 0 12 11 0.0000 4 105 360 9300 3600 0..*\001 +4 1 0 50 0 12 11 0.0000 4 105 360 12300 3600 0..*\001 +4 1 0 50 0 12 11 0.0000 4 105 360 8550 5100 0..*\001 +4 1 0 50 0 12 12 0.0000 4 180 735 12450 4500 RB_Path\001 +4 1 0 50 0 12 12 0.0000 4 180 420 11400 4350 path\001 +4 1 0 50 0 12 12 0.0000 4 90 420 12450 4950 name\001 +4 1 0 50 0 12 12 0.0000 4 90 420 9750 4950 name\001 +4 1 0 50 0 12 12 0.0000 4 180 735 9750 4500 RB_File\001 +4 1 0 50 0 12 12 0.0000 4 135 735 9750 5250 docname\001 +4 1 0 50 0 12 12 0.0000 4 135 735 12450 5250 docname\001 +4 1 0 50 0 12 12 0.0000 4 165 630 7650 8250 parent\001 +4 1 0 50 0 12 12 0.0000 4 135 525 3300 11100 links\001 +4 1 0 50 0 12 11 0.0000 4 105 360 3300 11550 0..*\001 diff --git a/Docs/bugs.xml b/Docs/bugs.xml new file mode 100644 index 0000000..814e322 --- /dev/null +++ b/Docs/bugs.xml @@ -0,0 +1,8 @@ + +
    +Suggestions and Bugs + If you find any bugs, catch them, put them in a jar, and + send them to: Frans Slothouber at rfsber {at} xs4all.nl. Suggestions are also welcome at + this address. Flames can be directed to the sun. +
    + diff --git a/Docs/configuration.xml b/Docs/configuration.xml new file mode 100644 index 0000000..efb60fe --- /dev/null +++ b/Docs/configuration.xml @@ -0,0 +1,464 @@ + + +
    +Customizing ROBODoc + + ROBODoc can be configured with a configuration file called + robodoc.rc. With it you can define item + names, frequently used options, and translations for English + terms. One should note that if a configuration file is specified, + its definitions over-ride ROBODoc internal (i.e. built-in) settings. + This is a feature; some arbitrary language may include syntax + which conflicts with ROBODoc's internal markers. By taking advantage + of a configuration file, these sort of issues and conflicts + can be circumvented. An example is shown below. + + + +# Example robodoc.rc +# +items: + NAME + FUNCTION + SYNOPSIS + INPUTS + OUTPUTS + SIDE EFFECTS + HISTORY + BUGS + EXAMPLE +ignore items: + HISTORY + BUGS +item order: + FUNCTION + SYNOPSIS + INPUTS + OUTPUTS +source items: + SYNOPSIS +preformatted items: + INPUTS + OUTPUTS +format items: + FUNCTION + SIDE EFFECTS +options: + --src ./source + --doc ./doc + --html + --multidoc + --index + --tabsize 8 +headertypes: + J "Projects" robo_projects 2 + F "Files" robo_files 1 + e "Makefile Entries" robo_mk_entries + x "System Tests" robo_syst_tests + q Queries robo_queries +ignore files: + README + CVS + *.bak + *~ + "a test_*" +accept files: + *.c + *.h + *.pl +header markers: + /**** + #**** +remark markers: + * + # +end markers: + **** + #**** +header separate characters: + , +header ignore characters: + [ +remark begin markers: + /* +remark end markers: + */ +source line comments: + // +keywords: + if + do + while + for + + +The configuration file consists of a number of blocks. + Each block starts with a name followed by a + :. + In each block you define a number of values. Each value must + start with at least one space. + + +
    items block + In this block you can define the names of items that + ROBODoc should recognize. Item names can consist of more than + one word but should be written in all uppercase characters. + Define one item name per line. You do not need to put quotes + around them if they contain spaces. + + + If you do not define an items block ROBODoc uses its + default list of item names. If you define an items block + ROBODoc uses only those item names, any of the default items names + (except SOURCE) are no longer recognized. +
    + +
    ignore items block + In this block you can define the names of items that + ROBODoc should ignore when generating documentation. + This can be useful if you want to create documentation + for a client, but for instance do not want to include + the history items and bugs items. +
    + +
    item order block + In this block you can define the order in which items + are to appear in the generated documentation. + The items listed here will appear in the given order in the + generated documentation. Any remaining items appear + after these items in the order they were found in the header. + This allows you to make the documentation look more uniform. + +
    + +
    +source items block + In this block you can define the names of items that + ROBODoc handles in the same way as the SOURCE item. + +
    + +
    preformatted items block + + In this block you can define the names of items that should be always + preformatted. This is useful if you have the + option + specified and want specific items (like input and output lists) to be + automatically preformatted. See + for more + information. + +
    + +
    format items block + + In this block you can define the names of items that should be formatted by + the feature + (like function descriptions) even if the + + option has not been specified. + +
    + +
    options block + In this block you can define frequently used options. + The options you specify here are added to any options you + specify on the command line. + + See . + +
    + +
    +headertypes block + In this block you can define your own header types. + These are added to the existing header types. Each new + header type requires three parameters: the character used to + indicate a header of this type, the title for this type as + used in the master index and the name of the file in which the + index of this type is stored. If you use a character of an + existing header type, this header type is overwritten. + + + Additionally the sorting priority can also be specified for each header + type. Headers with higher priority will appear earlier in the + generated output. (For example you can make module definitions appear + at the beginning of a page.) If this parameter is omitted, the header + will have the priority 0 (lowest) by default. All pre-defined header + types have zero priority, except + "", + which has the sorting priority 1. + See . + +
    + +
    ignore files block + In this block you can define the names of files or + directories that ROBODoc should ignore while scanning + the directory tree for source files. You can use the + wildcard symbols * and + ?. If you use spaces in the expression + enclose the expression in quotes. + + + For instance, the rc file above causes ROBODoc + to skip all README files, all files with + the name CVS (these are usually + directories). It also skips all files with a name that ends + with .bak or ~ or + that start with a test_ + + Normally you specify the names of directories here + and do the filtering of file names with a accept files block. + +
    + +
    accept files block + In this block you can define the names of files that + robodoc should accept. This test is carried out after the + 'ignore files' filtering is performed. Any files that do + not match the patterns in this block are ignored by ROBODoc. + + + + If there is no accept files block all files are accepted. + +
    + +
    header markers block + + In this block you define what ROBODoc will recognize + as start of a header. If you use this block ROBODoc only + recognizes these markers, any of the inbuilt markers will + be ignored. + +
    + +
    remark markers block + + In this block you define what ROBODoc will recognize + as start of remark. If you use this block ROBODoc only + recognizes these markers, any of the inbuilt markers will + be ignored. + +
    + +
    end markers block + + In this block you define what ROBODoc will recognize + as end of a header. If you use this block ROBODoc only + recognizes these markers, any of the inbuilt markers will + be ignored. + +
    + +
    +header separate characters block + + In this block you can specify the separation character(s) for multiple + header names. The default character is "," (comma) if + this block is missing. See + + for more information. + +
    + +
    +header ignore characters block + + In this block you can specify character(s) where the evaluation of a header + should stop. The default character is "[" if this block + is missing. This is useful to supply additional information to the header + that ROBODoc should not care about. + + + For example one can include the version number of the function: + + ****f* financial.library/StealMoney [2.0] + + +
    + +
    +remark begin markers and remark end markers block + + Some languages allow remarks to span more than one line. They + start a remark with a begin marker and end it with another + marker. For instance in C you can have: + + + /* This is a + multi-line remark. + */ + + + Here the markers are /* and */. + If you tell ROBODoc what these markers are in a remark begin + markers block and remark end markers block. ROBODoc can skip + them in source items. + + We illustrate this with an example. Say we have a language + that start a remark with |* and + *|. We define SYNOPSIS + to be a source like item. If we now run ROBODoc on the + without a remark begin markers and + end markers block on the following piece of source, + + +|****f* Bar/foo + * FUNCTION + * foo computes the foo factor. + * SYNOPSIS + *| +int foo( float correction ) +|* + * BUGS + * None + * SOURCE + *| . +{ + return correction * 42.0; +} +|*****| + + +the extracted documentation will look like: + + + FUNCTION + foo computes the foo factor. + SYNOPSIS + *| + int foo( float correction ) + |* + BUGS + None + SOURCE + *| . + { + return correction * 42.0; + } + + +because ROBODoc considers + |* and *|.to be part of the + source, and not part of the begin or end of a header. + + If you add + +remark begin markers: + |* +remark end markers: + *| + +the output will look like: + + FUNCTION + foo computes the foo factor. + SYNOPSIS + int foo( float correction ) + BUGS + None + SOURCE + { + return correction * 42.0; + } + + + + These markers will also be used to highlight block comments if the + + option (or the + + option) is specified (Similar to + ). + + +
    + +
    source line comments block + + Here you can specify markers which start whole line comments. + (Comments that span until the end of line like "//", + "REM", ";", etc...) + These lines will be highlighted in the generated HTML + output if the + + option (or the + + option) has been specified. + + You don't need this if you have the + + option specified. + + + The default highlighting color can be changed in the CSS + file (span.comment). + +
    + +
    keywords block + + Here you can specify the keywords in your SOURCE items. + These keywords will be highlighted in the generated HTML + output if the + + option (or the + + option) has been specified. Keywords meant to be the language native ones + (for, if, etc...). + + + You don't need this if you have the + + option specified. + + + The default highlighting color can be changed in the CSS + file (span.keyword). + +
    + +
    Configuration file location + + ROBODoc searches the your current directory for the + robodoc.rc file. If it can't find + it there it will search in $HOME/, then + $HOMEDRIVE$HOMEPATH/, and finally in + /usr/share/robodoc/. + + With the option you can tell ROBODoc to + use a different file than robodoc.rc as + configuration file. This is handy if you want to create + documentation in different formats. For instance: + + +robodoc --rc htmlsingle.rc +robodoc --rc rtfsingle.rc +robodoc --rc htmlmulti.rc + + +
    + +
    + diff --git a/Docs/docbook-simple/sdocbook.dtd b/Docs/docbook-simple/sdocbook.dtd new file mode 100644 index 0000000..b7b016d --- /dev/null +++ b/Docs/docbook-simple/sdocbook.dtd @@ -0,0 +1,1886 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Docs/example_makefile b/Docs/example_makefile new file mode 100644 index 0000000..8d6459d --- /dev/null +++ b/Docs/example_makefile @@ -0,0 +1,4 @@ +# +# OBSOLETE +# + diff --git a/Docs/examples.xml b/Docs/examples.xml new file mode 100644 index 0000000..15005f6 --- /dev/null +++ b/Docs/examples.xml @@ -0,0 +1,164 @@ + + +
    +Examples of How to Create Documentation + +
    +HTML Example + For this you need a web browser, say FireFox or Mozilla. You can try + this in the robodoc root directory. It creates a document called + HDocs/masterindex.html plus a lot of smaller + documents from all the source files in the directory + Source. + + +robodoc ./Source ./HDocs + +
    + +
    +RTF Example + + For this you need an rtf reader, for instance + Word. You can try this in the robodoc root + directory. + + +robodoc ./Source api + + + This will create a document called + api.rtf. + + By default the document looks pretty plain. There is no + chapter numbering or a table of contents, even if you asked for + it. All the information for this is included but not visible. + This is because chapter numbering and a table of contents are + generated by Word based on formatting information that is part of + a Word document but not part of a RTF document. + + To make it visible you include the generated document into a + bigger document with the right formatting options. This is best + done with a cut-and-paste operation. Use the cut-past-paste + special menu, and paste it as RTF formatted text into your Word + document. + +
    + +
    +LaTeX Example + + For this you need latex and + makeindex. You can try this in the robodoc root + directory. It creates a single document called + api.dvi from all the source files in the + directory Source. + + +robodoc ./Source api +latex api.tex +latex api.tex +makeindex api.idx +latex api.tex +xdvi api.dvi + +
    + +
    +XML DocBook Example + + + DocBook is a xml format to create technical documentation, see. + DocBook.org. + DocBook is quite nice. This manual for instance is written in DocBook and + automatically translated into html and pdf format. + + + + You can use the DocBook output of ROBODoc to create several other formats, + for instance: html, pdf, html-help. + For this you need a tool that can process a DocBook file. There + are several of these tools. + + +
    + DocBook with html output + +The easiest to use is xsltproc. It works under + Windows and Unix. A typical workflow under Windows is: + + + +robodoc ./Source api +xsltproc api.xsl api.xml > api.html + + + + Where api.xsl contains: + + + + + + + + +]]> + + +For this you need xsltproc. For Windows these can be found at + + http://www.zlatkovic.com libxml.en.html, + and the stylesheets which can be found at + http://docbook.sourceforge.net/. + In the example above the style sheets are installed on e:/docbook/. + + + + More information about xsl can be found at + http://www.sagehill.net/docbookxsl/. + + +
    + +
    + DocBook with html help output + +The same program can be used to + + create a html help + file. For this you need + + HTML Help Workshop + . The workflow now is: + + + +robodoc ./Source api +xsltproc api.xsl api.xml +hhc htmlhelp.hhp + + + + Where api.xsl contains: + + + + + + + + +]]> + + +
    + + +
    +
    + diff --git a/Docs/extracting.xml b/Docs/extracting.xml new file mode 100644 index 0000000..25b66ad --- /dev/null +++ b/Docs/extracting.xml @@ -0,0 +1,121 @@ +
    +Extracting Documentation with ROBODoc + + Now that you have prepared your source code for use with + ROBODoc you are ready to extract the documentation. There are + several choices to be made. + +
    +Single document or many smaller documents + + First of all, ROBODoc can be used in three modes. + + + + multidoc -- in this mode ROBODoc scans + all the source files in your source directory and creates a + separate document file for each of these in a document directory. + The document directory is created automatically. Its structure is + a mirror of the structure of your source directory. + + singledoc -- in this mode ROBODoc scans all the source + files in your source directory and creates a single documentation + file that contains all the documentation extracted from your + source files. + + singlefile -- in this mode ROBODoc scans a single source + file and creates a single documentation file. + + +
    + +
    +multidoc + + The multidoc mode is useful to create browsable documents. + For instance many small HTML files that can be viewed with a + web-browser. This mode requires the following arguments: + + + robodoc + --src source directory + --doc document directory + --multidoc + other options + + + + An additional option that is useful with this mode is + , this creates a series of index files, + one for each header type. + +
    + + +
    +singledoc + + The singledoc mode is useful to create bulk documentation + that can be incorporated in other documents, or that can be + delivered to a client as a single document. For instance a file + created in RTF format can be included into a larger design + document written in Word format. This mode requires the following + arguments: + + + robodoc + --src source directory + --doc document file without extension + --singledoc + other options + + + + An additional option that is useful with this mode is + , this causes the headers to follow a + section layout based on the module element hierarchy defined in the + header name. + +
    + + +
    +singlefile + + The singlefile mode is not very useful. It is mainly used + for debugging purposes. This mode requires the following + arguments: + + + robodoc + --src source file + --doc document file + --singlefile + other options + + + +
    + +
    +Output formats + + Your next choice is the output format. ROBODoc can create + documentation in several formats: + + + HTML, option + RTF, option + LaTeX, option + XML DocBook, option + + + What format to use depends on your wishes. If you want a + single printable document, use LaTeX or XML DocBook. If you want + a document that can be included into a larger (Word) document use + RTF. If you want something that is browsable use HTML, or use XML + DocBook and then convert it to HTML. + +
    +
    + diff --git a/Docs/faq.dat b/Docs/faq.dat new file mode 100644 index 0000000..73ff6d7 --- /dev/null +++ b/Docs/faq.dat @@ -0,0 +1,73 @@ + + +General +What problem does ROBODoc solve? +
    TODO + +General +What is the target audience for ROBODoc? +TODO + +General +What are the possible uses for ROBODoc? +TODO + +General +On what platforms foes ROBODoc run? +Win32, Unix, GNU/Linux, and Mac. But it probably works on +other OS-es that have a C compiler too. + +General +What programming languages are supported? +TODO + +General +What human languages are supported? +TODO + +General +Where can I download ROBODoc? +TODO + +General +Are there other similar tools that are better? +TODO + + + +Theory +What are headers +TODO + +Theory +What are headertypes +TODO + +Theory +What are items +TODO + +Theory +Do item names need to be all captitals? +No. They can be anything you like, but they +can not be followed by other text. You can +define your itemnames in the ROBODoc configuration +file robodoc.rc + + + +Use +Why should I use headertypes +TODO + + + +Configuration +How can I define my own items? +TODO + +Configuration +How can I define my own headertypes? +TODO + diff --git a/Docs/faqfooter.html b/Docs/faqfooter.html new file mode 100644 index 0000000..b15a54b --- /dev/null +++ b/Docs/faqfooter.html @@ -0,0 +1,9 @@ +
    + +

    Copyright (c) 2004 Frans Slothouber

    + +

    This list of questions and answers was generated by +makefaq. + + + diff --git a/Docs/faqheader.html b/Docs/faqheader.html new file mode 100644 index 0000000..3f9ab82 --- /dev/null +++ b/Docs/faqheader.html @@ -0,0 +1,25 @@ + + + + + +ROBODoc Frequently-Asked Questions + + + + + + + + +

    + +ROBODoc Frequently-Asked Questions + +

    + + +

    For more information about this faq, please contact Frans Slothouber + +


    diff --git a/Docs/header_specs.pl b/Docs/header_specs.pl new file mode 100644 index 0000000..53e08a3 --- /dev/null +++ b/Docs/header_specs.pl @@ -0,0 +1,203 @@ +#!/usr/bin/perl -w + +use strict; +use warnings; +use IO::File; + + +#------------------------------------------ +# +my @header_specs = ( + { language => [ 'C' ], + begin => '/****', + mid => '*', + end_1 => '****', + end_2 => '/****', + rem_begin => '/*', + rem_end => '*/' + }, + + { language => [ 'Modula-2' ], + begin => '(****', + mid => '*', + end_1 => '****', + end_2 => '(****', + rem_begin => '(*', + rem_end => '*)' + }, + + { language => [ 'Pascal' ], + begin => '{****', + mid => '*', + end_1 => '****', + end_2 => '{****', + rem_begin => '{*', + rem_end => '*}' + }, + + { language => [ 'C++' ], + begin => '//****', + mid => '//', + end_2 => '//****', + }, + + { language => [ 'Tcl', 'Perl' ], + begin => '#****', + mid => '#', + end_2 => '#****', + }, + + { language => [ 'LaTeX/TeX', 'Postscript' ], + begin => '%****', + mid => '%', + end_2 => '%****', + }, + + { language => [ 'Occam' ], + begin => '__****', + mid => '__', + end_2 => '__****', + }, + + +); + +#-------------------------------------------------------------------- +# + + +sub make_robodoc_rc_file { + my $spec = shift; + my $rc_file = ""; + + $rc_file .= "header markers:\n"; + $rc_file .= " $spec->{begin}\n"; + $rc_file .= "remark markers:\n"; + $rc_file .= " $spec->{mid}\n"; + $rc_file .= "end markers:\n"; + if ( exists( $spec->{end_1} ) ) { + $rc_file .= " $spec->{end_1}\n"; + } + if ( exists( $spec->{end_2} ) ) { + $rc_file .= " $spec->{end_2}\n"; + } + + if ( exists( $spec->{rem_end} ) ) { + $rc_file .= "remark begin markers:\n"; + $rc_file .= " $spec->{rem_begin}\n"; + $rc_file .= "remark end markers:\n"; + $rc_file .= " $spec->{rem_end}\n"; + } + + return $rc_file; +} + + +# +# given a header spec this returns an example header +# that does not contain any source items. +# +sub make_example_header_simple { + my $spec = shift; + my $header = ""; + + $header = $spec->{begin} . "f* ModuleName/Foo\n"; + $header .= $spec->{mid} . " FUNCTION\n"; + $header .= $spec->{mid} . " Foo computes the foo factor\n"; + $header .= $spec->{mid} . " using a fudge factor.\n"; + if ( exists( $spec->{end_1} ) ) { + $header .= $spec->{end_1} . "\n"; + $header .= $spec->{rem_end} . "\n"; + } else { + $header .= $spec->{end_2} . "\n"; + } +} + + +sub make_example_header { + my $spec = shift; + my $header = ""; + + $header = $spec->{begin} . "f* ModuleName/Foo\n"; + $header .= $spec->{mid} . " FUNCTION\n"; + $header .= $spec->{mid} . " Foo computes the foo factor\n"; + $header .= $spec->{mid} . " using a fudge factor.\n"; + $header .= $spec->{mid} . " SYNOPSIS\n"; + if ( exists( $spec->{rem_end} ) ) { + $header .= $spec->{rem_end} . "\n"; + } else { + + } + $header .= "int Foo( int fudge )\n"; + if ( exists( $spec->{rem_begin} ) ) { + $header .= $spec->{rem_begin} . "\n"; + } else { + + } + $header .= $spec->{mid} . " INPUTS\n"; + $header .= $spec->{mid} . " fudge -- the fudge factor\n"; + $header .= $spec->{mid} . " SOURCE\n"; + if ( exists( $spec->{rem_end} ) ) { + $header .= $spec->{rem_end} . "\n"; + } else { + + } + + $header .= "\n more source code..\n\n"; + + if ( exists( $spec->{rem_end} ) ) { + $header .= $spec->{end_2}; + $header .= $spec->{rem_end} . "\n"; + } else { + $header .= $spec->{end_2} . "\n"; + } + + return $header; +} + + + + +sub make_examples_for_manual { + my $filename = "header_examples.xml"; + my $file = IO::File->new(">$filename") or die "$filename : $!"; + foreach my $spec ( @header_specs ) { + foreach my $language ( @{$spec->{language}} ) { + print $file "
    \n"; + print $file "$language\n"; + print $file "\n\n"; + + print $file "\n"; + print $file "A simple header without any source items in $language.\n"; + print $file "\n"; + print $file make_example_header_simple( $spec ); + print $file "\n"; + print $file "\n"; + print $file "\n\n"; + + print $file "\n"; + print $file "A header with source items in $language.\n"; + print $file "\n"; + print $file make_example_header( $spec ); + print $file "\n"; + print $file "\n"; + print $file "\n\n"; + + print $file "\n"; + print $file "The robodoc.rc file required for $language if it were not supported by default.\n"; + print $file "\n"; + print $file make_robodoc_rc_file( $spec ); + print $file "\n"; + print $file "\n"; + + print $file "
    \n"; + } + } + + $file->close(); +} + + + +make_examples_for_manual; + diff --git a/Docs/installing.xml b/Docs/installing.xml new file mode 100644 index 0000000..58972ab --- /dev/null +++ b/Docs/installing.xml @@ -0,0 +1,33 @@ + + +
    + Installing ROBODoc + The easiest way to install ROBODoc is to use one of the + packages. There are package for RedHat, Debian, OSX, and a precompiled + executable for Windows. + You can also compile --- from the sources. On a system + with autoconfig it is as simple as: + +./configure +make +make install + + This currently does not work with cygwin. + Under Windows you can use one of the makefile. There is a makefile for Borland C, MINGW, + and Cygwin. For other compilers you might want to try makefile.plain. + + For instance for cygwin goto Source and run: + +make -f makefile.mingw-cygwin + + To install ROBODoc put the generated executable somewhere in your path. + You can test your executable, by going to the + Examples/PerlExample directory in the + archive, and running robodoc. + This should create a directory + called Doc. In there you should now + find a file called masterindex.html. + +
    diff --git a/Docs/main.css b/Docs/main.css new file mode 100644 index 0000000..5a5c7a0 --- /dev/null +++ b/Docs/main.css @@ -0,0 +1,139 @@ +body + { + margin-top:1em; + margin-bottom:1em; + margin-left:2.5em; + margin-right:2.5em; + font-family:sans-serif; + } + +/* +a:link + { + color:#00FF00; + } + +a:visited + { + color:#003333; + } + +a:active + { + color:#FF00FF; + } +*/ + +p, form + { + font-family:sans-serif; + font-size:12pt; + } + +/* +p + { + text-align:justify; + } +*/ + +b, strong, i, em, cite, var, tt, code, kbd, samp, img + { + display:inline; + } + +ul + { + margin-top:1em; + margin-bottom:1em; + list-style-type:disc; + display:block; + } + +li + { + margin-bottom:0.2em; + } + +b, strong + { + font-variant:small-caps; + font-weight:bold; + } + +i, cite, em, var, address, blockquote + { + font-style:italic; + } + +pre, tt, kbd, samp + { + font-family:monospace; + } + + +table + { + color:#000000; + background-color:#AAAAAA; + } + +tt + { + white-space:pre; + } + +code + { + font-family:monospace; + font-style:normal; + white-space:pre; + } + +pre + { + white-space:pre; + margin-top:0.5em; + } + +address + { + font-family:monospace; + font-size:12pt; + text-align:left; + margin-bottom:0.5em; + } + + + +h2, h3 + { + margin-top:0.5em; + } + +h1, h2, h3 + { + font-weight:bold; + } + +h1 + { + font-family:sans-serif; + font-size:24pt; + text-align:right; + margin-right:36px; + margin-top:0.5em; + margin-bottom:0.5em; + } + +h2 + { + font-family:sans-serif; + font-size:18pt; + } + +h3 + { + font-family:sans-serif; + font-size:14pt; + } diff --git a/Docs/makefile.am b/Docs/makefile.am new file mode 100644 index 0000000..e2515f5 --- /dev/null +++ b/Docs/makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to produce Makefile.in + +man_MANS = robodoc.1 robohdrs.1 + +if FINK +man1_MANS = robodoc.1 robohdrs.1 +else +man1_MANS = robodoc.1 robohdrs.1 +endif + +#if FINK +#docdir = $(prefix)/share/doc/$(PACKAGE) +#else +#docdir = $(prefix)/doc/$(PACKAGE)-$(VERSION) +#endif + +if FINK +doc_DATA = manual.html manual.css robodoc.rc +else +doc_DATA = manual.html manual.css robodoc.rc +endif + +# +# End of automake +# diff --git a/Docs/makefile.cygwin b/Docs/makefile.cygwin new file mode 100644 index 0000000..f9bbc92 --- /dev/null +++ b/Docs/makefile.cygwin @@ -0,0 +1,38 @@ +# Make the documentation under the CYGWIN environment... +# $Id: makefile.cygwin,v 1.3 2006/08/06 20:46:21 thuffir Exp $ + +CP = cp +RM = rm -rf + +SOURCE = manual.xml preparing.xml options.xml tips.xml installing.xml examples.xml extracting.xml bugs.xml configuration.xml header_examples.xml + + +# Manual as a single HTML file +manual.html : $(SOURCE) manual-cygwin.xsl + xsltproc manual-cygwin.xsl manual.xml > manual.html + +header_examples.xml : header_specs.pl + perl header_specs.pl + +# Manual in Windows help format. +htmlhelp.chm : $(SOURCE) manual_html_help-cygwin.xsl + xsltproc manual_html_help-cygwin.xsl manual.xml + -hhc htmlhelp.hhp + $(CP) htmlhelp.chm manual.chm + +# Clean up. +clean : + $(RM) \ + manual.html \ + index.html \ + ar*.html \ + *.chm \ + *.hhc \ + *.hhp \ + header_examples.xml \ + +all : manual.html htmlhelp.chm + +# Lint the manual to detect errors against the DTD. +test : manual.html + xmllint --noent --noout manual.xml diff --git a/Docs/makefile.plain b/Docs/makefile.plain new file mode 100644 index 0000000..1dbecde --- /dev/null +++ b/Docs/makefile.plain @@ -0,0 +1,19 @@ +# $Id: makefile.plain,v 1.1 2007/06/23 16:29:59 gumpu Exp $ + +SOURCE = manual.xml preparing.xml options.xml tips.xml installing.xml examples.xml extracting.xml bugs.xml configuration.xml header_examples.xml + +# Manual as a single HTML file +manual.html : $(SOURCE) manual.xsl + xsltproc manual.xsl manual.xml > manual.html + +header_examples.xml : header_specs.pl + perl header_specs.pl + + +clean : + +all : manual.html + +# Lint the manual to detect errors against the DTD. +test : + xmllint --noent --noout manual.xml diff --git a/Docs/makefile.win32 b/Docs/makefile.win32 new file mode 100644 index 0000000..d3de843 --- /dev/null +++ b/Docs/makefile.win32 @@ -0,0 +1,30 @@ +# $Id: makefile.win32,v 1.5 2007/02/06 22:31:38 gumpu Exp $ + +SOURCE = manual.xml preparing.xml options.xml tips.xml installing.xml examples.xml extracting.xml bugs.xml configuration.xml header_examples.xml + + +# Manual as a single HTML file +manual.html : $(SOURCE) manual.xsl + xsltproc manual.xsl manual.xml > manual.html + +header_examples.xml : header_specs.pl + perl header_specs.pl + +# Manual in Windows help format. +htmlhelp.chm : $(SOURCE) manual_html_help.xsl + xsltproc manual_html_help.xsl manual.xml + -hhc htmlhelp.hhp + copy htmlhelp.chm manual.chm + +clean : + -del ar*.html + -del *.chm + -del *.hhc + -del *.hhp + -del header_examples.xml + +all : manual.html htmlhelp.chm + +# Lint the manual to detect errors against the DTD. +test : + xmllint --noent --noout manual.xml diff --git a/Docs/manual-cygwin.xsl b/Docs/manual-cygwin.xsl new file mode 100644 index 0000000..b0aba10 --- /dev/null +++ b/Docs/manual-cygwin.xsl @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Docs/manual.css b/Docs/manual.css new file mode 100644 index 0000000..a591c71 --- /dev/null +++ b/Docs/manual.css @@ -0,0 +1,57 @@ +body +{ + background-color: #ffffff; + color: #000000; + font-family: 'Lucida Grande', Verdana, + Geneva, Lucida, Arial, + Helvetica, sans-serif; + font-size: 10pt; + margin: 2% 5%; +} +h1.title +{ + color: #000000; + text-align: left; + font-size: 16pt; + margin-top: 10%; +} + +h2.title +{ + color: #000000; + text-align: left; + font-size: 14pt; + margin-top: 3%; +} +h3.title +{ + color: #000000; + text-align: left; + font-size: 11pt; + margin-top: 3%; +} + +h3.author +{ + color: #000000; + text-align: left; + font-size: 10pt; +} +td.even, td.uneven +{ + color: #000000; + font-size: 10pt; +} +td.even +{ + background-color: #eeeeee; +} +pre.programlisting, pre.literallayout +{ + background:#ffe; + font-family: monospace; + border:solid #aa9 2px; + margin:4px; + white-space: pre; +} + diff --git a/Docs/manual.html b/Docs/manual.html new file mode 100644 index 0000000..8af0ffa --- /dev/null +++ b/Docs/manual.html @@ -0,0 +1,1690 @@ + + +ROBODoc 4.99.34 User Manual

    ROBODoc 4.99.34 User Manual

    Frans Slothouber

    Petteri Kettunen

    Gergely Budai

    Apr 2007


    1. Preface

    ROBODoc is an API documentation tool for C, C++, Java, Assembler, + Basic, Fortran, LaTeX, Postscript, Tcl/Tk, LISP, Forth, Perl, Shell + Scripts, Makefiles, Occam, COBOL, DCL, Visual Basic, HTML, DB/C, XML, + and many other languages. It can be made to work with any language that + supports comments.

    ROBODoc works by extracting specially formatted headers from your + source code and writes these to documentation files. These files can be + formatted in HTML, ASCII, XML DocBook, or RTF; and indirectly to + PDF and HTML Help.

    ROBODoc is similar to JavaDoc, though the idea is much + older than JavaDoc. ROBODoc allows you to maintain a program and + its documentation in a single file. This makes it easier to keep + your documentation up-to-date.

    ROBODoc can be used to document anything you like, + functions, methods, variables, definitions, test cases, makefile + entries, and anything else you can think of.

    It can create documentation consisting of many small files. + For instance in HTML format for easy browsing and publication on + the web. It can also create a single file in LaTeX or RTF format + for inclusion into bigger design documents. The RTF format is + suited to be included in Word documents.

    ROBODoc allows you to separate internal documentation from + external documentation. In singledoc mode it can create a section + layout based on the hierarchy of your modules.

    ROBODoc is designed to work with a lot of different + programming languages. It has no knowledge of the syntax of + programming languages. It only has some knowledge about how + comments start and end in a lot of programming languages. This + means that you sometimes have to do a little more work compared to + other tools that have detailed knowledge of the syntax of a + particular language. They can use that knowledge to figure out + some of the information automatically. This usually also means + that they work only with one or two languages.

    2. Installing ROBODoc

    The easiest way to install ROBODoc is to use one of the + packages. There are package for RedHat, Debian, OSX, and a precompiled + executable for Windows.

    You can also compile --- from the sources. On a system + with autoconfig it is as simple as:

    +./configure
    +make
    +make install
    +

    This currently does not work with cygwin.

    Under Windows you can use one of the makefile. There is a makefile for Borland C, MINGW, + and Cygwin. For other compilers you might want to try makefile.plain. +

    For instance for cygwin goto Source and run:

    +make -f makefile.mingw-cygwin
    +

    To install ROBODoc put the generated executable somewhere in your path.

    You can test your executable, by going to the + Examples/PerlExample directory in the + archive, and running robodoc. + This should create a directory + called Doc. In there you should now + find a file called masterindex.html. +

    3. Preparing your source code for ROBODoc

    ROBODoc allows you to mix the program documentation with + the source code. It does require though that this documentation + has a particular layout so ROBODoc can recognize it. There are + three key concepts: headers, items, and sections.

    3.1. Headers

    Headers are the building blocks of the documentation. Lets + look at an example. The following header was taken from the + documentation of the predecessor of ROBODoc, AutoDoc.

    Example 1. A ROBODoc header in C.

    + /****f* financial.library/StealMoney
    +  *  NAME
    +  *    StealMoney -- Steal money from the Federal Reserve Bank. (V77)
    +  *  SYNOPSIS
    +  *    error = StealMoney( userName, amount, destAccount, falseTrail )
    +  *  FUNCTION
    +  *    Transfer money from the Federal Reserve Bank into the
    +  *    specified interest-earning checking account.  No records of
    +  *    the transaction will be retained.
    +  *  INPUTS
    +  *    userName    - name to make the transaction under.  Popular
    +  *                  favorites include "Ronald Reagan" and
    +  *                  "Mohamar Quadaffi".
    +  *    amount      - Number of dollars to transfer (in thousands).
    +  *    destAccount - A filled-in AccountSpec structure detailing the
    +  *                  destination account (see financial/accounts.h).
    +  *                  If NULL, a second Great Depression will be
    +  *                  triggered.
    +  *    falseTrail  - If the DA_FALSETRAIL bit is set in the
    +  *                  destAccount, a falseTrail structure must be
    +  *                  provided.
    +  *  RESULT
    +  *    error - zero for success, else an error code is returned
    +  *           (see financial/errors.h).
    +  *  EXAMPLE
    +  *    Federal regulations prohibit a demonstration of this function.
    +  *  NOTES
    +  *    Do not run on Tuesdays!
    +  *  BUGS
    +  *    Before V88, this function would occasionally print the
    +  *    address and home phone number of the caller on local police
    +  *    976 terminals.  We are confident that this problem has been
    +  *    resolved.
    +  *  SEE ALSO
    +  *    CreateAccountSpec(),security.device/SCMD_DESTROY_EVIDENCE,
    +  *    financial/misc.h
    +  ******
    +  * You can use this space for remarks that should not be included
    +  * in the documentation.
    +  */
    +

    A header consists of three different elements: a + begin marker, a number of items, and an end marker. The begin marker + in the example is:

    +  ****f* financial.library/StealMoney
    +

    It marks the beginning of a header. It also tells ROBODoc +

    • the name of the element that is being documented, StealMoney,

    • the module it is part of, financial.library,

    • the kind of element, f, which stands for function.

    + ROBODoc always expects that a / separates the module name and an element name. + So ModFoo/funcBar + is a valid name, but funcBar is not. + See Sections for more + information. +

    + Names can also contain spaces but ROBODoc won't create links to names with + embedded spaces. +

    + You can also have multiple names for a header. This is useful if you + document similar objects together in one header (for example assembly + subroutines with multiple jump-in points). Multiple names are separated by + commas and can span over more than one line. +

    +  ****f* financial.library/StealMoney, Steal_Money
    +

    + In the above example all references found to StealMoney + and Steal_Money in other headers will be automatically + linked to this header. + The separation character(s) can be specified by the + header separate characters block. + See Customizing ROBODoc for more + information. +

    +The end marker: +

    +  ******
    +

    + marks the end of a header. +

    Items begin with an item name and are followed by the + item's body. An example:

    +  *  FUNCTION
    +  *    Transfer money from the Federal Reserve Bank into the
    +  *    specified interest-earning checking account.  No records of
    +  *    the transaction will be retained.
    +

    + In this case the item's name is FUNCTION. +

    + Each line of an item starts with a remark marker. In this case + *. +

    That what ROBODoc needs to recognize a header is therefore:

    Example 2. The markers needed by ROBODoc to recognize a header.

    + /****f* financial.library/StealMoney
    +  *  NAME
    +  *
    +  *  SYNOPSIS
    +  *
    +  *  FUNCTION
    +  *
    +  *
    +  *
    +  *  INPUTS
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *
    +  *  RESULT
    +  *
    +  *
    +  *  EXAMPLE
    +  *
    +  *  NOTES
    +  *
    +  *  BUGS
    +  *
    +  *
    +  *
    +  *
    +  *  SEE ALSO
    +  *
    +  *
    +  ******
    +

    + The above example is in C. ROBODoc supports many more + languages though. See Languages Supported by Default. +

    3.2. Header Types

    ROBODoc defines a number of header types. You don't need + to use them but they can be useful for sorting information. The + header type tells ROBODoc what kind of object you are documenting. + This information allows ROBODoc to create more useful index + tables.

    The type is identified by one or two characters. ROBODoc + expects to find them after the fourth * in the + begin marker. So #****f is a valid marker, + but #**f** is not.

    If a single character is given, the type is defined as + listed in the following table

    Table 1. Default header types

    cHeader for a class
    dHeader for a constant (from define)
    fHeader for a function
    hHeader for a module in a project
    mHeader for a method
    sHeader for a structure
    tHeader for a types
    uHeader for a unit test
    vHeader for a variable
    *Generic header for everything else

    If two characters are given, the first character should be + i and the second can be any of the other + characters from the table above. This creates an internal header + of the type specified by the second character. Internal headers + are special. They can be used to hide certain headers. They are + only extracted if requested. You can use them to document internal + functions, classes, etc. that you do not want clients to see, + creating what might be a programmer's manual as opposed to a + user's manual.

    So /****if* Module/func1 defines an + internal function called func1. +

    Headers marked internal are by default not included in the + generated documentation. If you want to include them use the + option --internal. You can also generate the + documentation from only the internal headers with the option + --internalonly. +

    You can define your own header types using the ROBODoc + configuration file, robodoc.rc. + See headertypes block. + This way you can document anything you like, for instance makefile + entries, system tests, or exceptions. +

    3.3. Items

    By default ROBODoc recognizes the following items:

    + NAME +

    Item name plus a short description. +

    + COPYRIGHT +

    Who own the copyright : "(c) <year>-<year> by + <company/person>" +

    + SYNOPSIS + , + USAGE +

    + How to use it. +

    + FUNCTION + , + DESCRIPTION + , + PURPOSE +

    + What does it do. +

    + AUTHOR +

    + Who wrote it. +

    + CREATION DATE +

    When did the work start. +

    + MODIFICATION HISTORY + , + HISTORY +

    Who has done which changes and when. +

    + INPUTS + , + ARGUMENTS + , + OPTIONS + , + PARAMETERS + , + SWITCHES +

    + What can we feed into it. +

    + OUTPUT + , + SIDE EFFECTS +

    What output is made. +

    + RESULT + , + RETURN VALUE +

    + What do we get returned. +

    + EXAMPLE +

    + A clear example of the items use. +

    + NOTES +

    + Any annotations +

    + DIAGNOSTICS +

    Diagnostic output. +

    + WARNINGS + , + ERRORS +

    Warning and error-messages. +

    + BUGS +

    Known bugs. +

    + TODO + , + IDEAS +

    What to implement next and ideas.

    + PORTABILITY +

    Where does it come from, where will it work.

    + SEE ALSO +

    References to other functions, man pages, other documentation.

    + METHODS + , + NEW METHODS +

    OOP methods.

    + ATTRIBUTES + , + NEW ATTRIBUTES +

    OOP attributes.

    + TAGS +

    Tag-item description. +

    + DERIVED FROM +

    OOP super class.

    + DERIVED BY +

    OOP sub class.

    + USES + , + CHILDREN +

    What modules are used by this one.

    + USED BY + , + PARENTS +

    Which modules do use this one.

    + COMMANDS +

    Command description.

    + SOURCE +

    Source code inclusion.

    You can define your own items using the ROBODoc + configuration file, robodoc.rc. See Customizing ROBODoc.

    3.4. Sections

    The structure of source code for a project is usually + hierarchical. A project might consists of several applications, + an application of several modules, a module of several functions + or even sub modules. ROBODoc allows you to show this hierarchy in + your documentation. For this you specify the hierarchy in the + header name. For instance, you have a project that is going to + create a new language called D. The D Language project might + consists of three applications: a preprocessor, a compiler, and a + linker. The compiler consists of two modules, a parser and a + generator. The parser module consists of several + functions.

    The following three headers show how this hierarchy can be + defined in the header name.

    +#****h* D-Language/Compiler
    +# FUNCTION
    +#   The compiler takes a preprocessed source file and
    +#   turns it into an object file.
    +#***
    +
    +#****h* D-Language/Linker
    +# FUNCTION
    +#   The linker module contains functions that scan a
    +#   object file and build the executable.
    +#***
    +
    +#****h* Compiler/Parser
    +# FUNCTION
    +#   The parser module contains functions that scan a
    +#   preprocessed source file and build the syntax tree.
    +#***
    +
    +#****f* Parser/ReadToken
    +# FUNCTION
    +#   ReadToken reads the next token from the input
    +#   file.
    +#***
    +

    When you generate documentation with the option + --section, ROBODoc uses the hierarchical + information when generating the table of contents and document + section information. For instance in HTML sections are started + with <H1>, <H2>, <H3> depending on the level + in the hierarchy. The table of contents will also contain levels. The + table of contents for the above example will be:

    +1. D-Language/Compiler
    +1.1 Compiler/Parser
    +1.1.1 Parser/ReadToken
    +2. D-Language/Linker
    +

    3.5. Smart Text Formatting

    By default ROBODoc creates preformatted text in the output +documentation for all the text it finds in an item. This means +that the formatting of the output looks the same as the formatting of +the text of an item. Line-breaks and indentation stay the same. +This is easy but does not always create the best looking +output.

    ROBODoc can also try to deduce the formatting of your text based +on the layout and indentation of your text and on special characters in the text. +It works a bit similar to the input method of Wikis. In the context of this +manual this is called Smart Formatting. +

    You switch this on with the option --nopre. +ROBODoc now tries to find three kind of elements: paragraphs, +lists, and preformatted text.

    Paragraphs are separated by empty lines. So the following item +has two paragraphs.

    Example 3. Two paragraphs.

    +  FUNCTION
    +    This function does something.
    +
    +    And it then does something else
    +    and a bit more.
    +

    A List starts with a line that ends with a ':' which is then +followed by one or more list items. List items should start with '*', +'-', or 'o'. So the following item contains a valid list:

    Example 4. A list.

    +  FUNCTION
    +     This function does:
    +     * a lot of foo
    +     * some snafuing
    +     * and a bit of foobarring.
    +

    A list item can span more than one line if the second and following +lines are indented. So this is also a valid list:

    Example 5. A list where one of the items spans more than one line.

    +  FUNCTION
    +     This function does:
    +     * a lot of foo and preprocessing of the
    +       raw input with the aid
    +       of the some magic
    +     * some snafuing
    +     * and a bit of foobarring.
    +

    If list items directly follow the name of a robodoc item they +also form a valid list. So this is a valid list:

    Example 6. an implicit list

    +  INPUTS
    +    * inputname -- the name of the input file
    +    * outputname -- the name of the output file
    +    * n -- the number of characters to be written
    +

    Preformatted text is indicated by indenting it more that the +surrounding text. The first non-empty line in an item determines the +base indenting. Any lines with an indentation larger than this are +preformatted. An example:

    Example 7. Preformatted text

    +   FUNCTION
    +     The following lines are preformatted
    +        +--------+
    +        | A box  |
    +        |        |
    +        +--------+
    +     End of the preformatted text.
    +

    The following is a complete example.

    Example 8. All three elements of smart formatting.

    +    This is some example text.
    +    And some more.
    +
    +    This is even more, and we start a list:
    +    * a list item
    +    * a list item
    +    * a list item
    +
    +    And we can also do preformatted stuff
    +    by indenting
    +        +--------+
    +        |        |
    +        +--------+
    +    The box will stay.
    +

    will be turn into

    Example 9. The corresponding HTML output.

    +    <p>This is some example text.
    +    And some more.</p>
    +
    +    <p>This is even more, and we start a list:</p>
    +    <ul>
    +    <li>a list item</li>
    +    <li>a list item</li>
    +    <li>a list item</li>
    +    </ul>
    +
    +    <p>And we can also do preformatted stuff
    +    by indenting</p>
    +    <pre>
    +        +--------+
    +        |        |
    +        +--------+
    +    </pre>
    +    <p> The box will stay.</p>
    +

    4. Extracting Documentation with ROBODoc

    Now that you have prepared your source code for use with + ROBODoc you are ready to extract the documentation. There are + several choices to be made.

    4.1. Single document or many smaller documents

    First of all, ROBODoc can be used in three modes.

    • multidoc -- in this mode ROBODoc scans + all the source files in your source directory and creates a + separate document file for each of these in a document directory. + The document directory is created automatically. Its structure is + a mirror of the structure of your source directory.

    • singledoc -- in this mode ROBODoc scans all the source + files in your source directory and creates a single documentation + file that contains all the documentation extracted from your + source files.

    • singlefile -- in this mode ROBODoc scans a single source + file and creates a single documentation file.

    4.2. multidoc

    The multidoc mode is useful to create browsable documents. + For instance many small HTML files that can be viewed with a + web-browser. This mode requires the following arguments:

    + robodoc + --src source directory + --doc document directory + --multidoc + other options + +

    An additional option that is useful with this mode is + --index, this creates a series of index files, + one for each header type.

    4.3. singledoc

    The singledoc mode is useful to create bulk documentation + that can be incorporated in other documents, or that can be + delivered to a client as a single document. For instance a file + created in RTF format can be included into a larger design + document written in Word format. This mode requires the following + arguments:

    + robodoc + --src source directory + --doc document file without extension + --singledoc + other options + +

    An additional option that is useful with this mode is + --sections, this causes the headers to follow a + section layout based on the module element hierarchy defined in the + header name.

    4.4. singlefile

    The singlefile mode is not very useful. It is mainly used + for debugging purposes. This mode requires the following + arguments:

    + robodoc + --src source file + --doc document file + --singlefile + other options + +

    4.5. Output formats

    Your next choice is the output format. ROBODoc can create + documentation in several formats:

    • HTML, option --html

    • RTF, option --rtf

    • LaTeX, option --latex

    • XML DocBook, option --dbxml

    What format to use depends on your wishes. If you want a + single printable document, use LaTeX or XML DocBook. If you want + a document that can be included into a larger (Word) document use + RTF. If you want something that is browsable use HTML, or use XML + DocBook and then convert it to HTML.

    5. Examples of How to Create Documentation

    5.1. HTML Example

    For this you need a web browser, say FireFox or Mozilla. You can try + this in the robodoc root directory. It creates a document called + HDocs/masterindex.html plus a lot of smaller + documents from all the source files in the directory + Source.

    +robodoc --src ./Source --doc ./HDocs --multidoc --index --html
    +

    5.2. RTF Example

    For this you need an rtf reader, for instance + Word. You can try this in the robodoc root + directory.

    +robodoc --src ./Source --doc api --singledoc --rtf --sections
    +

    This will create a document called + api.rtf.

    By default the document looks pretty plain. There is no + chapter numbering or a table of contents, even if you asked for + it. All the information for this is included but not visible. + This is because chapter numbering and a table of contents are + generated by Word based on formatting information that is part of + a Word document but not part of a RTF document.

    To make it visible you include the generated document into a + bigger document with the right formatting options. This is best + done with a cut-and-paste operation. Use the cut-past-paste + special menu, and paste it as RTF formatted text into your Word + document.

    5.3. LaTeX Example

    For this you need latex and + makeindex. You can try this in the robodoc root + directory. It creates a single document called + api.dvi from all the source files in the + directory Source.

    +robodoc --src ./Source --doc api --singledoc --latex --sections
    +latex api.tex
    +latex api.tex
    +makeindex api.idx
    +latex api.tex
    +xdvi api.dvi
    +

    5.4. XML DocBook Example

    + DocBook is a xml format to create technical documentation, see. + DocBook.org. + DocBook is quite nice. This manual for instance is written in DocBook and + automatically translated into html and pdf format. +

    + You can use the DocBook output of ROBODoc to create several other formats, + for instance: html, pdf, html-help. + For this you need a tool that can process a DocBook file. There + are several of these tools. +

    5.4.1. DocBook with html output

    The easiest to use is xsltproc. It works under + Windows and Unix. A typical workflow under Windows is: +

    +robodoc --src ./Source --doc api --singledoc --dbxml --sections
    +xsltproc api.xsl api.xml > api.html
    +

    + Where api.xsl contains: +

    +<?xml version='1.0'?>
    +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    +    <xsl:import href="e:/docbook/html/docbook.xsl"/>
    +    <xsl:param name="admon.graphics" select="1"/>
    +    <xsl:param name="section.autolabel" select="1"/>
    +</xsl:stylesheet>
    +
    +

    For this you need xsltproc. For Windows these can be found at + + http://www.zlatkovic.com libxml.en.html, + and the stylesheets which can be found at + http://docbook.sourceforge.net/. + In the example above the style sheets are installed on e:/docbook/. +

    + More information about xsl can be found at + http://www.sagehill.net/docbookxsl/. +

    5.4.2. DocBook with html help output

    The same program can be used to + + create a html help + file. For this you need + + HTML Help Workshop + . The workflow now is: +

    +robodoc --src ./Source --doc api --singledoc --dbxml --sections
    +xsltproc api.xsl api.xml
    +hhc htmlhelp.hhp
    +

    + Where api.xsl contains: +

    +<?xml version='1.0'?>
    +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    +    <xsl:import href="e:/docbook/htmlhelp/htmlhelp.xsl"/>
    +    <xsl:param name="admon.graphics" select="1"/>
    +    <xsl:param name="section.autolabel" select="1"/>
    +</xsl:stylesheet>
    +
    +

    6. Options

    The behavior of ROBODoc can be further fine-tune with a large number of + options.

    -c

    Show the copyright message.

    --cmode

    Use ANSI C grammar in SOURCE items and use this + for syntax highlighting (HTML only).

    --css

    Use the content of the specified file to create the + robodoc.css. The content of the file is + copied into robodoc.css.

    --dbxml

    Generate documentation in XML DocBook format.

    --debug

    Works like --tell, bug gives a lot more information.

    --doc

    Define the path to the documentation directory or + documentation file. A path can start with + ./ or /. Do not use + .. in the path. The documentation + directory can be a subdirectory of the source directory, + or be parallel to the source directory, + however they can not be equal. So + --src ./sources + together with + --doc ./documents + is fine, + but + --src ./Everything + together with + --doc ./Everything + is not. +

    --doctype_name

    DocBook output requires a <!DOCTYPE> tag. + With this option you can specify your own version of it. You have + to use it in combination with --doctype_location. + An example: +

    +    robodoc --src test --doc test
    +        --doctype_location "-//OASIS//DTD Simplified DocBook XML V1.1//EN"
    +        --doctype_name docbook-simple/sdocbook.dtd
    +        --dbxml
    +

    + results in the following docbook file with the following head: +

    +<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V1.1//EN"
    +"docbook-simple/sdocbook.dtd">
    +
    --doctype_location

    See --doctype_name.

    --headless

    Do not create the head of a document. This allows you to + create documents that can be included in other documents, or + to which you can add your own style.

    For html output this means that no + <html><head> ..... <body> + is generated. +

    For LaTeX output this means none of the document + initialization code is generated, such as + \documentclass{article} or + \begin{document} is generated. If you use + this option in combination with --footless + you can use \include or + \input commands to include the ROBODoc + generated documents in a larger document.

    For XML DocBook output this means no + <!DOCTYPE>, + <article>, and + <articleinfo> is generated. +

    --first_section_level

    Make the first section start at the specified level + instead of 1. This is useful if you want to include the + generated documentation in another document. +

    --footless

    Do not create the foot of a document. This allows you to + create documents that can be included in other documents, or + to which you can add your own style.

    For html output this means that no + </body></html> + is generated. +

    For LaTeX output this means no + \end{document} is generated. +

    For XML DocBook output this means no + </article> is generated. +

    --html

    Generate documentation in HTML format.

    --ignore_case_when_linking

    Ignore differences in case when creating cross links. + This is handy for languages such as Fortran or Pascal, but + in most cases it is better not to use it.

    --internal

    Also include headers marked internal.

    --internalonly

    Only include headers marked internal.

    --index

    Also create a master index file.

    --lock

    Per source file robodoc locks on the first header marker + it finds and will recognize only that particular header marker + for the remaining part of the file. In addition it locks on + the first remark marker in each header and will recognize only + that particular remark marker for the remaining part of the + header.

    --multidoc

    Generate one document per source file, and copy the + directory hierarchy.

    --nosource

    Do not include the SOURCE items.

    --no_subdirectories

    Do not create any subdirectories in the documentation directory + instead write all the documentation files in the root directory. The root directory is the one specified with --doc.

    --nodesc

    Do not scan any subdirectories, scan only the top level + directory of the source tree.

    --nosort

    Do not sort the headers when generating the + documentation. The headers will appear in the same order in + the documentation as they appear in the source code.

    --nopre

    With this option ROBODoc does not generate preformatted + text when creating the item documentation. (Using + the <PRE> and + </PRE> construction in HTML format + for instance). Instead ROBODoc tries to deduce + the formatting from the indentation and special + characters. See Smart Text Formatting. This creates much better + looking documentation. +

    --nogeneratedwith

    Do not add the "generated with robodoc" message at the + top of each documentation file.

    --one_file_per_header

    Create a separate documentation file for each header. +

    --rc

    Use the specified file instead of robodoc.rc. +

    --rtf

    Generate documentation in RTF format.

    --sections

    Create sections based on the module hierarchy.

    --sectionnameonly

    ROBODoc generates the section headers with names only, + no chapter numbers, no parent section names.

    --singledoc

    Define the documentation directory or documentation + file.

    --singlefile

    Generate a single document from a single file

    --src

    Define the path for the source directory or source + file. The path can start with ./ or + /. Do not use .. in the + path.

    --tabsize

    Lets you specify the tab size.

    --tabstops

    Specify tab stop locations in a comma separated list.

    + Example: --tabstops 10,20,40,80 +

    --toc

    Add a table of contents. This works in multidoc mode as + well as singledoc mode.

    --latex

    Generate documentation in LaTeX format.

    --tell

    ROBODoc tells you what steps it is taking.

    --documenttitle

    Specify the Title of the whole documentation.

    --altlatex

    Alternate LaTeX file format + (bigger / clearer than normal). +

    --latexparts

    Make the first module level as PART + in LaTeX output + (Gives you one more subsection level).

    --syntaxcolors_enable

    Enable only specific syntax highlighting features in + SOURCE items (HTML only).

    Usage: + --syntaxcolors_enable + quotes,squotes,line_comments,block_comments,keywords,non_alpha +

    • quotes + -- Enable highlighting of "string literals" +
    • squotes + -- Enable highlighting of 'string literals' +
    • line_comments + -- Enable highlighting of comments that span until the end of lines + (See source line comments block) +
    • block_comments + -- Enable highlighting of block comments + (See +remark begin markers and remark end markers block) +
    • keywords + -- Enable highlighting of keywords + (See keywords block) +
    • non_alpha + -- Enable highlighting of non alphanumeric characters + (like: #, $, %, etc...) +

    You don't need this if you have the + --cmode + option specified. +

    See also the + --syntaxcolors + option. +

    --syntaxcolors

    Turn on all syntax highlighting features in SOURCE + items (HTML only).

    This option equals to: + --syntaxcolors_enable + quotes,squotes,line_comments,block_comments,keywords,non_alpha +

    You don't need this if you have the + --cmode + option specified. +

    See also the + --syntaxcolors_enable + option. +

    --dotname

    Specify the name (and path / options) of + DOT tool.

    See Using external tools.

    --masterindex

    Specify the title and filename of the master index page +

    Usage: + --masterindex + title,filename + +

    Example: + --masterindex "Index Page,index" +

    --sourceindex

    Specify the title and filename of the source files index + page

    Usage: + --sourceindex + title,filename + +

    Example: + --sourceindex "Source files,sources" +

    --header_breaks

    If a header has multiple names, ROBODoc can insert line breaks after every + specified number of header names to improve readability. If you do not specify this + option, ROBODoc will insert a line break after every two header names. Set it to + zero to disable the line breaks.

    + Example: --header_breaks 3 +

    7. Customizing ROBODoc

    ROBODoc can be configured with a configuration file called + robodoc.rc. With it you can define item + names, frequently used options, and translations for English + terms. One should note that if a configuration file is specified, + its definitions over-ride ROBODoc internal (i.e. built-in) settings. + This is a feature; some arbitrary language may include syntax + which conflicts with ROBODoc's internal markers. By taking advantage + of a configuration file, these sort of issues and conflicts + can be circumvented. An example is shown below. +

    +# Example robodoc.rc
    +#
    +items:
    +    NAME
    +    FUNCTION
    +    SYNOPSIS
    +    INPUTS
    +    OUTPUTS
    +    SIDE EFFECTS
    +    HISTORY
    +    BUGS
    +    EXAMPLE
    +ignore items:
    +    HISTORY
    +    BUGS
    +item order:
    +    FUNCTION
    +    SYNOPSIS
    +    INPUTS
    +    OUTPUTS
    +source items:
    +    SYNOPSIS
    +preformatted items:
    +    INPUTS
    +    OUTPUTS
    +format items:
    +    FUNCTION
    +    SIDE EFFECTS
    +options:
    +    --src ./source
    +    --doc ./doc
    +    --html
    +    --multidoc
    +    --index
    +    --tabsize 8
    +headertypes:
    +    J  "Projects"          robo_projects    2
    +    F  "Files"             robo_files       1
    +    e  "Makefile Entries"  robo_mk_entries
    +    x  "System Tests"      robo_syst_tests
    +    q  Queries             robo_queries
    +ignore files:
    +    README
    +    CVS
    +    *.bak
    +    *~
    +    "a test_*"
    +accept files:
    +    *.c
    +    *.h
    +    *.pl
    +header markers:
    +    /****
    +    #****
    +remark markers:
    +    *
    +    #
    +end markers:
    +    ****
    +    #****
    +header separate characters:
    +    ,
    +header ignore characters:
    +    [
    +remark begin markers:
    +    /*
    +remark end markers:
    +    */
    +source line comments:
    +    //
    +keywords:
    +    if
    +    do
    +    while
    +    for
    +

    The configuration file consists of a number of blocks. + Each block starts with a name followed by a + :. + In each block you define a number of values. Each value must + start with at least one space. +

    7.1. items block

    In this block you can define the names of items that + ROBODoc should recognize. Item names can consist of more than + one word but should be written in all uppercase characters. + Define one item name per line. You do not need to put quotes + around them if they contain spaces. +

    If you do not define an items block ROBODoc uses its + default list of item names. If you define an items block + ROBODoc uses only those item names, any of the default items names + (except SOURCE) are no longer recognized.

    7.2. ignore items block

    In this block you can define the names of items that + ROBODoc should ignore when generating documentation. + This can be useful if you want to create documentation + for a client, but for instance do not want to include + the history items and bugs items.

    7.3. item order block

    In this block you can define the order in which items + are to appear in the generated documentation. + The items listed here will appear in the given order in the + generated documentation. Any remaining items appear + after these items in the order they were found in the header. + This allows you to make the documentation look more uniform. +

    7.4. source items block

    In this block you can define the names of items that + ROBODoc handles in the same way as the SOURCE item. +

    7.5. preformatted items block

    + In this block you can define the names of items that should be always + preformatted. This is useful if you have the + --nopre option + specified and want specific items (like input and output lists) to be + automatically preformatted. See + Smart Text Formatting for more + information. +

    7.6. format items block

    + In this block you can define the names of items that should be formatted by + the Smart Text Formatting feature + (like function descriptions) even if the + --nopre + option has not been specified. +

    7.7. options block

    In this block you can define frequently used options. + The options you specify here are added to any options you + specify on the command line.

    + See Options. +

    7.8. headertypes block

    In this block you can define your own header types. + These are added to the existing header types. Each new + header type requires three parameters: the character used to + indicate a header of this type, the title for this type as + used in the master index and the name of the file in which the + index of this type is stored. If you use a character of an + existing header type, this header type is overwritten. +

    + Additionally the sorting priority can also be specified for each header + type. Headers with higher priority will appear earlier in the + generated output. (For example you can make module definitions appear + at the beginning of a page.) If this parameter is omitted, the header + will have the priority 0 (lowest) by default. All pre-defined header + types have zero priority, except + "Header for a module in a project", + which has the sorting priority 1. + See Header Types. +

    7.9. ignore files block

    In this block you can define the names of files or + directories that ROBODoc should ignore while scanning + the directory tree for source files. You can use the + wildcard symbols * and + ?. If you use spaces in the expression + enclose the expression in quotes. +

    For instance, the rc file above causes ROBODoc + to skip all README files, all files with + the name CVS (these are usually + directories). It also skips all files with a name that ends + with .bak or ~ or + that start with a test_

    Normally you specify the names of directories here + and do the filtering of file names with a accept files block. +

    7.10. accept files block

    In this block you can define the names of files that + robodoc should accept. This test is carried out after the + 'ignore files' filtering is performed. Any files that do + not match the patterns in this block are ignored by ROBODoc. +

    + If there is no accept files block all files are accepted. +

    7.11. header markers block

    + In this block you define what ROBODoc will recognize + as start of a header. If you use this block ROBODoc only + recognizes these markers, any of the inbuilt markers will + be ignored. +

    7.12. remark markers block

    + In this block you define what ROBODoc will recognize + as start of remark. If you use this block ROBODoc only + recognizes these markers, any of the inbuilt markers will + be ignored. +

    7.13. end markers block

    + In this block you define what ROBODoc will recognize + as end of a header. If you use this block ROBODoc only + recognizes these markers, any of the inbuilt markers will + be ignored. +

    7.14. header separate characters block

    + In this block you can specify the separation character(s) for multiple + header names. The default character is "," (comma) if + this block is missing. See + Preparing your source code for ROBODoc + for more information. +

    7.15. header ignore characters block

    + In this block you can specify character(s) where the evaluation of a header + should stop. The default character is "[" if this block + is missing. This is useful to supply additional information to the header + that ROBODoc should not care about. +

    + For example one can include the version number of the function: +

    +  ****f* financial.library/StealMoney [2.0]
    +

    +

    7.16.  +remark begin markers and remark end markers block

    + Some languages allow remarks to span more than one line. They + start a remark with a begin marker and end it with another + marker. For instance in C you can have: +

    +   /* This is a
    +      multi-line remark.
    +    */
    +

    + Here the markers are /* and */. + If you tell ROBODoc what these markers are in a remark begin + markers block and remark end markers block. ROBODoc can skip + them in source items.

    We illustrate this with an example. Say we have a language + that start a remark with |* and + *|. We define SYNOPSIS + to be a source like item. If we now run ROBODoc on the + without a remark begin markers and + end markers block on the following piece of source,

    +|****f* Bar/foo
    + * FUNCTION
    + *   foo computes the foo factor.
    + * SYNOPSIS
    + *|
    +int foo( float correction )
    +|*
    + * BUGS
    + *   None
    + * SOURCE
    + *|  .
    +{
    +    return correction * 42.0;
    +}
    +|*****|
    +

    the extracted documentation will look like:

    + FUNCTION
    +   foo computes the foo factor.
    + SYNOPSIS
    +   *|
    +   int foo( float correction )
    +   |*
    + BUGS
    +   None
    + SOURCE
    +   *|  .
    +   {
    +      return correction * 42.0;
    +   }
    +

    because ROBODoc considers + |* and *|.to be part of the + source, and not part of the begin or end of a header.

    If you add

    +remark begin markers:
    +       |*
    +remark end markers:
    +       *|
    +

    the output will look like:

    + FUNCTION
    +   foo computes the foo factor.
    + SYNOPSIS
    +   int foo( float correction )
    + BUGS
    +   None
    + SOURCE
    +   {
    +      return correction * 42.0;
    +   }
    +

    + These markers will also be used to highlight block comments if the + + --syntaxcolors_enable + block_comments + + option (or the + + --syntaxcolors + + option) is specified (Similar to + source line comments block). +

    7.17. source line comments block

    + Here you can specify markers which start whole line comments. + (Comments that span until the end of line like "//", + "REM", ";", etc...) + These lines will be highlighted in the generated HTML + output if the + + --syntaxcolors_enable + line_comments + + option (or the + + --syntaxcolors + + option) has been specified.

    + You don't need this if you have the + + --cmode + + option specified. +

    + The default highlighting color can be changed in the CSS + file (span.comment). +

    7.18. keywords block

    + Here you can specify the keywords in your SOURCE items. + These keywords will be highlighted in the generated HTML + output if the + + --syntaxcolors_enable + keywords + + option (or the + + --syntaxcolors + + option) has been specified. Keywords meant to be the language native ones + (for, if, etc...). +

    + You don't need this if you have the + + --cmode + + option specified. +

    + The default highlighting color can be changed in the CSS + file (span.keyword). +

    7.19. Configuration file location

    ROBODoc searches the your current directory for the + robodoc.rc file. If it can't find + it there it will search in $HOME/, then + $HOMEDRIVE$HOMEPATH/, and finally in + /usr/share/robodoc/.

    With the --rc option you can tell ROBODoc to + use a different file than robodoc.rc as + configuration file. This is handy if you want to create + documentation in different formats. For instance:

    +robodoc --rc  htmlsingle.rc
    +robodoc --rc  rtfsingle.rc
    +robodoc --rc  htmlmulti.rc
    +

    8. Tips and Tricks

    8.1. The SOURCE Item

    With a little extra work you can include part of your + source code into your documentation too. The following example + shows how this is done:

    +/****f* Robodoc/RB_Panic [2.0d]
    + * NAME
    + *   RB_Panic - Shout panic, free resources, and shut down.
    + * SYNOPSIS
    + *   RB_Panic (cause, add_info)
    + *   RB_Panic (char *, char *)
    + * FUNCTION
    + *   Prints an error message.
    + *   Frees all resources used by robodoc.
    + *   Terminates program.
    + * INPUTS
    + *   cause    - pointer to a string which describes the
    + *              cause of the error.
    + *   add_info - pointer to a string with additional information.
    + * SEE ALSO
    + *   RB_Close_The_Shop ()
    + * SOURCE
    + */
    +
    +  void RB_Panic (char *cause, char *add_info)
    +  {
    +    printf ("Robodoc: Error, %s\n",cause) ;
    +    printf ("         %s\n", add_info) ;
    +    printf ("Robodoc: Panic Fatal error, closing down..\n") ;
    +    RB_Close_The_Shop () ; /* Free All Resources */
    +    exit(100) ;
    +  }
    +
    +/*******/
    +

    You can add a SOURCE item as the last item of your header. Then + instead of closing your header with an end marker, you close it + normally. The end marker is instead placed at the end of the + fragment of source code that you want to include.

    SOURCE items are included by default. If you want to create a + document without the SOURCE items use the option + --nosource.

    You can also make normal items work like the source item, + see source items block. +

    8.2. Minimizing Duplicate Information

    It is always good to avoid having the same information in several different locations. + It is easy to create headers that have a lot information duplication. Take for instance + the following header. +

    +/****f* Robodoc/RB_Panic [2.0d]
    + * NAME
    + *   RB_Panic - Shout panic, free resources, and shut down.
    + * SYNOPSIS
    + *   RB_Panic (cause, add_info)
    + *   RB_Panic (char *, char *)
    + * FUNCTION
    + *   Prints an error message.
    + *   Frees all resources used by robodoc.
    + *   Terminates program.
    + * INPUTS
    + *   cause    - pointer to a string which describes the
    + *              cause of the error.
    + *   add_info - pointer to a string with additional information.
    + * SEE ALSO
    + *   RB_Close_The_Shop ()
    + * SOURCE
    + */
    +
    +  void RB_Panic (char *cause, char *add_info)
    +  {
    +    printf ("Robodoc: Error, %s\n",cause) ;
    +    printf ("         %s\n", add_info) ;
    +    printf ("Robodoc: Panic Fatal error, closing down..\n") ;
    +    RB_Close_The_Shop () ; /* Free All Resources */
    +    exit(100) ;
    +  }
    +
    +/*******/
    +

    + The name RB_Panic occurs five times. This is tedious to + type and difficult to maintain. + However with a the right robodoc.rc this can be changed + to: +

    +/****f* Robodoc/RB_Panic [2.0d]
    + * SUMMARY
    + *   Shout panic, free resources, and shut down.
    + * SYNOPSIS
    + */
    +
    +void RB_Panic (char* cause, char *add_info)
    +
    +/*
    + * FUNCTION
    + *   Prints an error message.
    + *   Frees all resources used by robodoc.
    + *   Terminates program.
    + * INPUTS
    + *   cause    - pointer to a string which describes the
    + *              cause of the error.
    + *   add_info - pointer to a string with additional information.
    + * SEE ALSO
    + *   RB_Close_The_Shop ()
    + * SOURCE
    + */
    +  {
    +    printf ("Robodoc: Error, %s\n",cause) ;
    +    printf ("         %s\n", add_info) ;
    +    printf ("Robodoc: Panic Fatal error, closing down..\n") ;
    +    RB_Close_The_Shop () ; /* Free All Resources */
    +    exit(100) ;
    +  }
    +
    +/*******/
    +

    RB_Panic occurs only twice now. In addition changes +to the function definition only have to be done once.

    The robodoc.rc required for this is:

    +# robodoc.rc file
    +items:
    +    SUMMARY
    +    SYNOPSIS
    +    INPUTS
    +    OUTPUTS
    +    SEE ALSO
    +    BUGS
    +source items:
    +    SYNOPSIS
    +remark begin markers:
    +    /*
    +remark end markers:
    +    */
    +

    8.3. Advanced formatting with raw HTML and LaTeX code

    By default an item's body shows up in your documentation in + the same way as it is formatted in your source code. All special + characters for the output mode are escaped. For instance an < + is translated to a &lt; in HTML mode. Sometimes however you + like to have some more control of what goes into the + documentation. This is possible with the piping. If a line of + your item's body starts with one of the special piping markers, the + text after this marker is copied verbatim into your documentation. + The following example shows how this is done, and how to add + equations to your documentation. +

    +/****m* pipe/pipetest
    + * NAME
    + *   pipetest
    + * DESCRIPTION
    + *   Simple header to show "piping" features in items.
    + * EXAMPLE
    + *   Only "pipes" which match selected output style are picked up.
    + *   |html <CENTER>This will be included in <B>HTML</B> output.</CENTER>
    + *   |latex \centerline{This will be included in \LaTeX output}
    + *   Space is mandatory following the pipe marker. The following is not a
    + *   valid pipe marker:
    + *   |html<B>Moi!</B>
    + *   You should see an equation on the following line:
    + *   |html y = x^2 (sorry, plain HTML is not very powerful)
    + *   |latex \centerline{$y = x^2$}
    + *   How does this look like?
    + *   Here comes a multi-line equation array:
    + *    |latex \begin{eqnarray}
    + *    |latex \frac{\partial u}{\partial \tau} & = & D_u {\nabla}^2 u +
    + *    |latex \frac{1}{\epsilon}
    + *    |latex \left ( \hat{u}-{\hat{u}}^2-f\, {v} \, \frac{\hat{u}-q}{\hat{u}+q}
    + *    |latex \right ) \; ,  \label{diffspot:1} \\
    + *    |latex \frac{\partial v}{\partial \tau} & = & \hat{u}-v \; ,
    + *    |latex \label{diffspot:2} \\
    + *    |latex \frac{\partial r}{\partial \tau} & = & D_r {\nabla}^2 r \; .
    + *    |latex \label{diffspAot:3}
    + *    |latex \end{eqnarray}
    + *    |html <I>TODO: write this in html</I>
    + *   End of the example.
    + ******
    + */
    +

    8.4. Linking to external documents (href, file, mailto, images)

    In HTML mode ROBODoc recognizes the following links to + external documents.

    • href:body -- This is replaced with + <a href="body">body</A> +

    • file:/body -- This is replaced with + <a href="file:/body">file:/body</A> +

    • mailto:body -- This is replaced with + <a href="mailto:body">body</A> +

    • http://body -- This is replaced with + <a href="http://body">http://body</A> +

    • image:body -- This is replaced with + <image src="body"> +

    8.5. Linking from an external document

    To link from an external document to one of the HTML + documents generated by ROBODoc you need a label. ROBODoc creates + two labels for each header. The first one starts with + robo followed by a number. You can not use + this one because the numbers will change each time you run + ROBODoc. The second label is an escaped version of the whole + header name. In this label all the non alphanumeric characters of + the name are replaced by their two digit hexadecimal code.

    An example, if your header name is + Analyser/RB_ToBeAdded the label is + Analyser2fRB5fToBeAdded. Here + / was replaced by 2f and + _ was replaced by 5f. As + long as you do not change the header name, this label stays the + same each time you run ROBODoc.

    8.6. Using external tools

    + You can also execute external tools from ROBODoc and even + pass data to them. + The output of these tools can be included in your documentation for instance. +

    + There are several types of external tools you can use: +

    1. Arbitrary tool with passing data through stdin
    2. Arbitrary tool without passing data through stdin
    3. The DOT tool

    + The following example shows how to use each of them. +

    +/****m* tools/tooltest
    + *
    + * NAME
    + *   Tooltest
    + *
    + * DESCRIPTION
    + *   Example showing how to invoke external tools.
    + *
    + * EXAMPLE
    + * This one sorts elements into the file href:nexus-6.txt
    + * The input data is passed through stdin.
    + *
    + * |tool sort > nexus-6.txt
    + * Zhora
    + * Pris
    + * Leon Kowalski
    + * Roy Batty
    + * Rachel
    + * Rick Deckard?
    + * |tool end
    + *
    + * We can also execute tools without having any stdin data.
    + * In the following example the output is simply redirected into href:tears.txt
    + *
    + * |exec echo "All those moments will be lost in time like tears in rain." > tears.txt
    + *
    + * You can also include neat DOT graphs in your documentation.
    + * This one shows a hash table.
    + *
    + * |dot start
    + * digraph G {
    + *   nodesep=.05;
    + *   rankdir=LR;
    + *   node [shape=record,width=.1,height=.1];
    + *
    + *   node0 [label = "<f0> |<f1> |<f2> |<f3> |<f4> |<f5> |<f6> | ",height=2.0];
    + *   node [width = 1.5];
    + *   node1 [label = "{<n> n14 | 719 |<p> }"];
    + *   node2 [label = "{<n> a1  | 805 |<p> }"];
    + *   node3 [label = "{<n> i9  | 718 |<p> }"];
    + *   node4 [label = "{<n> e5  | 989 |<p> }"];
    + *   node5 [label = "{<n> t20 | 959 |<p> }"] ;
    + *   node6 [label = "{<n> o15 | 794 |<p> }"] ;
    + *   node7 [label = "{<n> s19 | 659 |<p> }"] ;
    + *
    + *   node0:f0 -> node1:n;
    + *   node0:f1 -> node2:n;
    + *   node0:f2 -> node3:n;
    + *   node0:f5 -> node4:n;
    + *   node0:f6 -> node5:n;
    + *   node2:p -> node6:n;
    + *   node4:p -> node7:n;
    + * }
    + * |dot end
    + *
    + ******
    + */
    +

    + If you want to use the DOT tool you need the + Graphviz package. + More information and the binaries can be found at + + http://www.graphviz.org/ + . + The created graphs are automatically included in the documentation + (HTML and LaTeX only). + If you generate PDF output from your LaTeX + file and you want to include DOT graphs in it, you will also + need the epstopdf utility. + ROBODoc lets DOT generate + PNG images for HTML output and + PS and PDF images for + LaTeX output. +

    8.7. ROBODoc-ing an existing project

    + The ROBODoc package includes also a standalone binary named + robohdrs. + This helper program can take clean source file and insert + ROBODoc headers to functions, global variables, and macros. + There are issues with this tool but it saves lots of cumbersome typing + when starting on documenting an existing code-base with ROBODoc. + Type + +man robohdrs + + or + +robohdrs -h + + for help. + Example: + +robohdrs -s -p testproj -i "MODIFICATION HISTORY" -i IDEAS testproj.c + +

    + Note that robohdrs is supported on UNIX-like platforms only. + It requires fork() and Exuberant Ctags 5.3.1 or newer. +

    8.8. Using ROBODoc under Windows

    When you use ROBODoc under windows, don't forget that it is + a command line tool. ROBODoc relies on the console window to + inform you about problems and errors.

    An easy mistake to make is to create a shortcut to + robodoc.exe and then click on the icon to + generate the documentation each time you made some changes to your + source code. If you have a fast machine a console window pops up + quickly and after that your documentation is ready.

    This works very fine until you make a mistake in one of your + headers. The console window still pops up, but before you have a chance + to read any of the error messages it is gone again. Most likely + you won't even have noticed there were error messages. You will + end up with empty documentation or old documentation.

    It is Better to create a batch file with the following commands + and to store all the options in a robodoc.rc + file:

    +robodoc.exe
    +pause
    +

    Now the console window stays open and you have the + opportunity to read the error messages.

    While the window is open, right click on the title bar, + go to properties->layout and set the buffer size to something + like 2500. That way, the next time you run it, you can scroll back + and view all error messages. +

    9. Languages Supported by Default

    + ROBODoc support a whole range of languages by default. + These languages are listed in the following sections. + For each language two example headers are shown. + One example header without any source items and + one example header with source items. +

    Any of these markers can be mixed, and they are not limited + to the languages listed. So if you have a language that is not + listed but that has remarks that start with a # + you can use the Tcl markers, and create headers such as: +

    +#****f* Foo/Bar
    +# FUNCTION
    +#   Bar snarfs the Foo input and mangles it.  Given the right settings
    +#   it might also do a bit of snu snu.
    +#***
    +

    + In addition for each language the corresponding entries in + the robodoc.rc are shown. + You do not need these, as ROBODoc has these entries + built-in. They are shown to make it easier + to determine what needs to be specified for languages + that ROBODoc does not yet support. +

    + You can also use these entries if you want to create + a robodoc.rc that supports only a limited + number of languages. + This because if you specify your own markers, ROBODoc + ignores any of the in-built markers. +

    9.1. C

    Example 10. A simple header without any source items in C.

    +/****f* ModuleName/Foo
    +* FUNCTION
    +*   Foo computes the foo factor
    +*   using a fudge factor.
    +****
    +*/
    +

    Example 11. A header with source items in C.

    +/****f* ModuleName/Foo
    +* FUNCTION
    +*   Foo computes the foo factor
    +*   using a fudge factor.
    +* SYNOPSIS
    +*/
    +int Foo( int fudge )
    +/*
    +* INPUTS
    +*   fudge -- the fudge factor
    +* SOURCE
    +*/
    +
    + more source code..
    +
    +/*****/
    +

    Example 12. The robodoc.rc file required for C if it were not supported by default.

    +header markers:
    +  /****
    +remark markers:
    +  *
    +end markers:
    +  ****
    +  /****
    +remark begin markers:
    +  /*
    +remark end markers:
    +  */
    +

    9.2. Modula-2

    Example 13. A simple header without any source items in Modula-2.

    +(****f* ModuleName/Foo
    +* FUNCTION
    +*   Foo computes the foo factor
    +*   using a fudge factor.
    +****
    +*)
    +

    Example 14. A header with source items in Modula-2.

    +(****f* ModuleName/Foo
    +* FUNCTION
    +*   Foo computes the foo factor
    +*   using a fudge factor.
    +* SYNOPSIS
    +*)
    +int Foo( int fudge )
    +(*
    +* INPUTS
    +*   fudge -- the fudge factor
    +* SOURCE
    +*)
    +
    + more source code..
    +
    +(*****)
    +

    Example 15. The robodoc.rc file required for Modula-2 if it were not supported by default.

    +header markers:
    +  (****
    +remark markers:
    +  *
    +end markers:
    +  ****
    +  (****
    +remark begin markers:
    +  (*
    +remark end markers:
    +  *)
    +

    9.3. Pascal

    Example 16. A simple header without any source items in Pascal.

    +{****f* ModuleName/Foo
    +* FUNCTION
    +*   Foo computes the foo factor
    +*   using a fudge factor.
    +****
    +*}
    +

    Example 17. A header with source items in Pascal.

    +{****f* ModuleName/Foo
    +* FUNCTION
    +*   Foo computes the foo factor
    +*   using a fudge factor.
    +* SYNOPSIS
    +*}
    +int Foo( int fudge )
    +{*
    +* INPUTS
    +*   fudge -- the fudge factor
    +* SOURCE
    +*}
    +
    + more source code..
    +
    +{*****}
    +

    Example 18. The robodoc.rc file required for Pascal if it were not supported by default.

    +header markers:
    +  {****
    +remark markers:
    +  *
    +end markers:
    +  ****
    +  {****
    +remark begin markers:
    +  {*
    +remark end markers:
    +  *}
    +

    9.4. C++

    Example 19. A simple header without any source items in C++.

    +//****f* ModuleName/Foo
    +// FUNCTION
    +//   Foo computes the foo factor
    +//   using a fudge factor.
    +//****
    +

    Example 20. A header with source items in C++.

    +//****f* ModuleName/Foo
    +// FUNCTION
    +//   Foo computes the foo factor
    +//   using a fudge factor.
    +// SYNOPSIS
    +int Foo( int fudge )
    +// INPUTS
    +//   fudge -- the fudge factor
    +// SOURCE
    +
    + more source code..
    +
    +//****
    +

    Example 21. The robodoc.rc file required for C++ if it were not supported by default.

    +header markers:
    +  //****
    +remark markers:
    +  //
    +end markers:
    +  //****
    +

    9.5. Tcl

    Example 22. A simple header without any source items in Tcl.

    +#****f* ModuleName/Foo
    +# FUNCTION
    +#   Foo computes the foo factor
    +#   using a fudge factor.
    +#****
    +

    Example 23. A header with source items in Tcl.

    +#****f* ModuleName/Foo
    +# FUNCTION
    +#   Foo computes the foo factor
    +#   using a fudge factor.
    +# SYNOPSIS
    +int Foo( int fudge )
    +# INPUTS
    +#   fudge -- the fudge factor
    +# SOURCE
    +
    + more source code..
    +
    +#****
    +

    Example 24. The robodoc.rc file required for Tcl if it were not supported by default.

    +header markers:
    +  #****
    +remark markers:
    +  #
    +end markers:
    +  #****
    +

    9.6. Perl

    Example 25. A simple header without any source items in Perl.

    +#****f* ModuleName/Foo
    +# FUNCTION
    +#   Foo computes the foo factor
    +#   using a fudge factor.
    +#****
    +

    Example 26. A header with source items in Perl.

    +#****f* ModuleName/Foo
    +# FUNCTION
    +#   Foo computes the foo factor
    +#   using a fudge factor.
    +# SYNOPSIS
    +int Foo( int fudge )
    +# INPUTS
    +#   fudge -- the fudge factor
    +# SOURCE
    +
    + more source code..
    +
    +#****
    +

    Example 27. The robodoc.rc file required for Perl if it were not supported by default.

    +header markers:
    +  #****
    +remark markers:
    +  #
    +end markers:
    +  #****
    +

    9.7. LaTeX/TeX

    Example 28. A simple header without any source items in LaTeX/TeX.

    +%****f* ModuleName/Foo
    +% FUNCTION
    +%   Foo computes the foo factor
    +%   using a fudge factor.
    +%****
    +

    Example 29. A header with source items in LaTeX/TeX.

    +%****f* ModuleName/Foo
    +% FUNCTION
    +%   Foo computes the foo factor
    +%   using a fudge factor.
    +% SYNOPSIS
    +int Foo( int fudge )
    +% INPUTS
    +%   fudge -- the fudge factor
    +% SOURCE
    +
    + more source code..
    +
    +%****
    +

    Example 30. The robodoc.rc file required for LaTeX/TeX if it were not supported by default.

    +header markers:
    +  %****
    +remark markers:
    +  %
    +end markers:
    +  %****
    +

    9.8. Postscript

    Example 31. A simple header without any source items in Postscript.

    +%****f* ModuleName/Foo
    +% FUNCTION
    +%   Foo computes the foo factor
    +%   using a fudge factor.
    +%****
    +

    Example 32. A header with source items in Postscript.

    +%****f* ModuleName/Foo
    +% FUNCTION
    +%   Foo computes the foo factor
    +%   using a fudge factor.
    +% SYNOPSIS
    +int Foo( int fudge )
    +% INPUTS
    +%   fudge -- the fudge factor
    +% SOURCE
    +
    + more source code..
    +
    +%****
    +

    Example 33. The robodoc.rc file required for Postscript if it were not supported by default.

    +header markers:
    +  %****
    +remark markers:
    +  %
    +end markers:
    +  %****
    +

    9.9. Occam

    Example 34. A simple header without any source items in Occam.

    +__****f* ModuleName/Foo
    +__ FUNCTION
    +__   Foo computes the foo factor
    +__   using a fudge factor.
    +__****
    +

    Example 35. A header with source items in Occam.

    +__****f* ModuleName/Foo
    +__ FUNCTION
    +__   Foo computes the foo factor
    +__   using a fudge factor.
    +__ SYNOPSIS
    +int Foo( int fudge )
    +__ INPUTS
    +__   fudge -- the fudge factor
    +__ SOURCE
    +
    + more source code..
    +
    +__****
    +

    Example 36. The robodoc.rc file required for Occam if it were not supported by default.

    +header markers:
    +  __****
    +remark markers:
    +  __
    +end markers:
    +  __****
    +

    10. Suggestions and Bugs

    If you find any bugs, catch them, put them in a jar, and + send them to: Frans Slothouber at rfsber {at} xs4all.nl. Suggestions are also welcome at + this address. Flames can be directed to the sun.

    diff --git a/Docs/manual.xml b/Docs/manual.xml new file mode 100644 index 0000000..6259c7f --- /dev/null +++ b/Docs/manual.xml @@ -0,0 +1,110 @@ + + + + + + + + + + +] > + + + +
    + + + ROBODoc 4.99.36 User Manual + + + Frans + Slothouber + + + Petteri + Kettunen + + + Gergely + Budai + + + Users Guide $Revision: 1.63 $ + Apr 2007 + + 1994-2007 + + Frans Slothouber, Petteri Kettunen, + Jacco van Weert, Gergely Budai + + + + +&preface; + +&installing; + +&preparing; + +&extracting; + +&examples; + +&options; + +&configuration; + +&tips; + + + +
    + Languages Supported by Default + + ROBODoc support a whole range of languages by default. + These languages are listed in the following sections. + For each language two example headers are shown. + One example header without any source items and + one example header with source items. + + + Any of these markers can be mixed, and they are not limited + to the languages listed. So if you have a language that is not + listed but that has remarks that start with a # + you can use the Tcl markers, and create headers such as: + + + +#****f* Foo/Bar +# FUNCTION +# Bar snarfs the Foo input and mangles it. Given the right settings +# it might also do a bit of snu snu. +#*** + + + + In addition for each language the corresponding entries in + the robodoc.rc are shown. + You do not need these, as ROBODoc has these entries + built-in. They are shown to make it easier + to determine what needs to be specified for languages + that ROBODoc does not yet support. + + + + You can also use these entries if you want to create + a robodoc.rc that supports only a limited + number of languages. + This because if you specify your own markers, ROBODoc + ignores any of the in-built markers. + + &header_examples; +
    + +&bugs; + +
    + diff --git a/Docs/manual.xsl b/Docs/manual.xsl new file mode 100644 index 0000000..6e4a004 --- /dev/null +++ b/Docs/manual.xsl @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Docs/manual_html_help-cygwin.xsl b/Docs/manual_html_help-cygwin.xsl new file mode 100644 index 0000000..4d64fd5 --- /dev/null +++ b/Docs/manual_html_help-cygwin.xsl @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Docs/manual_html_help.xsl b/Docs/manual_html_help.xsl new file mode 100644 index 0000000..5a88fe9 --- /dev/null +++ b/Docs/manual_html_help.xsl @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Docs/manual_html_help_win32.xsl b/Docs/manual_html_help_win32.xsl new file mode 100644 index 0000000..6c53693 --- /dev/null +++ b/Docs/manual_html_help_win32.xsl @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Docs/manual_win32.xsl b/Docs/manual_win32.xsl new file mode 100644 index 0000000..203bb81 --- /dev/null +++ b/Docs/manual_win32.xsl @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Docs/options.xml b/Docs/options.xml new file mode 100644 index 0000000..36130e7 --- /dev/null +++ b/Docs/options.xml @@ -0,0 +1,400 @@ + + + +
    + Options + + The behavior of ROBODoc can be further fine-tune with a large number of + options. + + + + -c + Show the copyright message. + + + --cmode + Use ANSI C grammar in SOURCE items and use this + for syntax highlighting (HTML only). + + + --css + Use the content of the specified file to create the + robodoc.css. The content of the file is + copied into robodoc.css. + + + --dbxml + Generate documentation in XML DocBook format. + + + --debug + Works like --tell, bug gives a lot more information. + + + --doc + Define the path to the documentation directory or + documentation file. A path can start with + ./ or /. Do not use + .. in the path. The documentation + directory can be a subdirectory of the source directory, + or be parallel to the source directory, + however they can not be equal. So + --src ./sources + together with + --doc ./documents + is fine, + but + --src ./Everything + together with + --doc ./Everything + is not. + + + + --doctype_name + DocBook output requires a <!DOCTYPE> tag. + With this option you can specify your own version of it. You have + to use it in combination with --doctype_location. + An example: + + + robodoc --src test --doc test + --doctype_location "-//OASIS//DTD Simplified DocBook XML V1.1//EN" + --doctype_name docbook-simple/sdocbook.dtd + --dbxml + + + results in the following docbook file with the following head: + + +<!DOCTYPE article PUBLIC "-//OASIS//DTD Simplified DocBook XML V1.1//EN" +"docbook-simple/sdocbook.dtd"> + + + + + --doctype_location + See --doctype_name. + + + --headless + Do not create the head of a document. This allows you to + create documents that can be included in other documents, or + to which you can add your own style. + + For html output this means that no + <html><head> ..... <body> + is generated. + + + For LaTeX output this means none of the document + initialization code is generated, such as + \documentclass{article} or + \begin{document} is generated. If you use + this option in combination with + you can use \include or + \input commands to include the ROBODoc + generated documents in a larger document. + + For XML DocBook output this means no + <!DOCTYPE>, + <article>, and + <articleinfo> is generated. + + + + + --first_section_level + Make the first section start at the specified level + instead of 1. This is useful if you want to include the + generated documentation in another document. + + + + --footless + Do not create the foot of a document. This allows you to + create documents that can be included in other documents, or + to which you can add your own style. + + For html output this means that no + </body></html> + is generated. + + + For LaTeX output this means no + \end{document} is generated. + + + For XML DocBook output this means no + </article> is generated. + + + + --html + Generate documentation in HTML format. + + + --ignore_case_when_linking + Ignore differences in case when creating cross links. + This is handy for languages such as Fortran or Pascal, but + in most cases it is better not to use it. + + + --internal + Also include headers marked internal. + + + --internalonly + Only include headers marked internal. + + + --index + Also create a master index file. + + + --lock + Per source file robodoc locks on the first header marker + it finds and will recognize only that particular header marker + for the remaining part of the file. In addition it locks on + the first remark marker in each header and will recognize only + that particular remark marker for the remaining part of the + header. + + + --multidoc + Generate one document per source file, and copy the + directory hierarchy. + + + --nosource + Do not include the SOURCE items. + + + + --no_subdirectories + Do not create any subdirectories in the documentation directory + instead write all the documentation files in the root directory. The root directory is the one specified with . + + + + --nodesc + Do not scan any subdirectories, scan only the top level + directory of the source tree. + + + --nosort + Do not sort the headers when generating the + documentation. The headers will appear in the same order in + the documentation as they appear in the source code. + + + + --nopre + With this option ROBODoc does not generate preformatted + text when creating the item documentation. (Using + the <PRE> and + </PRE> construction in HTML format + for instance). Instead ROBODoc tries to deduce + the formatting from the indentation and special + characters. See . This creates much better + looking documentation. + + + + --nogeneratedwith + Do not add the "generated with robodoc" message at the + top of each documentation file. + + + --one_file_per_header + Create a separate documentation file for each header. + + + + --rc + Use the specified file instead of robodoc.rc. + + + + --rtf + Generate documentation in RTF format. + + + --sections + Create sections based on the module hierarchy. + + + --sectionnameonly + ROBODoc generates the section headers with names only, + no chapter numbers, no parent section names. + + + + --singledoc + Define the documentation directory or documentation + file. + + + --singlefile + Generate a single document from a single file + + + --src + Define the path for the source directory or source + file. The path can start with ./ or + /. Do not use .. in the + path. + + + --tabsize + Lets you specify the tab size. + + + --tabstops + Specify tab stop locations in a comma separated list. + + Example: + + + + --toc + Add a table of contents. This works in multidoc mode as + well as singledoc mode. + + + --latex + Generate documentation in LaTeX format. + + + --tell + ROBODoc tells you what steps it is taking. + + + --documenttitle + Specify the Title of the whole documentation. + + + --altlatex + Alternate LaTeX file format + (bigger / clearer than normal). + + + + --latexparts + Make the first module level as PART + in LaTeX output + (Gives you one more subsection level). + + + + --syntaxcolors_enable + Enable only specific syntax highlighting features in + SOURCE items (HTML only). + Usage: + + + + + -- Enable highlighting of "string literals" + + + -- Enable highlighting of 'string literals' + + + + -- Enable highlighting of comments that span until the end of lines + (See ) + + + + -- Enable highlighting of block comments + (See ) + + + + -- Enable highlighting of keywords + (See ) + + + -- Enable highlighting of non alphanumeric characters + (like: #, $, %, etc...) + + + You don't need this if you have the + + option specified. + + See also the + + option. + + + + + --syntaxcolors + Turn on all syntax highlighting features in SOURCE + items (HTML only). + This option equals to: + + + You don't need this if you have the + + option specified. + + See also the + + option. + + + + --dotname + Specify the name (and path / options) of + DOT tool. + See . + + + --masterindex + Specify the title and filename of the master index page + + Usage: + + + Example: + + + + + --sourceindex + Specify the title and filename of the source files index + page + Usage: + + + Example: + + + + + --header_breaks + If a header has multiple names, ROBODoc can insert line breaks after every + specified number of header names to improve readability. If you do not specify this + option, ROBODoc will insert a line break after every two header names. Set it to + zero to disable the line breaks. + + Example: + + + + + +
    + + diff --git a/Docs/preface.xml b/Docs/preface.xml new file mode 100644 index 0000000..d447ef8 --- /dev/null +++ b/Docs/preface.xml @@ -0,0 +1,46 @@ + +
    + Preface + + ROBODoc is an API documentation tool for C, C++, Java, Assembler, + Basic, Fortran, LaTeX, Postscript, Tcl/Tk, LISP, Forth, Perl, Shell + Scripts, Makefiles, Occam, COBOL, DCL, Visual Basic, HTML, DB/C, XML, + and many other languages. It can be made to work with any language that + supports comments. + + ROBODoc works by extracting specially formatted headers from your + source code and writes these to documentation files. These files can be + formatted in HTML, ASCII, XML DocBook, or RTF; and indirectly to + PDF and HTML Help. + + ROBODoc is similar to JavaDoc, though the idea is much + older than JavaDoc. ROBODoc allows you to maintain a program and + its documentation in a single file. This makes it easier to keep + your documentation up-to-date. + + ROBODoc can be used to document anything you like, + functions, methods, variables, definitions, test cases, makefile + entries, and anything else you can think of. + + It can create documentation consisting of many small files. + For instance in HTML format for easy browsing and publication on + the web. It can also create a single file in LaTeX or RTF format + for inclusion into bigger design documents. The RTF format is + suited to be included in Word documents. + + ROBODoc allows you to separate internal documentation from + external documentation. In singledoc mode it can create a section + layout based on the hierarchy of your modules. + + ROBODoc is designed to work with a lot of different + programming languages. It has no knowledge of the syntax of + programming languages. It only has some knowledge about how + comments start and end in a lot of programming languages. This + means that you sometimes have to do a little more work compared to + other tools that have detailed knowledge of the syntax of a + particular language. They can use that knowledge to figure out + some of the information automatically. This usually also means + that they work only with one or two languages. + +
    + diff --git a/Docs/preparing.xml b/Docs/preparing.xml new file mode 100644 index 0000000..3b47f03 --- /dev/null +++ b/Docs/preparing.xml @@ -0,0 +1,784 @@ + + +
    +Preparing your source code for ROBODoc + + ROBODoc allows you to mix the program documentation with + the source code. It does require though that this documentation + has a particular layout so ROBODoc can recognize it. There are + three key concepts: headers, items, and sections. + +
    +Headers + + Headers are the building blocks of the documentation. Lets + look at an example. The following header was taken from the + documentation of the predecessor of ROBODoc, AutoDoc. + + + A ROBODoc header in C. + + /****f* financial.library/StealMoney + * NAME + * StealMoney -- Steal money from the Federal Reserve Bank. (V77) + * SYNOPSIS + * error = StealMoney( userName, amount, destAccount, falseTrail ) + * FUNCTION + * Transfer money from the Federal Reserve Bank into the + * specified interest-earning checking account. No records of + * the transaction will be retained. + * INPUTS + * userName - name to make the transaction under. Popular + * favorites include "Ronald Reagan" and + * "Mohamar Quadaffi". + * amount - Number of dollars to transfer (in thousands). + * destAccount - A filled-in AccountSpec structure detailing the + * destination account (see financial/accounts.h). + * If NULL, a second Great Depression will be + * triggered. + * falseTrail - If the DA_FALSETRAIL bit is set in the + * destAccount, a falseTrail structure must be + * provided. + * RESULT + * error - zero for success, else an error code is returned + * (see financial/errors.h). + * EXAMPLE + * Federal regulations prohibit a demonstration of this function. + * NOTES + * Do not run on Tuesdays! + * BUGS + * Before V88, this function would occasionally print the + * address and home phone number of the caller on local police + * 976 terminals. We are confident that this problem has been + * resolved. + * SEE ALSO + * CreateAccountSpec(),security.device/SCMD_DESTROY_EVIDENCE, + * financial/misc.h + ****** + * You can use this space for remarks that should not be included + * in the documentation. + */ + + + A header consists of three different elements: a + begin marker, a number of items, and an end marker. The begin marker + in the example is: + + + ****f* financial.library/StealMoney + + +It marks the beginning of a header. It also tells ROBODoc + + + the name of the element that is being documented, StealMoney, + the module it is part of, financial.library, + the kind of element, f, which stands for function. + + + + ROBODoc always expects that a / separates the module name and an element name. + So ModFoo/funcBar + is a valid name, but funcBar is not. + See for more + information. + + + + Names can also contain spaces but ROBODoc won't create links to names with + embedded spaces. + + + + You can also have multiple names for a header. This is useful if you + document similar objects together in one header (for example assembly + subroutines with multiple jump-in points). Multiple names are separated by + commas and can span over more than one line. + + ****f* financial.library/StealMoney, Steal_Money + + In the above example all references found to StealMoney + and Steal_Money in other headers will be automatically + linked to this header. + The separation character(s) can be specified by the + . + See for more + information. + + + +The end marker: + + + + ****** + + + + marks the end of a header. + + + Items begin with an item name and are followed by the + item's body. An example: + + + * FUNCTION + * Transfer money from the Federal Reserve Bank into the + * specified interest-earning checking account. No records of + * the transaction will be retained. + + + + In this case the item's name is FUNCTION. + + + + Each line of an item starts with a remark marker. In this case + *. + + +That what ROBODoc needs to recognize a header is therefore: + + + The markers needed by ROBODoc to recognize a header. + + /****f* financial.library/StealMoney + * NAME + * + * SYNOPSIS + * + * FUNCTION + * + * + * + * INPUTS + * + * + * + * + * + * + * + * + * + * + * + * RESULT + * + * + * EXAMPLE + * + * NOTES + * + * BUGS + * + * + * + * + * SEE ALSO + * + * + ****** + + + + + The above example is in C. ROBODoc supports many more + languages though. See . + + +
    + + +
    +Header Types + + ROBODoc defines a number of header types. You don't need + to use them but they can be useful for sorting information. The + header type tells ROBODoc what kind of object you are documenting. + This information allows ROBODoc to create more useful index + tables. + + The type is identified by one or two characters. ROBODoc + expects to find them after the fourth * in the + begin marker. So #****f is a valid marker, + but #**f** is not. + + If a single character is given, the type is defined as + listed in the following table + +Default header types + + + + + cHeader for a class + dHeader for a constant (from define) + fHeader for a function + h + Header for a module in a project + mHeader for a method + sHeader for a structure + tHeader for a types + uHeader for a unit test + vHeader for a variable + *Generic header for everything else + + +
    + + If two characters are given, the first character should be + i and the second can be any of the other + characters from the table above. This creates an internal header + of the type specified by the second character. Internal headers + are special. They can be used to hide certain headers. They are + only extracted if requested. You can use them to document internal + functions, classes, etc. that you do not want clients to see, + creating what might be a programmer's manual as opposed to a + user's manual. + + So /****if* Module/func1 defines an + internal function called func1. + + + Headers marked internal are by default not included in the + generated documentation. If you want to include them use the + option . You can also generate the + documentation from only the internal headers with the option + . + + + You can define your own header types using the ROBODoc + configuration file, robodoc.rc. + See . + This way you can document anything you like, for instance makefile + entries, system tests, or exceptions. + + +
    + +
    Items + + By default ROBODoc recognizes the following items: + + + + + NAME + + + Item name plus a short description. + + + + + + + COPYRIGHT + + + Who own the copyright : "(c) <year>-<year> by + <company/person>" + + + + + + + SYNOPSIS + + + USAGE + + + + How to use it. + + + + + + + FUNCTION + + + DESCRIPTION + + + PURPOSE + + + + What does it do. + + + + + + + AUTHOR + + + + Who wrote it. + + + + + + + CREATION DATE + + + When did the work start. + + + + + + + MODIFICATION HISTORY + + + HISTORY + + + Who has done which changes and when. + + + + + + + INPUTS + + + ARGUMENTS + + + OPTIONS + + + PARAMETERS + + + SWITCHES + + + + What can we feed into it. + + + + + + + OUTPUT + + + SIDE EFFECTS + + + What output is made. + + + + + + + RESULT + + + RETURN VALUE + + + + What do we get returned. + + + + + + + EXAMPLE + + + + A clear example of the items use. + + + + + + + NOTES + + + + Any annotations + + + + + + + DIAGNOSTICS + + + Diagnostic output. + + + + + + + WARNINGS + + + ERRORS + + + Warning and error-messages. + + + + + + + BUGS + + + Known bugs. + + + + + + + TODO + + + IDEAS + + What to implement next and ideas. + + + + + PORTABILITY + + Where does it come from, where will it work. + + + + + SEE ALSO + + References to other functions, man pages, other documentation. + + + + + + METHODS + + + NEW METHODS + + OOP methods. + + + + + + + ATTRIBUTES + + + NEW ATTRIBUTES + + OOP attributes. + + + + + + TAGS + + + Tag-item description. + + + + + + DERIVED FROM + + OOP super class. + + + + + DERIVED BY + + OOP sub class. + + + + + USES + + + CHILDREN + + What modules are used by this one. + + + + + USED BY + + + PARENTS + + Which modules do use this one. + + + + + COMMANDS + + Command description. + + + + + SOURCE + + Source code inclusion. + + + + + You can define your own items using the ROBODoc + configuration file, robodoc.rc. See . + +
    + +
    +Sections + + The structure of source code for a project is usually + hierarchical. A project might consists of several applications, + an application of several modules, a module of several functions + or even sub modules. ROBODoc allows you to show this hierarchy in + your documentation. For this you specify the hierarchy in the + header name. For instance, you have a project that is going to + create a new language called D. The D Language project might + consists of three applications: a preprocessor, a compiler, and a + linker. The compiler consists of two modules, a parser and a + generator. The parser module consists of several + functions. + + The following three headers show how this hierarchy can be + defined in the header name. + + +#****h* D-Language/Compiler +# FUNCTION +# The compiler takes a preprocessed source file and +# turns it into an object file. +#*** + + + +#****h* D-Language/Linker +# FUNCTION +# The linker module contains functions that scan a +# object file and build the executable. +#*** + + + +#****h* Compiler/Parser +# FUNCTION +# The parser module contains functions that scan a +# preprocessed source file and build the syntax tree. +#*** + + + +#****f* Parser/ReadToken +# FUNCTION +# ReadToken reads the next token from the input +# file. +#*** + + + When you generate documentation with the option + , ROBODoc uses the hierarchical + information when generating the table of contents and document + section information. For instance in HTML sections are started + with <H1>, <H2>, <H3> depending on the level + in the hierarchy. The table of contents will also contain levels. The + table of contents for the above example will be: + + +1. D-Language/Compiler +1.1 Compiler/Parser +1.1.1 Parser/ReadToken +2. D-Language/Linker + + +
    + +
    Smart Text Formatting + +By default ROBODoc creates preformatted text in the output +documentation for all the text it finds in an item. This means +that the formatting of the output looks the same as the formatting of +the text of an item. Line-breaks and indentation stay the same. +This is easy but does not always create the best looking +output. + +ROBODoc can also try to deduce the formatting of your text based +on the layout and indentation of your text and on special characters in the text. +It works a bit similar to the input method of Wikis. In the context of this +manual this is called Smart Formatting. + + +You switch this on with the option . +ROBODoc now tries to find three kind of elements: paragraphs, +lists, and preformatted text. + +Paragraphs are separated by empty lines. So the following item +has two paragraphs. + + + Two paragraphs. + + FUNCTION + This function does something. + + And it then does something else + and a bit more. + + + + A List starts with a line that ends with a ':' which is then +followed by one or more list items. List items should start with '*', +'-', or 'o'. So the following item contains a valid list: + + + A list. + + FUNCTION + This function does: + * a lot of foo + * some snafuing + * and a bit of foobarring. + + + + A list item can span more than one line if the second and following +lines are indented. So this is also a valid list: + + + A list where one of the items spans more than one line. + + FUNCTION + This function does: + * a lot of foo and preprocessing of the + raw input with the aid + of the some magic + * some snafuing + * and a bit of foobarring. + + + + +If list items directly follow the name of a robodoc item they +also form a valid list. So this is a valid list: + + + an implicit list + + INPUTS + * inputname -- the name of the input file + * outputname -- the name of the output file + * n -- the number of characters to be written + + + + Preformatted text is indicated by indenting it more that the +surrounding text. The first non-empty line in an item determines the +base indenting. Any lines with an indentation larger than this are +preformatted. An example: + + + Preformatted text + + FUNCTION + The following lines are preformatted + +--------+ + | A box | + | | + +--------+ + End of the preformatted text. + + + +The following is a complete example. + + + All three elements of smart formatting. + + This is some example text. + And some more. + + This is even more, and we start a list: + * a list item + * a list item + * a list item + + And we can also do preformatted stuff + by indenting + +--------+ + | | + +--------+ + The box will stay. + + + +will be turn into + + + The corresponding HTML output. + + <p>This is some example text. + And some more.</p> + + <p>This is even more, and we start a list:</p> + <ul> + <li>a list item</li> + <li>a list item</li> + <li>a list item</li> + </ul> + + <p>And we can also do preformatted stuff + by indenting</p> + <pre> + +--------+ + | | + +--------+ + </pre> + <p> The box will stay.</p> + + + +
    + +
    + + diff --git a/Docs/robodoc.1 b/Docs/robodoc.1 new file mode 100644 index 0000000..8ce7dc5 --- /dev/null +++ b/Docs/robodoc.1 @@ -0,0 +1,188 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH ROBODoc "1" "Jul 2006" "ROBODoc 4.99.36" + +.SH NAME +ROBODoc \- Extract documentation from source code. + +.SH SYNOPSIS +.B robodoc +.I --src + +.I --doc + +.B [options] + +.SH DESCRIPTION + +ROBODoc extracts specially formated documentation from the source code. +It allows you to maintain a program and its documentation in a single +file. + +.SH OPTIONS + +.IP -c +Show the copyright message. + +.IP --cmode +Use ANSI C grammar in SOURCE items and use this for some syntax +highlighting (HTML only). + +.IP --doc +Define the documentation directory or documentation file. +A directory should start with a '/' or a './' and +should not include any '..'. + +.IP --src +Define the source directory or source file. A directory should start +with a '/' or a './' and should not include any '..'. + +.IP --ascii +Generate documentation in ASCII format. + +.IP --html +Generate documentation in HTML format. + +.IP --css +Use to content of the specified file to create the +.IR robodoc.css . +The content of the file is copied into +.IR robodoc.css . + +.IP --dbxml +Generate documentation in XML DocBook format. + +.IP --latex +Generate documentation in LaTeX format. + +.IP --rtf +Generate documentation in RTF format. + +.IP --index +Create an additional master index file. + +.IP --multidoc +Store all documentation in seperate files. + +.IP --singledoc +Store all documentation in a single file. + +.IP --singlefile +Generate a single document from a single file + +.IP --toc +Add a table of contents. This works in multidoc mode as well as singledoc mode. + +.IP --internal +Also include headers marked internal. + +.IP --internalonly +Only include headers marked internal. + +.IP --ignore_case_when_linking +Ignore the case of the symbols when trying to find crosslinks. +In this mode FOO and Foo will be linked to foo. + +.IP --footless +Do not create the food of a document. + +.IP --headless +Do not create the head of a document. + +.IP --lock +Per source file +.B ROBODoc +locks on the first headermarker it finds and will recognize only that +particular headermarker for the remaining part of the file. In addition +it locks on the first remark marker in each header and will recognize +only that particular remark marker for the remaining part of the header. + +.IP --nosource +Do not include the SOURCE items. + +.IP --nodesc +Do not scan any subdirectories, scan only the top level directory +of the source tree. + +.IP --nopre +Do not use
     and 
    in the HTML output, instead based on +the layout of the text create paragraphs, item lists, and +preformatted sections. + +.IP --rc +Use the specified file instead of +.IR robodoc.rc . +Note that definitions in a configuration file over-ride +built-in settings. + +.IP --sections +Create sections based on the module hierarchy. + +.IP --tabsize +Lets you specify the tabsize. + +.IP --tell +.B ROBODoc +tells you about every step it takes. + +.IP --version +Print version information and exit. + +.SH EXAMPLES + +.EX +robodoc --src ./ --doc myproject --singledoc --html +.EE + +Creates a document called myproject.html from all source files +in the current directory. + +.EX +robodoc --src ./myproject/ + --doc ./myprojectdoc --multidoc --html --index +.EE + +Creates seperate documents for all the source files found in +the directory ./myproject they are stored in the directory ./myprojectdoc. +A master index file called ./myprojectdoc/masterindex.html is also +created. This provides links to all the individual files. + +.SH FILES +.SS "Example headers" +.PP +.nf +\fI/usr/local/share/doc/robodoc/Examples\fR +.fi + +.SH COPYRIGHT + +Copyright \(co 1994-2003 Frans Slothouber, Petteri Kettunen, and Jacco van Weert. + +.br +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +.SH AUTHORS + +Frans Slothouber, Jacco van Weert, Petteri Kettunen, Bernd Koesling, +Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, Sasha Vasko, +Nathan Prewitt and Dennis Stampfer. + +.SH SEE ALSO + +The documentation in HTML format that comes with ROBODoc. Latest +version can be found from http://www.xs4all.nl/~rfsber/Robo/ or from +http://sourceforge.net/projects/robodoc/. + +.BR robohdrs(1) diff --git a/Docs/robodoc.1.in b/Docs/robodoc.1.in new file mode 100644 index 0000000..dab6510 --- /dev/null +++ b/Docs/robodoc.1.in @@ -0,0 +1,188 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH ROBODoc "1" "Jul 2006" "ROBODoc 4.99.28" + +.SH NAME +ROBODoc \- Extract documentation from source code. + +.SH SYNOPSIS +.B robodoc +.I --src + +.I --doc + +.B [options] + +.SH DESCRIPTION + +ROBODoc extracts specially formated documentation from the source code. +It allows you to maintain a program and its documentation in a single +file. + +.SH OPTIONS + +.IP -c +Show the copyright message. + +.IP --cmode +Use ANSI C grammar in SOURCE items and use this for some syntax +highlighting (HTML only). + +.IP --doc +Define the documentation directory or documentation file. +A directory should start with a '/' or a './' and +should not include any '..'. + +.IP --src +Define the source directory or source file. A directory should start +with a '/' or a './' and should not include any '..'. + +.IP --ascii +Generate documentation in ASCII format. + +.IP --html +Generate documentation in HTML format. + +.IP --css +Use to content of the specified file to create the +.IR robodoc.css . +The content of the file is copied into +.IR robodoc.css . + +.IP --dbxml +Generate documentation in XML DocBook format. + +.IP --latex +Generate documentation in LaTeX format. + +.IP --rtf +Generate documentation in RTF format. + +.IP --index +Create an additional master index file. + +.IP --multidoc +Store all documentation in seperate files. + +.IP --singledoc +Store all documentation in a single file. + +.IP --singlefile +Generate a single document from a single file + +.IP --toc +Add a table of contents. This works in multidoc mode as well as singledoc mode. + +.IP --internal +Also include headers marked internal. + +.IP --internalonly +Only include headers marked internal. + +.IP --ignore_case_when_linking +Ignore the case of the symbols when trying to find crosslinks. +In this mode FOO and Foo will be linked to foo. + +.IP --footless +Do not create the food of a document. + +.IP --headless +Do not create the head of a document. + +.IP --lock +Per source file +.B ROBODoc +locks on the first headermarker it finds and will recognize only that +particular headermarker for the remaining part of the file. In addition +it locks on the first remark marker in each header and will recognize +only that particular remark marker for the remaining part of the header. + +.IP --nosource +Do not include the SOURCE items. + +.IP --nodesc +Do not scan any subdirectories, scan only the top level directory +of the source tree. + +.IP --nopre +Do not use
     and 
    in the HTML output, instead based on +the layout of the text create paragraphs, item lists, and +preformatted sections. + +.IP --rc +Use the specified file instead of +.IR robodoc.rc . +Note that definitions in a configuration file over-ride +built-in settings. + +.IP --sections +Create sections based on the module hierarchy. + +.IP --tabsize +Lets you specify the tabsize. + +.IP --tell +.B ROBODoc +tells you about every step it takes. + +.IP --version +Print version information and exit. + +.SH EXAMPLES + +.EX +robodoc --src ./ --doc myproject --singledoc --html +.EE + +Creates a document called myproject.html from all source files +in the current directory. + +.EX +robodoc --src ./myproject/ + --doc ./myprojectdoc --multidoc --html --index +.EE + +Creates seperate documents for all the source files found in +the directory ./myproject they are stored in the directory ./myprojectdoc. +A master index file called ./myprojectdoc/masterindex.html is also +created. This provides links to all the individual files. + +.SH FILES +.SS "Example headers" +.PP +.nf +\fI@prefix@/share/doc/robodoc/Examples\fR +.fi + +.SH COPYRIGHT + +Copyright \(co 1994-2003 Frans Slothouber, Petteri Kettunen, and Jacco van Weert. + +.br +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +.SH AUTHORS + +Frans Slothouber, Jacco van Weert, Petteri Kettunen, Bernd Koesling, +Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, Sasha Vasko, +Nathan Prewitt and Dennis Stampfer. + +.SH SEE ALSO + +The documentation in HTML format that comes with ROBODoc. Latest +version can be found from http://www.xs4all.nl/~rfsber/Robo/ or from +http://sourceforge.net/projects/robodoc/. + +.BR robohdrs(1) diff --git a/Docs/robodoc.rc b/Docs/robodoc.rc new file mode 100644 index 0000000..5a89f80 --- /dev/null +++ b/Docs/robodoc.rc @@ -0,0 +1,113 @@ +# +# $Id: robodoc.rc,v 1.3 2006/08/21 19:15:58 gumpu Exp $ +# +# Example robodoc.rc file. +# +options: + --doc MultiDocOPHHtml + --one_file_per_header + --src Source + --html + --multidoc + --documenttitle "ROBODoc API" + --index + --cmode + --tabsize 8 + --nopre + --sections +source items: + SYNOPSIS +items: + SOURCE + NAME + COPYRIGHT + SYNOPSIS + USAGE + FUNCTION + DESCRIPTION + PURPOSE + AUTHOR + CREATION DATE + MODIFICATION HISTORY + HISTORY + INPUTS + INPUT + ARGUMENTS + OPTIONS + PARAMETERS + SWITCHES + OUTPUT + SIDE EFFECTS + RESULTS + RESULT + RETURN VALUE + EXAMPLE + NOTE + NOTES + DIAGNOSTICS + WARNINGS + ERRORS + BUGS + TODO + IDEAS + PORTABILITY + SEE ALSO + METHODS + NEW METHODS + ATTRIBUTES + NEW ATTRIBUTES + TAGS + COMMANDS + DERIVED FROM + DERIVED BY + USES + CHILDREN + USED BY + PARENTS +ignore items: + HISTORY +headertypes: + u Unittests robo_unittest + x "System tests" robo_sys_tests + e "Makefile entries" robo_mk_entries +ignore files: + t + makefile.am + README + CVS + Doc + Doc1 + Doc2 + Doc3 + FileFilterSrc + FileFilterSrc_2 + RoboHeaders + Scr1 + Scr2 + SortSource + *.dat + *.html + *.rc + late* + troff* + sgml* + *.css + *.refs + *.in + *.txt + *~ + *.stderr + Scr1 + Scr2 + Doc1 + Doc2 + SortSource + RoboHeaders + FileFilterSrc +remark begin markers: + /* + # +remark end markers: + */ + # + diff --git a/Docs/robohdrs.1 b/Docs/robohdrs.1 new file mode 100644 index 0000000..7e4394c --- /dev/null +++ b/Docs/robohdrs.1 @@ -0,0 +1,80 @@ +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH robohdrs "1" "August 2003" "robohdrs 0.02" +.SH NAME +robohdrs \- insert ROBODoc headers to source code. +.SH SYNOPSIS +.B robohdrs +.B [options] + + +.SH DESCRIPTION + +robohdrs inserts ROBODoc headers to source code files. This program +processes one source file at the time. Existing ROBODoc headers, if +any, are not checked for. Beware since this may result in double +headers. Current working directory should be the same as where the +source file is located. + +By default NAME and SYNOPSIS items are included in the template +header. + +.SH OPTIONS + +.IP -h +Show brief help on usage and exit. +.IP -i +Specify an extra header item to be included in template header. Repeat +if multiple extra items are desired. +.IP -l +Specify source code language (default C/C++) Supported options are: +fortran, fortran90, script, and tex. +.IP -p +Specify project name for source file header. +.IP -s +Include SOURCE item. +.IP -t +Specify version control tag to be included in the main header. +.IP -x +Specify path to ctags binary which is used. + +.SH EXAMPLES + +.EX +robohdrs -s -p myproj -i "MODIFICATION HISTORY" -i IDEAS test.c +.EE + +Specifies project name myproj and inserts extra items MODIFICATION +HISTORY, IDEAS, and SOURCE to all template headers (excluding source +file header). + +.EX +robohdrs -s -p myproj -l script test.tcl +.EE + +Insert headers to a Tcl/Tk script. + +.SH COPYRIGHT + +Copyright \(co 2003 Frans Slothouber and Petteri Kettunen and Jacco van Weert. +.br +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +.SH SEE ALSO + +.BR robodoc(1) + + + diff --git a/Docs/tips.xml b/Docs/tips.xml new file mode 100644 index 0000000..79d23d3 --- /dev/null +++ b/Docs/tips.xml @@ -0,0 +1,436 @@ +
    +Tips and Tricks + +
    +The SOURCE Item + + With a little extra work you can include part of your + source code into your documentation too. The following example + shows how this is done: + + +/****f* Robodoc/RB_Panic [2.0d] + * NAME + * RB_Panic - Shout panic, free resources, and shut down. + * SYNOPSIS + * RB_Panic (cause, add_info) + * RB_Panic (char *, char *) + * FUNCTION + * Prints an error message. + * Frees all resources used by robodoc. + * Terminates program. + * INPUTS + * cause - pointer to a string which describes the + * cause of the error. + * add_info - pointer to a string with additional information. + * SEE ALSO + * RB_Close_The_Shop () + * SOURCE + */ + + void RB_Panic (char *cause, char *add_info) + { + printf ("Robodoc: Error, %s\n",cause) ; + printf (" %s\n", add_info) ; + printf ("Robodoc: Panic Fatal error, closing down..\n") ; + RB_Close_The_Shop () ; /* Free All Resources */ + exit(100) ; + } + +/*******/ + + +You can add a SOURCE item as the last item of your header. Then + instead of closing your header with an end marker, you close it + normally. The end marker is instead placed at the end of the + fragment of source code that you want to include. + +SOURCE items are included by default. If you want to create a + document without the SOURCE items use the option + . + +You can also make normal items work like the source item, + see . + +
    + + +
    +Minimizing Duplicate Information + +It is always good to avoid having the same information in several different locations. + It is easy to create headers that have a lot information duplication. Take for instance + the following header. + + + +/****f* Robodoc/RB_Panic [2.0d] + * NAME + * RB_Panic - Shout panic, free resources, and shut down. + * SYNOPSIS + * RB_Panic (cause, add_info) + * RB_Panic (char *, char *) + * FUNCTION + * Prints an error message. + * Frees all resources used by robodoc. + * Terminates program. + * INPUTS + * cause - pointer to a string which describes the + * cause of the error. + * add_info - pointer to a string with additional information. + * SEE ALSO + * RB_Close_The_Shop () + * SOURCE + */ + + void RB_Panic (char *cause, char *add_info) + { + printf ("Robodoc: Error, %s\n",cause) ; + printf (" %s\n", add_info) ; + printf ("Robodoc: Panic Fatal error, closing down..\n") ; + RB_Close_The_Shop () ; /* Free All Resources */ + exit(100) ; + } + +/*******/ + + + + The name RB_Panic occurs five times. This is tedious to + type and difficult to maintain. + However with a the right robodoc.rc this can be changed + to: + + + +/****f* Robodoc/RB_Panic [2.0d] + * SUMMARY + * Shout panic, free resources, and shut down. + * SYNOPSIS + */ + +void RB_Panic (char* cause, char *add_info) + +/* + * FUNCTION + * Prints an error message. + * Frees all resources used by robodoc. + * Terminates program. + * INPUTS + * cause - pointer to a string which describes the + * cause of the error. + * add_info - pointer to a string with additional information. + * SEE ALSO + * RB_Close_The_Shop () + * SOURCE + */ + { + printf ("Robodoc: Error, %s\n",cause) ; + printf (" %s\n", add_info) ; + printf ("Robodoc: Panic Fatal error, closing down..\n") ; + RB_Close_The_Shop () ; /* Free All Resources */ + exit(100) ; + } + +/*******/ + + +RB_Panic occurs only twice now. In addition changes +to the function definition only have to be done once. + +The robodoc.rc required for this is: + + +# robodoc.rc file +items: + SUMMARY + SYNOPSIS + INPUTS + OUTPUTS + SEE ALSO + BUGS +source items: + SYNOPSIS +remark begin markers: + /* +remark end markers: + */ + + +
    + + + +
    +Advanced formatting with raw HTML and LaTeX code + + By default an item's body shows up in your documentation in + the same way as it is formatted in your source code. All special + characters for the output mode are escaped. For instance an < + is translated to a &lt; in HTML mode. Sometimes however you + like to have some more control of what goes into the + documentation. This is possible with the piping. If a line of + your item's body starts with one of the special piping markers, the + text after this marker is copied verbatim into your documentation. + The following example shows how this is done, and how to add + equations to your documentation. + + + +/****m* pipe/pipetest + * NAME + * pipetest + * DESCRIPTION + * Simple header to show "piping" features in items. + * EXAMPLE + * Only "pipes" which match selected output style are picked up. + * |html <CENTER>This will be included in <B>HTML</B> output.</CENTER> + * |latex \centerline{This will be included in \LaTeX output} + * Space is mandatory following the pipe marker. The following is not a + * valid pipe marker: + * |html<B>Moi!</B> + * You should see an equation on the following line: + * |html y = x^2 (sorry, plain HTML is not very powerful) + * |latex \centerline{$y = x^2$} + * How does this look like? + * Here comes a multi-line equation array: + * |latex \begin{eqnarray} + * |latex \frac{\partial u}{\partial \tau} & = & D_u {\nabla}^2 u + + * |latex \frac{1}{\epsilon} + * |latex \left ( \hat{u}-{\hat{u}}^2-f\, {v} \, \frac{\hat{u}-q}{\hat{u}+q} + * |latex \right ) \; , \label{diffspot:1} \\ + * |latex \frac{\partial v}{\partial \tau} & = & \hat{u}-v \; , + * |latex \label{diffspot:2} \\ + * |latex \frac{\partial r}{\partial \tau} & = & D_r {\nabla}^2 r \; . + * |latex \label{diffspAot:3} + * |latex \end{eqnarray} + * |html <I>TODO: write this in html</I> + * End of the example. + ****** + */ + +
    + +
    +Linking to external documents (href, file, mailto, images) + + In HTML mode ROBODoc recognizes the following links to + external documents. + + + + href:body -- This is replaced with + <a href="body">body</A> + + + file:/body -- This is replaced with + <a href="file:/body">file:/body</A> + + + mailto:body -- This is replaced with + <a href="mailto:body">body</A> + + + http://body -- This is replaced with + <a href="http://body">http://body</A> + + + image:body -- This is replaced with + <image src="body"> + + + +
    + + +
    +Linking from an external document + + To link from an external document to one of the HTML + documents generated by ROBODoc you need a label. ROBODoc creates + two labels for each header. The first one starts with + robo followed by a number. You can not use + this one because the numbers will change each time you run + ROBODoc. The second label is an escaped version of the whole + header name. In this label all the non alphanumeric characters of + the name are replaced by their two digit hexadecimal code. + + An example, if your header name is + Analyser/RB_ToBeAdded the label is + Analyser2fRB5fToBeAdded. Here + / was replaced by 2f and + _ was replaced by 5f. As + long as you do not change the header name, this label stays the + same each time you run ROBODoc. + +
    + +
    +Using external tools + + You can also execute external tools from ROBODoc and even + pass data to them. + The output of these tools can be included in your documentation for instance. + + + There are several types of external tools you can use: + + + Arbitrary tool with passing data through stdin + Arbitrary tool without passing data through stdin + The DOT tool + + + The following example shows how to use each of them. + + + +/****m* tools/tooltest + * + * NAME + * Tooltest + * + * DESCRIPTION + * Example showing how to invoke external tools. + * + * EXAMPLE + * This one sorts elements into the file href:nexus-6.txt + * The input data is passed through stdin. + * + * |tool sort > nexus-6.txt + * Zhora + * Pris + * Leon Kowalski + * Roy Batty + * Rachel + * Rick Deckard? + * |tool end + * + * We can also execute tools without having any stdin data. + * In the following example the output is simply redirected into href:tears.txt + * + * |exec echo "All those moments will be lost in time like tears in rain." > tears.txt + * + * You can also include neat DOT graphs in your documentation. + * This one shows a hash table. + * + * |dot start + * digraph G { + * nodesep=.05; + * rankdir=LR; + * node [shape=record,width=.1,height=.1]; + * + * node0 [label = "<f0> |<f1> |<f2> |<f3> |<f4> |<f5> |<f6> | ",height=2.0]; + * node [width = 1.5]; + * node1 [label = "{<n> n14 | 719 |<p> }"]; + * node2 [label = "{<n> a1 | 805 |<p> }"]; + * node3 [label = "{<n> i9 | 718 |<p> }"]; + * node4 [label = "{<n> e5 | 989 |<p> }"]; + * node5 [label = "{<n> t20 | 959 |<p> }"] ; + * node6 [label = "{<n> o15 | 794 |<p> }"] ; + * node7 [label = "{<n> s19 | 659 |<p> }"] ; + * + * node0:f0 -> node1:n; + * node0:f1 -> node2:n; + * node0:f2 -> node3:n; + * node0:f5 -> node4:n; + * node0:f6 -> node5:n; + * node2:p -> node6:n; + * node4:p -> node7:n; + * } + * |dot end + * + ****** + */ + + + + If you want to use the DOT tool you need the + Graphviz package. + More information and the binaries can be found at + + http://www.graphviz.org/ + . + The created graphs are automatically included in the documentation + (HTML and LaTeX only). + If you generate PDF output from your LaTeX + file and you want to include DOT graphs in it, you will also + need the epstopdf utility. + ROBODoc lets DOT generate + PNG images for HTML output and + PS and PDF images for + LaTeX output. + +
    + +
    +ROBODoc-ing an existing project + + + The ROBODoc package includes also a standalone binary named + robohdrs. + This helper program can take clean source file and insert + ROBODoc headers to functions, global variables, and macros. + There are issues with this tool but it saves lots of cumbersome typing + when starting on documenting an existing code-base with ROBODoc. + Type + +man robohdrs + + or + +robohdrs -h + + for help. + Example: + +robohdrs -s -p testproj -i "MODIFICATION HISTORY" -i IDEAS testproj.c + + + + + Note that robohdrs is supported on UNIX-like platforms only. + It requires fork() and Exuberant Ctags 5.3.1 or newer. + + +
    + + +
    +Using ROBODoc under Windows + When you use ROBODoc under windows, don't forget that it is + a command line tool. ROBODoc relies on the console window to + inform you about problems and errors. + + An easy mistake to make is to create a shortcut to + robodoc.exe and then click on the icon to + generate the documentation each time you made some changes to your + source code. If you have a fast machine a console window pops up + quickly and after that your documentation is ready. + + This works very fine until you make a mistake in one of your + headers. The console window still pops up, but before you have a chance + to read any of the error messages it is gone again. Most likely + you won't even have noticed there were error messages. You will + end up with empty documentation or old documentation. + + It is Better to create a batch file with the following commands + and to store all the options in a robodoc.rc + file: + +robodoc.exe +pause + + Now the console window stays open and you have the + opportunity to read the error messages. + + While the window is open, right click on the title bar, + go to properties->layout and set the buffer size to something + like 2500. That way, the next time you run it, you can scroll back + and view all error messages. + + +
    + +
    + diff --git a/Examples/PerlExample/Doc/robo_classes.html b/Examples/PerlExample/Doc/robo_classes.html new file mode 100644 index 0000000..9d894c8 --- /dev/null +++ b/Examples/PerlExample/Doc/robo_classes.html @@ -0,0 +1,40 @@ + + + + +Classes + + + + + +Generated from ./Source/ with ROBODoc v4.0.17 on Mon Dec 29 20:09:37 2003 +
    +

    +[Sourcefiles] +[Index] +[Classes] +[Modules] +[Methods] +

    +

    Classes

    + + + + + + + + + + + + + +
    +Box +RectangularBox +SmartLoader +SquareBox
    + + diff --git a/Examples/PerlExample/Doc/robo_methods.html b/Examples/PerlExample/Doc/robo_methods.html new file mode 100644 index 0000000..9053c84 --- /dev/null +++ b/Examples/PerlExample/Doc/robo_methods.html @@ -0,0 +1,40 @@ + + + + +Methods + + + + + +Generated from ./Source/ with ROBODoc v4.0.17 on Mon Dec 29 20:09:37 2003 +
    +

    +[Sourcefiles] +[Index] +[Classes] +[Modules] +[Methods] +

    +

    Methods

    + + + + + + + + + + + + + +
    +RectangularBox::volume +SmartLoader::pack +SquareBox::side +SquareBox::volume
    + + diff --git a/Examples/PerlExample/Doc/robo_modules.html b/Examples/PerlExample/Doc/robo_modules.html new file mode 100644 index 0000000..2d523f0 --- /dev/null +++ b/Examples/PerlExample/Doc/robo_modules.html @@ -0,0 +1,37 @@ + + + + +Modules + + + + + +Generated from ./Source/ with ROBODoc v4.0.17 on Mon Dec 29 20:09:37 2003 +
    +

    +[Sourcefiles] +[Index] +[Classes] +[Modules] +[Methods] +

    +

    Modules

    + + + + + + + + + + + +
    +Cargo +Loader +TruckPacker
    + + diff --git a/Examples/PerlExample/Doc/robo_sourcefiles.html b/Examples/PerlExample/Doc/robo_sourcefiles.html new file mode 100644 index 0000000..c216b60 --- /dev/null +++ b/Examples/PerlExample/Doc/robo_sourcefiles.html @@ -0,0 +1,52 @@ + + + + +Sourcefiles + + + + + +Generated from ./Source/ with ROBODoc v4.0.17 on Mon Dec 29 20:09:37 2003 +
    +

    +[Sourcefiles] +[Index] +[Classes] +[Modules] +[Methods] +

    + + + diff --git a/Examples/PerlExample/Source/Box.pm b/Examples/PerlExample/Source/Box.pm new file mode 100644 index 0000000..3677aac --- /dev/null +++ b/Examples/PerlExample/Source/Box.pm @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +#****c* Cargo/Box +# FUNCTION +# A box that can be packed into truck. +# Several other classes are derived from Box. +# Box +# | +# +---- SquareBox +# | +# +---- RectangularBox +#****** + +package Box; + +sub new { + my $class = shift; + my $self = { }; + bless ($self, $class); + return $self; +} + +1; + diff --git a/Examples/PerlExample/Source/Box/RectangularBox.pm b/Examples/PerlExample/Source/Box/RectangularBox.pm new file mode 100644 index 0000000..c04a6d1 --- /dev/null +++ b/Examples/PerlExample/Source/Box/RectangularBox.pm @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +#****c* Box/RectangularBox +# FUNCTION +# A box with the property that are sides are equal. +# ATTRIBUTES +# DEPTH -- the depth of the box. +# HEIGHT -- the height of the box. +# WIDTH -- the width of the box. +# DERIVED FROM +# Box +#****** + +package RectangularBox; + +use Box; +use vars ('@ISA'); +@ISA = ("Box"); + +sub new { + my $classname = shift; + my $self = $classname->SUPER::new(@_); + $self->{DEPTH} = 1; + $self->{HEIGHT} = 1; + $self->{WIDTH} = 1; + return $self; +} + +#****m* Box/RectangularBox::volume +# FUNCTION +# Compute the volume of the rectangular box. +# SYNOPSIS +# my $volume = $boxref->volume(); +# RETURN VALUE +# The volume of the box +# SOURCE + +sub volume { + my $self = { }; + return $self->{DEPTH} * $self->{HEIGHT} * $self->{WIDTH}; +} + +#***** + +1; + + diff --git a/Examples/PerlExample/Source/Box/SquareBox.pm b/Examples/PerlExample/Source/Box/SquareBox.pm new file mode 100644 index 0000000..902ecfd --- /dev/null +++ b/Examples/PerlExample/Source/Box/SquareBox.pm @@ -0,0 +1,65 @@ +#!/usr/bin/perl -w + +#****c* Box/SquareBox +# FUNCTION +# A box with the property that are sides are equal. +# ATTRIBUTES +# SIDE_LENGTH -- the length of each side +# DERIVED FROM +# Box +# SOURCE + +package SquareBox; + +use Box; +use vars ('@ISA'); +@ISA = ("Box"); + +sub new { + my $classname = shift; + my $self = $classname->SUPER::new(@_); + $self->{SIDE} = 1; + return $self; +} + +#******* + + +#****m* Box/SquareBox::side +# FUNCTION +# Set or get the side length of the square box. +# SYNOPSIS +# $boxref->side(100.25); +# my $length = $boxref->side(); +# RETURN VALUE +# The volume of the box +# SOURCE + +sub side { + my $self = shift; + if (@_) { + my $length = shift; + $self->{SIDE} = $length; + } + return $self->{SIDE}; +} + +#******* + +#****m* Box/SquareBox::volume +# FUNCTION +# Compute the volume of a square box. +# SYNOPSIS +# my $volume = $boxref->volume(); +# RETURN VALUE +# The volume of the box +# SOURCE + +sub volume { + my $self = { }; + return $self{SIDE} * $self{SIDE} * $self{SIDE} ; +} + +#***** +1; + diff --git a/Examples/PerlExample/Source/Cargo.txt b/Examples/PerlExample/Source/Cargo.txt new file mode 100644 index 0000000..b20e97f --- /dev/null +++ b/Examples/PerlExample/Source/Cargo.txt @@ -0,0 +1,9 @@ + +#****h* TruckPacker/Cargo +# FUNCTION +# +# The Cargo module consist of a number of classes that represent +# that cargo that can be loaded into a truck. +# The most important one is Box. +# +#**** diff --git a/Examples/PerlExample/Source/Loader.txt b/Examples/PerlExample/Source/Loader.txt new file mode 100644 index 0000000..20249d3 --- /dev/null +++ b/Examples/PerlExample/Source/Loader.txt @@ -0,0 +1,9 @@ +#****h* TruckPacker/Loader +# FUNCTION +# The Loader module consist of a number of classes that represent +# that various algorithms to pack Cargo into a truck.. +# +# Currently only on algorithm (SmartLoader) has been implemented. +# +#**** + diff --git a/Examples/PerlExample/Source/SmartLoader.pm b/Examples/PerlExample/Source/SmartLoader.pm new file mode 100644 index 0000000..f1ca4ce --- /dev/null +++ b/Examples/PerlExample/Source/SmartLoader.pm @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w + +#****c* Loader/SmartLoader +# FUNCTION +# This class implements an O(1) packing +# algorithm. +# ATTRIBUTES +# CARGO -- the cargo to be packed. +#****** + +Package SmartLoader; + +sub new { + my $class = shift; + my $self = { }; + bless ($self, $class); + my $self->{CARGO} = (); + return $self; +} + +#****m* Loader/SmartLoader::pack +# FUNCTION +# A O(1) packing algorithm. +# SYNOPSIS +# my $sequence = $packref->pack(); +# RETURN VALUE +# A squence that specifies how to pack the truck. +#****** + +sub pack { + return 0; +} + +1; diff --git a/Examples/PerlExample/Source/TruckPacker.pl b/Examples/PerlExample/Source/TruckPacker.pl new file mode 100644 index 0000000..ac635a8 --- /dev/null +++ b/Examples/PerlExample/Source/TruckPacker.pl @@ -0,0 +1,25 @@ +#!/usr/bin/perl -w + +#****h* FactoryTools/TruckPacker +# FUNCTION +# A program to effectively pack a truck with cargo. +# It consists of two modules: +# Cargo -- classes to define the kind of cargo +# that can be packed. +# Loader -- classes to define various packing +# algorithms. +# +#**** + +use Box; +use SquareBox; +use RectangularBox; +use Loader; + +sub main { + print "Hello world\n"; +} + +main(); + + diff --git a/Examples/PerlExample/robodoc.rc b/Examples/PerlExample/robodoc.rc new file mode 100644 index 0000000..4a8532d --- /dev/null +++ b/Examples/PerlExample/robodoc.rc @@ -0,0 +1,11 @@ +options: + --src ./Source + --doc ./Doc + --html + --multidoc + --sections + --tell + --toc + --index +ignore files: + CVS diff --git a/Headers/assembler.sample b/Headers/assembler.sample new file mode 100644 index 0000000..dbf066b --- /dev/null +++ b/Headers/assembler.sample @@ -0,0 +1,63 @@ +****h* main_module/module [1.0] * +* +* NAME +* +* COPYRIGHT +* +* FUNCTION +* +* AUTHOR +* +* CREATION DATE +* +* MODIFICATION HISTORY +* +* NOTES +* +******* + + +****f* module/procname [1.0] * +* +* NAME +* +* SYNOPSIS +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +********** + + +****i* module/i_procname [1.0] * +* +* NAME +* +* SYNOPSIS +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +********** diff --git a/Headers/basic.sample b/Headers/basic.sample new file mode 100644 index 0000000..22fca0c --- /dev/null +++ b/Headers/basic.sample @@ -0,0 +1,63 @@ +REM ****h* main_module/module [1.0] * +REM +REM NAME +REM +REM COPYRIGHT +REM +REM FUNCTION +REM +REM AUTHOR +REM +REM CREATION DATE +REM +REM MODIFICATION HISTORY +REM +REM NOTES +REM +REM ***** + + +REM ***** module/procname [1.0] * +REM +REM NAME +REM +REM SYNOPSIS +REM +REM FUNCTION +REM +REM INPUTS +REM +REM RESULT +REM +REM EXAMPLE +REM +REM NOTES +REM +REM BUGS +REM +REM SEE ALSO +REM +REM ******** + + +REM ****i* module/i_procname [1.0] * +REM +REM NAME +REM +REM SYNOPSIS +REM +REM FUNCTION +REM +REM INPUTS +REM +REM RESULT +REM +REM EXAMPLE +REM +REM NOTES +REM +REM BUGS +REM +REM SEE ALSO +REM +REM ******** diff --git a/Headers/c.sample b/Headers/c.sample new file mode 100644 index 0000000..292710d --- /dev/null +++ b/Headers/c.sample @@ -0,0 +1,46 @@ +/****h* projectname/module_name [1.0] +* NAME +* COPYRIGHT +* FUNCTION +* AUTHOR +* CREATION DATE +* MODIFICATION HISTORY +* NOTES +******* +*/ + + +/****f* module_name/function_name [1.0] * +* NAME +* SYNOPSIS +* FUNCTION +* INPUTS +* RESULT +* EXAMPLE +* NOTES +* BUGS +* SEE ALSO +********** +*/ + + +/****s* module_name/stucture_name [1.0] * +* NAME +* PURPOSE +* ATTRIBUTES +* NOTES +* BUGS +* SEE ALSO +********** +*/ + + +/****v* module_name/variable_name [1.0] * +* NAME +* PURPOSE +* NOTES +* BUGS +* SEE ALSO +********** +*/ + diff --git a/Headers/cpp.sample b/Headers/cpp.sample new file mode 100644 index 0000000..1a64a60 --- /dev/null +++ b/Headers/cpp.sample @@ -0,0 +1,68 @@ +/****h* projectname/module_name [1.0] +* NAME +* COPYRIGHT +* FUNCTION +* AUTHOR +* CREATION DATE +* MODIFICATION HISTORY +* NOTES +******* +*/ + + +/****f* module_name/funtion_name [1.0] * +* NAME +* SYNOPSIS +* FUNCTION +* INPUTS +* RESULT +* EXAMPLE +* NOTES +* BUGS +* SEE ALSO +********** +*/ + +/****f* module_name/funtion_name2 [1.0] * +* NAME +* SYNOPSIS +* FUNCTION +* INPUTS +* RESULT +* EXAMPLE +* NOTES +* BUGS +* SEE ALSO +* SOURCE +*/ + +example() + +/**********/ + + +/****c* module_name/class_name [1.0] * +* NAME +* PURPOSE +* METHODS +* DERIVED FROM +* DERIVED BY +* EXAMPLE +* NOTES +* BUGS +* SEE ALSO +********** +*/ + + +/****m* module_name/method_name [1.0] * +* NAME +* SYNOPSIS +* PURPOSE +* EXAMPLE +* NOTES +* BUGS +* SEE ALSO +********** +*/ + diff --git a/Headers/forth.sample b/Headers/forth.sample new file mode 100644 index 0000000..14c1c6e --- /dev/null +++ b/Headers/forth.sample @@ -0,0 +1,43 @@ +\ ****h* main_module/module [1.0] * +\ NAME +\ module +\ COPYRIGHT +\ moi copyright +\ FUNCTION +\ moi function +\ AUTHOR +\ moi author +\ CREATION DATE +\ moi date +\ MODIFICATION HISTORY +\ moi history +\ NOTES +\ ******* + +\ ****f* module/procname [1.0] * +\ NAME +\ SYNOPSIS +\ FUNCTION +\ INPUTS +\ RESULT +\ EXAMPLE +\ NOTES +\ BUGS +\ SEE ALSO +\ ******** + +\ ****f* module/procname2 [1.0] * +\ NAME +\ SYNOPSIS +\ FUNCTION +\ INPUTS +\ RESULT +\ EXAMPLE +\ NOTES +\ BUGS +\ SEE ALSO +\ SOURCE + +hello_forth() + +\ ******** diff --git a/Headers/fortran.sample b/Headers/fortran.sample new file mode 100644 index 0000000..b646a73 --- /dev/null +++ b/Headers/fortran.sample @@ -0,0 +1,63 @@ +C ****h* main_module/module [1.0] * +C +C NAME +C +C COPYRIGHT +C +C FUNCTION +C +C AUTHOR +C +C CREATION DATE +C +C MODIFICATION HISTORY +C +C NOTES +C +C ***** + + +C ***** module/procname [1.0] * +C +C NAME +C +C SYNOPSIS +C +C FUNCTION +C +C INPUTS +C +C RESULT +C +C EXAMPLE +C +C NOTES +C +C BUGS +C +C SEE ALSO +C +C ******** + + +C ****i* module/i_procname [1.0] * +C +C NAME +C +C SYNOPSIS +C +C FUNCTION +C +C INPUTS +C +C RESULT +C +C EXAMPLE +C +C NOTES +C +C BUGS +C +C SEE ALSO +C +C ******** diff --git a/Headers/html.sample b/Headers/html.sample new file mode 100644 index 0000000..1d6d7ba --- /dev/null +++ b/Headers/html.sample @@ -0,0 +1,38 @@ + + + + + + + +

    Example Source

    + + diff --git a/Headers/makefile b/Headers/makefile new file mode 100644 index 0000000..8d25b83 --- /dev/null +++ b/Headers/makefile @@ -0,0 +1,2 @@ +clean: + rm -f *~ diff --git a/Headers/tcl.sample b/Headers/tcl.sample new file mode 100644 index 0000000..f3551f5 --- /dev/null +++ b/Headers/tcl.sample @@ -0,0 +1,39 @@ +#****h* main_module/module [1.0] * +# NAME +# COPYRIGHT +# FUNCTION +# AUTHOR +# CREATION DATE +# MODIFICATION HISTORY +# NOTES +#****** +# + +#****f* module/procname [1.0] * +# NAME +# SYNOPSIS +# FUNCTION +# INPUTS +# RESULT +# EXAMPLE +# NOTES +# BUGS +# SEE ALSO +#******** +# + +#****f* module/procname2 [1.0] * +# NAME +# SYNOPSIS +# FUNCTION +# INPUTS +# RESULT +# EXAMPLE +# NOTES +# BUGS +# SEE ALSO +# SOURCE + +example() + +#******** diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..095b1eb --- /dev/null +++ b/INSTALL @@ -0,0 +1,231 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +will cause the specified gcc to be used as the C compiler (unless it is +overridden in the site shell script). + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/INSTALL.Debian b/INSTALL.Debian new file mode 100644 index 0000000..ddd8f09 --- /dev/null +++ b/INSTALL.Debian @@ -0,0 +1,4 @@ +Debian users can install ROBODoc using apt-get as follows: + + apt-get install robodoc + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..1c53bca --- /dev/null +++ b/NEWS @@ -0,0 +1,3 @@ +See the changelog for a detailed list of add new +features. + diff --git a/README b/README new file mode 100644 index 0000000..7a921bb --- /dev/null +++ b/README @@ -0,0 +1,51 @@ +$d: README,v 1.5 2003/01/16 06:26:43 gumpu Exp $ + +ROBODoc Version 4.99.36 Jul 2007. + +ROBODoc is program documentation tool. The idea is to include for +every function or procedure a standard header containing all +sorts of information about the procedure or function. ROBODoc +extracts these headers from the source file and puts them in a +separate autodocs-file. ROBODoc thus allows you to include the +program documentation in the source code and avoid having to +maintain two separate documents. Or as Petteri puts it: "robodoc +is very useful - especially for programmers who don't like +writing documents with Word or some other strange tool." + +ROBODoc can format the headers in a number of different formats: +HTML, RTF, LaTeX, or XML DocBook. In HTML mode it can +generate cross links between headers. You can even include parts +of your source code. + +ROBODoc works with many programming languages: For instance C, +Pascal, Shell Scripts, Assembler, COBOL, Occam, Postscript, +Forth, Tcl/Tk, C++, Java -- basically any program in which you +can use remarks/comments. + + o For information on how to build and install see INSTALL + o For information on how to use ROBODoc see Docs/manual.html. + o Blank headers for various languages can be found in Headers/ + o For an example on how ROBODoc can be used see + the ROBODoc source code in Source/ + o For licence information see COPYING + o For a change log see Source/robodoc.c + +Many people contributed to ROBODoc, to name a few: + +o Petteri Kettunen + Bug fixes, FOLD, C features. +o Bernd Koesling + Bug fixes, functional improvements, code cleanup. +o Anthon Pang + RTF support, Bug fixes. +o Thomas Aglassinger + Fixes and cleanup of HTML-output +o Stefan Kost + Idea of the master index file and different header types. + +Questions, found a bug or a typo; send an email to [rfsber -a-t- xs4all.nl] + +(c) 1994-2005 Frans Slothouber, Petteri Kettunen, and Jacco van Weert + + + diff --git a/Source/.indent.pro b/Source/.indent.pro new file mode 100644 index 0000000..b93cb5d --- /dev/null +++ b/Source/.indent.pro @@ -0,0 +1,13 @@ +-nut +-i 4 +-bli 0 +-bls +-bad +-npcs +-bfda +-di20 +-prs +-npsl +--verbose +-T FILE +-T actions_t diff --git a/Source/Test/FileFilterSrc/README b/Source/Test/FileFilterSrc/README new file mode 100644 index 0000000..b532f3d --- /dev/null +++ b/Source/Test/FileFilterSrc/README @@ -0,0 +1 @@ +For testing diff --git a/Source/Test/FileFilterSrc/test.pas b/Source/Test/FileFilterSrc/test.pas new file mode 100644 index 0000000..a561404 --- /dev/null +++ b/Source/Test/FileFilterSrc/test.pas @@ -0,0 +1,5 @@ +#****f* Test/Test1 +# DESCRIPTION +# for testing +#***** + diff --git a/Source/Test/FileFilterSrc/test2.c b/Source/Test/FileFilterSrc/test2.c new file mode 100644 index 0000000..53ff1a4 --- /dev/null +++ b/Source/Test/FileFilterSrc/test2.c @@ -0,0 +1,5 @@ +#****f* Test/Test2 +# DESCRIPTION +# for testing +#***** + diff --git a/Source/Test/FileFilterSrc/test3.c b/Source/Test/FileFilterSrc/test3.c new file mode 100644 index 0000000..1968aca --- /dev/null +++ b/Source/Test/FileFilterSrc/test3.c @@ -0,0 +1,5 @@ +#****f* Test/Test3 +# DESCRIPTION +# for testing +#***** + diff --git a/Source/Test/FileFilterSrc/test4.c b/Source/Test/FileFilterSrc/test4.c new file mode 100644 index 0000000..c251968 --- /dev/null +++ b/Source/Test/FileFilterSrc/test4.c @@ -0,0 +1,5 @@ +#****f* Test/Test4 +# DESCRIPTION +# for testing +#***** + diff --git a/Source/Test/FileFilterSrc_2/AcceptDir/accept.h b/Source/Test/FileFilterSrc_2/AcceptDir/accept.h new file mode 100644 index 0000000..a6986b2 --- /dev/null +++ b/Source/Test/FileFilterSrc_2/AcceptDir/accept.h @@ -0,0 +1,5 @@ +#****f* Accept/TT3 +# NAME +# TT3 +#**** + diff --git a/Source/Test/FileFilterSrc_2/accept.c b/Source/Test/FileFilterSrc_2/accept.c new file mode 100644 index 0000000..dcd65c4 --- /dev/null +++ b/Source/Test/FileFilterSrc_2/accept.c @@ -0,0 +1,5 @@ +#****f* Accept/TT +# NAME +# TT +#**** + diff --git a/Source/Test/FileFilterSrc_2/accept.pl b/Source/Test/FileFilterSrc_2/accept.pl new file mode 100644 index 0000000..bd20a56 --- /dev/null +++ b/Source/Test/FileFilterSrc_2/accept.pl @@ -0,0 +1,5 @@ +#****f* Accept/TT2 +# NAME +# TT2 +#**** + diff --git a/Source/Test/FileFilterSrc_2/ignore.ign b/Source/Test/FileFilterSrc_2/ignore.ign new file mode 100644 index 0000000..6f3375e --- /dev/null +++ b/Source/Test/FileFilterSrc_2/ignore.ign @@ -0,0 +1,4 @@ +#****f* Ignore/Ignore +# Name +# Ignore +#*** diff --git a/Source/Test/FileFilterSrc_2/ignore.xxx b/Source/Test/FileFilterSrc_2/ignore.xxx new file mode 100644 index 0000000..6f3375e --- /dev/null +++ b/Source/Test/FileFilterSrc_2/ignore.xxx @@ -0,0 +1,4 @@ +#****f* Ignore/Ignore +# Name +# Ignore +#*** diff --git a/Source/Test/ROBOTest.pm b/Source/Test/ROBOTest.pm new file mode 100644 index 0000000..5092237 --- /dev/null +++ b/Source/Test/ROBOTest.pm @@ -0,0 +1,57 @@ +use strict; +package ROBOTest; + +my $ok = 1; +my $name = "unknown"; + +sub start { + $name = shift; +# printf("%-50s", $name); +} + +sub assertNotDir { + my $filename = shift; + assert( !( -d $filename ), "Directory $filename does not exists"); +} + +sub assertDir { + my $filename = shift; + assert( -d $filename, "Directory $filename exists"); +} + +sub assertNotFile { + my $filename = shift; + assert( !( -f $filename ), "File $filename does not exists"); +} + +sub assertFile { + my $filename = shift; + assert( -f $filename, "File $filename exists"); +} + +sub assert { + my $arg_ok = shift; + my $title = shift; + printf("%-32s", $name); + if ($title) { + printf("%-40s", $title); + } else { + printf("%-40s", "--"); + } + if ($arg_ok) { + print " OK\n"; + } else { + print " FAIL\n"; + } +} + +sub finish { +# if ($ok) { +# print "OK\n"; +# } else { +# print "FAIL\n"; +# } +} + +1; + diff --git a/Source/Test/RoboHeaders/rbh_test1.dat b/Source/Test/RoboHeaders/rbh_test1.dat new file mode 100644 index 0000000..6e536e0 --- /dev/null +++ b/Source/Test/RoboHeaders/rbh_test1.dat @@ -0,0 +1,20 @@ + + +int an_int_var = 100; + + +int test_function( int x, int y ) +{ + int i; + for ( i = 0; i < 100; ++i ) + { + printf("Hello\n"); + } +} + +int test_function2( int x, int y ) +{ + + +} + diff --git a/Source/Test/Scr1/Subdir/ccfile.dat b/Source/Test/Scr1/Subdir/ccfile.dat new file mode 100644 index 0000000..a78b3a5 --- /dev/null +++ b/Source/Test/Scr1/Subdir/ccfile.dat @@ -0,0 +1,9 @@ +#****h* Bbb__level2__/Dbb__level3__ +# FUNCTION +# Test. Level 3. +#****** + +#****v* Dbb__level3/__var1__ +# FUNCTION +# Test. +#**** diff --git a/Source/Test/Scr1/aafile.dat b/Source/Test/Scr1/aafile.dat new file mode 100644 index 0000000..82acfa9 --- /dev/null +++ b/Source/Test/Scr1/aafile.dat @@ -0,0 +1,27 @@ + +#****h* Aaa__level0__/Aaa__level1__ +# FUNCTION +# Test. This has name Aaa.. so it should +# be a the begin of the TOC +#****** + +#****h* Aaa__level1__/Bbb__level2__ +# FUNCTION +# Test. Level 2. +#****** + +#****h* Bbb__level2__/Abb__level3__ +# FUNCTION +# Test. Level 3. +#****** + +#****h* Bbb__level2__/Bbb__level3__ +# FUNCTION +# Test. Level 3. +#****** + +#****h* Bbb__level2__/Cbb__level3__ +# FUNCTION +# Test. Level 3. +#****** + diff --git a/Source/Test/Scr1/bbfile.dat b/Source/Test/Scr1/bbfile.dat new file mode 100644 index 0000000..4e0d208 --- /dev/null +++ b/Source/Test/Scr1/bbfile.dat @@ -0,0 +1,71 @@ + +#****d* Test/_test_def1_test_ +# NAME +# +#**** + +#****d* Test/_test_def2_test_ +# NAME +# +#**** + + +#****f* Test/_test_fun1_test_ +# NAME +# +#**** + +#****f* Test/_test_fun2_test_ +# NAME +# +#**** + +#****c* Test/_test_class1_test_ +# NAME +# +#**** + +#****c* Test/_test_class2_test_ +# NAME +# +#**** + +#****c* Test/_test_class3_test_ +# NAME +# +#**** + + +#****v* Test/_test_var1_test_ +# NAME +# +#***** + +#****h* Test/_test_mod1_test_ +# NAME +# +#******* + +#****s* Test/_test_struct1_test_ +# NAME +# +#****** + + +#****t* Test/_test_type1_test_ +# NAME +# +#****** + +#****e* Test/_test_exception1_test_ +# NAME +# +#****** + + +#****p* Test/_test_procedure1_test_ +# NAME +# +#****** + + diff --git a/Source/Test/Scr2/master_index_test.dat b/Source/Test/Scr2/master_index_test.dat new file mode 100644 index 0000000..639275f --- /dev/null +++ b/Source/Test/Scr2/master_index_test.dat @@ -0,0 +1,23 @@ +/****if* Test/Internal1 + * NAME + * Internal1 + * + ***** + */ + +/****f* Test/Public1 + * NAME + * Public1 + * + ***** + */ + +/****iv* Test/Internal_Var1 + * NAME + * Internal1 + * + ***** + */ + + + diff --git a/Source/Test/SortSource/sorted.c b/Source/Test/SortSource/sorted.c new file mode 100644 index 0000000..4f97a4d --- /dev/null +++ b/Source/Test/SortSource/sorted.c @@ -0,0 +1,21 @@ +#****h* AA_Header/BB_header +# NAME +# BB_Header -- +#**** + +#****f* BB_header/aaa_function +# NAME +# aaa_function -- +#**** + +#****f* BB_header/bbb_function +# NAME +# bbb_function -- +#**** + +#****f* BB_header/ccc_function +# NAME +# ccc_function -- +#**** + + diff --git a/Source/Test/SortSource/unsorted.c b/Source/Test/SortSource/unsorted.c new file mode 100644 index 0000000..dec4781 --- /dev/null +++ b/Source/Test/SortSource/unsorted.c @@ -0,0 +1,46 @@ +#****h* XX_Header/ZZ_Header +# NAME +# ZZ_Header -- +#**** + +#****h* XX_Header/AA_Header +# NAME +# AA_Header -- +#**** + +#****h* ZZ_Header/DD_Header +# NAME +# DD_Header -- +#**** + +#****h* AA_Header/CC_header +# NAME +# CC_Header -- +#**** + +#****f* DD_header/aaa_function +# NAME +# bbb_function -- +#**** + +#****f* CC_header/ccc_function +# NAME +# ccc_function -- +#**** + +#****f* CC_header/aaa_function +# NAME +# aaa_function -- +#**** + +#****f* CC_header/fff_function +# NAME +# fff_function -- +#**** + +#****f* CC_header/eee_function +# NAME +# eee_function -- +#**** + + diff --git a/Source/Test/alt_rc_file.rc b/Source/Test/alt_rc_file.rc new file mode 100644 index 0000000..402dbf3 --- /dev/null +++ b/Source/Test/alt_rc_file.rc @@ -0,0 +1,6 @@ +options: + --src + ./option_rc_test.dat + --doc + ./option_rc_test + --singlefile diff --git a/Source/Test/cmode_test.dat b/Source/Test/cmode_test.dat new file mode 100644 index 0000000..2c065fa --- /dev/null +++ b/Source/Test/cmode_test.dat @@ -0,0 +1,28 @@ +/* C_MODE test file */ +/* $Id: cmode_test.dat,v 1.3 2002/04/06 06:25:29 petterik Exp $ */ +/****f* Test/cmode +* NAME +* C_MODE test file +* SOURCE +*/ + +void tes(void) +{ + char quote = 0; /* TEST_COMMENT */ + printf("'"); /* TEST_COMMENT */ + ch = '\''; /* TEST_COMMENT */ + ch = '\\'; /* TEST_COMMENT */ + char *str1 = "\\huuhaa"; /* TEST_COMMENT */ + char *str2 = "'''"; /* TEST_COMMENT */ + printf("/* huuhaa */" "\\" "huuhaa"); /* TEST_COMMENT */ + /* unbalanced double quotes in comments "foobar"" */ + /* TEST_COMMENT */ + /* unbalanced single quotes in comments ' */ + /* TEST_COMMENT */ + strncmp("/*", cur_char, 2); /* TEST_COMMENT */ + fprintf(dest_doc, "/*"); /* TEST_COMMENT */ + strncmp("*/", cur_char, 2); /* TEST_COMMENT */ + fprintf(dest_doc, "*/"); /* TEST_COMMENT */ +} + +/**********/ diff --git a/Source/Test/cmode_test1.pl b/Source/Test/cmode_test1.pl new file mode 100755 index 0000000..69d6789 --- /dev/null +++ b/Source/Test/cmode_test1.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +#****x* SystemTest/cmode_test1_pl +# FUNCTION +# Tests the option --cmode. With this option +# comments in C sourcecode should be colored. +# We test this by looking for the tag. +# SOURCE +# + +ROBOTest::start("C-mode Test"); + +my $ok = 1; +while (my $line = <>) { + if ($line =~ /TEST_COMMENT/) { + my @match = ($line =~ m/FONT/ig); + my $cnt = scalar(@match); + if ($cnt != 2) { + $ok = 0; + last; + } + } +} + +ROBOTest::assert($ok); +ROBOTest::finish(); + +0; + +#***** diff --git a/Source/Test/doc_dir_filter_test.pl b/Source/Test/doc_dir_filter_test.pl new file mode 100755 index 0000000..5c133d7 --- /dev/null +++ b/Source/Test/doc_dir_filter_test.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w +# +# +# $Id: doc_dir_filter_test.pl,v 1.1 2004/06/20 09:24:36 gumpu Exp $ +# + +#****x* SystemTest/doc_dir_filter_test_pl +# FUNCTION +# If a user specifies a doc dir that is a subdir of the source +# dir that robodoc has to skip it when scanning the sources. +# We test this by running robodoc twice with the options +# --src . +# --doc ./NotDoc +# (These are specified in doc_dir_filter_test.rc +# SOURCE +# + +use strict; +use ROBOTest; +ROBOTest::start("Doc Dir Filter Test"); +ROBOTest::assertNotDir("DocNot/DocNot"); +ROBOTest::finish; + +#****** diff --git a/Source/Test/doc_dir_filter_test.rc b/Source/Test/doc_dir_filter_test.rc new file mode 100644 index 0000000..77f71ca --- /dev/null +++ b/Source/Test/doc_dir_filter_test.rc @@ -0,0 +1,13 @@ +options: + --src . + --doc ./DocNot + --multidoc + --html +ignore files: + CVS +accept files: + *.pl +headertypes: + u Unittests robo_unittest + x "System tests" robo_sys_tests + e "Makefile entries" robo_mk_entries diff --git a/Source/Test/encoding_test.dat b/Source/Test/encoding_test.dat new file mode 100644 index 0000000..cc8f49f --- /dev/null +++ b/Source/Test/encoding_test.dat @@ -0,0 +1,6 @@ +#****h* ROBODoc/Makefile.plain +# NAME +# Makefile.plain -- Plain makefile that does not need autoconf +# AUTHOR +# Mäkelä +#***** diff --git a/Source/Test/error_missing_header_end_test.dat b/Source/Test/error_missing_header_end_test.dat new file mode 100644 index 0000000..d9948cd --- /dev/null +++ b/Source/Test/error_missing_header_end_test.dat @@ -0,0 +1,20 @@ +#****f* Test/test +# NAME +# Test +# +# +# +# +# + + + + +#****f* Test/test2 + + + + + + +# there is no end marker diff --git a/Source/Test/error_missing_header_end_test_2.dat b/Source/Test/error_missing_header_end_test_2.dat new file mode 100644 index 0000000..3f0bc89 --- /dev/null +++ b/Source/Test/error_missing_header_end_test_2.dat @@ -0,0 +1,14 @@ +#****f* Test/test +# NAME +# Test +# +# +# +# +# + + + + +# there is no end marker +# last line of the file... diff --git a/Source/Test/filter_test_1.pl b/Source/Test/filter_test_1.pl new file mode 100755 index 0000000..316ed92 --- /dev/null +++ b/Source/Test/filter_test_1.pl @@ -0,0 +1,17 @@ +#!/usr/bin/perl -w +# +# +# $Id: filter_test_1.pl,v 1.2 2004/08/20 21:29:00 gumpu Exp $ +# + +use strict; +use ROBOTest; +ROBOTest::start("File Filter Test 1"); +ROBOTest::assertFile("Doc1/robo_functions.html"); +ROBOTest::assertFile("Doc1/test2_c.html"); +ROBOTest::assertDir("Doc1/ToBeAccepted"); +ROBOTest::assertNotDir("Doc1/ToBeIgnored"); +ROBOTest::assertNotFile("Doc1/test1_pas.html"); +ROBOTest::assertNotFile("Doc1/README.html"); +ROBOTest::finish; + diff --git a/Source/Test/filter_test_1.rc b/Source/Test/filter_test_1.rc new file mode 100644 index 0000000..11debc3 --- /dev/null +++ b/Source/Test/filter_test_1.rc @@ -0,0 +1,4 @@ +ignore files: + ??ADME + *.pas + ToBeIgnored diff --git a/Source/Test/filter_test_2.pl b/Source/Test/filter_test_2.pl new file mode 100755 index 0000000..37d7ec9 --- /dev/null +++ b/Source/Test/filter_test_2.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w +# +# +# $Id: filter_test_2.pl,v 1.1 2004/08/20 21:52:47 gumpu Exp $ +# + +use strict; +use ROBOTest; +ROBOTest::start("File Filter Test 2"); +ROBOTest::assertFile("Doc3/robo_functions.html"); +ROBOTest::assertFile("Doc3/accept_c.html"); +ROBOTest::assertFile("Doc3/accept_pl.html"); +ROBOTest::assertDir("Doc3/AcceptDir"); +ROBOTest::assertFile("Doc3/AcceptDir/accept_h.html"); +ROBOTest::assertNotDir("Doc3/ToBeIgnored"); +ROBOTest::assertNotFile("Doc3/ignore_ign.html"); +ROBOTest::assertNotFile("Doc3/ignore_xxx.html"); +ROBOTest::finish; + diff --git a/Source/Test/filter_test_2.rc b/Source/Test/filter_test_2.rc new file mode 100644 index 0000000..1057d3d --- /dev/null +++ b/Source/Test/filter_test_2.rc @@ -0,0 +1,6 @@ +ignore files: + ToBeIgnored +accept files: + *.c + *.pl + *.h diff --git a/Source/Test/header_size_test.dat b/Source/Test/header_size_test.dat new file mode 100644 index 0000000..0ac7ccb --- /dev/null +++ b/Source/Test/header_size_test.dat @@ -0,0 +1,133 @@ +/****** Test/Test + * NAME + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_1 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_2 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_3 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_4 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_5 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_6 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_7 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_8 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_9 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_10 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_11 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_12 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_13 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_14 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_15 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_16 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_17 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_18 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_19 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_20 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_21 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_22 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_23 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_24 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_25 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_26 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_27 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_28 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_29 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_30 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_31 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_32 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_33 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_34 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_35 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_36 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_37 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_38 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_39 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_40 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_41 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_42 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_43 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_44 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_45 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_46 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_47 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_48 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_49 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_50 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_51 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_52 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_53 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_54 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_55 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_56 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_57 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_58 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_59 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_60 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_61 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_62 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_63 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_64 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_65 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_66 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_67 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_68 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_69 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_70 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_71 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_72 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_73 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_74 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_75 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_76 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_77 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_78 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_79 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_80 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_81 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_82 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_83 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_84 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_85 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_86 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_87 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_88 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_89 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_90 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_91 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_92 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_93 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_94 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_95 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_96 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_97 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_98 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_99 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_100 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_101 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_102 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_103 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_104 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_105 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_106 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_107 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_108 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_109 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_110 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_111 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_112 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_113 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_114 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_115 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_116 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_117 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_118 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_119 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_120 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_121 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_122 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_123 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_124 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_125 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_126 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_127 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_128 + * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_129 + ****/ + diff --git a/Source/Test/header_size_test.pl b/Source/Test/header_size_test.pl new file mode 100755 index 0000000..526f43c --- /dev/null +++ b/Source/Test/header_size_test.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +#****x* SystemTest/header_size_test_pl +# FUNCTION +# Test whether robodoc can handle large headers. Robodoc uses a +# dynamically expanding buffer for storing headers. This dynamic +# expansion might go wrong. The input file for this test is +# generated by the makefile entry header_size_test +# SOURCE +# + +ROBOTest::start("Header Size Test"); + +# They are 129 lines of the form +# xxxxxxxxx_ +# in the header. +# Lets test if they all turn up in the documentation. +# +my $checksum = 0; +foreach my $n (1 .. 129) { + $checksum += $n; +} +my $sum = 0; +while (my $line = <>) { + if ($line =~ m/xxxx_(\d+)/) { + $sum += $1; + } +} + +ROBOTest::assert( $sum == $checksum ); +ROBOTest::finish; + +0; + +#***** + diff --git a/Source/Test/header_test.dat b/Source/Test/header_test.dat new file mode 100644 index 0000000..dd4fc85 --- /dev/null +++ b/Source/Test/header_test.dat @@ -0,0 +1,137 @@ +/****m* Muppets/Header_1 + * + * NAME + * testmark 1 testmark + * NAME +CTest testmark 1000 testmark This should not appear + * test + * PURPOSE + * test + * SEE ALSO + * Puppet::walk + ****** + */ + + +/****c* Muppets/Header_2 [1.0] + * + * + * NAME + * testmark 2 testmark + * NAME +;*Test testmark 1001 testmark This should not appear + * SEE ALSO + * Puppet::talk + ***** + */ + + +#****f* T_1_/Header_3 +# NAME +# testmark 3 testmark +# SOURCE + +tcl () + +#*** + + + +|****v* T_2_/Header_4 +| NAME +| testmark 4 testmark +| SOURCE + +assembler () + +|**** + + +//****d* T_3_/Header_5 +// NAME +// testmark 5 testmark +// SOURCE + +c++ () + +//**** + + +--****h* T_4_/Header_6 +-- NAME +-- testmark 6 testmark +-- SOURCE + +occam () + +--*** + + + + + + +REM ****f* T_6_/Header_8 +REM NAME +REM testmark 8 testmark +REM *** + + + +Rem ****f* T_7_/Header_9 +Rem NAME +Rem testmark 9 testmark +Rem *** + + +#****f* T_7_/Header_10 +# NAME +# testmark 10 testmark +#*** + + +%****f* T_11_/Header_11 +% NAME +% testmark 11 testmark +%*** + + +(****f* T_12_/Header_12 +* NAME +* testmark 12 testmark +****) + +'****f* T_13_/Header_13 +'* NAME +'* testmark 13 testmark +'***** + +!!****f* T_14_/Header_14 +!! NAME +!! MYSUB +!! NOTES +!! testmark 14 testmark +!! SOURCE +!! + +USE MYMODULE +IMPLICIT NONE +END IF + +!!****** + +.****f* T_15_/Header_15 +.* NAME +.* testmark 15 testmark +.* NOTES +.* no notes +.**** + diff --git a/Source/Test/header_test.pl b/Source/Test/header_test.pl new file mode 100755 index 0000000..9eec9d1 --- /dev/null +++ b/Source/Test/header_test.pl @@ -0,0 +1,48 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +#****x* SystemTest/header_test_pl +# FUNCTION +# Test if robodoc recognizes all the different headers in the +# various languages that robodoc supports. The input file for this +# test is generated with the makefile entry header_test +# SOURCE +# + +ROBOTest::start("Header Test"); + +# We scan the output file for the headers. +# Each header has a name item with the text +# testmark testmark +# the name of each header has the form +# Header_ +# We compute the sum of all the numbers. + +# There are 15 headers numbered 1 .. 15 +my $checksum = 0; +foreach my $n (1 .. 15) { + $checksum += $n; +} + +my $sum = 0; +while (my $line = <>) { + # The numbers between the marks. + if ($line =~ m//i) { + $sum += $1; + } +} + +# Does each header number occur twice? +ROBOTest::assert( $sum == (2 * $checksum) ); +ROBOTest::finish; + +0; + +#****** diff --git a/Source/Test/header_test2.dat b/Source/Test/header_test2.dat new file mode 100644 index 0000000..4b921c5 --- /dev/null +++ b/Source/Test/header_test2.dat @@ -0,0 +1,116 @@ +/* (almost) Identical to header_test.dat except headers indented */ + /****m* Muppets/Header_1 + * NAME + * testmark 1 testmark + * PURPOSE + * test + * blah-blah-blah + * moi moi moi + * SEE ALSO + * Puppet::walk + ****** + */ + + + /****c* Muppets/Header_2 [1.0] + * NAME + * testmark 2 testmark + * SEE ALSO + * Puppet::talk + ***** + */ + + + + #****f* T_1_/Header_3 + # NAME + # testmark 3 testmark + # SOURCE + + tcl () + + #*** + + + + |****f* T_2_/Header_4 + | NAME + | testmark 4 testmark + | SOURCE + + assembler () + + |**** + + + //****f* T_3_/Header_5 + // NAME + // testmark 5 testmark + // SOURCE + + c++ () + + //**** + + +--****f* T_4_/Header_6 +-- NAME +-- testmark 6 testmark +-- SOURCE + +occam () + +--*** + + + + + + + REM ****f* T_6_/Header_8 + REM NAME + REM testmark 8 testmark + REM *** + + + + Rem ****f* T_7_/Header_9 + Rem NAME + Rem testmark 9 testmark + Rem *** + + + #****f* T_7_/Header_10 + # NAME + # testmark 10 testmark + #*** + + + %****f* T_11_/Header_11 + % NAME + % testmark 11 testmark + %*** + + + (****f* T_12_/Header_12 + * NAME + * testmark 12 testmark + ****) + + + +#****f* Crash/crash +# NAME +# Used to crash on this +# SOURCE +foo +#**** + diff --git a/Source/Test/header_test2.pl b/Source/Test/header_test2.pl new file mode 100755 index 0000000..039d4bf --- /dev/null +++ b/Source/Test/header_test2.pl @@ -0,0 +1,32 @@ +#!/usr/bin/perl -w + +use ROBOTest; +ROBOTest::start("Indented Header Test"); + +# There are 12 headers numbered 1 .. 12 +my $checksum = 0; +foreach my $n (1 .. 12) { + $checksum += $n; +} + +# Now we scan the output file for the headers +# The should occur after a and compute the sum +# of the header numbers +my $sum = 0; +# count the number of testmarkers and the number of +# Headers in blocks (table of content) +# and between the word "testmark" in the NAME item +# We extract the header number and compute the sum. +while (my $line = <>) { + if ($line =~ m//i) { + $sum += $1; + } +} +# Dus each header number occur twice? +ROBOTest::assert($sum == 2 * $checksum); +ROBOTest::finish; + diff --git a/Source/Test/header_test3.dat b/Source/Test/header_test3.dat new file mode 100644 index 0000000..9a5c577 --- /dev/null +++ b/Source/Test/header_test3.dat @@ -0,0 +1,65 @@ +#****f* Test/T1 +# NAME +# __1__ +# FUNCTION +# __2__ +# +# SEE ALSO +# +# __3__ +# +#****** + + + +#****f* Test/T2 +# NAME +# __4__ +# __5__ +# FUNCTION +# __6__ +# __7__ +# +# SEE ALSO +# +# __8__ +# __9__ +# +#****** + +#****f* Test/T1b +# NAME +# +# __12__ +# +# SEE ALSO +# __11__ +#***** + +#****f* Test/T3 +# NAME +# +# +# __13__ +# __14__ +# __15__ +# +# +# SEE ALSO +# +# +# +# +# __16__ +# __17__ +# +# __18__ +# SEE ALSO +# +# __19__ +# __20__ +# __10__ +# +#****** + + diff --git a/Source/Test/header_test3.pl b/Source/Test/header_test3.pl new file mode 100755 index 0000000..625ff9d --- /dev/null +++ b/Source/Test/header_test3.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +ROBOTest::start("Header Item Body Test"); + +# There are a number of headers. They contain items that +# have lines numbered __1__ to __20__ +# They should all show up. +# +my $checksum = 0; +foreach my $n (1 .. 20) { + $checksum += $n; +} + +# Now we scan the output file for the headers +# find the numbers and add them... +my $sum = 0; +while (my $line = <>) { + if ($line =~ m/__(\d+)__/) { + $sum += $1; + } +} + +# Does each number occur ? + +ROBOTest::assert( $sum == $checksum ); +ROBOTest::finish; + diff --git a/Source/Test/header_test4.dat b/Source/Test/header_test4.dat new file mode 100644 index 0000000..0d7b174 --- /dev/null +++ b/Source/Test/header_test4.dat @@ -0,0 +1,22 @@ + +#****f* A_Module_TEST/a_function_test +# FUNCTION +# A Test +#***** + +#****f* A_Module_TEST/a function test +# FUNCTION +# A Test +#***** + +#****f* A_Module_TEST/a function_test +# FUNCTION +# A Test ^^^^ evil extra spaces ^^^^ +#***** + +#****f* A Module TEST/a_function_test +# FUNCTION +# A Test +#***** + + diff --git a/Source/Test/header_test4.pl b/Source/Test/header_test4.pl new file mode 100755 index 0000000..d3b6267 --- /dev/null +++ b/Source/Test/header_test4.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +#****x* SystemTest/header_test4_pl +# FUNCTION +# Test if robodoc can handle module and object names with +# spaces in it. For this we process a file with four +# headers looking something like +# A_Module_TEST/a function test +# Each header has the words A, Module, TEST, a, function, and +# test. They are either separated with spaces or with a '_'. +# ROBODoc should find them all. +# SOURCE +# + +ROBOTest::start("Names with Spaces Test"); + +my $count = 0; +while (my $line = <>) { + if ( $line =~ m/HEADER_MODULE\s+(\S.*?)$/ ) { + my $module = $1; + if ( ( $module =~ m/A/ ) and + ( $module =~ m/Module/ ) and + ( $module =~ m/TEST/ ) ) { + $count++; + } + } + if ( $line =~ m/HEADER_FUNCTION_NAME\s+(\S.*?)$/ ) { + my $object = $1; + if ( ( $object =~ m/a/ ) and + ( $object =~ m/function/ ) and + ( $object =~ m/test/ ) ) { + $count++; + } + ROBOTest::assert( $object !~ m/\s+$/, "no spaces at end of name" ); + } +} + +# There are 4 valid headers, so the count should be 8 +ROBOTest::assert( $count == 8, "All 4 headers found" ); +ROBOTest::finish; + +0; + +#****** diff --git a/Source/Test/header_test5.dat b/Source/Test/header_test5.dat new file mode 100644 index 0000000..3a235ca --- /dev/null +++ b/Source/Test/header_test5.dat @@ -0,0 +1,86 @@ +#****f* T5Test/test +# FUNCTION +# Test oo1 +# SOURCE +testmark 1 +# testmark 2 +testmark 3 +# +# NOTES +# testmark 4 +# NAME +# testmark 5 +#**** + +#****f* T5Test/test2 +# FUNCTION +# Test +# SOURCE +# +testmark 1 +# testmark 2 +testmark 3 +# NOTES +# testmark 4 +# NAME +# testmark 5 +#**** + +#****f* T5Test/test3 +# FUNCTION +# Test + testmark 2100 should not be in the doc + testmark 2200 should not be in the doc +# SYNOPSIS +# testmark 1 +# testmark 2 +testmark 3 +# NOTES +# testmark 4 +# NAME +# testmark 5 +# SOURCE +# + aaaa + bbbb + cccc + dddd + eeee +#**** + +testmark 33000 should not be in the doc + + + +/****f* T5Test/test4 + * FUNCTION + * Test + testmark 2100 should not be in the doc + testmark 2200 should not be in the doc + * SYNOPSIS + */ +/* testmark 1 */ +/* testmark 2 */ + +testmark 3 + +/* + * NOTES + * testmark 4 + * NAME + * testmark 5 + * SOURCE + */ + aaaa + bbbb + cccc + dddd + eeee +/*****/ + +testmark 33001 should not be in the doc + + +/*****/ + + diff --git a/Source/Test/header_test5.pl b/Source/Test/header_test5.pl new file mode 100755 index 0000000..d4c2ec1 --- /dev/null +++ b/Source/Test/header_test5.pl @@ -0,0 +1,60 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +#****x* SystemTest/header_test5_pl +# FUNCTION +# ROBODoc allows a user to define that some items should +# work similar to the source item. These tests check wether +# this works. +# SOURCE +# + +ROBOTest::start("Source Item Test"); + +# We scan the output file for the headers. +# In each header there are items that contains +# testmark 1 testmark +# testmark 2 testmark +# testmark 3 testmark +# testmark 4 testmark +# testmark 5 testmark +# in such locations that they end-up in the final +# documentation. We scan the final documentation +# and collect and the numbers between the test +# marks. + +my $checksum = 1 + 2 + 3 + 4 + 5; + +my $sum = 0; +my $sum_empty_remark = 0; + +while (my $line = <>) { + # The numbers between the marks. + if ( $line =~ m/testmark\s(\d+)/ ) { + $sum += $1; + } + # There should be no empty '/*' or '*/' in the documentation + # robodoc is supposed to remove these from the begin and + # end of a 'source' item. + + # No /* + if ( $line =~ m/^\s*\/\*\s*$/ ) { + $sum_empty_remark++; + } + # No */ + if ( $line =~ m/^\s\*\/\s*$/ ) { + $sum_empty_remark++; + } +} + +# There are 4 headers so: +ROBOTest::assert( $sum == (4 * $checksum), "All source is included" ); +ROBOTest::assert( $sum_empty_remark == 0, "No empty remark begin or ends" ); +ROBOTest::finish; +# + +0; + +#****** diff --git a/Source/Test/html_specialchar_test.dat b/Source/Test/html_specialchar_test.dat new file mode 100644 index 0000000..1fe3cf5 --- /dev/null +++ b/Source/Test/html_specialchar_test.dat @@ -0,0 +1,18 @@ + +/****f* bad1&bad1/bad2>>bad2 + * NAME + * bad2>>bad2 + * SEE ALSO + * bad3<>bad2 + ****** + */ + diff --git a/Source/Test/html_specialchar_test.pl b/Source/Test/html_specialchar_test.pl new file mode 100755 index 0000000..4e6abe5 --- /dev/null +++ b/Source/Test/html_specialchar_test.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +ROBOTest::start("HTML Special Char Test"); + +# In the headers there are three bad names +# bad1&bad1 +# bad2>>bad2 +# and +# bad3<) { + if ($line =~ m/bad\d([^b]+)bad/) { + my $string = $1; + if (($string eq ">>") or + ($string eq "<<") or + ($string eq "&")) { + ++$count; + } + } +} + +ROBOTest::assert($count == 0); +ROBOTest::finish; diff --git a/Source/Test/ignore_test.dat b/Source/Test/ignore_test.dat new file mode 100644 index 0000000..5899573 --- /dev/null +++ b/Source/Test/ignore_test.dat @@ -0,0 +1,14 @@ +/****f* Test/Test + * NAME + * test appear + * FUNCTION + * should not be displayed + * should not be displayed + * should not be displayed + * should not be displayed + * SEE ALSO + * should not be displayed + * RETURN VALUE + * test appear + *****/ + diff --git a/Source/Test/ignore_test.pl b/Source/Test/ignore_test.pl new file mode 100755 index 0000000..1c732af --- /dev/null +++ b/Source/Test/ignore_test.pl @@ -0,0 +1,27 @@ +#!/usr/bin/perl -w + +# +# Test whether robodoc can handle the --lock mode +# In the lock mode it will lock on to one kind of header marker +# per file and one kind of remark marker per header. All +# other ones should be skipped. +# + +use strict; +use ROBOTest; + +ROBOTest::start("ignore items: Test"); +my $checksum_not_appear = 0; +my $checksum_appear = 0; +while (my $line = <>) { + if ($line =~ m/not\sbe\sdisplayed/) { + ++$checksum_not_appear; + } + if ( $line =~ m/appear/ ) { + ++$checksum_appear; + } +} +ROBOTest::assert( $checksum_not_appear == 0 ); +ROBOTest::assert( $checksum_appear == 2 ); +ROBOTest::finish; + diff --git a/Source/Test/ignore_test.rc b/Source/Test/ignore_test.rc new file mode 100644 index 0000000..451c802 --- /dev/null +++ b/Source/Test/ignore_test.rc @@ -0,0 +1,3 @@ +ignore items: + FUNCTION + SEE ALSO diff --git a/Source/Test/internalheader_test.dat b/Source/Test/internalheader_test.dat new file mode 100644 index 0000000..eb3e78d --- /dev/null +++ b/Source/Test/internalheader_test.dat @@ -0,0 +1,94 @@ +/* Classes */ + +/****ic* InternalHeaderTest/InternalClass_it_1 + * NAME + * InternalClass_ -- + *****/ + +/****ic* InternalHeaderTest/InternalClass_2_it_2 + * NAME + * InternalClass_2 -- + *****/ + +/****c* InternalHeaderTest/Class + * NAME + * Class -- + *****/ + +/****c* InternalHeaderTest/Class_2 + * NAME + * Class_2 -- + *****/ + +/* Headers */ + +/****h* InternalHeaderTest/Header + * NAME + * Header -- + *****/ + +/****ih* InternalHeaderTest/InternalHeader_it_3 + * NAME + * InternalHeader -- + *****/ + +/* Methods */ + +/****m* InternalHeaderTest/Method + * NAME + * Method -- + *****/ + +/****im* InternalHeaderTest/InternalMethod_it_4 + * NAME + * InternalMethod -- + *****/ + +/* Functions */ + +/****f* InternalHeaderTest/Function + * NAME + * Function -- + *****/ + +/****if* InternalHeaderTest/InternalFunction_it_5 + * NAME + * InternalFunction -- + *****/ + +/* Constants */ + +/****d* InternalHeaderTest/Constant + * NAME + * Constant -- + *****/ + +/****id* InternalHeaderTest/InternalConstant_it_6 + * NAME + * InternalConstant -- + *****/ + +/* Variable */ + +/****v* InternalHeaderTest/Variable + * NAME + * Variable -- + *****/ + +/****iv* InternalHeaderTest/InternalVariable_it_7 + * NAME + * InternalVariable -- + *****/ + +/* Structures */ + +/****s* InternalHeaderTest/Structure + * NAME + * Structure -- + *****/ + +/****is* InternalHeaderTest/InternalStructure_it_8 + * NAME + * InternalStructure -- + *****/ + diff --git a/Source/Test/internalheader_test.pl b/Source/Test/internalheader_test.pl new file mode 100755 index 0000000..a4734b1 --- /dev/null +++ b/Source/Test/internalheader_test.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +#****x* SystemTest/internalheader_test +# FUNCTION +# Test to see if robodoc handles all the internal +# headers and the options to go with it correctly. +# For this we created a testfile with internal and +# normal headers. We generate the documentation for +# it and check if the internal headers show up. +# SOURCE +# + +use strict; +use ROBOTest; + +ROBOTest::start("Internalheader Test"); + +# There are 8 internal headers numbered 1 .. 8 in the .dat file +my $checksum = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8; + +# We now extract them and compute the sum of all the numbers +my %seen = (); + +while (my $line = <>) { +# the internal header names end with it_1, it_2, etc, so +# we extract these numbers. + if ($line =~ m/it_(\d+)) { + if ($line =~ m/it_(\d+)) { + if ($line =~ m/) { + if (($line =~ m/begin{verbatim/) .. + ($line =~ m/end{verbatim/)) { + + } else { + if ($line =~ m/bad\d([^b]+)bad/) { + my $string = $1; + if (($string eq "\$") or + ($string eq "_") or + ($string eq "%")) { + ++$count; + } + } + } +} + +ROBOTest::assert($count == 0); +ROBOTest::finish; diff --git a/Source/Test/link_test.dat b/Source/Test/link_test.dat new file mode 100644 index 0000000..9372240 --- /dev/null +++ b/Source/Test/link_test.dat @@ -0,0 +1,83 @@ +/****f* LinkTest/link_1_ + * NAME + * link_1_ + ******/ + + +/****f* _LinkTest_/_link_2_ + * NAME + * _link_2_ + ******/ + + +/****f* LinkTest/link3 + * NAME + * link3 + ******/ + + +/****f* LinkTest/-link4 + * NAME + * -link4 + ******/ + +/****f* LinkTest/Llink5 + * NAME + * Llink5 + ******/ + + +/****f* LinkTest/thelinks1 + * NAME + * thelink + * SEE ALSO + * A link at the end of the line link_1_. + * A link as function link_1_(test). + * link_1_ as the begin of a sentence. + * A comma sentence link_1_, this is. + *****/ + + +/****f* LinkTest/thelinks2 + * NAME + * thelink + * SEE ALSO + * A link at the end of the line _link_2_. + * A link as function _link_2_(test). + * _link_2_ as the begin of a sentence. + * A comma sentence _link_2_, this is. + *****/ + + +/****f* LinkTest/thelinks3 + * NAME + * thelink + * SEE ALSO + * A link at the end of the line link3. + * A link as function link3(test). + * link3 as the begin of a sentence. + * A comma sentence link3, this is. + *****/ + + +/****f* LinkTest/thelinks4 + * NAME + * thelink + * SEE ALSO + * A link at the end of the line -link4. + * A link as function -link4(test). + * -link4 as the begin of a sentence. + * A comma sentence -link4, this is. + *****/ + +/****f* LinkTest/thelinks5 + * NAME + * thelink + * SEE ALSO + * A link at the end of the line Llink5. + * A link as function Llink5(test). + * Llink5 as the begin of a sentence. + * A comma sentence Llink5, this is. + *****/ + + diff --git a/Source/Test/link_test.pl b/Source/Test/link_test.pl new file mode 100755 index 0000000..b4294a5 --- /dev/null +++ b/Source/Test/link_test.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w +use strict; +use ROBOTest; + +#****x* SystemTest/link_test_pl +# FUNCTION +# Test if ROBODoc correctly creates links between words +# and headers. +# +# There are four links, link_1_, _link_2_, link3, and -link4 +# they should each occur four times in a +# SOURCE +# + + +ROBOTest::start("Link Test"); + +my %count = (); +$count{"link_1_"} = 0; +$count{"_link_2_"} = 0; +$count{"link3"} = 0; +$count{"-link4"} = 0; +$count{"Llink5"} = 0; + +while (my $line = <>) { + if ($line =~ m#]+>([^<]+)#i) { + my $link_name = $1; + ++$count{$link_name}; + } +} + +ROBOTest::assert( + ($count{"link_1_"} == 4) and + ($count{"_link_2_"} == 4) and + ($count{"link3"} == 4) and + ($count{"-link4"} == 4) and + ($count{"Llink5"} == 4), + "linking"); + +#***** diff --git a/Source/Test/lock_test.dat b/Source/Test/lock_test.dat new file mode 100755 index 0000000..2835cb7 --- /dev/null +++ b/Source/Test/lock_test.dat @@ -0,0 +1,32 @@ +Program Test +!!****f* main/test +!! NAME +!! Testing 1 2 3 +!! Program Test + Test1 = ABC & + // det ! This should not be displayed + Test2 = ABC & + * detail ! This should not be displayed + Test3 = ABC + & + C * D ! This should not be displayed + TEst4 = ABC * & + REM * B ! This should not be displayed + Test5 = & + 'Test' ! This should not be displayed + End Program Test +!!*** + + +/****f* main/test2 + * NAME + * This should not be displayed + * FUNCTION + * This should not be displayed + * SOURCE + */ + +This should not be displayed +This should not be displayed + +/******/ + diff --git a/Source/Test/lock_test.pl b/Source/Test/lock_test.pl new file mode 100755 index 0000000..bb2402b --- /dev/null +++ b/Source/Test/lock_test.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl -w + +# +# Test whether robodoc can handle the --lock mode +# In the lock mode it will lock on to one kind of header marker +# per file and one kind of remark marker per header. All +# other ones should be skipped. +# + +use strict; +use ROBOTest; + +ROBOTest::start("--lock Test"); +my $checksum = 0; + +while (my $line = <>) { + if ($line =~ m/not\sbe\sdisplayed/) { + ++$checksum; + } +} +ROBOTest::assert( $checksum == 0 ); +ROBOTest::finish; + diff --git a/Source/Test/makefile b/Source/Test/makefile new file mode 100644 index 0000000..a6e16ef --- /dev/null +++ b/Source/Test/makefile @@ -0,0 +1,540 @@ +#****h* ROBODoc/SystemTest +# DESCRIPTION +# The systemtest is a series of tests that test the +# behaviour of robodoc and robohdrs. +# +# Most tests consists of: +# * One or more data files (.dat) +# * One or more result files (.html etc). The result files are generated +# by running robodoc on the .dat files. Or sometimes on whole +# directories with source files. +# * A perl script that checks the results and prints either OK or FAIL +# For instance there is a test that checks if robodoc correctly +# recognizes all Item names. The data files for this is +# item_test.dat. It contains all item names with in between +# testmark dd +# where dd is a number from 1 to 43 +# +# Robodoc is run on this data file and a file +# called item_test.html is generated. A script called item_test.pl +# scans this .html file finds all the "testmark dd"s and check if +# all number from 1 to 43 occur. If so it prints OK if not it +# print FAIL. +# +# To run the test do a +# make +# +# To cleanup all the generated files do a +# make clean +# +#***** +# $Id: makefile,v 1.54 2007/01/29 22:23:53 gumpu Exp $ +# + + +# The programs to be tested. +# +ROBODOC = ../robodoc +ROBOHDRS = ../robohdrs + +# No unnecessary output. +.SILENT : + +all: permissions clean test + +# TODO header_test4 +# TODO header_test5 + +test : item_test \ + header_test \ + header_test2 \ + header_test3 \ + url_test \ + header_size_test \ + cmode_test \ + link_test \ + html_specialchar_test \ + internalheader_test \ + internalheader_test2 \ + latex_specialchar_test \ + remarkmarker_test \ + multidoc_test1 \ + encoding_test \ + tabtest \ + pipe_test \ + lock_test \ + user_specified_css_file_test \ + master_index_test \ + robohdrs_test \ + filter_test_1 \ + filter_test_2 \ + sort_test \ + nosource_test \ + ignore_test \ + nosort_test \ + forth_test \ + doc_dir_filter_test + +# temporarily excluded: parameter_test + +# +# TODO +# outputformat_test +# These test error handling, but they are not +# finished yet. +# error_missing_header_end_test +# error_missing_header_end_test_2 + + +permissions: + chmod 755 *.pl + +clean: doc1_clean doc2_clean + -rm -f *.res *.html *.tex *.rtf *.xml *.toc *.log *.idx *.dvi *.aux *.pdf + -rm -f *.tst + -rm -rf outputformat_test.txt + -rm -rf *.stderr + -rm -rf RoboHeaders/*.c + -rm -rf robohdrs_test.hdrs + -rm -rf cmode_test1.css + -rm -rf header_size_test.css + -rm -rf header_test2.css + -rm -rf header_test3.css + -rm -rf header_test4.css + -rm -rf header_test.css + -rm -rf html_specialchar_test2.css + -rm -rf html_specialchar_test.css + -rm -rf internalheader_test2.css + -rm -rf internalheader_test.css + -rm -rf item_test.css + -rm -rf link_test.css + -rm -rf lock_test.css + -rm -rf outputformat_test.css + -rm -rf parameter_test.css + -rm -rf pipe_test.css + -rm -rf remarkmarker_test.css + -rm -rf tabtest.css + -rm -rf url_test.css + -rm -rf forth_test.css + -rm -rf error_test.css + -rm -rf ignore_test.css + -rm -rf nosource_test.css + +# +# +# Test the handling of HTML reserver characters. +# +html_specialchar_test : html_specialchar_test.html html_specialchar_test2.html + ./$(@F).pl < html_specialchar_test.html + ./$(@F).pl < html_specialchar_test2.html + +html_specialchar_test.html : html_specialchar_test.dat + $(ROBODOC) --src html_specialchar_test.dat --doc html_specialchar_test --html --singlefile + +html_specialchar_test2.html : html_specialchar_test.dat + $(ROBODOC) --src html_specialchar_test.dat --doc html_specialchar_test2 --html --singlefile --sections --toc + +#****e* SystemTest/latex_specialchar_test +# FUNCTION +# Create input for testing the handling of latex reserved characters +# SOURCE +# +latex_specialchar_test : latex_specialchar_test.tex latex_specialchar_test2.tex + ./$(@F).pl < latex_specialchar_test.tex + ./$(@F).pl < latex_specialchar_test2.tex + +latex_specialchar_test.tex : latex_specialchar_test.dat + $(ROBODOC) --src latex_specialchar_test.dat --doc latex_specialchar_test --latex --singlefile + +latex_specialchar_test2.tex : latex_specialchar_test.dat + $(ROBODOC) --src latex_specialchar_test.dat --doc latex_specialchar_test2 --latex --singlefile --sections --toc + +#****** + + +#****e* SystemTest/header_size_test +# FUNCTION +# Create the input file for header_size_test_pl. +# SOURCE +# +header_size_test : header_size_test.html + ./$(@F).pl < header_size_test.html + +header_size_test.html : header_size_test.dat + $(ROBODOC) --src $< --doc header_size_test --html --singlefile + +#***** + + +#****e* SystemTest/internalheader_test, internalheader_test2 +# FUNCTION +# Create the input for the internalheader_test. +# SOURCE +# +internalheader_test : internalheader_test.html + ./$(@F).pl < internalheader_test.html + +internalheader_test.html : internalheader_test.dat + $(ROBODOC) --src internalheader_test.dat --doc internalheader_test --html --singlefile --index --toc --internal + +# +internalheader_test2 : internalheader_test2.html + ./$(@F).pl < internalheader_test2.html + +internalheader_test2.html : internalheader_test.dat + $(ROBODOC) --src internalheader_test.dat --doc internalheader_test2 --html --singlefile --index --toc + +#********** + + +# +# +outputformat_test : outputformat_test.html \ + outputformat_test.txt \ + outputformat_test.rtf +# outputformat_test_dbsgml.res \ +# outputformat_test_troff.res + ./$(@F).pl + + +outputformat_test.html : outputformat_test.dat + $(ROBODOC) --src $< --doc outputformat_test --singlefile --html + +outputformat_test.txt : outputformat_test.dat + $(ROBODOC) --src $< --doc outputformat_test --singlefile --ascii + +outputformat_test.rtf : outputformat_test.dat + $(ROBODOC) --src $< --doc outputformat_test --singlefile --rtf + +# outputformat_test.dbsgml : outputformat_test.dat +# $(ROBODOC) --src $< --doc $@ DBSGML +# +# outputformat_test_troff.res : outputformat_test.dat +# $(ROBODOC) --src $< --doc $@ TROFF + + +# +# Test if we recognize all predefined items. +# +item_test : item_test.html + ./$(@F).pl < item_test.html + +item_test.html : item_test.dat + $(ROBODOC) --src item_test.dat --doc item_test --html --singlefile + +# +# Test the linking of keywords to headers. +# +link_test : link_test.html + ./$(@F).pl < link_test.html + +link_test.html : link_test.dat + $(ROBODOC) --src link_test.dat --doc link_test --html --singlefile + +#****e* SystemTest/header_test, header_test2, header_test3, header_test4, header_test5 +# FUNCTION +# Create the input file for header_test_pl. +# SOURCE +# +header_test : header_test.html + ./$(@F).pl < header_test.html + +header_test.html : header_test.dat + $(ROBODOC) --src header_test.dat --doc header_test --html --toc --singlefile + + +# +# indented header test case +# +header_test2 : header_test2.html + ./header_test2.pl < header_test2.html + +header_test2.html : header_test2.dat + $(ROBODOC) --src header_test2.dat --doc header_test2 --html --toc --singlefile + +# +# indented header test case +# +header_test3 : header_test3.html + ./header_test3.pl < header_test3.html + +header_test3.html : header_test3.dat + $(ROBODOC) --src header_test3.dat --doc header_test3 --html --toc --singlefile + +header_test4 : header_test4.tst + ./$(@F).pl < header_test4.tst + +header_test4.tst : header_test4.dat + $(ROBODOC) --src header_test4.dat --doc header_test4 --test --toc --singlefile + +header_test5 : header_test5.tst + ./$(@F).pl < header_test5.tst + +header_test5.tst : header_test5.dat + $(ROBODOC) --rc header_test5.rc --src header_test5.dat --doc header_test5 --test --toc --singlefile + +#************* + +# +# Test if we can recognize all the different remark markers for +# all the languages we defined. +# +remarkmarker_test : remarkmarker_test.html + ./$(@F).pl < remarkmarker_test.html + +remarkmarker_test.html : remarkmarker_test.dat + $(ROBODOC) --src remarkmarker_test.dat --doc remarkmarker_test --html --singlefile + +# +# Test the automatic recognition of urls +# +url_test : url_test.html + ./$(@F).pl < url_test.html + +url_test.html : url_test.dat + $(ROBODOC) --src url_test.dat --doc url_test --html --singlefile + +# +# Test the syntax colouring of C code. +# +cmode_test : cmode_test1.html + ./cmode_test1.pl < cmode_test1.html + +cmode_test1.html : cmode_test.dat + $(ROBODOC) --src cmode_test.dat --doc cmode_test1 --html --cmode --singlefile + +# +# Test the --multidoc mode +# +# +multidoc_test1 : multidoc_test1.html + ./multidoc_test1.pl + +multidoc_test1.html : + $(ROBODOC) --src ./Scr1 --doc ./Doc1 --html --multidoc --index --sections --toc + touch multidoc_test1.html + + +# +# This tests if specifying the tabsize with --tabsize works. +# +tabtest : tabtest.html + ./$(@F).pl < tabtest.html + +tabtest.html : tabtest.dat + $(ROBODOC) --src tabtest.dat --doc tabtest --html --singlefile --tabsize 4 + +# +# This test if we can specify a full path to the source file +# when we use --singlefile. (This borrows the code from tabtest) +# +parameter_test : parameter_test.html + ./$(@F).pl + +parameter_test.html : parameter_test.dat + $(ROBODOC) --src /home/robodoc/robo/Source/Test/parameter_test.dat --doc /home/robodoc/robo/Source/Test/parameter_test --html --singlefile + + +# The xml file uses UTF-8 encoding. Although xmlto seems not to _write_ +# UTF-8, it does _read_ that correctly in input and complains if that is +# not proper UTF-8 format. + +encoding_test: encoding_test.html + @ if [ -x "`which xmlto`" ] ; then \ + xmlto html-nochunks encoding_test.xml ; \ + else \ + echo "xmlto missing, can not perform test"; \ + fi ; +#rm -f encoding_test.html encoding_test.xml encoding_test.pdf + +# Source file uses Latin-1 i.e. iso-8859-1 encoding +encoding_test.html: encoding_test.dat + $(ROBODOC) --src encoding_test.dat --doc encoding_test --singlefile --dbxml + + +# +# Test if we can specify an alternative robodoc.rc file using +# the --rc option. +# + +option_rc_test: option_rc_test.html + ./$(@F).pl < option_rc_test.html + +option_rc_test.html: alt_rc_file.rc + $(ROBODOC) --rc alt_rc_file.rc --html + + +# +# Test the error generated for a header end messing from a header +# that is not the last header in a file. +# + +error_missing_header_end_test: error_missing_header_end_test.stderr + echo "TODO" + +error_missing_header_end_test.stderr : error_missing_header_end_test.dat + -$(ROBODOC) --src error_missing_header_end_test.dat --doc error_test --singlefile --html 2> error_missing_header_end_test.stderr + +# +# Test the error generated for a header end missing from a header +# that _is_ the last header in a file. +# + +error_missing_header_end_test_2: error_missing_header_end_test_2.stderr + echo "TODO" + +error_missing_header_end_test_2.stderr : error_missing_header_end_test_2.dat + -$(ROBODOC) --src error_missing_header_end_test_2.dat --doc error_test --singlefile --html 2> error_missing_header_end_test_2.stderr + + +# +# The if a user can specify its own css file. +# + +user_specified_css_file_test : user_specified_css_file_test.html + ./$(@F).pl < ./Doc1/robodoc.css + +user_specified_css_file_test.html : user_css.css + $(ROBODOC) --src ./Scr1 --doc ./Doc1 --html --multidoc --index --sections --toc --css user_css.css +# touch user_specified_css_file_test.html + + +lock_test : lock_test.html + ./$(@F).pl < lock_test.html + +lock_test.html: lock_test.dat + $(ROBODOC) --src lock_test.dat --doc lock_test --singlefile --lock --html + +# +# Test the forth headers +# + +forth_test: forth_test.html + +forth_test.html: + $(ROBODOC) --src ../../Headers/forth.sample --doc forth_test --singlefile --html --toc + +# +# +# + +pipe_test : + $(ROBODOC) --src pipe_test.dat --doc pipe_test --singlefile --html + ./pipe_test.pl 1 0 < pipe_test.html + ./pipe_test.pl 2 1 < pipe_test.html + ./pipe_test.pl 3 0 < pipe_test.html + $(ROBODOC) --src pipe_test.dat --doc pipe_test --singlefile --latex + @ if [ -x "`which latex`" ] ; then \ + latex pipe_test.tex > /dev/null 2>&1 ; rm -f pipe_test/dvi ; \ + else \ + echo "latex missing, can not perform test"; \ + fi ; + ./pipe_test.pl 2 0 < pipe_test.tex + ./pipe_test.pl 1 1 < pipe_test.tex + +# +# +# +master_index_test : Doc2/masterindex.html + ./$(@F).pl + +Doc2/masterindex.html : Scr2/master_index_test.dat + $(ROBODOC) --src Scr2 --doc Doc2 --html --multidoc --index --internal + + +# +# +# +# +RoboHeaders/rbh_test1.c : RoboHeaders/rbh_test1.dat + cp RoboHeaders/rbh_test1.dat RoboHeaders/rbh_test1.c + +robohdrs_test.hdrs : RoboHeaders/rbh_test1.c + cd RoboHeaders; ../$(ROBOHDRS) -p HDRS rbh_test1.c ; cd .. + touch robohdrs_test.hdrs + + +# +# +# +# +robohdrs_test.doc : robohdrs_test.hdrs + -rm -rf Doc1/*.* + $(ROBODOC) --src RoboHeaders --doc Doc1 --html --multidoc --index + +robohdrs_test : robohdrs_test.doc + ./$(@F).pl + + +doc_dir_filter_test.doc : doc_dir_filter_test.rc + $(ROBODOC) --rc doc_dir_filter_test.rc + $(ROBODOC) --rc doc_dir_filter_test.rc + +doc_dir_filter_test : doc_dir_filter_test.doc + ./$(@F).pl + -rm -rf DocNot + + + +# +# +# +filter_test_2.doc : + -rm -rf Doc3/* + $(ROBODOC) --src FileFilterSrc_2 --doc Doc3 --html --multidoc --index --rc filter_test_2.rc + +filter_test_2 : filter_test_2.doc + ./$(@F).pl + +# +# +# +filter_test_1.doc : + -rm -rf Doc1/* + $(ROBODOC) --src FileFilterSrc --doc Doc1 --html --multidoc --index --rc filter_test_1.rc + +filter_test_1 : filter_test_1.doc + ./$(@F).pl + + +# +# +# +sort_test.doc : + -rm -rf Doc1/*.* + $(ROBODOC) --src SortSource --doc Doc1 --html --multidoc --index --toc + +sort_test : sort_test.doc + ./$(@F).pl + +# +# +# +nosort_test.doc : + -rm -rf Doc1/*.* + $(ROBODOC) --src SortSource --doc Doc1 --html --multidoc --index --toc --nosort + +nosort_test : nosort_test.doc + ./$(@F).pl + + +nosource_test : nosource_test.html + ./$(@F).pl < nosource_test.html + +nosource_test.html : nosource_test.dat + $(ROBODOC) --src nosource_test.dat --doc nosource_test --singlefile --nosource --html + +ignore_test : ignore_test.html + ./$(@F).pl < ignore_test.html + +ignore_test.html : ignore_test.dat + $(ROBODOC) --src ignore_test.dat --doc ignore_test --singlefile --html --rc ignore_test.rc + + +doc1_clean : + rm -rf Doc1/Subdir + rm -rf Doc1/ToBeAccepted + rm -rf Doc1/*.* + +doc2_clean : + rm -rf Doc2/*.* diff --git a/Source/Test/master_index_test.pl b/Source/Test/master_index_test.pl new file mode 100755 index 0000000..74da647 --- /dev/null +++ b/Source/Test/master_index_test.pl @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w +# +# +# $Id: master_index_test.pl,v 1.1 2003/12/14 17:45:10 gumpu Exp $ +# + +use strict; +use ROBOTest; +ROBOTest::start("Masterindex Test"); +ROBOTest::assertFile("Doc2/robo_functions.html"); +ROBOTest::assertFile("Doc2/robo_variables.html"); +ROBOTest::finish; + diff --git a/Source/Test/multidoc_test1.pl b/Source/Test/multidoc_test1.pl new file mode 100755 index 0000000..0ee1daa --- /dev/null +++ b/Source/Test/multidoc_test1.pl @@ -0,0 +1,128 @@ +#!/usr/bin/perl -w +# + +use strict; +use ROBOTest; +ROBOTest::start("Multidoc Test"); + +use IO::File; + + + +sub Fail { + my $ok = shift; + if ( $ok ) { + print "OK\n"; + } else { + print "FAIL\n"; + } +} + + +sub Test_Master_Index { + my $mi = IO::File->new("Doc1/masterindex.html"); + my @lines = <$mi>; + $mi->close; + my %seen = (); + my $ok = 1; + + # All header types are in the source files, + # so they should also be listed in the master index. + # Lets test this. + foreach my $line (@lines) { + if ($line =~ m/top">([^<]+)<\/a>]/i) { + $seen{$1}++; + } + } + foreach my $file ("Modules", "Sourcefiles", + "Classes", "Structures", "Functions", + "Variables", "Procedures", + "Types", "Exceptions", "Definitions" ) { + $ok = 0 unless ( defined($seen{$file}) and $seen{$file} == 1 ); + } + # Test if all source files are listed. +# foreach my $line (@lines) { +# if (($line =~ m/Source\sFiles/) .. +# ($line =~ m/\/table/i)) { +# if ($line =~ m/([a-z][a-z]file\.dat)/) { +# $seen{$1}++; +# } +# } +# } +# foreach my $file ( qw( ccfile.dat bbfile.dat aafile.dat) ) { +# $ok = 0 unless ( defined($seen{$file}) and $seen{$file} == 1 ); +# } +# # Test table for /****d* +# foreach my $line (@lines) { +# if (($line =~ m/Constants/) .. +# ($line =~ m/\/table/i)) { +# if ($line =~ m/_test_(\S+)_test_/) { +# $seen{$1}++; +# } +# } +# } +# foreach my $name ( qw( def1 def2 ) ) { +# $ok = 0 unless ( defined($seen{$name}) and $seen{$name} == 1 ); +# } +# # Test table for /****f* +# foreach my $line (@lines) { +# if (($line =~ m/Functions/) .. +# ($line =~ m/\/table/i)) { +# if ($line =~ m/_test_(\S+)_test_/) { +# $seen{$1}++; +# } +# } +# } +# foreach my $name ( qw( fun1 fun2 ) ) { +# $ok = 0 unless ( defined($seen{$name}) and $seen{$name} == 1 ); +# } +# # Test table for /****c* +# foreach my $line (@lines) { +# if (($line =~ m/Classes/) .. +# ($line =~ m/\/table/i)) { +# if ($line =~ m/_test_(\S+)_test_/) { +# $seen{$1}++; +# } +# } +# } +# foreach my $name ( qw( class1 class2 class3 ) ) { +# $ok = 0 unless ( defined($seen{$name}) and $seen{$name} == 1 ); +# } + return $ok; +} + +# +# This tests the TOC of aafile.dat +# +# +sub Test_aafile_dat { + my $mi = IO::File->new("Doc1/aafile_dat.html"); + my @lines = <$mi>; + $mi->close; + my %seen = (); + my $ok = 1; + # Scan the table of content + foreach my $line (@lines) { + if (($line =~ m/TABLE\sOF\sCONTENTS/i) .. + ($line =~ m/\/UL/i)) { + if ($line =~ m/\/([ABCD][ab][ab]__level\d__)/) { + $seen{$1}++; + } + } + } + foreach my $name ( qw( Aaa__level1__ Bbb__level2__ Abb__level3__ Bbb__level3__ Cbb__level3__ Dbb__level3__ ) ) { + $ok = 0 unless ( defined($seen{$name}) and $seen{$name} == 1 ); + } + + return $ok; +} + +ROBOTest::assertFile("Doc1/masterindex.html"); +ROBOTest::assertDir("Doc1/Subdir"); +ROBOTest::assertFile("Doc1/Subdir/ccfile_dat.html"); +ROBOTest::assertFile("Doc1/aafile_dat.html"); +ROBOTest::assertFile("Doc1/bbfile_dat.html"); +ROBOTest::assert( Test_Master_Index(), "Master index content" ); +ROBOTest::assert( Test_aafile_dat(), "aafile TOC" ); + +ROBOTest::finish; diff --git a/Source/Test/nosort_test.pl b/Source/Test/nosort_test.pl new file mode 100755 index 0000000..55a92ca --- /dev/null +++ b/Source/Test/nosort_test.pl @@ -0,0 +1,88 @@ +#!/usr/bin/perl -w +# +# +# $Id: nosort_test.pl,v 1.2 2004/06/20 09:24:36 gumpu Exp $ +# + +use strict; +use warnings; +use ROBOTest; +use IO::File; + +#****x* SystemTest/nosort_test_pl +# FUNCTION +# ROBODoc sorts the TOC and the headers so that they appear in +# a particular order in the documentation. +# Here we test if the order is the order we expect. +# This is done by generating the documentation and comparing +# the order with a table. There are two source files, one +# that is already sorted, and one that is unsorted. +# The documentation for both should end up sorted. +# SOURCE +# + + +ROBOTest::start("Sort Test"); + +# in the documentation for the sorted file when +# it is sorted the TOC should look like this. +my @toc_sorted_names = qw( + AA_Header/BB_header + BB_header/aaa_function + BB_header/bbb_function + BB_header/ccc_function +); + +my @toc_unsorted_names = qw( + XX_Header/ZZ_Header + XX_Header/AA_Header + ZZ_Header/DD_Header + AA_Header/CC_header + CC_header/ccc_function + DD_header/aaa_function + CC_header/aaa_function + CC_header/fff_function + CC_header/eee_function +); + + +sub check_toc_order { + my $ok = 1; + my $filename = shift; # filename of the file with the headers + my $order = shift; # order of the headers + my $number = shift; # number of headers + my $file = IO::File->new("<$filename") or die; + my $index = 0; + while( my $line = <$file> ) { + if ( $line =~ m/robo\d+">([^<]+)close(); + + return $ok; +} + +ROBOTest::assertFile("Doc1/sorted_c.html"); +ROBOTest::assert( + check_toc_order( "Doc1/sorted_c.html", \@toc_sorted_names, 4 ), + "Is the TOC still sorted" +); + +ROBOTest::assertFile("Doc1/unsorted_c.html"); +ROBOTest::assert( + check_toc_order( "Doc1/unsorted_c.html", \@toc_unsorted_names, 4 ), + "Is the TOC now sorted" +); + +ROBOTest::finish; + +#**** + diff --git a/Source/Test/nosource_test.dat b/Source/Test/nosource_test.dat new file mode 100644 index 0000000..0beaba7 --- /dev/null +++ b/Source/Test/nosource_test.dat @@ -0,0 +1,11 @@ +/****f* Test/test + * NAME + * Test + * SOURCE + */ + +should not appear; +should not appear; +should not appear; + +/****/ diff --git a/Source/Test/nosource_test.pl b/Source/Test/nosource_test.pl new file mode 100755 index 0000000..a227300 --- /dev/null +++ b/Source/Test/nosource_test.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl -w + +# +# Test whether robodoc can handle the --lock mode +# In the lock mode it will lock on to one kind of header marker +# per file and one kind of remark marker per header. All +# other ones should be skipped. +# + +use strict; +use ROBOTest; + +ROBOTest::start("--nosource Test"); +my $checksum = 0; + +while (my $line = <>) { + if ($line =~ m/should\snot\sappear/) { + ++$checksum; + } +} +ROBOTest::assert( $checksum == 0 ); +ROBOTest::finish; + diff --git a/Source/Test/option_rc_test.dat b/Source/Test/option_rc_test.dat new file mode 100644 index 0000000..2f62720 --- /dev/null +++ b/Source/Test/option_rc_test.dat @@ -0,0 +1,5 @@ +#****f* Test/test +# NAME +# Test +# +#***** diff --git a/Source/Test/option_rc_test.pl b/Source/Test/option_rc_test.pl new file mode 100755 index 0000000..b2db8e2 --- /dev/null +++ b/Source/Test/option_rc_test.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl -w +# +# Test the --rc option +# If the works there should be a file called +# option_rc_test.html +# +# $Id: option_rc_test.pl,v 1.1 2003/08/13 20:42:07 gumpu Exp $ +# + +use strict; +use ROBOTest; +ROBOTest::start("Test of --rc"); +ROBOTest::assertFile( "option_rc_test.html" ); +ROBOTest::finish; diff --git a/Source/Test/outputformat_test.dat b/Source/Test/outputformat_test.dat new file mode 100644 index 0000000..226c0f3 --- /dev/null +++ b/Source/Test/outputformat_test.dat @@ -0,0 +1,17 @@ +/****h* ATest/Test1 + * NAME + * Test2 + * RESULT + * Test3 + ****** + */ + + +/****h* ATest/Test10 + * NAME + * Test20 + * RESULT + * Test30 + ****** + */ + diff --git a/Source/Test/outputformat_test.pl b/Source/Test/outputformat_test.pl new file mode 100755 index 0000000..9353bba --- /dev/null +++ b/Source/Test/outputformat_test.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl -w + +# +# Test whether robodoc can generate output in all the formats +# it is supposed to support. +# + +# TODO +# +use strict; + +print "Outputformat Test: "; + +print<This will be included in HTML output. + * |latex \centerline{This will be included in \LaTeX output} + * Space is mandatory following the pipe marker. The following is not a + * valid pipe marker: + * |htmlMoi! + * You should see an equation on the following line: + * |html y = x^2 (sorry, plain HTML is not very powerfull) + * |latex \centerline{$y = x^2$} + * How does this look like? + * Here comes a multi-line equation array: + * |latex \begin{eqnarray} + * |latex \frac{\partial u}{\partial \tau} & = & D_u {\nabla}^2 u + + * |latex \frac{1}{\epsilon} + * |latex \left ( \hat{u}-{\hat{u}}^2-f\, {v} \, \frac{\hat{u}-q}{\hat{u}+q} + * |latex \right ) \; , \label{diffspot:1} \\ + * |latex \frac{\partial v}{\partial \tau} & = & \hat{u}-v \; , + * |latex \label{diffspot:2} \\ + * |latex \frac{\partial r}{\partial \tau} & = & D_r {\nabla}^2 r \; . + * |latex \label{diffspAot:3} + * |latex \end{eqnarray} + * |html TODO: write this in html + * Remove this line and you'll experience a bug... + ****** + */ diff --git a/Source/Test/pipe_test.pl b/Source/Test/pipe_test.pl new file mode 100755 index 0000000..5842d88 --- /dev/null +++ b/Source/Test/pipe_test.pl @@ -0,0 +1,51 @@ +#!/usr/bin/perl -w +# $Id: pipe_test.pl,v 1.1 2003/11/18 12:10:26 petterik Exp $ + +use strict; +use ROBOTest; + +my $n = $ARGV[0] || 1; +my $expected = $ARGV[1] || 0; + +sub test1 { + my $res = 1; + while (my $line = ) { + if ($line =~ m/
    This will be included in HTML<\/B> output.<\/CENTER>/) { + $res = 0; + } + } + return $res; +} + +sub test2 { + my $res = 1; + while (my $line = ) { + if ($line =~ m/\\centerline{This will be included in \\LaTeX output}/) { + $res = 0; + } + } + return $res; +} + +sub test3 { + my $res = 1; + while (my $line = ) { + if ($line =~ /\|html<\;B>\;Moi!<\;\/B>\;/) { + $res = 0; + } + } + return $res; +} + +my %tests = ( + 1 => \&test1, + 2 => \&test2, + 3 => \&test3 + ); + +ROBOTest::start("Pipe Test $n-$expected"); + +my $status = $tests{$n}(); + +ROBOTest::assert( $status == $expected ); +ROBOTest::finish; diff --git a/Source/Test/readme.txt b/Source/Test/readme.txt new file mode 100644 index 0000000..415e926 --- /dev/null +++ b/Source/Test/readme.txt @@ -0,0 +1,3 @@ + +See documentation in the makefile. + diff --git a/Source/Test/remarkmarker_test.dat b/Source/Test/remarkmarker_test.dat new file mode 100644 index 0000000..867d17e --- /dev/null +++ b/Source/Test/remarkmarker_test.dat @@ -0,0 +1,25 @@ +/****f* Test/Test * + * NAME + * remark markers test + * LINE 1 +// LINE 2 +* LINE 3 +;* LINE 4 +; LINE 5 +C LINE 6 +REM LINE 7 +% LINE 8 +# LINE 9 + * LINE 10 +-- LINE 11 +| LINE 12 +!! LINE 13 + LINE 14 Should be skipped, because it does not start with a + remark marker +# SOURCE + + LINE 15 Should not be skipped because it is part of a source item +# LINE 16 This too should be there +/******/ + + diff --git a/Source/Test/remarkmarker_test.pl b/Source/Test/remarkmarker_test.pl new file mode 100755 index 0000000..ff0ea3d --- /dev/null +++ b/Source/Test/remarkmarker_test.pl @@ -0,0 +1,29 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +ROBOTest::start("RemarkMarker Test"); + +# +# The ,res should look like +# LINE 1 +# LINE 2 +# LINE 3 +# etc +# We extract all the numbers and store them +# in a hash +# +my %count = (); +while (my $line = <>) { + if ($line =~ m/\s*LINE\s+(\d+)\s/) { + $count{$1}++; + } +} + +# there should be 15 different lines +# +my $number_of_lines = scalar(keys %count); + +ROBOTest::assert($number_of_lines == 15, "header types"); +ROBOTest::finish; diff --git a/Source/Test/robodoc.rc b/Source/Test/robodoc.rc new file mode 100644 index 0000000..e2b7460 --- /dev/null +++ b/Source/Test/robodoc.rc @@ -0,0 +1,5 @@ +#options: +# --tell +# +ignore files: + CVS diff --git a/Source/Test/robohdrs_test.pl b/Source/Test/robohdrs_test.pl new file mode 100644 index 0000000..8f0ef6e --- /dev/null +++ b/Source/Test/robohdrs_test.pl @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w +# +# +# $Id: robohdrs_test.pl,v 1.2 2003/12/26 22:31:29 gumpu Exp $ +# + +use strict; +use ROBOTest; +ROBOTest::start("ROBOHDRS Test"); +ROBOTest::assertFile("Doc1/robo_functions.html"); +ROBOTest::assertFile("Doc1/robo_variables.html"); +ROBOTest::finish; + diff --git a/Source/Test/sort_test.pl b/Source/Test/sort_test.pl new file mode 100755 index 0000000..6f21c45 --- /dev/null +++ b/Source/Test/sort_test.pl @@ -0,0 +1,87 @@ +#!/usr/bin/perl -w +# +# +# $Id: sort_test.pl,v 1.2 2004/06/20 09:24:36 gumpu Exp $ +# + +use strict; +use warnings; +use ROBOTest; +use IO::File; + +#****x* SystemTest/sort_test_pl +# FUNCTION +# ROBODoc sorts the TOC and the headers so that they appear in +# a particular order in the documentation. +# Here we test if the order is the order we expect. +# This is done by generating the documentation and comparing +# the order with a table. There are two source files, one +# that is already sorted, and one that is unsorted. +# The documentation for both should end up sorted. +# SOURCE +# + + +ROBOTest::start("Sort Test"); + +# in the documentation for the sorted file when +# it is sorted the TOC should look like this. +my @toc_sorted_names = qw( + AA_Header/BB_header + BB_header/aaa_function + BB_header/bbb_function + BB_header/ccc_function +); + +my @toc_unsorted_names = qw( + AA_Header/CC_header + XX_Header/AA_Header + XX_Header/ZZ_Header + ZZ_Header/DD_Header + CC_header/aaa_function + CC_header/ccc_function + CC_header/eee_function + CC_header/fff_function + DD_header/aaa_function +); + + +sub check_toc_order { + my $ok = 1; + my $filename = shift; # filename of the file with the headers + my $order = shift; # order of the headers + my $number = shift; # number of headers + my $file = IO::File->new("<$filename") or die; + my $index = 0; + while( my $line = <$file> ) { + if ( $line =~ m/robo\d">([^<]+)close(); + + return $ok; +} + +ROBOTest::assertFile("Doc1/sorted_c.html"); +ROBOTest::assert( + check_toc_order( "Doc1/sorted_c.html", \@toc_sorted_names, 4 ), + "Is the TOC still sorted" +); + +ROBOTest::assertFile("Doc1/unsorted_c.html"); +ROBOTest::assert( + check_toc_order( "Doc1/unsorted_c.html", \@toc_unsorted_names, 4 ), + "Is the TOC now sorted" +); + +ROBOTest::finish; + +#***** diff --git a/Source/Test/tabtest.dat b/Source/Test/tabtest.dat new file mode 100644 index 0000000..7b3b9d6 --- /dev/null +++ b/Source/Test/tabtest.dat @@ -0,0 +1,15 @@ +/****h* URLTest/URLTest + * NAME + * URLTest + * NOTES + * dummy + * XXX 1 + * XXX 2 + * XXX 3 + * XXX 4 + * XXX 5 + * + * + ***** + */ + diff --git a/Source/Test/tabtest.pl b/Source/Test/tabtest.pl new file mode 100755 index 0000000..43b2828 --- /dev/null +++ b/Source/Test/tabtest.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl -w +# +# +# $Id: tabtest.pl,v 1.3 2003/08/13 20:42:07 gumpu Exp $ +# + +use strict; +use ROBOTest; + +ROBOTest::start("Tab Test"); + +my $count = 0; +while (my $line = <>) { + if ($line =~ m/^\s\s\s\s\s\sXXX/i) { + $count++; + } +} + +ROBOTest::assert( $count == 5, "Testing tabsize of 4" ); +ROBOTest::finish; + diff --git a/Source/Test/url_test.dat b/Source/Test/url_test.dat new file mode 100644 index 0000000..0078ddb --- /dev/null +++ b/Source/Test/url_test.dat @@ -0,0 +1,13 @@ +/****h* URLTest/URLTest + * NAME + * URLTest + * NOTES + * file:/my_file.testmark_1 + * href:ftp://my_href.testmark_2 + * http://my_http.testmark_3 + * http://my_http.testmark_4. + * mailto:my_mail@testmark_5 + * image:http://www.jinwicked.com/images/art/stallman.jpg + ***** + */ + diff --git a/Source/Test/url_test.pl b/Source/Test/url_test.pl new file mode 100755 index 0000000..7796eb6 --- /dev/null +++ b/Source/Test/url_test.pl @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +use strict; +use ROBOTest; + +ROBOTest::start("URL Test"); + +my $count = 0; +while (my $line = <>) { + if (($line =~ m//i) + ) { + $count++; + } +} + +# there should be 6 +# +ROBOTest::assert($count == 6); +ROBOTest::finish; + diff --git a/Source/Test/user_css.css b/Source/Test/user_css.css new file mode 100644 index 0000000..e2c0709 --- /dev/null +++ b/Source/Test/user_css.css @@ -0,0 +1,27 @@ +# ROBO_UnitTest +# +body +{ + background-color: #ffffff; + color: #000000; + font-family: 'Lucida Grande', Verdana, + Geneva, Lucida, Arial, + Helvetica, sans-serif; + font-size: 10pt; + margin: 2% 5%; +} +h2 +{ + background-color: #dddddd; + color: #000000; + text-align: right; + font-size: 11pt; +} +pre +{ + background-color: #ffffff; + color: #000000; + font-size: 10pt; +} +# +# ROBO_UnitTest diff --git a/Source/Test/user_specified_css_file_test.pl b/Source/Test/user_specified_css_file_test.pl new file mode 100755 index 0000000..3d84b71 --- /dev/null +++ b/Source/Test/user_specified_css_file_test.pl @@ -0,0 +1,28 @@ +#!/usr/bin/perl -w + +# +# This tests the option --css +# +# +# $Id: user_specified_css_file_test.pl,v 1.2 2003/08/31 09:29:28 gumpu Exp $ + +use strict; +use ROBOTest; +ROBOTest::start("Option --css Test"); +# +# +# The file user_css.css +# contains twice the word ROBO_UnitTest +# It should therefore also appear twice +# in the robodoc.css file. +# +my $sum = 0; +while (my $line = <>) { + if ( $line =~ m/ROBO_UnitTest/ ) { + $sum++; + } +} + +ROBOTest::assert( $sum == 2 ); +ROBOTest::finish; + diff --git a/Source/analyser.c b/Source/analyser.c new file mode 100644 index 0000000..7d82641 --- /dev/null +++ b/Source/analyser.c @@ -0,0 +1,2077 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + + +/****h* ROBODoc/Analyser + * NAME + * Analyser -- Functions to scan source and collect headers + * FUNCTION + * This module provides the functions to scan a sourcefile and + * collect all the headers. + * + ***** + * $Id: analyser.c,v 1.73 2007/07/10 19:13:51 gumpu Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include "robodoc.h" +#include "globals.h" +#include "headers.h" +#include "headertypes.h" +#include "items.h" +#include "util.h" +#include "links.h" +#include "analyser.h" +#include "document.h" +#include "file.h" +#include "part.h" +#include "roboconfig.h" + +#ifdef DMALLOC +#include +#endif + +static int ToBeAdded( + struct RB_Document *document, + struct RB_header *header ); +static int Find_Header_Name( + FILE *, + struct RB_header * ); +static struct RB_header *Grab_Header( + FILE *sourcehandle, + struct RB_Document *arg_document ); +static char *Function_Name( + char *header_name ); +static char *Module_Name( + char *header_name ); +static int Find_End_Marker( + FILE *document, + struct RB_header *new_header ); +struct RB_HeaderType *AnalyseHeaderType( + char **cur_char, + int *is_internal ); +static struct RB_HeaderType *RB_Find_Marker( + FILE *document, + int *is_internal, + int reuse_previous_line ); +static int Analyse_Items( + struct RB_header *arg_header ); +static int Is_ListItem_Start( + char *arg_line, + int arg_indent ); + +/****f* Analyser/Is_Pipe_Marker + * NAME + * Is_Pipe_Marker + * FUNCTION + * Check for "pipe" markers e.g. "|html ". + * SYNOPSIS + */ +static char *Is_Pipe_Marker( + char *cur_char, + int *pipe_mode ) +/* + * RESULT + * Pointer to the data to be piped to document or in case no pointers + * are found. + * SEE ALSO + * RB_Check_Pipe + * SOURCE + */ +{ + char *s = cur_char + 1; + + *pipe_mode = -1; + if ( *cur_char == '|' && *s ) + { + if ( strncmp( "html ", s, 5 ) == 0 ) + { + *pipe_mode = HTML; + return ( s + 5 ); + } + else if ( strncmp( "latex ", s, 6 ) == 0 ) + { + *pipe_mode = LATEX; + return ( s + 6 ); + } + else if ( strncmp( "rtf ", s, 4 ) == 0 ) + { + *pipe_mode = RTF; + return ( s + 4 ); + } + else if ( strncmp( "dbxml ", s, 6 ) == 0 ) + { + *pipe_mode = XMLDOCBOOK; + return ( s + 6 ); + } + else if ( strncmp( "ascii ", s, 6 ) == 0 ) + { + *pipe_mode = ASCII; + return ( s + 6 ); + } + } + + return ( char * ) NULL; +} + +/*****/ + + +/****f* Analyser/Is_Tool + * SYNOPSIS + */ +static char *Is_Tool( + char *cur_char, + enum ItemLineKind *itemkind, + int *tool_active ) +/* + * FUNCTION + * Checks for tool start and end markers + * SOURCE + */ +{ + char *s = cur_char + 1; + + if ( *cur_char == '|' && *s ) + { + // Check if tool starts or ends + if ( !strncmp( "tool ", s, 5 ) ) + { + if ( *tool_active ) + { + *itemkind = ITEM_LINE_TOOL_END; + *tool_active = 0; + } + else + { + *itemkind = ITEM_LINE_TOOL_START; + *tool_active = 1; + } + + return ( s + 5 ); + } + // Check if DOT starts or ends + if ( !strncmp( "dot ", s, 4 ) ) + { + if ( *tool_active ) + { + *itemkind = ITEM_LINE_DOT_END; + *tool_active = 0; + } + else + { + *itemkind = ITEM_LINE_DOT_START; + *tool_active = 1; + } + + return ( s + 4 ); + } + // Check for DOT file includes + else if ( !strncmp( "dotfile ", s, 8 ) && !*tool_active ) + { + *itemkind = ITEM_LINE_DOT_FILE; + return ( s + 8 ); + } + // Check for exec items + else if ( !strncmp( "exec ", s, 5 ) && !*tool_active ) + { + *itemkind = ITEM_LINE_EXEC; + return ( s + 5 ); + } + } + + return NULL; +} + +/*****/ + +/****f* Analyser/RB_Analyse_Document + * foo + * FUNCTION + * Scan all the sourcefiles of all parts of a document for + * headers. Store these headers in each part (RB_Part). + * SYNOPSIS + */ +void RB_Analyse_Document( + struct RB_Document *arg_document ) +/* + * INPUTS + * o document -- document to be analysed. + * RESULT + * Each part will contain the headers that were found in the + * sourcefile of the part. + * SOURCE + */ +{ + struct RB_Part *a_part; + struct RB_Filename *a_filename; + FILE *filehandle; + + for ( a_part = arg_document->parts; a_part; a_part = a_part->next ) + { + struct RB_header *new_header = NULL; + + a_filename = a_part->filename; + RB_Say( "analysing %s\n", SAY_DEBUG, Get_Fullname( a_filename ) ); + RB_SetCurrentFile( Get_Fullname( a_filename ) ); + + RB_Header_Lock_Reset( ); + filehandle = RB_Open_Source( a_part ); + line_number = 0; + + for ( new_header = Grab_Header( filehandle, arg_document ); + new_header; + new_header = Grab_Header( filehandle, arg_document ) ) + { + if ( ToBeAdded( arg_document, new_header ) ) + { + /* The Add is required before the + * Analyse because Add sets the owner of the header + * which is needed for error messages. + */ + RB_Part_Add_Header( a_part, new_header ); + Analyse_Items( new_header ); + } + else + { + RB_Free_Header( new_header ); + } + } + fclose( filehandle ); + } +} + +/*****/ + +#if 0 +/****f* Analyser/Check_Header_Start + * FUNCION + * Sometimes a user makes a spelling mistake in the name of the first item. + * ROBODoc then ignores all the lines leading up to the second item, + * (which is the first item ROBODoc recognized). This function + * checks for this condition and gives the user a warning. + * SYNOPSIS + */ +static void Check_Header_Start( + struct RB_header *arg_header, + int first_item ) +/* + * INPUTS + * * arg_header -- the header to be checked. + * * first -- the line on which the first item was found + * RESULT + * A warning is given if the condition occured. + * SOURCE + */ +{ + if ( first_item ) + { + int i = 0; + + for ( i = 0; i < first_item; ++i ) + { + char *c = arg_header->lines[i]; + + c = RB_Skip_Whitespace( c ); + if ( RB_Has_Remark_Marker( c ) ) + { + c = RB_Skip_Remark_Marker( c ); + for ( ; *c; ++c ) + { + if ( !utf8_isspace( *c ) ) + { + RB_Warning_Full( Get_Fullname + ( arg_header->owner->filename ), + arg_header->line_number, + "Header \"%s\" contains text before the fist item, " + "this might be caused by a misspelled item name.\n", + arg_header->name ); + return; + } + } + } + } + } +} + +/*******/ +#endif + +/****f* Analyser/Is_Empty_Line + * FUNCTION + * Check if line is empty. This assumes that + * Copy_Lines_To_Item has been run on the item. + * SYNOPSIS + */ +static int Is_Empty_Line( + char *line ) +/* + * INPUTS + * * line -- the string to be analysed. + * SOURCE + */ +{ + line = RB_Skip_Whitespace( line ); + return ( *line == '\0' ); +} + +/******/ + + +/****f* Analyser/Get_Indent + * FUNCION + * Determine the indentation of a line by counting + * the number of spaces at the begining of the line. + * SYNOPSIS + */ +static int Get_Indent( + char *line ) +/* + * INPUTS + * * line -- the line + * RESULT + * The indentation. + * SOURCE + */ +{ + int i; + + for ( i = 0; line[i] && utf8_isspace( line[i] ); ++i ) + { + /* empty */ + } + return i; +} + +/*****/ + + +/****f* Analyser/Is_ListItem_Start + * FUNCTION + * Test if a line starts with something that indicates a list item. + * List items start with '*', '-', or 'o'. + * SYNPOPSIS + */ +static int Is_ListItem_Start( + char *arg_line, + int arg_indent ) +/* + * INPUTS + * * line -- the line + * RESULT + * * TRUE -- it did start with one of those characters + * * FALSE -- it did not. + * SOURCE + */ +{ + char *c = arg_line; + int cur_indent = Get_Indent( arg_line ); + + if ( cur_indent == arg_indent ) + { + /* TODO Think there is a function for this */ + for ( ; *c && utf8_isspace( *c ); ++c ) + { /* empty */ + }; + + if ( *c && ( strlen( c ) >= 3 ) ) + { + if ( strchr( "*-o", *c ) && utf8_isspace( *( c + 1 ) ) ) + { + return TRUE; + } + } + } + else + { + /* The line is indented so it must be + * the start of a pre block */ + } + + return FALSE; +} + +/*****/ + + +/****f* Analyser/Is_List_Item_Continuation + * FUNCTION + * Is it like the second line in something like: + * * this is a list item + * that continues + * SYNPOPSIS + */ +static int Is_List_Item_Continuation( + char *arg_line, + int indent ) +/* + * INPUTS + * * arg_line -- the current line + * * indent -- the indent of the current item. + * RESULT + * * TRUE -- it is. + * * FALSE -- it is not. + * SOURCE + */ +{ + int this_indent = Get_Indent( arg_line ); + + return ( this_indent > indent ); +} + +/*****/ + + +#if 0 +/****f* Analyser/Is_End_of_List + * FUNCTION + * Check... (TODO) + * INPUTS + * * arg_line -- + * * indent -- + * SOURCE + */ + +static int Is_End_of_List( + char *arg_line, + int indent ) +{ + int this_indent = Get_Indent( arg_line ); + + return ( this_indent <= indent ); +} + +/******/ +#endif + + +/****f* Analyser/Is_Start_List + * FUNCTION + * Check... (TODO) + * INPUTS + * * arg_line -- + * * indent -- + * SOURCE + */ + +static int Is_Start_List( + char *arg_line, + int indent ) +{ + int this_indent = Get_Indent( arg_line ); + char *c = strrchr( arg_line, ':' ); + + if ( ( this_indent == indent ) && c ) + { + for ( ++c; *c; ++c ) + { + if ( !utf8_isspace( *c ) ) + { + return FALSE; + } + } + return TRUE; + } + return FALSE; +} + +/*******/ + + +/****f* Analyser/Remove_List_Char + * FUNCTION + * Remove... (TODO) + * INPUTS + * * arg_item -- the item to be analysed. + * * start_index -- + * SOURCE + */ + +static void Remove_List_Char( + struct RB_Item *arg_item, + int start_index ) +{ + char *c = arg_item->lines[start_index]->line; + + for ( ; *c && utf8_isspace( *c ); ++c ) + { /* empty */ + }; + if ( *c && ( strlen( c ) >= 3 ) ) + { + if ( strchr( "*-o", *c ) && utf8_isspace( *( c + 1 ) ) ) + { + char *temp = arg_item->lines[start_index]->line; + + *c = ' '; + arg_item->lines[start_index]->line = RB_StrDup( temp + 2 ); + free( temp ); + } + } +} + +/*******/ + +/****f* Analyser/Analyse_ListBody + * FUNCTION + * Analyse... (TODO) + * SYNPOPSIS + */ +static int Analyse_ListBody( + struct RB_Item *arg_item, + int start_index, + int arg_indent ) +/* + * INPUTS + * * arg_item -- the item to be analysed. + * * start_index -- + * * arg_index -- + * SOURCE + */ +{ + int i = start_index; + + for ( ; i < arg_item->no_lines; i++ ) + { + char *line = arg_item->lines[i]->line; + + if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) || + ( arg_item->lines[i]->kind == ITEM_LINE_END ) ) + { + if ( Is_ListItem_Start( line, arg_indent ) ) + { + arg_item->lines[i]->format |= RBILA_END_LIST_ITEM; + arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM; + Remove_List_Char( arg_item, i ); + } + else if ( Is_List_Item_Continuation( line, arg_indent ) ) + { + /* Nothing */ + } + else + { + /* Must be the end of the list */ + arg_item->lines[i]->format |= RBILA_END_LIST_ITEM; + arg_item->lines[i]->format |= RBILA_END_LIST; + break; + } + } + } + return i; +} + +/*******/ + +/****f* Analyser/Analyse_List + * FUNCTION + * Parse the item text to see if there are any lists. + * A list is either case I: + * ITEMNAME + * o bla bla + * o bla bla + * or case II: + * some text: <-- begin of a list + * o bla bla <-- list item + * bla bla bla <-- continuation of list item. + * o bla bla <-- list item + * <-- end of a list + * bla bla <-- this can also be the end of a list. + * SYNPOPSIS + */ +static void Analyse_List( + struct RB_Item *arg_item, + int indent ) +/* + * INPUTS + * * arg_item -- the item to be parsed. + * * indent -- the indent of this item. + * OUTPUT + * * arg_item -- the itemlines will contain formatting information + * for all the lists that were found. + * SOURCE + */ +{ + if ( arg_item->no_lines >= 1 ) + { + int i = 0; + char *line = arg_item->lines[i]->line; + + /* Case I */ + if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) && + Is_ListItem_Start( line, indent ) ) + { + /* Case I, the is a list item right after the item name */ + arg_item->lines[i]->format |= RBILA_BEGIN_LIST; + arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM; + Remove_List_Char( arg_item, i ); + /* Now try to find the end of the list */ + i = Analyse_ListBody( arg_item, 1, indent ); + } + + /* Now search for case II cases */ + for ( ; i < arg_item->no_lines; i++ ) + { + line = arg_item->lines[i]->line; + if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) && + Is_Start_List( line, indent ) ) + { + ++i; + if ( i < arg_item->no_lines ) + { + line = arg_item->lines[i]->line; + if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) && + Is_ListItem_Start( line, indent ) ) + { + arg_item->lines[i]->format |= RBILA_BEGIN_LIST; + arg_item->lines[i]->format |= RBILA_BEGIN_LIST_ITEM; + Remove_List_Char( arg_item, i ); + ++i; + i = Analyse_ListBody( arg_item, i, indent ); + + + /* One list might be immediately followed + * by another. In this case we have to + * analyse the last line again. */ + line = arg_item->lines[i]->line; + if ( ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) + && Is_Start_List( line, indent ) ) + { + --i; + } + + } + } + } + } + } +} + +/******/ + +// If (unused(this_function)) { delete(this_function) } +#if 0 +/****f* Analyser/Dump_Item + * FUNCTION + * Print debug information. + */ +static void Dump_Item( + struct RB_Item *arg_item ) +/* + * INPUTS + * * arg_item -- the item to be pretty-printed. + * SOURCE + */ +{ + int i; + + /* preformatted blocks */ + for ( i = 0; i < arg_item->no_lines; i++ ) + { + char *line = arg_item->lines[i]->line; + int format = arg_item->lines[i]->format; + + printf( "%04d ", i ); + printf( ( format & RBILA_END_PARAGRAPH ) ? "p" : " " ); + printf( ( format & RBILA_BEGIN_PARAGRAPH ) ? "P" : " " ); + printf( ( format & RBILA_END_PRE ) ? "e" : " " ); + printf( ( format & RBILA_BEGIN_PRE ) ? "E" : " " ); + printf( ( format & RBILA_END_LIST ) ? "l" : " " ); + printf( ( format & RBILA_BEGIN_LIST ) ? "L" : " " ); + printf( ( format & RBILA_END_LIST_ITEM ) ? "i" : " " ); + printf( ( format & RBILA_BEGIN_LIST_ITEM ) ? "I" : " " ); + printf( " (%s)\n", line ); + } +} + +/*******/ +#endif + +/****f* Analyser/Preformat_All + * FUNCTION + * Process... (TODO) + * SYNPOPSIS + */ +static void Preformat_All( + struct RB_Item *arg_item, + int source ) +/* + * INPUTS + * * arg_item -- the item to be pre-formatted. + * * source -- is it a source item ? + * SOURCE + */ +{ + int i; + int preformatted = FALSE; + char *line = NULL; + + if ( arg_item->no_lines > 0 ) + { + i = 0; + /* Skip any pipe stuff */ + for ( ; + ( i < arg_item->no_lines ) + && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i ) + { + /* Empty */ + } + + line = arg_item->lines[i]->line; + if ( ( arg_item->lines[i]->kind == ITEM_LINE_RAW ) || + ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) ) + { + arg_item->lines[i]->format |= + RBILA_BEGIN_PRE | ( source ? RBILA_BEGIN_SOURCE : 0 ); + preformatted = TRUE; + + for ( ++i; i < arg_item->no_lines; i++ ) + { + if ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ) + { + /* Temporarily end the preformatting to allow + * the piping to happen + */ + arg_item->lines[i]->format |= + RBILA_END_PRE | ( source ? RBILA_END_SOURCE : 0 ); + /* Find the end of the pipe stuff */ + for ( ; ( i < arg_item->no_lines ) && + ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); + ++i ) + { /* Empty */ + }; + /* Every item ends with an ITEM_LINE_END, so: */ + assert( i < arg_item->no_lines ); + /* And re-enable preformatting */ + arg_item->lines[i]->format |= + RBILA_BEGIN_PRE | ( source ? RBILA_BEGIN_SOURCE : 0 ); + } + + if ( arg_item->lines[i]->kind == ITEM_LINE_END ) + { + /* If the last line ends with a begin_pre remove + * it, otherwise a begin and end pre will be + * generated, in the wrong order, on the same line in the output. + */ + if ( arg_item->lines[i]->format & RBILA_BEGIN_PRE ) { + arg_item->lines[i]->format &= ~( RBILA_BEGIN_PRE ); + } else { + arg_item->lines[i]->format |= RBILA_END_PRE; + } + arg_item->lines[i]->format |= ( source ? RBILA_END_SOURCE : 0 ); + } + } + } + } +} + +/******/ + +/* + * aaaaa + * aa + *

    + * aa

    + * aaa + * aaaa + * + * + */ + +/****f* Analyser/Analyse_Preformatted + * FUNCTION + * Analyse preformatted text ... (TODO) + * SYNPOPSIS + */ +static void Analyse_Preformatted( + struct RB_Item *arg_item, + int indent ) +/* + * INPUTS + * * arg_item -- the item to be analysed. + * * indent -- + * SOURCE + */ +{ + int i; + int in_list = FALSE; + int new_indent = -1; + int preformatted = FALSE; + char *line = NULL; + + /* preformatted blocks */ + if ( arg_item->no_lines > 0 ) + { + i = 0; + /* Skip any pipe stuff */ + for ( ; + ( i < arg_item->no_lines ) + && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i ) + { + /* Empty */ + } + + line = arg_item->lines[i]->line; + + if ( ( !in_list ) + && ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) ) + { + in_list = TRUE; + } + if ( ( in_list ) && ( arg_item->lines[i]->format & RBILA_END_LIST ) ) + { + in_list = FALSE; + } + + for ( ++i; i < arg_item->no_lines; i++ ) + { + if ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ) + { + if ( preformatted ) + { + arg_item->lines[i]->format |= RBILA_END_PRE; + } + for ( ; ( i < arg_item->no_lines ) && + ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i ) + { /* Empty */ + }; + /* Every item ends with an ITEM_LINE_END, so: */ + assert( i < arg_item->no_lines ); + if ( preformatted ) + { + arg_item->lines[i]->format |= RBILA_BEGIN_PRE; + } + } + + line = arg_item->lines[i]->line; + new_indent = Get_Indent( line ); + + if ( ( !in_list ) + && ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) ) + { + in_list = TRUE; + } + if ( ( in_list ) + && ( arg_item->lines[i]->format & RBILA_END_LIST ) ) + { + in_list = FALSE; + } + + if ( !in_list ) + { + if ( ( new_indent > indent ) && !preformatted ) + { + preformatted = TRUE; + arg_item->lines[i]->format |= RBILA_BEGIN_PRE; + } + else if ( ( new_indent <= indent ) && preformatted ) + { + preformatted = FALSE; + arg_item->lines[i]->format |= RBILA_END_PRE; + } + else + { + /* An empty line */ + } + } + else + { + /* We are in a list, do nothing */ + } + } + } +} + +/******/ + +/****f* Analyser/Analyse_Paragraphs + * FUNCTION + * Analyse paragraphs... (TODO) + * SYNPOPSIS + */ +static void Analyse_Paragraphs( + struct RB_Item *arg_item ) +/* + * INPUTS + * * arg_item -- the item to be analysed. + * SOURCE + */ +{ + int i; + int in_par = FALSE; + int in_list = FALSE; + int in_pre = FALSE; + int is_empty = FALSE; + int prev_is_empty = FALSE; + + for ( i = 0; + ( i < arg_item->no_lines ) + && ( arg_item->lines[i]->kind == ITEM_LINE_PIPE ); ++i ) + { + /* Empty */ + } + assert( i < arg_item->no_lines ); + + if ( ( arg_item->lines[i]->format == 0 ) ) + { + arg_item->lines[i]->format |= RBILA_BEGIN_PARAGRAPH; + in_par = TRUE; + } + for ( ; i < arg_item->no_lines; i++ ) + { + char *line = arg_item->lines[i]->line; + + prev_is_empty = is_empty; + is_empty = Is_Empty_Line( line ); + if ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) + { + in_list = TRUE; + } + if ( arg_item->lines[i]->format & RBILA_BEGIN_PRE ) + { + in_pre = TRUE; + } + if ( arg_item->lines[i]->format & RBILA_END_LIST ) + { + in_list = FALSE; + } + if ( arg_item->lines[i]->format & RBILA_END_PRE ) + { + in_pre = FALSE; + } + if ( in_par ) + { + if ( ( arg_item->lines[i]->format & RBILA_BEGIN_LIST ) || + ( arg_item->lines[i]->format & RBILA_BEGIN_PRE ) || + is_empty ) + { + in_par = FALSE; + arg_item->lines[i]->format |= RBILA_END_PARAGRAPH; + } + } + else + { + if ( ( arg_item->lines[i]->format & RBILA_END_LIST ) || + ( arg_item->lines[i]->format & RBILA_END_PRE ) || + ( !is_empty && prev_is_empty && !in_list && !in_pre ) ) + { + in_par = TRUE; + arg_item->lines[i]->format |= RBILA_BEGIN_PARAGRAPH; + } + } + } + if ( in_par ) + { + arg_item->lines[arg_item->no_lines - 1]->format |= + RBILA_END_PARAGRAPH; + } +} + +/******/ + + +/****f* Analyser/Analyse_Indentation + * FUNCTION + * Figure out how text is indented. + * SYNPOPSIS + */ +static int Analyse_Indentation( + struct RB_Item *arg_item ) +/* + * INPUTS + * * arg_item -- the item to be analysed. + * SOURCE + */ +{ + int i; + int indent = -1; + + assert( arg_item->no_lines > 0 ); + + for ( i = 0; i < arg_item->no_lines; ++i ) + { + if ( arg_item->lines[i]->kind == ITEM_LINE_PLAIN ) + { + char *line = arg_item->lines[i]->line; + + if ( Is_Empty_Line( line ) ) + { + /* Empty */ + indent = 0; + } + else + { + indent = Get_Indent( line ); + break; + } + } + } + assert( indent >= 0 ); + return indent; +} + +/******/ + +/****f* Analyser/Analyse_Item_Format + * FUNCTION + * Try to determine the formatting of an item. + * An empty line generates a new paragraph + * Things that are indented more that the rest of the text + * are preformatted. + * Things that start with a '*' or '-' create list items + * unless they are indented more that the rest of the text. + * SYNPOPSIS + */ +static void Analyse_Item_Format( + struct RB_Item *arg_item ) +/* + * INPUTS + * * arg_item -- the item to be analysed. + * SOURCE + */ +{ + // If item is not empty + if ( arg_item->no_lines ) + { + // If it is a SOURCE item + if ( Works_Like_SourceItem( arg_item->type ) ) + { + // Preformat it like a SOURCE item + Preformat_All( arg_item, TRUE ); + } + // Check if we have to analyse this item + else if ( ( course_of_action.do_nopre + || Is_Format_Item( arg_item->type ) ) + && !Is_Preformatted_Item( arg_item->type ) ) + { + // analyse item + int indent = Analyse_Indentation( arg_item ); + + Analyse_List( arg_item, indent ); + Analyse_Preformatted( arg_item, indent ); + Analyse_Paragraphs( arg_item ); + } + // If none of above, preformat item + else + { + // Preformat it + Preformat_All( arg_item, FALSE ); + } + } + // Item is empty + else + { + // Do nothing + } +} + +/*****/ + + + +static int Trim_Empty_Item_Begin_Lines( + struct RB_header *arg_header, + struct RB_Item *arg_item, + int current_index ) +{ + + char *c; + + if ( Works_Like_SourceItem( arg_item->type ) ) + { + /* We skip the first line after the source item, if + * it an remark end marker -- such as '*)' + */ + c = arg_header->lines[current_index]; + if ( RB_Is_Remark_End_Marker( c ) ) + { + c = RB_Skip_Remark_End_Marker( c ); + c = RB_Skip_Whitespace( c ); + if ( *c != '\0' ) + { + c = arg_header->lines[current_index]; + RB_Warning( "text following a remark end marker:\n%s\n", c ); + } + ++current_index; + } + } + + if ( current_index > arg_item->end_index ) + { + /* item is empty */ + } + else + { + do + { + c = arg_header->lines[current_index]; + c = RB_Skip_Whitespace( c ); + if ( RB_Has_Remark_Marker( c ) ) + { + c = RB_Skip_Remark_Marker( c ); + } + c = RB_Skip_Whitespace( c ); + if ( *c == '\0' ) + { + ++current_index; + } + } + while ( ( *c == '\0' ) && ( current_index < arg_item->end_index ) ); + } + + return current_index; +} + + + +static int Trim_Empty_Item_End_Lines( + struct RB_header *arg_header, + struct RB_Item *arg_item, + int current_index ) +{ + char *c; + + if ( Works_Like_SourceItem( arg_item->type ) ) + { + c = arg_header->lines[current_index]; + if ( RB_Is_Remark_Begin_Marker( c ) ) + { + c = RB_Skip_Remark_Begin_Marker( c ); + c = RB_Skip_Whitespace( c ); + if ( *c != '\0' ) + { + c = arg_header->lines[current_index]; + RB_Warning( "text following a remark begin marker:\n%s\n", + c ); + } + --current_index; + } + } + + do + { + c = arg_header->lines[current_index]; + c = RB_Skip_Whitespace( c ); + if ( RB_Has_Remark_Marker( c ) ) + { + c = RB_Skip_Remark_Marker( c ); + } + c = RB_Skip_Whitespace( c ); + if ( *c == '\0' ) + { + --current_index; + } + } + while ( ( *c == '\0' ) && ( current_index > arg_item->begin_index ) ); + + return current_index; +} + + + +static void Trim_Empty_Item_Lines( + struct RB_header *arg_header, + struct RB_Item *arg_item ) +{ + arg_item->no_lines = arg_item->end_index - arg_item->begin_index + 1; + if ( arg_item->no_lines <= 1 ) + { + /* item is empty */ + arg_item->no_lines = 0; + } + else + { + int current_index; + + /* trim all empty lines at the begin of an item */ + + /* we skip the first line because that contains the item name. + */ + current_index = arg_item->begin_index + 1; + current_index = + Trim_Empty_Item_Begin_Lines( arg_header, arg_item, + current_index ); + + /* Is there anything left? */ + if ( current_index <= arg_item->end_index ) + { + arg_item->begin_index = current_index; + + /* trim all the empty lines at the end of an item */ + current_index = arg_item->end_index; + current_index = + Trim_Empty_Item_End_Lines( arg_header, arg_item, + current_index ); + if ( current_index >= arg_item->begin_index ) + { + arg_item->end_index = current_index; + arg_item->no_lines = + arg_item->end_index - arg_item->begin_index + 1; + } + else + { + /* item is empty */ + arg_item->no_lines = 0; + } + } + else + { + /* item is empty */ + arg_item->no_lines = 0; + } + } +} + + + + +/* TODO This routine is way too long */ + +static void Copy_Lines_To_Item( + struct RB_header *arg_header, + struct RB_Item *arg_item ) +{ +#if 0 + printf( "%d\n%d\n%s\n%s\n", + arg_item->begin_index, + arg_item->end_index, + arg_header->lines[arg_item->begin_index], + arg_header->lines[arg_item->end_index] ); +#endif + + Trim_Empty_Item_Lines( arg_header, arg_item ); + + if ( arg_item->no_lines > 0 ) + { + int i = 0; + int j = 0; + struct RB_Item_Line *itemline = NULL; + int tool_active = 0; // Shows wether we are inside a tool body + + /* Allocate enough memory for all the lines, plus one + * extra line + */ + ++arg_item->no_lines; + arg_item->lines = + calloc( arg_item->no_lines, sizeof( struct RB_Item_Line * ) ); + if ( !arg_item->lines ) + { + RB_Panic( "Out of memory! %s\n", "Copy_Lines_To_Item" ); + } + + /* And create an RB_Item_Line for each of them, and add + * those to the RB_Item + */ + for ( i = 0; i < arg_item->no_lines - 1; ++i ) + { + char *c = + arg_header->lines[arg_item->begin_index + i]; + /* TODO should be a Create_ItemLine() */ + itemline = malloc( sizeof( struct RB_Item_Line ) ); + if ( !itemline ) + { + RB_Panic( "Out of memory! %s (2)\n", "Copy_Lines_To_Item" ); + } + + c = ExpandTab( c ); + c = RB_Skip_Whitespace( c ); + // Lines with remark marker + if ( RB_Has_Remark_Marker( c ) + && !Works_Like_SourceItem( arg_item->type ) ) + { + char *c2, *c3; + int pipe_mode; + enum ItemLineKind item_kind; + + c = RB_Skip_Remark_Marker( c ); + c2 = RB_Skip_Whitespace( c ); + if ( *c2 ) + { + // Check wether a tool starts or ends + if ( ( c3 = Is_Tool( c2, &item_kind, &tool_active ) ) ) + { + itemline->kind = item_kind; + c = c3; + } + // If we have an active tool, copy the body lines + else if ( tool_active ) + { + itemline->kind = ITEM_LINE_TOOL_BODY; + c++; // Skip space after the remark marker + } + // Check for pipes + else if ( ( c3 = Is_Pipe_Marker( c2, &pipe_mode ) ) ) + { + itemline->kind = ITEM_LINE_PIPE; + itemline->pipe_mode = pipe_mode; + c = c3; + } + // Plain Items ... + else + { + itemline->kind = ITEM_LINE_PLAIN; + } + } + // Empty lines with remark markers and active tool + else if ( tool_active ) + { + itemline->kind = ITEM_LINE_TOOL_BODY; + } + // Plain empty lines with remark markers... + else + { + itemline->kind = ITEM_LINE_PLAIN; + } + } + else + { + itemline->kind = ITEM_LINE_RAW; + /* The is raw code, so we do not want to have the + * whitespace stripped of + */ + c = arg_header->lines[arg_item->begin_index + i]; + c = ExpandTab( c ); + } + + if ( ( !Works_Like_SourceItem( arg_item->type ) && + ( itemline->kind != ITEM_LINE_RAW ) ) || + Works_Like_SourceItem( arg_item->type ) ) + { + itemline->line = RB_StrDup( c ); + itemline->format = 0; + arg_item->lines[j] = itemline; + ++j; + } + else + { + /* We dump the RAW item lines if we are not in a + * source item. + */ + free( itemline ); + } + } + + if ( j > 0 ) + { + /* And one empty line to mark the end of an item and + * to be able to store some additional formatting actions + */ + itemline = malloc( sizeof( struct RB_Item_Line ) ); + if ( !itemline ) + { + RB_Panic( "Out of memory! %s (3)\n", "Copy_Lines_To_Item" ); + } + + itemline->kind = ITEM_LINE_END; + itemline->line = RB_StrDup( "" ); + itemline->format = 0; + arg_item->lines[j] = itemline; + + /* Store the real number of lines we copied */ + assert( arg_item->no_lines >= ( j + 1 ) ); + arg_item->no_lines = j + 1; + } + else + { + arg_item->no_lines = 0; + free( arg_item->lines ); + arg_item->lines = NULL; + } + } + else + { + arg_item->no_lines = 0; + arg_item->lines = NULL; + } +} + + +/****f* Analyser/RB_Analyse_Items + * FUNCTION + * Locate the items in the header and create RB_Item structures for + * them. + * SYNPOPSIS + */ +static int Analyse_Items( + struct RB_header *arg_header ) +/* + * SOURCE + */ +{ + int line_nr; + enum ItemType item_type = NO_ITEM; + struct RB_Item *new_item; + struct RB_Item *cur_item; + + RB_Item_Lock_Reset( ); + + /* find the first item */ + for ( line_nr = 0; line_nr < arg_header->no_lines; ++line_nr ) + { + item_type = RB_Is_ItemName( arg_header->lines[line_nr] ); + if ( item_type != NO_ITEM ) + { + break; + } + } + + /* and all the others */ + while ( ( item_type != NO_ITEM ) && ( line_nr < arg_header->no_lines ) ) + { + new_item = RB_Create_Item( item_type ); + new_item->begin_index = line_nr; + + /* Add the item to the end of the list of items. */ + if ( arg_header->items ) + { + for ( cur_item = arg_header->items; cur_item->next; + cur_item = cur_item->next ) + { + /* Empty */ + } + cur_item->next = new_item; + } + else + { + arg_header->items = new_item; + } + /* Find the next item */ + for ( ++line_nr; line_nr < arg_header->no_lines; ++line_nr ) + { + item_type = RB_Is_ItemName( arg_header->lines[line_nr] ); + if ( item_type != NO_ITEM ) + { + break; + } + } + + /* This points to the last line in the item */ + new_item->end_index = line_nr - 1; + + assert( new_item->end_index >= new_item->begin_index ); + + /* Now analyse and copy the lines */ + Copy_Lines_To_Item( arg_header, new_item ); + Analyse_Item_Format( new_item ); + /* Handy for debugging wiki formatting + * Dump_Item( new_item ); + */ + } + + return 0; +} + +/******/ + + + +/****f* Analyser/ToBeAdded + * FUNCTION + * Test whether or not a header needs to be added to the + * list of headers. This implements the options + * --internal + * and + * --internalonly + * SYNPOPSIS + */ +static int ToBeAdded( + struct RB_Document *document, + struct RB_header *header ) +/* + * INPUTS + * o document -- a document (to determine the options) + * o header -- a header + * RESULT + * TRUE -- Add header + * FALSE -- Don't add header + * SOURCE + */ +{ + int add = FALSE; + + if ( header->is_internal ) + { + if ( ( document->actions.do_include_internal ) || + ( document->actions.do_internal_only ) ) + { + add = TRUE; + } + else + { + add = FALSE; + } + } + else + { + if ( document->actions.do_internal_only ) + { + add = FALSE; + } + else + { + add = TRUE; + } + } + return add; +} + +/******/ + + + +/****f* Analyser/Grab_Header + * FUNCTION + * Grab a header from a source file, that is scan a source file + * until the start of a header is found. Then search for the end + * of a header and store all the lines in between. + * SYNPOPSIS + */ +static struct RB_header *Grab_Header( + FILE *sourcehandle, + struct RB_Document *arg_document ) +/* + * INPUTS + * o sourcehandle -- an opened source file. + * OUTPUT + * o sourcehandle -- will point to the line following the end marker. + * RESULT + * 0 if no header was found, or a pointer to a new header otherwise. + * SOURCE + */ +{ + struct RB_header *new_header = NULL; + int is_internal = 0; + struct RB_HeaderType *header_type = NULL; + int good_header = FALSE; + int reuse = FALSE; + + do + { + good_header = FALSE; + header_type = RB_Find_Marker( sourcehandle, &is_internal, reuse ); + reuse = FALSE; + if ( header_type ) + { + struct RB_header *duplicate_header = NULL; + long previous_line = 0; + + new_header = RB_Alloc_Header( ); + new_header->htype = header_type; + new_header->is_internal = is_internal; + + if ( Find_Header_Name( sourcehandle, new_header ) ) + { + new_header->line_number = line_number; + RB_Say( "found header [line %5d]: \"%s\"\n", SAY_DEBUG, + line_number, new_header->name ); + duplicate_header = + RB_Document_Check_For_Duplicate( arg_document, + new_header ); + if ( duplicate_header ) + { + /* Duplicate headers do not crash the program so + * we accept them. But we do warn the user. + */ + RB_Warning + ( "A header with the name \"%s\" already exists.\n See %s(%d)\n", + new_header->name, + Get_Fullname( duplicate_header->owner->filename ), + duplicate_header->line_number ); + } + + if ( ( new_header->function_name = + Function_Name( new_header->name ) ) == NULL ) + { + RB_Warning( "Can't determine the \"function\" name.\n" ); + RB_Free_Header( new_header ); + new_header = NULL; + } + else + { + if ( ( new_header->module_name = + Module_Name( new_header->name ) ) == NULL ) + { + RB_Warning + ( "Can't determine the \"module\" name.\n" ); + RB_Free_Header( new_header ); + new_header = NULL; + } + else + { + previous_line = line_number; + if ( Find_End_Marker( sourcehandle, new_header ) == + 0 ) + { + RB_Warning + ( "found header on line %d with name \"%s\"\n" + " but I can't find the end marker\n", + previous_line, new_header->name ); + /* Reuse the current line while finding the next + * Marking using RB_Find_Marker() + */ + reuse = TRUE; + RB_Free_Header( new_header ); + new_header = NULL; + } + else + { + RB_Say( "found end header [line %5d]:\n", + SAY_DEBUG, line_number ); + /* Good header found, we can stop */ + good_header = TRUE; + } + } + } + } + else + { + RB_Warning( "found header marker but no name\n" ); + RB_Free_Header( new_header ); + new_header = NULL; + } + } + else + { + /* end of the file */ + good_header = TRUE; + } + } + while ( !good_header ); + return new_header; +} + +/*******/ + + + +/****f* Analyser/Module_Name + * FUNCTION + * Get the module name from the header name. The header name will be + * something like + * + * module/functionname. + * + * SYNPOPSIS + */ +static char *Module_Name( + char *header_name ) +/* + * INPUTS + * o header_name -- a pointer to a nul terminated string. + * RESULT + * Pointer to the modulename. You're responsible for freeing it. + * SEE ALSO + * Function_Name() + * SOURCE + */ +{ + char *cur_char; + char c; + char *name = NULL; + + assert( header_name ); + + for ( cur_char = header_name; *cur_char && *cur_char != '/'; ++cur_char ); + if ( *cur_char ) + { + c = *cur_char; + *cur_char = '\0'; + name = RB_StrDup( header_name ); + *cur_char = c; + } + return name; +} + +/******/ + + + +/****f* Analyser/Function_Name + * FUNCTION + * A header name is consists of two parts. The module name and + * the function name. This returns a pointer to the function name. + * The name "function name" is a bit obsolete. It is really the name + * of any of objects that can be documented; classes, methods, + * variables, functions, projects, etc. + * SYNOPSIS + */ +static char *Function_Name( + char *header_name ) +/* + * SOURCE + */ +{ + char *cur_char; + char *name; + + name = NULL; + if ( ( cur_char = header_name ) != NULL ) + { + for ( ; *cur_char != '\0'; ++cur_char ) + { + if ( '/' == *cur_char ) + { + ++cur_char; + if ( *cur_char ) + { + name = cur_char; + break; + } + } + } + } + if ( name ) + { + return RB_StrDup( name ); + } + else + { + return ( name ); + } +} + +/*** Function_Name ***/ + + +/****f* Analyser/RB_Find_Marker + * NAME + * RB_Find_Marker -- Search for header marker in document. + * FUNCTION + * Read document file line by line, and search each line for + * any of the headers defined in the array header_markers (OR + * if using the -rh switch, robo_head) + * SYNOPSIS + */ +static struct RB_HeaderType *RB_Find_Marker( + FILE *document, + int *is_internal, + int reuse_previous_line ) +/* + * INPUTS + * document - pointer to the file to be searched. + * the gobal buffer line_buffer. + * OUTPUT + * o document will point to the line after the line with + * the header marker. + * o is_internal will be TRUE if the header is an internal + * header. + * RESULT + * o header type + * BUGS + * Bad use of feof(), fgets(). + * SEE ALSO + * Find_End_Marker + * SOURCE + */ +{ + int found; + char *cur_char; + struct RB_HeaderType *header_type = 0; + + cur_char = NULL; + found = FALSE; + while ( !feof( document ) && !found ) + { + if ( reuse_previous_line ) + { + /* reuse line in the line_buffer */ + reuse_previous_line = FALSE; + } + else + { + RB_FreeLineBuffer( ); + myLine = RB_ReadWholeLine( document, line_buffer, &readChars ); + } + if ( !feof( document ) ) + { + line_number++; + found = RB_Is_Begin_Marker( myLine, &cur_char ); + if ( found ) + { + header_type = AnalyseHeaderType( &cur_char, is_internal ); + RB_Say( "found header marker of type %s\n", SAY_DEBUG, + header_type->indexName ); + } + } + } + + return header_type; +} + +/******** END RB_Find_Marker ******/ + + +/****f* Analyser/AnalyseHeaderType + * FUNCTION + * Determine the type of the header. + * SYNOPSIS + */ +struct RB_HeaderType *AnalyseHeaderType( + char **cur_char, + int *is_internal ) +/* + * INPUTS + * o cur_char -- pointer to the header type character + * OUTPUT + * o is_internal -- indicates if it is an internal header or not.* + * o cur_char -- points to the header type character + * RESULT + * o pointer to a RB_HeaderType + * SOURCE + */ +{ + struct RB_HeaderType *headertype = 0; + + *is_internal = RB_IsInternalHeader( **cur_char ); + + if ( *is_internal ) + { + /* Skip the character */ + ++( *cur_char ); + } + headertype = RB_FindHeaderType( **cur_char ); + if ( !headertype ) + { + RB_Panic( "Undefined headertype (%c)\n", **cur_char ); + } + + return headertype; +} + +/*******/ + + + +/****f* Analyser/Find_End_Marker + * FUNCTION + * Scan and store all lines from a source file until + * an end marker is found. + * SYNOPSIS + */ +static int Find_End_Marker( + FILE *document, + struct RB_header *new_header ) +/* + * INPUTS + * o document -- a pointer to an opened source file. + * OUTPUT + * o new_header -- the lines of source code will be added + * here. + * RESULT + * o TRUE -- an end marker was found. + * o FALSE -- no end marker was found while scanning the + * source file. + * SOURCE + */ +{ + int found = FALSE; + unsigned int no_lines = 0; + unsigned int max_no_lines = 10; + char **lines = NULL; + char **new_lines = NULL; + char *dummy; + + lines = ( char ** ) calloc( max_no_lines, sizeof( char * ) ); + if ( !lines ) + { + RB_Panic( "Out of memory! %s()\n", "Find_End_Marker" ); + } + + while ( !feof( document ) ) + { + RB_FreeLineBuffer( ); + myLine = RB_ReadWholeLine( document, line_buffer, &readChars ); + ++line_number; /* global linecounter, koessi */ + if ( RB_Is_Begin_Marker( myLine, &dummy ) ) + { + /* Bad... found a begin marker but was expecting to + find an end marker. Panic... */ + found = FALSE; + return found; + } + else if ( RB_Is_End_Marker( myLine ) ) + { + RB_Say( "Found end marker \"%s\"", SAY_DEBUG, myLine ); + found = TRUE; + break; + } + else + { + unsigned int n; + char *line; + + line = RB_StrDup( myLine ); + n = strlen( line ); + assert( n > 0 ); + assert( line[n - 1] == '\n' ); + /* Strip CR */ + line[n - 1] = '\0'; + lines[no_lines] = line; + ++no_lines; + if ( no_lines == max_no_lines ) + { + max_no_lines *= 2; + new_lines = realloc( lines, max_no_lines * sizeof( char * ) ); + + if ( !new_lines ) + { + RB_Panic( "Out of memory! %s()\n", "Find_End_Marker" ); + } + + lines = new_lines; + } + } + } + + new_header->no_lines = no_lines; + new_header->lines = lines; + + return found; +} + + +/******/ + + +/* TODO Documentation */ +static void Remove_Trailing_Asterics( + char *line ) +{ + int i = strlen( line ) - 1; + + for ( ; ( i > 0 ) && utf8_isspace( line[i] ); i-- ) + { + /* Empty */ + } + for ( ; ( i > 0 ) && ( line[i] == '*' ); i-- ) + { + line[i] = ' '; + } +} + + +/****if* Utilities/RB_WordWithSpacesLen + * SYNOPSIS + */ +static int RB_WordWithSpacesLen( + char *str ) +/* + * FUNCTION + * get the amount of bytes until next separator character or ignore character + * or end of line + * INPUTS + * char *str -- the line + * RESULT + * int -- length of the next word or 0 + * SEE ALSO + * RB_Find_Header_Name() + * SOURCE + */ +{ + int len; + char c; + + for ( len = 0; ( ( c = *str ) != '\0' ) && ( c != '\n' ); ++str, ++len ) + { + // Look for header truncating characters + if ( Find_Parameter_Char( &( configuration.header_separate_chars ), + c ) != NULL + || + Find_Parameter_Char( &( configuration.header_ignore_chars ), + c ) != NULL ) + { + // and exit loop if any found + break; + } + } + /* Don't count any of the trailing spaces. */ + if ( len ) + { + --str; + for ( ; utf8_isspace( *str ); --len, --str ) + { + /* empty */ + } + } + return ( len ); +} + +/*** RB_WordWithSpacesLen ***/ + + +/* TODO Documentation */ +static int Find_Header_Name( + FILE *fh, + struct RB_header *hdr ) +{ + char *cur_char = myLine; + char **names = NULL; + int num = 0; + + Remove_Trailing_Asterics( cur_char ); + skip_while( *cur_char != '*' ); + skip_while( !utf8_isspace( *cur_char ) ); + skip_while( utf8_isspace( *cur_char ) ); + while ( *cur_char ) + { + int length = RB_WordWithSpacesLen( cur_char ); + + if ( length == 0 ) + break; + names = realloc( names, ( ++num ) * sizeof *names ); + + if ( !names ) + { + RB_Panic( "Out of memory! %s()\n", "Find_Header_Name" ); + } + + names[num - 1] = RB_StrDupLen( cur_char, length ); + /* printf("%c adding name = %s\n", num > 1 ? ' ' : '*', names[ num - 1 ] ); */ + cur_char += length; + if ( Find_Parameter_Char( &( configuration.header_separate_chars ), + *cur_char ) ) + { + for ( cur_char++; utf8_isspace( *cur_char ); cur_char++ ); + /* End of line reach, but comma encountered, more headernames follow on next line */ + if ( *cur_char == 0 ) + { + /* Skip comment */ + RB_FreeLineBuffer( ); + myLine = RB_ReadWholeLine( fh, line_buffer, &readChars ); + line_number++; + for ( cur_char = myLine; *cur_char && !utf8_isalpha( *cur_char ); + cur_char++ ); + } + } + } + hdr->names = names; + hdr->no_names = num; + hdr->name = num ? names[0] : NULL; + return num; +} + +/***** Find_Header_Name *****/ diff --git a/Source/analyser.h b/Source/analyser.h new file mode 100644 index 0000000..e28faf7 --- /dev/null +++ b/Source/analyser.h @@ -0,0 +1,32 @@ +#ifndef ROBODOC_ANALYSER_H +#define ROBODOC_ANALYSER_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "document.h" + +void RB_Analyse_Document( + struct RB_Document *arg_document ); + +#endif /* ROBODOC_ANALYSER_H */ diff --git a/Source/ascii_generator.c b/Source/ascii_generator.c new file mode 100644 index 0000000..0e35803 --- /dev/null +++ b/Source/ascii_generator.c @@ -0,0 +1,264 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/* vi: spell ff=unix + */ +/****h* ROBODoc/ASCII_Generator + * NAME + * ASCII_Generator -- Generator for ASCII output + * FUNCTION + * Plain ascii output, no formatting. + * MODIFICATION HISTORY + * 2003-06-17 Frans Slothouber V1.0 + ******* + * $Id: ascii_generator.c,v 1.21 2007/07/10 19:13:51 gumpu Exp $ + */ + +#include +#include + +#include "ascii_generator.h" +#include "util.h" +#include "robodoc.h" +#include "globals.h" +#include "items.h" +#include "headers.h" +#include "headertypes.h" +#include "generator.h" + +#ifdef DMALLOC +#include +#endif + +/*x**h* ROBODoc/ASCII_Generator + * FUNCTION + * Generator for plain ASCII output + ******* + */ + + +/*x**f* ASCII_Generator/RB_ASCII_Generate_Doc_Start + * NAME + * RB_ASCII_Generate_Doc_Start -- + ****** + */ + +void RB_ASCII_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char toc ) +{ + USE( src_name ); + USE( name ); + USE( toc ); + + if ( course_of_action.do_toc ) + { + fprintf( dest_doc, "TABLE OF CONTENTS\n" ); + /* TODO TOC */ +#if 0 + for ( cur_header = first_header, header_nr = 1; + cur_header; cur_header = cur_header->next_header, header_nr++ ) + { + if ( cur_header->name && cur_header->function_name ) + { + fprintf( dest_doc, "%4.4d %s\n", + header_nr, cur_header->name ); + } + } +#endif + fputc( '\f', dest_doc ); + } +} + +/*x**f* ASCII_Generator/RB_ASCII_Generate_Doc_End + * NAME + * RB_ASCII_Generate_Doc_End -- + ****** + */ + +void RB_ASCII_Generate_Doc_End( + FILE *dest_doc, + char *name ) +{ + USE( dest_doc ); + USE( name ); + /* Empty */ +} + +/*x**f* ASCII_Generator/RB_ASCII_Generate_Header_Start + * NAME + * RB_ASCII_Generate_Header_Start -- + ****** + */ + +void RB_ASCII_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + fprintf( dest_doc, "%s", cur_header->name ); + fprintf( dest_doc, "\n\n" ); +} + +void RB_ASCII_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + USE( cur_header ); + fprintf( dest_doc, + "\n---------------------------------------------------------------------------\n" ); + /* form-feeds are annoying fputc( '\f', dest_doc ); */ +} + +/*x**f* ASCII_Generator/RB_ASCII_Generate_Empty_Item + * NAME + * RB_ASCII_Generate_Empty_Item -- + ****** + */ + +void RB_ASCII_Generate_Empty_Item( + FILE *dest ) +{ + USE( dest ); + /* Empty */ +} + +/* TODO Documentation */ +void RB_ASCII_Generate_String( + FILE *dest, + char *string ) +{ + fprintf( dest, "%s", string ); +} + +/* TODO Documentation */ +void RB_ASCII_Generate_False_Link( + FILE *dest_doc, + char *name ) +{ + fprintf( dest_doc, "%s", name ); +} + +/* TODO Documentation */ +char *RB_ASCII_Get_Default_Extension( + void ) +{ + return ( ".txt" ); +} + +/* TODO Documentation */ +void RB_ASCII_Generate_Item_Name( + FILE *dest_doc, + char *name ) +{ + fprintf( dest_doc, "%s\n", name ); +} + + +/* TODO Documentation */ +void RB_ASCII_Generate_Item_Begin( + FILE *dest_doc ) +{ + USE( dest_doc ); + /* Empty */ +} + + +/* TODO Documentation */ +void RB_ASCII_Generate_Char( + FILE *dest_doc, + int c ) +{ + fputc( c, dest_doc ); +} + + +/* TODO Documentation */ +void RB_ASCII_Generate_Item_End( + FILE *dest_doc ) +{ + USE( dest_doc ); + /* Empty */ +} + + +static int section_counters[ASCII_MAX_SECTION_DEPTH]; +void RB_ASCII_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ) +{ + int i; + + ++section_counters[depth]; + for ( i = depth + 1; i < ASCII_MAX_SECTION_DEPTH; ++i ) + { + section_counters[i] = 0; + } + if ( depth < ASCII_MAX_SECTION_DEPTH ) + { + if ( !( course_of_action.do_sectionnameonly ) ) + { + for ( i = 1; i <= depth; ++i ) + { + fprintf( dest_doc, "%d.", section_counters[i] ); + } + fprintf( dest_doc, " " ); + } + + // Print Header "first" name + RB_ASCII_Generate_String( dest_doc, name ); + + // Print further names + for ( i = 1; i < header->no_names; i++ ) + { + fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",\n" ); + RB_ASCII_Generate_String( dest_doc, header->names[i] ); + } + + // Include module name if not sectionnameonly + if ( !( course_of_action.do_sectionnameonly ) ) + { + fprintf( dest_doc, " [ " ); + RB_ASCII_Generate_String( dest_doc, header->htype->indexName ); + fprintf( dest_doc, " ]" ); + } + } + else + { + /* too deep, don't do anything. */ + assert( 0 ); + } +} + +void RB_ASCII_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ) +{ + USE( dest_doc ); + USE( name ); + USE( depth ); + /* Empty */ +} diff --git a/Source/ascii_generator.h b/Source/ascii_generator.h new file mode 100644 index 0000000..56ecbf4 --- /dev/null +++ b/Source/ascii_generator.h @@ -0,0 +1,78 @@ +#ifndef ROBODOC_ASCII_GENERATOR_H +#define ROBODOC_ASCII_GENERATOR_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +#include "headers.h" + + +#define ASCII_MAX_SECTION_DEPTH 7 + +void RB_ASCII_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char toc ); +void RB_ASCII_Generate_Doc_End( + FILE *dest_doc, + char *name ); +void RB_ASCII_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_ASCII_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_ASCII_Generate_Index( + FILE *dest, + char *source ); +void RB_ASCII_Generate_Empty_Item( + FILE *dest ); +void RB_ASCII_Generate_False_Link( + FILE *dest_doc, + char *name ); +char *RB_ASCII_Get_Default_Extension( + void ); +void RB_ASCII_Generate_Item_Name( + FILE *dest_doc, + char *name ); +void RB_ASCII_Generate_Item_Begin( + FILE *dest_doc ); + +void RB_ASCII_Generate_Char( + FILE *dest_doc, + int c ); +void RB_ASCII_Generate_Item_End( + FILE *dest_doc ); + +void RB_ASCII_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ); + +void RB_ASCII_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ); + +#endif /* ROBODOC_ASCII_GENERATOR_H */ diff --git a/Source/config.h.in b/Source/config.h.in new file mode 100644 index 0000000..e4ab7d9 --- /dev/null +++ b/Source/config.h.in @@ -0,0 +1,94 @@ +/* Source/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strftime' function. */ +#undef HAVE_STRFTIME + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strstr' function. */ +#undef HAVE_STRSTR + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* default location for robodoc.rc */ +#undef ROBO_PREFIX + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if does not define. */ +#undef pid_t + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/Source/css_to_c.pl b/Source/css_to_c.pl new file mode 100644 index 0000000..250ae48 --- /dev/null +++ b/Source/css_to_c.pl @@ -0,0 +1,94 @@ +#!/usr/bin/perl -w +#****h* Module/css_to_c.pl +# USAGE: +# ./css_to_c.pl +# +# FUNCTION +# Turns a .css file into a piece of C code. +# +# AUTHOR +# Frans Slothouber (FSL), Gumpu Consulting +# CREATED: +# 6-7-2006 12:45:01 W. Europe Standard Time +# REVISION: --- +# +#****************************************************************************** +# $Id: css_to_c.pl,v 1.4 2006/07/27 19:12:18 gumpu Exp $ + +use strict; +use warnings; +use IO::File; + + +# First preprocess the CSS code. +my $robodoc_css_file_name = "robodoc_basic_style.css"; +my $robodoc_css_file = IO::File->new("<$robodoc_css_file_name") or die; +my @css = <$robodoc_css_file>; +$robodoc_css_file->close(); + +# Remove \n +# Replace all % by %% +# Replace all " by \" +# wrap inside a " .. \n" +@css = map { chomp($_); s/%/%%/g; s/"/\\"/g; "\"$_\\n\"\n" } @css; + +# Split the whole file into several parts each with +# it's own fprintf(). +# This to avoid compiler warning about string that +# are too long. +my @split_css_code = (); +my $l = 0; # Length of the string +push( @split_css_code, " fprintf( css_file,\n" ); +foreach my $line ( @css ) +{ + push( @split_css_code, $line ); + $l += length( $line ); + if ( $l > 2000 ) { + $l = 0; + push( @split_css_code, " );\n" ); + push( @split_css_code, " fprintf( css_file,\n" ); + } +} +push( @split_css_code, " );\n" ); + + +# Insert CSS code into html_generator.c + +# Read the original code. +my $html_generator_file = IO::File->new("; +$html_generator_file->close(); + +# Create a backup. +my $html_generator_file_bak = IO::File->new(">html_generator_bak.c") or die; +print $html_generator_file_bak @code; +$html_generator_file_bak->close(); + +# Merge the C code with the CSS code. +my @new_code = (); +my $skip = 0; +foreach my $line ( @code ) { + if ( $line =~ m/BEGIN\sBEGIN\s/ ) { + $skip = 1; + push( @new_code, $line ); + push( @new_code, @split_css_code ); + + } elsif ( $line =~ m/END\sEND\s/ ) { + push( @new_code, $line ); + $skip = 0; + } else { + if ( $skip ) { + #nothing + } else { + push( @new_code, $line ); + } + } +} + +# Write the result. +$html_generator_file = IO::File->new(">html_generator.c") or die; + +print $html_generator_file @new_code; + +$html_generator_file->close(); + diff --git a/Source/directory.c b/Source/directory.c new file mode 100644 index 0000000..000bbe5 --- /dev/null +++ b/Source/directory.c @@ -0,0 +1,1045 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* ROBODoc/Directory + * NAME + * This module contains function to scan a directory tree and to + * create a RB_Directory structure. Most of the OS dependend parts + * of ROBODoc can be found in this module.. + * + * This module currently works under: + * o Cygwin http://cygwin.com + * o Redhad 7.3 Linux + * o VC++ under Windows NT + * o MINGW http://www.mingw.org/ + * o OS/X + * + * AUTHOR + * Frans Slothouber + ***** + * $Id: directory.c,v 1.41 2007/07/10 19:13:51 gumpu Exp $ + */ + +#include +#include +#include "robodoc.h" +#include "directory.h" +#include "util.h" +#include "globals.h" +#include "roboconfig.h" + +#if defined (RB_MSVC) || defined(__MINGW32__) + +# include +# include + +#else + +# if defined _DIRENT_HAVE_D_TYPE + /* Empty */ +# else +# include +# endif + + /* no dirent in strict ansi !!! */ +# include + +#endif + +#include +#include + +#ifdef DMALLOC +# include +#endif + + +/****v* Directory/content_buffer + * FUNCTION + * Temporary buffer file file content and filenames. + * SOURCE + */ + +#define RB_CBUFFERSIZE 8191 +char content_buffer[RB_CBUFFERSIZE + 1]; + +/*****/ + + +/* Local functions */ +static int RB_Is_PathCharacter( + int c ); + + +#if defined (RB_MSVC) || defined(__MINGW32__) +/* empty */ +#else + +/****f* Directory/RB_FileType + * FUNCTION + * Determine the type of the file. This function is used for all + * compilers except VC++. + * + * If _DIRENT_HAVE_D_TYPE is defined we can find the filetype + * directly in the a_direntry. If not we have to stat the file to + * find out. + * SYNOPSIS + */ +T_RB_FileType RB_FileType( + char *arg_pathname, + struct dirent *a_direntry ) +/* + * INPUTS + * o arg_pathname -- the path leading up to this file + * o a_direntry -- a directory entry read by readdir() + * RESULT + * The type of the file. + ****** + */ +{ + T_RB_FileType file_type = RB_FT_UNKNOWN; + +#if defined _DIRENT_HAVE_D_TYPE + if ( a_direntry->d_type == DT_REG ) + { + file_type = RB_FT_FILE; + } + else if ( a_direntry->d_type == DT_DIR ) + { + file_type = RB_FT_DIRECTORY; + } + else + { + file_type = RB_FT_UNKNOWN; + } +#endif + if ( file_type == RB_FT_UNKNOWN ) + { + char *file_name = a_direntry->d_name; + struct stat filestat; + int result; + + /* Either we do not have d_type, or it gives + * no information, so we try it a different + * way. (BUG 715778) + */ + content_buffer[0] = '\0'; + strcat( content_buffer, arg_pathname ); + if ( content_buffer[strlen( content_buffer ) - 1] != '/' ) + { + strcat( content_buffer, "/" ); + } + strcat( content_buffer, file_name ); + result = stat( content_buffer, &filestat ); + if ( result == 0 ) + { + if ( S_ISREG( filestat.st_mode ) ) + { + file_type = RB_FT_FILE; + } + else if ( S_ISDIR( filestat.st_mode ) ) + { + file_type = RB_FT_DIRECTORY; + } + else + { + file_type = RB_FT_UNKNOWN; + } + } + else + { + /* Some error occurred while statting the file */ + } + } + return file_type; +} +#endif + +/****f* Directory/RB_Directory_Insert_RB_Path + * SYNOPSIS + */ + +void RB_Directory_Insert_RB_Path( + struct RB_Directory *arg_rb_directory, + struct RB_Path *arg_rb_path ) +/* + * FUNCTION + * Insert a RB_Path into a RB_Directory. + * The RB_Path is added at the beginning of the list. + * SOURCE + */ +{ + arg_rb_path->next = arg_rb_directory->first_path; + arg_rb_directory->first_path = arg_rb_path; +} + +/*****/ + +/****f* Directory/RB_Directory_Insert_RB_File + * SYNOPSIS + */ +void RB_Directory_Insert_RB_Filename( + struct RB_Directory *arg_rb_directory, + struct RB_Filename *arg_rb_filename ) +/* + * FUNCTION + * Insert an RB_File structure into a RB_Directory structure. + * The RB_File is added at the end of the list. + * SOURCE + */ +{ + if ( arg_rb_directory->last == 0 ) + { + arg_rb_directory->first = arg_rb_filename; + arg_rb_filename->next = 0; + arg_rb_directory->last = arg_rb_filename; + } + else + { + arg_rb_directory->last->next = arg_rb_filename; + arg_rb_filename->next = 0; + arg_rb_directory->last = arg_rb_filename; + } +} + +/******/ + +/****f* Directory/RB_Free_RB_Directory + * FUNCTION + * Free all the memory use by the RB_Directory structure. + * SYNOPSIS + */ +void RB_Free_RB_Directory( + struct RB_Directory *arg_directory ) +/* + * INPUTS + * o arg_directory -- the thing to be freed. + * SOURCE + */ +{ + struct RB_Filename *rb_filename; + struct RB_Filename *rb_filename2; + struct RB_Path *rb_path; + struct RB_Path *rb_path2; + + /* TODO Not complete... check for leaks. */ + rb_filename = arg_directory->first; + + while ( rb_filename ) + { + rb_filename2 = rb_filename; + rb_filename = rb_filename->next; + RB_Free_RB_Filename( rb_filename2 ); + } + + rb_path = arg_directory->first_path; + + while ( rb_path ) + { + rb_path2 = rb_path; + rb_path = rb_path->next; + RB_Free_RB_Path( rb_path2 ); + } + + free( arg_directory ); +} + +/******/ + + +/****f* Directory/RB_Get_RB_Directory + * NAME + * RB_Get_RB_Directory -- get a RB_Directory structure + * FUNCTION + * Returns a RB_Directory structure to the give directory, + * specified by the path. + * This structure can then be uses to walk through all the + * files in the directory and it's subdirectories. + * SYNOPSIS + */ +struct RB_Directory *RB_Get_RB_Directory( + char *arg_rootpath_name, + char *arg_docroot_name ) +/* + * INPUTS + * arg_rootpath -- the name a the directory to get, + * a nul terminated string. + * arg_docroot_name -- the name of the directory the documentation + * file are stored in. This directory is + * skipped while scanning for sourcefiles. + * It can be NULL. + * RESULT + * A freshly allocated RB_Directory filled with source files. + * SOURCE + */ +{ + struct RB_Directory *rb_directory; + struct RB_Path *doc_path = NULL; + + rb_directory = + ( struct RB_Directory * ) malloc( sizeof( struct RB_Directory ) ); + rb_directory->first = 0; + rb_directory->last = 0; + rb_directory->first_path = RB_Get_RB_Path( arg_rootpath_name ); + + if ( arg_docroot_name ) + { + doc_path = RB_Get_RB_Path( arg_docroot_name ); + } + + RB_Fill_Directory( rb_directory, rb_directory->first_path, doc_path ); + if ( ( RB_Number_Of_Filenames( rb_directory ) > 0 ) && + ( RB_Number_Of_Paths( rb_directory ) > 0 ) ) + { + RB_SortDirectory( rb_directory ); + } + else + { + + RB_Panic( "No files found! (Or all were filtered out)\n" ); + } + return rb_directory; +} + +/********/ + + + +/****f* Directory/RB_Get_RB_SingleFileDirectory + * NAME + * RB_Get_RB_SingleFileDirectory -- get a RB_Directory structure + * SYNOPSIS + */ +struct RB_Directory *RB_Get_RB_SingleFileDirectory( + char *arg_fullpath ) +/* + * FUNCTION + * Returns a RB_Directory structure to the give directory, + * specified by the path that contains only a single file. + * This is used for the --singlefile option. + * INPUT + * o filename -- a filename. This may include the path. + * RESULT + * a freshly allocated RB_Directory that contains only + * a single file. + * SOURCE + */ +{ + struct RB_Directory *rb_directory; + struct RB_Path *path; + char *pathname = NULL; + char *filename = NULL; + + assert( arg_fullpath ); + + pathname = RB_Get_PathName( arg_fullpath ); + filename = RB_Get_FileName( arg_fullpath ); + + if ( pathname ) + { + path = RB_Get_RB_Path( pathname ); + } + else + { + /* no directory was specified so we use + * the current directory + */ + path = RB_Get_RB_Path( "./" ); + } + + rb_directory = + ( struct RB_Directory * ) malloc( sizeof( struct RB_Directory ) ); + rb_directory->first = 0; + rb_directory->last = 0; + + rb_directory->first_path = path; + + RB_Directory_Insert_RB_Filename( rb_directory, + RB_Get_RB_Filename( filename, path ) ); + + return rb_directory; +} + +/*******/ + + +/****f* Directory/RB_Fill_Directory + * NAME + * RB_Fill_Directory -- fill a RB_Directory structure + * SYNOPSIS + */ +void RB_Fill_Directory( + struct RB_Directory *arg_rb_directory, + struct RB_Path *arg_path, + struct RB_Path *arg_doc_path ) +/* + * FUNCTION + * Walks through all the files in the directory pointed to + * by arg_path and adds all the files to arg_rb_directory. + * This is a recursive function. + * INPUTS + * o arg_rb_directory -- the result. + * o arg_path -- the current path that is scanned. + * o arg_doc_path -- the path to the documentation files. + * RESULT + * a RB_Directory structure filled with all sourcefiles and + * subdirectories in arg_path. + * NOTE + * This a is a recursive function. + * SOURCE + */ +{ + +#if defined (RB_MSVC) || defined(__MINGW32__) + struct _finddata_t c_file; + long hFile; + char *wildcard = NULL; + int len; + + RB_Say( "Scanning %s\n", SAY_INFO, arg_path->name ); + len = strlen( arg_path->name ) + strlen( "*.*" ) + 1; + wildcard = ( char * ) malloc( len ); + assert( wildcard ); + wildcard[0] = '\0'; + strcat( wildcard, arg_path->name ); + strcat( wildcard, "*.*" ); + if ( ( hFile = _findfirst( wildcard, &c_file ) ) == -1L ) + { + RB_Panic( "No files found!\n" ); + } + else + { + int found = TRUE; + + while ( found ) + { + if ( ( c_file.attrib & _A_SUBDIR ) ) + { + /* It's a directory */ + if ( ( strcmp( ".", c_file.name ) == 0 ) + || ( strcmp( "..", c_file.name ) == 0 ) ) + { + /* Don't recurse into . or .. + because that will result in an infinite + loop. */ + } + else + { + if ( RB_To_Be_Skipped( c_file.name ) ) + { + /* User asked this directory to be skipped */ + } + else + { + if ( course_of_action.do_nodesc ) + { + /* Don't descent into the subdirectories */ + } + else + { + struct RB_Path *rb_path = + RB_Get_RB_Path2( arg_path->name, + c_file.name ); + + if ( ( arg_doc_path + && strcmp( rb_path->name, + arg_doc_path->name ) ) + || !arg_doc_path ) + { + rb_path->parent = arg_path; + RB_Directory_Insert_RB_Path( arg_rb_directory, + rb_path ); + RB_Fill_Directory( arg_rb_directory, rb_path, + arg_doc_path ); + } + else + { + RB_Say( "skipping %s\n", SAY_INFO, + rb_path->name ); + } + } + } + } + } + else + { + if ( RB_Is_Source_File( arg_path, c_file.name ) ) + { + RB_Directory_Insert_RB_Filename( arg_rb_directory, + RB_Get_RB_Filename + ( c_file.name, + arg_path ) ); + } + else + { + /* It's not a sourcefile so we skip it. */ + } + } + /* Find the rest of the *.* files */ + found = ( _findnext( hFile, &c_file ) == 0 ); + } + _findclose( hFile ); + } + free( wildcard ); +#else + struct dirent *a_direntry; + DIR *a_dirstream; + + RB_Say( "Scanning %s\n", SAY_INFO, arg_path->name ); + a_dirstream = opendir( arg_path->name ); + + if ( a_dirstream ) + { + T_RB_FileType file_type; + + for ( a_direntry = readdir( a_dirstream ); + a_direntry; a_direntry = readdir( a_dirstream ) ) + { + file_type = RB_FileType( arg_path->name, a_direntry ); + if ( file_type == RB_FT_FILE ) + { + /* It is a regular file. See if it is a sourcefile. */ + if ( RB_Is_Source_File( arg_path, a_direntry->d_name ) ) + { + /* It is, so we add it to the directory tree */ + RB_Directory_Insert_RB_Filename( arg_rb_directory, + RB_Get_RB_Filename + ( a_direntry->d_name, + arg_path ) ); + } + else + { + /* It's not a sourcefile so we skip it. */ + } + } + else if ( file_type == RB_FT_DIRECTORY ) + { + if ( ( strcmp( ".", a_direntry->d_name ) == 0 ) || + ( strcmp( "..", a_direntry->d_name ) == 0 ) ) + { + /* Don't recurse into . or .. + because that will result in an infinite */ + } + else + { + if ( RB_To_Be_Skipped( a_direntry->d_name ) ) + { + /* User asked this directory to be skipped */ + } + else + { + if ( course_of_action.do_nodesc ) + { + /* Don't descent into the subdirectories */ + } + else + { + struct RB_Path *rb_path = + RB_Get_RB_Path2( arg_path->name, + a_direntry->d_name ); + + rb_path->parent = arg_path; + if ( ( arg_doc_path + && strcmp( rb_path->name, + arg_doc_path->name ) ) + || !arg_doc_path ) + { + RB_Directory_Insert_RB_Path( arg_rb_directory, + rb_path ); + RB_Fill_Directory( arg_rb_directory, rb_path, + arg_doc_path ); + } + else + { + RB_Say( "skipping %s\n", SAY_INFO, + rb_path->name ); + } + } + } + } + } + else + { + /* Not a file and also not a directory */ + } + } + } + closedir( a_dirstream ); +#endif +} + +/*****/ + +/****f* Directory/RB_Is_Source_File + * NAME + * RB_Is_Source_File -- Is a file a sourcefile? + * SYNOPSIS + */ +int RB_Is_Source_File( + struct RB_Path *path, + char *filename ) +/* + * FUNCTION + * This functions examines the content of a file to + * see whether or not it is a sourcefile. + * + * Currently it checks if there are no nul characters + * in the first 8191 characters of the file. + * SOURCE + */ +{ + int is_source = 1; + + if ( RB_Not_Accepted( filename ) ) + { + /* File needs to be skipped based on it's name */ + is_source = 0; + } + else + { + unsigned int size = 0; + + /* Compute the length of the filename including + the path. */ + size += strlen( path->name ); + size += 1; + size += strlen( filename ); + if ( size < RB_CBUFFERSIZE ) + { + FILE *file; + + /* We use the content_buffer buffer temporarily to + store the filename. */ + content_buffer[0] = '\0'; + strcat( content_buffer, path->name ); + strcat( content_buffer, filename ); + if ( ( file = fopen( content_buffer, "rb" ) ) ) + { + int no_read; + no_read = + fread( content_buffer, sizeof( char ), RB_CBUFFERSIZE, + file ); + if ( no_read > 10 ) + { + char *c; + + for ( c = content_buffer; no_read; --no_read, c++ ) + { + if ( *c == 0 ) + { + is_source = 0; + break; + } + } + } + else + { + /* A file with only 9 characters can not + contain any source plus documentation. */ + is_source = 0; + } + fclose( file ); + } + else + { + /* The file could not be opened. */ + is_source = 0; + } + } + else + { + /* The filename is longer than 8191 characters, + that's way too long... so we skip it. */ + is_source = 0; + } + } + return is_source; +} + +/*****/ + + +/****f* Directory/RB_To_Be_Skipped + * FUNCTION + * Test if a file should not be included in the list of source files + * that are scanned for documentation. + * + * This test is done based on the wildcard expressions specified + * in configuration.ignore_files. + * SYNOPSIS + */ +int RB_To_Be_Skipped( + char *filename ) +/* + * INPUTS + * o filename -- the name of the file + * SOURCE + */ +{ + unsigned int i; + int skip = FALSE; + + for ( i = 0; i < configuration.ignore_files.number; ++i ) + { + if ( RB_Match( filename, configuration.ignore_files.names[i] ) ) + { + skip = TRUE; + break; + } + } + return skip; +} + +/******/ + + +/****f* Directory/RB_Not_Accepted + * FUNCTION + * Test if a file should be skipped, + * because it does not match a pattern in "accept files:" + * + * This test is done based on the wildcard expressions specified + * in configuration.accept_files. + * SYNOPSIS + */ +int RB_Not_Accepted( + char *filename ) +/* + * INPUTS + * o filename -- the name of the file + * SOURCE + */ +{ + unsigned int i; + int skip = FALSE; + + skip = RB_To_Be_Skipped( filename ); + + if ( !skip && configuration.accept_files.number > 0 ) + { + skip = TRUE; + for ( i = 0; i < configuration.accept_files.number; ++i ) + { + if ( RB_Match( filename, configuration.accept_files.names[i] ) ) + { + RB_Say( "accept >%s< with >%s<\n", SAY_INFO, filename, + configuration.accept_files.names[i] ); + skip = FALSE; + break; + } + } + } + return skip; +} + +/******/ + + +/****f* Directory/RB_Get_FileName + * NAME + * RB_Get_PathName -- extract the file name + * SYNOPSIS + */ +char *RB_Get_FileName( + char *arg_fullpath ) +/* + * FUNCTION + * Given a full path to a file, that is a filename, or a filename + * prefixed with a pathname, return the filename. + * So + * "./filename" returns "filename" + * "/home/et/filename" returns "filename" + * "filename" return "filename" + * INPUTS + * arg_fullpath -- a full path to a file, with or without a path. + * + * RESULT + * 0 -- The full path did not contain a filename + * pointer to the filename -- otherwise. + * NOTES + * You are responsible for deallocating it. + * SOURCE + */ +{ + int n; + int i; + int found; + char *result = 0; + + assert( arg_fullpath ); + + n = strlen( arg_fullpath ); + + /* Try and find a path character ( ':' or '/' ) */ + for ( found = FALSE, i = 0; i < n; ++i ) + { + if ( RB_Is_PathCharacter( arg_fullpath[i] ) ) + { + found = TRUE; + break; + } + } + + if ( !found ) + { + /* The full path does not contain a pathname, + * so we can return the arg_fullpath as + * the filename. + */ + result = RB_StrDup( arg_fullpath ); + } + else + { + /* The full path does contain a pathname, + * strip this and return the remainder + */ + + for ( i = n - 1; i > 0; --i ) + { + if ( RB_Is_PathCharacter( arg_fullpath[i] ) ) + { + assert( i < ( n - 1 ) ); + result = RB_StrDup( &( arg_fullpath[i + 1] ) ); + break; + } + } + } + + return result; +} + +/********/ + + + +/****f* Directory/RB_Get_PathName + * NAME + * RB_Get_PathName -- extract the path name + * SYNOPSIS + */ +char *RB_Get_PathName( + char *arg_fullpath ) +/* + * FUNCTION + * Given a full path to a file, that is a filename, or a filename + * prefixed with a pathname, return the pathname. + * So + * "./filename" returns "./" + * "/home/et/filename" returns "/home/et/" + * "filename" return "" + * INPUTS + * arg_fullpath -- a full path to a file, with or without a path. + * + * RESULT + * 0 -- The full path did not contain a path + * pointer to the pathname -- otherwise. + * NOTES + * You are responsible for deallocating it. + * SOURCE + */ +{ + int n; + int i; + int found; + char *result = 0; + + assert( arg_fullpath ); + + n = strlen( arg_fullpath ); + + /* Try and find a path character ( ':' or '/' ) */ + for ( found = FALSE, i = 0; i < n; ++i ) + { + if ( RB_Is_PathCharacter( arg_fullpath[i] ) ) + { + found = TRUE; + break; + } + } + + if ( found ) + { + /* Copy the whole file name and then + replace the character after the + first path character found + counting from the back with a '\0' + */ + result = RB_StrDup( arg_fullpath ); + + for ( i = n - 1; i > 0; --i ) + { + if ( RB_Is_PathCharacter( result[i] ) ) + { + assert( i < ( n - 1 ) ); + result[i + 1] = '\0'; + break; + } + } + } + + return result; +} + +/*******/ + + +/****f* Directory/RB_Is_PathCharacter + * FUNCTION + * Test if a character is part of the group of + * characters that you would normally find in + * a path. + * SYNOPSIS + */ +static int RB_Is_PathCharacter( + int c ) +/* + * INPUTS + * c -- the character to be tested. + * RESULT + * TRUE -- it is a path character. + * FALSE -- it is not. + * SOURCE + */ +{ + return ( ( c == ':' ) || ( c == '/' ) ); +} + +/******/ + + +/* Sort the files and paths */ + +/* TODO FS Document */ +unsigned int RB_Number_Of_Filenames( + struct RB_Directory *arg_rb_directory ) +{ + unsigned int number_of_filenames = 0; + struct RB_Filename *rb_filename = NULL; + + for ( rb_filename = arg_rb_directory->first; + rb_filename; + ++number_of_filenames, rb_filename = rb_filename->next ) + { + /* Empty */ + } + return number_of_filenames; +} + + +/* TODO FS Document */ +unsigned int RB_Number_Of_Paths( + struct RB_Directory *arg_rb_directory ) +{ + unsigned int number_of_paths = 0; + struct RB_Path *rb_path = NULL; + + for ( rb_path = arg_rb_directory->first_path; + rb_path; ++number_of_paths, rb_path = rb_path->next ) + { + /* Empty */ + } + return number_of_paths; +} + +/* TODO FS Document */ +int RB_Path_Compare( + void *p1, + void *p2 ) +{ + struct RB_Path *path_1 = p1; + struct RB_Path *path_2 = p2; + + return RB_Str_Case_Cmp( path_1->name, path_2->name ); +} + +/* TODO FS Document */ +int RB_Filename_Compare( + void *p1, + void *p2 ) +{ + struct RB_Filename *filename_1 = p1; + struct RB_Filename *filename_2 = p2; + + return RB_Str_Case_Cmp( filename_1->name, filename_2->name ); +} + + +/* TODO FS Document */ +void RB_SortDirectory( + struct RB_Directory *arg_rb_directory ) +{ + unsigned int number_of_filenames = + RB_Number_Of_Filenames( arg_rb_directory ); + unsigned int number_of_paths = + RB_Number_Of_Paths( arg_rb_directory ); + unsigned int i; + struct RB_Path *rb_path = NULL; + struct RB_Filename *rb_filename = NULL; + struct RB_Path **paths = NULL; + struct RB_Filename **filenames = NULL; + + assert( number_of_filenames > 0 ); + assert( number_of_paths > 0 ); + paths = calloc( number_of_paths, sizeof( struct RB_Path * ) ); + filenames = calloc( number_of_filenames, sizeof( struct RB_Filename * ) ); + + + RB_Say( "Sorting Directory\n", SAY_INFO ); + for ( i = 0, rb_path = arg_rb_directory->first_path; + rb_path; rb_path = rb_path->next ) + { + assert( i < number_of_paths ); + paths[i] = rb_path; + ++i; + } + + for ( i = 0, rb_filename = arg_rb_directory->first; + rb_filename; rb_filename = rb_filename->next ) + { + assert( i < number_of_filenames ); + filenames[i] = rb_filename; + ++i; + } + + RB_QuickSort( ( void ** ) paths, 0, number_of_paths - 1, + RB_Path_Compare ); + RB_QuickSort( ( void ** ) filenames, 0, number_of_filenames - 1, + RB_Filename_Compare ); + + for ( i = 0; i < number_of_paths - 1; ++i ) + { + paths[i]->next = paths[i + 1]; + } + paths[number_of_paths - 1]->next = NULL; + arg_rb_directory->first_path = paths[0]; + + for ( i = 0; i < number_of_filenames - 1; ++i ) + { + filenames[i]->next = filenames[i + 1]; + } + filenames[number_of_filenames - 1]->next = NULL; + arg_rb_directory->first = filenames[0]; + arg_rb_directory->last = filenames[number_of_filenames - 1]; + + free( paths ); + free( filenames ); +} diff --git a/Source/directory.h b/Source/directory.h new file mode 100644 index 0000000..275c8c1 --- /dev/null +++ b/Source/directory.h @@ -0,0 +1,135 @@ +#ifndef ROBODOC_DIRECTORY_H +#define ROBODOC_DIRECTORY_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "file.h" + +/****s* Directory/RB_Directory + * NAME + * RB_Directory -- the directory tree with the source files. + * FUNCTION + * Stores information about files in a directory tree. + * The whole structure consist of two linked lists. One for + * directory paths, and one for filenames. + * EXAMPLE + * The following show an example structure. + * RB_Directory RB_Path + * +-------+ +------+ +-------+ +-----------+ + * | +-->| . |--->| ./sub |-->| ./sub/sub | + * | | +------+ +-------+ +-----------+ + * | | ^ ^ ^ + * | | | | | + * | | |-----------+ +------+ +------+ + * | | | | | | + * | | | | | | + * | | +------+ +------+ +------+ +-------+ + * | +-->| a.c |--->| b.c |-->| sa.c |-->| ssb.c | + * +-------+ +------+ +------+ +------+ +-------+ + * RB_Filename + * + * ATTRIBUTES + * * first -- first RB_Filename in the list of files + * * current -- the last file that was returned in + * RB_Get_Next_Filename. + * * last -- the last RB_Filename in the list of files + * used for the insert operation + * * first_path -- first RB_Path in the list of paths. + * SOURCE + */ + +struct RB_Directory +{ + struct RB_Filename *first; /* TODO should be called files */ + struct RB_Filename *last; + struct RB_Path *first_path; /* TODO should be called paths */ +}; + +/******/ + + +/****t* Directory/T_RB_FileType + * FUNCTION + * Constants for the two different filetypes that + * ROBODoc recognizes. + * SOURCE + */ + +typedef enum +{ + RB_FT_DIRECTORY = 1, + RB_FT_FILE = 2, + RB_FT_UNKNOWN = 3 +} T_RB_FileType; + +/******/ + + +struct RB_Directory *RB_Get_RB_Directory( + char *arg_rootpath, + char *arg_docroot_name ); +struct RB_Directory *RB_Get_RB_SingleFileDirectory( + char *arg_fullpath ); +void RB_Dump_RB_Directory( + struct RB_Directory *arg_rb_directory ); +void RB_Free_RB_Directory( + struct RB_Directory *arg_directory ); +void RB_Directory_Insert_RB_Path( + struct RB_Directory *arg_rb_directory, + struct RB_Path *arg_rb_path ); +void RB_Directory_Insert_RB_Filename( + struct RB_Directory *arg_rb_directory, + struct RB_Filename *arg_rb_filename ); + +void RB_Fill_Directory( + struct RB_Directory *arg_rb_directory, + struct RB_Path *arg_path, + struct RB_Path *arg_doc_path ); +int RB_Is_Source_File( + struct RB_Path *path, + char *filename ); +int RB_To_Be_Skipped( + char *filename ); +int RB_Not_Accepted( + char *filename ); + + +char *RB_Get_FileName( + char *arg_fullpath ); +char *RB_Get_PathName( + char *arg_fullpath ); +void RB_SortDirectory( + struct RB_Directory *arg_rb_directory ); + +int RB_Path_Compare( + void *p1, + void *p2 ); +int RB_Filename_Compare( + void *p1, + void *p2 ); +unsigned int RB_Number_Of_Filenames( + struct RB_Directory *arg_rb_directory ); +unsigned int RB_Number_Of_Paths( + struct RB_Directory *arg_rb_directory ); + +#endif /* ROBODOC_DIRECTORY_H */ diff --git a/Source/document.c b/Source/document.c new file mode 100644 index 0000000..c1fe4b4 --- /dev/null +++ b/Source/document.c @@ -0,0 +1,825 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* ROBODoc/Document + * FUNCTION + * This module contains functions to manipulate the central data + * structure (RB_Document) that contains information about the + * source files, and documentation files, and headers. + * + * The name is a bit confusing because it sort of implies that + * it contains the documentation extracted from the sourcefiles. + * + * For each run a RB_Document structure is created, it is filled + * by the analyser and directory module and then used by the + * generator module to create the documentation. + * MODIFICATION HISTORY + * * ????-??-?? Frans Slothouber V1.0 + * * 2003-02-03 Frans Slothouber Refactoring + * * 2003-10-30 David White Removed unistd.h for Borland + ******* + */ + +#include +#include +#include + +#include +#include +#if defined (RB_BCC) || defined( RB_MSVC ) +#else +#include /* Not used for Borland */ +#endif + +#include "robodoc.h" +#include "document.h" +#include "part.h" +#include "path.h" +#include "directory.h" +#include "headers.h" +#include "links.h" +#include "util.h" +#include +#include "generator.h" +#include "file.h" +#include "globals.h" + + +#ifdef DMALLOC +#include +#endif + + +/****f* Document/RB_Document_Add_Part + * FUNCTION + * Add a new part to the document. + * SYNOPSIS + */ +void RB_Document_Add_Part( + struct RB_Document *document, + struct RB_Part *part ) +/* + * INPUTS + * o document -- the document the part is to be added to. + * o part -- the part to be added + * SOURCE + */ +{ + part->next = document->parts; + document->parts = part; +} + +/*****/ + + +/* TODO Documentation */ +void RB_Free_RB_Document_Parts( + struct RB_Document *document ) +{ + if ( document->parts ) + { + struct RB_Part *a_part = NULL; + struct RB_Part *a_part2 = NULL; + + for ( a_part = document->parts; a_part; a_part = a_part2 ) + { + a_part2 = a_part->next; + RB_Free_RB_Part( a_part ); + } + } + document->parts = NULL; +} + + +/* TODO Documentation */ +void RB_Free_RB_Document( + struct RB_Document *document ) +{ + RB_Free_RB_Document_Parts( document ); + if ( document->headers ) + { + unsigned long i; + + for ( i = 0; i < document->no_headers; ++i ) + { + RB_Free_Header( document->headers[i] ); + + } + free( document->headers ); + } + free( document ); +} + +/****f* Document/RB_Document_Create_Parts + * FUNCTION + * Create all the parts of a document based on the sourcefiles in + * the source tree. This creates a new RB_Part for each file in + * the source tree. + * INPUTS + * o document -- the document for which the parts are generated. + * SOURCE + */ + +void RB_Document_Create_Parts( + struct RB_Document *document ) +{ + struct RB_Filename *i_file = NULL; + + assert( document ); + assert( document->srctree ); + + for ( i_file = document->srctree->first; i_file; i_file = i_file->next ) + { + struct RB_Part *rbpart; + + rbpart = RB_Get_RB_Part( ); + RB_Part_Add_Source( rbpart, i_file ); + RB_Document_Add_Part( document, rbpart ); + } +} + +/*******/ + + +/****f* Document/RB_Fill_Header_Filename + * FUNCTION + * Fill the file_name attribute of all headers based either on the + * part or the singledoc name. The file_name tells in which file + * the documentation for the header is to be stored. + * SYNOPSIS + */ +void RB_Fill_Header_Filename( + struct RB_Document *document ) +/* + * SOURCE + */ +{ + struct RB_Part *i_part; + + RB_Say( "Computing file_name attribute for all headers.\n", SAY_DEBUG ); + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + + for ( i_header = i_part->headers; + i_header; i_header = i_header->next ) + { + if ( document->actions.do_singledoc ) + { + i_header->file_name = document->singledoc_name; + } + else if ( document->actions.do_multidoc ) + { + i_header->file_name = RB_Get_FullDocname( i_part->filename ); + } + else if ( document->actions.do_singlefile ) + { + i_header->file_name = document->singledoc_name; + } + else + { + assert( 0 ); + } + } + } +} + +/******/ + + +/****f* Document/RB_Document_Determine_DocFilePaths + * FUNCTION + * Determine the path of each of the documentation files based on + * the path of the source file and the documentation root path and + * the source root path. + * SYNOPSIS + */ +void RB_Document_Determine_DocFilePaths( + struct RB_Document *document ) +/* + * EXAMPLE + * srcpath = ./test/mysrc/sub1/sub2 + * srcroot = ./test/mysrc/ + * docroot = ./test/mydoc/ + * ==> + * docpath = ./test/mydoc/sub1/sub2 + * SOURCE + */ +{ + struct RB_Path *path; + int docroot_length; + int srcroot_length; + int length; + + assert( document->srctree ); + assert( document->srcroot ); + assert( document->docroot ); + + docroot_length = strlen( document->docroot->name ); + srcroot_length = strlen( document->srcroot->name ); + + for ( path = document->srctree->first_path; path; path = path->next ) + { + char *name; + char *new_name; + char *tail; + + name = path->name; + length = strlen( name ); + assert( length >= srcroot_length ); + tail = name + srcroot_length; + new_name = calloc( docroot_length + + ( length - srcroot_length ) + 1, sizeof( char ) ); + assert( new_name ); + strcat( new_name, document->docroot->name ); + if ( document->actions.do_no_subdirectories ) + { + /* No subdirectory */ + } + else + { + strcat( new_name, tail ); + } + path->docname = new_name; + } +} + +/******/ + + +/****f* Document/RB_Document_Create_DocFilePaths + * FUNCTION + * This function creates the whole document directory + * tree. It tests if the directories exist and if they + * do not the directory is created. + * SYNOPSIS + */ +void RB_Document_Create_DocFilePaths( + struct RB_Document *document ) +/* + * INPUTS + * o document -- the document for which the tree is created. + * SOURCE + */ +{ + struct RB_Path *path; + + for ( path = document->srctree->first_path; path; path = path->next ) + { + char *pathname = NULL; + char *c2 = NULL; + + RB_Say( "Trying to create directory %s\n", SAY_INFO, path->docname ); + /* Don't want to modify the docname in the path + structure. So we make a copy that we later + destroy. */ + + pathname = RB_StrDup( path->docname ); + for ( c2 = pathname + 1; /* We skip the leading '/' */ + *c2; ++c2 ) + { + if ( *c2 == '/' ) + { + struct stat dirstat; + + *c2 = '\0'; /* Replace the '/' with a '\0'. */ + /* We now have one of the paths leading up to the + total path. Test if it exists. */ + if ( stat( pathname, &dirstat ) == 0 ) + { + /* Path exists. */ + } + else if ( ( strlen( pathname ) == 2 ) && + ( utf8_isalpha( pathname[0] ) ) && + ( pathname[1] == ':' ) ) + { + /* Is is a drive indicator, ( A: B: C: etc ) + * stat fails on this, but we should not + * create either, so we do nothing. + */ + } + else + { + int result; + +#if defined(__MINGW32__) || defined( RB_MSVC ) + result = mkdir( pathname ); +#else + result = mkdir( pathname, 0770 ); +#endif + if ( result == 0 ) + { + /* Path was created. */ + } + else + { + perror( NULL ); + RB_Panic( "Can't create directory %s\n", pathname ); + } + } + /* Put the '/' back in it's place. */ + *c2 = '/'; + } + } + free( pathname ); + } +} + +/*******/ + + +/* TODO Documentation */ + +/*x**f* + * FUNCTION + * Compare two header types for sorting. + * RESULT + * -1 h1 < h2 + * 0 h1 == h2 + * 1 h1 > h2 + * SOURCE + */ + +int RB_CompareHeaders( + void *h1, + void *h2 ) +{ + struct RB_header *header_1 = h1; + struct RB_header *header_2 = h2; + + // Check for priorities + if ( header_1->htype->priority > header_2->htype->priority ) + { + // Header 1 has higher priority + return -1; + } + else if ( header_1->htype->priority < header_2->htype->priority ) + { + // Header 2 has higher priority + return 1; + } + else + { + // Priorities are equal + // Check if we sort on full name or just the function name + if ( course_of_action.do_sectionnameonly ) + { + // Do not include parent name in sorting if they are not displayed + return RB_Str_Case_Cmp( header_1->function_name, + header_2->function_name ); + } + else + { + // Sort on full name ( module/function ) + return RB_Str_Case_Cmp( header_1->name, header_2->name ); + } + } +} + +/*****/ + +/* TODO Documentation */ +void RB_Document_Sort_Headers( + struct RB_Document *document ) +{ + struct RB_Part *i_part; + unsigned long part_count = 0; + + RB_Say( "Sorting headers per part (file)\n", SAY_INFO ); + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + + /* Count the number of headers */ + for ( part_count = 0, i_header = i_part->headers; + i_header; i_header = i_header->next ) + { + part_count++; + } + + if ( part_count ) + { + /* Sort them */ + struct RB_header **temp_headers = + calloc( part_count, sizeof( struct RB_header * ) ); + unsigned int i = 0; + + i_header = i_part->headers; + for ( i = 0; i < part_count; ++i ) + { + assert( i_header ); + temp_headers[i] = i_header; + i_header = i_header->next; + } + RB_QuickSort( ( void ** ) temp_headers, 0, part_count - 1, + RB_CompareHeaders ); + i_part->headers = temp_headers[0]; + i_part->headers->next = NULL; + i_header = temp_headers[0]; + for ( i = 1; i < part_count; ++i ) + { + assert( i_header ); + i_header->next = temp_headers[i]; + i_header = i_header->next; + } + temp_headers[part_count - 1]->next = NULL; + free( temp_headers ); + } + } + RB_Say( "Sorting all headers\n", SAY_INFO ); + RB_QuickSort( ( void ** ) document->headers, 0, document->no_headers - 1, + RB_CompareHeaders ); +} + + +/****f* Document/RB_Document_Collect_Headers + * FUNCTION + * Create a table of pointers to all headers. This is done to + * have easy access to all heades without having to scan all + * RB_Parts. + * INPUTS + * o document -- the document for which the table is created. + * OUTPUT + * o document->headers + * o document->no_headers + * SOURCE + */ + +void RB_Document_Collect_Headers( + struct RB_Document *document ) +{ + struct RB_Part *i_part; + struct RB_header **headers; /* Pointer to an array of pointers RB_headers. */ + unsigned long count = 0; + unsigned long part_count = 0; + unsigned long i = 0; + + RB_Say( "Collecting all headers in a single table\n", SAY_INFO ); + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + + /* Count the number of headers */ + for ( part_count = 0, i_header = i_part->headers; + i_header; i_header = i_header->next ) + { + part_count++; + } + /* Compute the total count */ + count += part_count; + } + headers = + ( struct RB_header ** ) calloc( count, sizeof( struct RB_header * ) ); + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + + for ( i_header = i_part->headers; + i_header; i_header = i_header->next ) + { + headers[i] = i_header; + i++; + } + } + document->headers = headers; + document->no_headers = count; +} + +/*******/ + +/* TODO Documentation */ + +struct RB_header *RB_Document_Check_For_Duplicate( + struct RB_Document *arg_document, + struct RB_header *hdr ) +{ + struct RB_Part *i_part; + + for ( i_part = arg_document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + + for ( i_header = i_part->headers; i_header; + i_header = i_header->next ) + { + int i; + + if ( hdr == i_header ) + continue; + + for ( i = 0; i < hdr->no_names; i++ ) + if ( strcmp( hdr->names[i], i_header->name ) == 0 ) + return i_header; + } + } + return NULL; +} + + +/* TODO Documentation + If A is called qqqq/ffff and B is called ffff/zzzz then A is the + parent of B +*/ + +void RB_Document_Link_Headers( + struct RB_Document *document ) +{ + unsigned long i; + unsigned long j; + struct RB_header *parent; + struct RB_header *child; + char *parent_name; + char *child_name; + + RB_Say( "Linking all %d headers\n", SAY_INFO, document->no_headers ); + for ( i = 0; i < document->no_headers; i++ ) + { + parent = ( document->headers )[i]; + parent_name = parent->function_name; + for ( j = 0; j < document->no_headers; j++ ) + { + if ( i != j ) + { + child = ( document->headers )[j]; + child_name = child->module_name; + if ( strcmp( child_name, parent_name ) == 0 ) + { + child->parent = parent; + } + } + } + } +} + + +void RB_Document_Split_Parts( + struct RB_Document *document ) +{ + struct RB_Part *i_part = NULL; + struct RB_Part **new_parts = NULL; + int new_number_of_parts = 0; + int n = 0; + int i; + + /* split eacht part in several parts. One for each header + * in the original part. + */ + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + + for ( i_header = i_part->headers; + i_header; i_header = i_header->next ) + { + ++new_number_of_parts; + } + } + + new_parts = calloc( new_number_of_parts, sizeof( struct RB_Part * ) ); + + if ( new_parts ) + { + /* Create new parts */ + + RB_Say( "Splitting parts based on headers.\n", SAY_DEBUG ); + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + struct RB_header *i_header; + struct RB_header *i_next_header; + + for ( i_header = i_part->headers; + i_header; i_header = i_next_header ) + { + struct RB_Part *new_part; + + i_next_header = i_header->next; + + RB_Say( "Creating new part.\n", SAY_DEBUG ); + new_part = RB_Get_RB_Part( ); + RB_Part_Add_Source( new_part, + RB_Copy_RB_Filename( RB_Part_Get_Source + ( i_part ) ) ); + /* remove header from i_part and add to new_part. + */ + RB_Part_Add_Header( new_part, i_header ); + assert( n < new_number_of_parts ); + new_parts[n] = new_part; + ++n; + } + i_part->headers = NULL; + i_part->last_header = NULL; + } + /* Remove old part from document */ + RB_Free_RB_Document_Parts( document ); + /* Add new parts to document */ + for ( i = 0; i < n; ++i ) + { + RB_Document_Add_Part( document, new_parts[i] ); + } + /* clean-up temp array */ + free( new_parts ); + } + else + { + RB_Panic( "Out of memory! RB_Document_Split_Parts()" ); + } +} + +/* TODO Documentation */ +void RB_Document_Determine_DocFileNames( + struct RB_Document *document ) +{ + struct RB_Filename *filename; + unsigned int length = 0; + char *name; + char *c; + + struct RB_Part *part; + + assert( document->actions.do_multidoc ); + + for ( part = document->parts; part; part = part->next ) + { + + filename = part->filename; + /* turn mysource.c into mysource_c.html + First find the total length. */ + length = strlen( filename->name ); + /* add one for the '.' */ + ++length; + + if ( document->actions.do_one_file_per_header ) + { + struct RB_header *i_header = part->headers; + + assert( i_header ); + /* add the name of the header to the filename */ + /* We make this twice as long because some of the + * characters in the file are escaped to 2 hexadecimal + * digits. + */ + length += 2 * strlen( i_header->name ); + } + + length += RB_Get_Len_Extension( document->extension ); + /* plus one for the '\0' */ + ++length; + name = ( char * ) calloc( length, sizeof( char ) ); + assert( name ); + strcat( name, filename->name ); + for ( c = name; *c != '\0'; c++ ) + { + if ( *c == '.' ) + { + *c = '_'; + } + } + + if ( document->actions.do_one_file_per_header ) + { + unsigned int i; + struct RB_header *i_header = part->headers; + + assert( i_header ); + /* add the name of the header to the filename */ + for ( i = 0; i < strlen( i_header->name ); ++i ) + { + if ( utf8_isalnum( i_header->name[i] ) ) + { + sprintf( c, "%c", i_header->name[i] ); + c++; + } + else + { + sprintf( c, "%2X", i_header->name[i] ); + c++; + c++; + } + } + } + RB_Add_Extension( document->extension, name ); + + RB_Say( "Filename for part is %s\n", SAY_DEBUG, name ); + part->filename->docname = name; + } +} + +/****f* Document/RB_Open_SingleDocumentation + * FUNCTION + * Open the file that will contain the documentation in + * case we create a single document. + * SYNOPSIS + */ +FILE *RB_Open_SingleDocumentation( + struct RB_Document *document ) +/* + * RESULT + * An opened file. + * SOURCE + */ +{ + FILE *file; + static char *default_name = "singledoc"; + char *name = NULL; + size_t size = 0; + + if ( document->singledoc_name ) + { + size += strlen( document->singledoc_name ); + } + else + { + size += strlen( default_name ); + } + size++; /* and the '\0'; */ + size += RB_Get_Len_Extension( document->extension ); + + name = ( char * ) calloc( size, sizeof( char ) ); + assert( name ); + if ( document->singledoc_name ) + { + strcat( name, document->singledoc_name ); + } + else + { + strcat( name, default_name ); + } + RB_Add_Extension( document->extension, name ); + + file = fopen( name, "w" ); + if ( file ) + { + /* File opened */ + } + else + { + RB_Panic( "Can't open %s\n", name ); + } + free( name ); + return file; +} + +/****/ + +/****f* Document/RB_Get_RB_Document + * FUNCTION + * Allocate and initialize an RB_Document structure. + * SYNOPSIS + */ +struct RB_Document *RB_Get_RB_Document( + void ) +/* + * RESULT + * An initialized document structure. + * SOURCE + */ +{ + struct RB_Document *document = 0; + document = + ( struct RB_Document * ) malloc( sizeof( struct RB_Document ) ); + if ( document ) + { + document->cur_part = NULL; + document->parts = NULL; + document->links = NULL; + document->headers = NULL; + document->doctype = UNKNOWN; + document->actions = No_Actions(); + document->srctree = NULL; + document->srcroot = NULL; + document->docroot = NULL; + document->singledoc_name = NULL; + document->no_headers = 0; + document->charset = NULL; + document->extension = NULL; + document->first_section_level = 1; + document->doctype_name = NULL; + document->doctype_location = NULL; + } + else + { + RB_Panic( "out of memory" ); + } + return document; +} + +/*******/ diff --git a/Source/document.h b/Source/document.h new file mode 100644 index 0000000..3a2634c --- /dev/null +++ b/Source/document.h @@ -0,0 +1,128 @@ +#ifndef ROBODOC_DOCUMENT_H +#define ROBODOC_DOCUMENT_H +// vi: spell ff=unix +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include +#include "robodoc.h" + +/****s* Document/RB_Document + * NAME + * RB_Document -- Information store. + * FUNCTION + * A document is a collection of source files and documentation + * files. Depending on the mode that is used there is either a + * single documentation file or there is one documentation file for + * each source file. This mapping is stored in RB_Document. For + * each source file there is an RB_Part. It points to the source + * file, the documentation file, and contains all the headers that + * were found in the source file. + * + * ATTRIBUTES + * * links -- linked list of all links. + * * parts -- linked list of all parts. + * * no_headers -- total number of headers + * * headers -- array of pointers to all the headers. + * * srctree -- the list of all sourcefiles in the srcroot. + * * doctype -- the kind of documentation to be generated. + * * actions -- what to de while analysing en generating. + * * srcroot -- root dir for the sourcecode. + * * docroot -- root dir for the documentation. + * * charset -- the character set used for HTML and XML + * documentation. + * * first_section_level -- level of the first section, + * Defaults to 1 so the first section will + * be 1. + * If set to 2 the first section will be 1.1 + * * extension -- the extension used for the documentation + * files. + * * css -- the cascading style sheet to be used. + * * cur_part -- unused TODO remove. + * SOURCE + */ + +struct RB_Document +{ + struct RB_Part *cur_part; + struct RB_Part *parts; + struct RB_link *links; + unsigned long no_headers; + struct RB_header **headers; + struct RB_Directory *srctree; + T_RB_DocType doctype; /* HTML RTF etc */ + actions_t actions; + int first_section_level; /* TODO document use of first_section_level in manual */ + long debugmode; /* TODO This should not be in document */ + char *singledoc_name; + struct RB_Path *srcroot; /* TODO Better make this a char* */ + struct RB_Path *docroot; /* TODO Better make this a char* */ + char *charset; /* HTML, XML? */ + char *css; + char *extension; + char *compress; + char *section; + /* Docbook specific */ + char *doctype_name; /* name part of the to be used with docbook output */ + char *doctype_location;/* location part of the to be used with docbook output */ +}; + +/*****/ + +struct RB_Document *RB_Get_RB_Document( + void ); +void RB_Free_RB_Document( + struct RB_Document *document ); +void RB_Document_Add_Part( + struct RB_Document *document, + struct RB_Part *part ); +void RB_Document_Dump( + struct RB_Document *document ); +void RB_Document_Determine_DocFilePaths( + struct RB_Document *document ); +void RB_Document_Determine_DocFileNames( + struct RB_Document *document ); +void RB_Document_Create_DocFilePaths( + struct RB_Document *document ); +FILE *RB_Open_SingleDocumentation( + struct RB_Document *document ); +void RB_Document_Create_Parts( + struct RB_Document *document ); +void RB_Document_Collect_Headers( + struct RB_Document *document ); +void RB_Document_Link_Headers( + struct RB_Document *document ); +void RB_Fill_Header_Filename( + struct RB_Document *document ); + +struct RB_header *RB_Document_Check_For_Duplicate( + struct RB_Document *arg_document, + struct RB_header *hdr ); + +void RB_Document_Sort_Headers( + struct RB_Document *document ); + +void RB_Document_Split_Parts( + struct RB_Document *document ); + +#endif /* ROBODOC_DOCUMENT_H */ diff --git a/Source/file.c b/Source/file.c new file mode 100644 index 0000000..5cc8b25 --- /dev/null +++ b/Source/file.c @@ -0,0 +1,256 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +#include "file.h" +#include +#include +#include + + +#ifdef DMALLOC +#include +#endif +#include "util.h" + +/****h* ROBODoc/Filename + * NAME + * Functions to deal with keeping track + * of filenames and directory names. + ***** + */ + +/****f* Filename/RB_Get_RB_Filename + * NAME + * RB_Get_RB_Filename + * SYNOPSIS + */ +struct RB_Filename* RB_Get_RB_Filename( char *arg_filename, struct RB_Path *arg_rb_path ) +/* + * INPUTS + * o arg_rb_filename -- + * o arg_rb_path -- + * FUNCTION + * Create a new RB_Filename structure based on arg_filename and + * arg_rb_path. + * SOURCE + */ +{ + struct RB_Filename *rb_filename = + ( struct RB_Filename * ) malloc( sizeof( struct RB_Filename ) ); + rb_filename->name = ( char * ) malloc( strlen( arg_filename ) + 1 ); + rb_filename->docname = 0; + rb_filename->fullname = 0; + rb_filename->fulldocname = 0; + strcpy( rb_filename->name, arg_filename ); + rb_filename->path = arg_rb_path; + return rb_filename; +} + +/*****/ + +struct RB_Filename *RB_Copy_RB_Filename( struct RB_Filename* arg_rb_filename ) +{ + return RB_Get_RB_Filename( arg_rb_filename->name, arg_rb_filename->path ); +} + + +void +RB_Filename_Dump( struct RB_Filename *arg_rb_filename ) +{ + printf( "[%s %s %s] ", RB_Get_Path( arg_rb_filename ), + RB_Get_Filename( arg_rb_filename ), + RB_Get_Extension( arg_rb_filename ) ); + printf( "%s\n", Get_Fullname( arg_rb_filename ) ); +} + +/*x**f* Filename/RB_Free_RB_Filename + * NAME + * RB_Free_RB_Filename -- free a RB_Filename structure. + * + ***** + * TODO Documentation + */ + +void +RB_Free_RB_Filename( struct RB_Filename *arg_rb_filename ) +{ + free( arg_rb_filename->name ); + if ( arg_rb_filename->docname ) + { + free( arg_rb_filename->docname ); + } + if ( arg_rb_filename->fullname ) + { + free( arg_rb_filename->fullname ); + } + if ( arg_rb_filename->fulldocname ) + { + free( arg_rb_filename->fulldocname ); + } + free( arg_rb_filename ); +} + +/* Set the fulldoc name, this is used in singledoc mode + * since there the docname is preset by the user and not + * derived from the sourcefile name. + */ + +void RB_Set_FullDocname( struct RB_Filename *arg_rb_filename, char* name ) +{ + arg_rb_filename->fulldocname = RB_StrDup( name ); +} + +/* TODO Documentation RB_Get_FullDocname */ +char * +RB_Get_FullDocname( struct RB_Filename *arg_rb_filename ) +{ + char *result = arg_rb_filename->fulldocname; + + if ( result == NULL ) + { + unsigned int size = strlen( arg_rb_filename->docname ) + + strlen( arg_rb_filename->path->docname ) + 1; + result = ( char * ) malloc( size * sizeof( char ) ); + assert( result ); + *result = '\0'; + strcat( result, arg_rb_filename->path->docname ); + strcat( result, arg_rb_filename->docname ); + /* Save the result so it can be reused later on, and we can properly deallocate it. */ + arg_rb_filename->fulldocname = result; + } + return result; +} + + +/****f* Filename/Get_Fullname + * NAME + * Get_Fullname -- + * SYNOPSIS + */ +char* Get_Fullname( struct RB_Filename *arg_rb_filename ) +/* + * FUNCTION + * Give the full name of the file, that is the name of + * the file including the extension and the path. + * The path can be relative or absolute. + * NOTE + * The string returned is owned by this function + * so don't change it. + * SOURCE + */ +{ + char *result = arg_rb_filename->fullname; + + if ( result == NULL ) + { + unsigned int size = strlen( arg_rb_filename->name ) + + strlen( arg_rb_filename->path->name ) + 1; + result = ( char * ) malloc( size * sizeof( char ) ); + assert( result ); + *result = '\0'; + strcat( result, arg_rb_filename->path->name ); + strcat( result, arg_rb_filename->name ); + /* Save the result so it can be reused later on, and we can properly deallocate it. */ + arg_rb_filename->fullname = result; + } + return result; +} +/******/ + +/****f* Filename/RB_Get_Path + * SYNOPSIS + */ +char* RB_Get_Path( struct RB_Filename *arg_rb_filename ) +/* + * FUNCTION + * Give the path for this file. + * NOTE + * The string returned is owned by this function + * so don't change it. + ****** + */ +{ + return arg_rb_filename->path->name; +} + + +/****f* Filename/RB_Get_Extension + * NAME + * RB_Get_Extension -- + * FUNCTION + * Give the extension of this file. That is the part after + * the last '.' if there is any. + * SYNOPSIS + */ +char* RB_Get_Extension( struct RB_Filename *arg_rb_filename ) +/* + * RESULT + * pointer to the extension + * pointer to a '\0' if no extension was found. + * NOTE + * The string returned is owned by this function + * so don't change it. + * SOURCE + */ +{ + char *c = arg_rb_filename->name; + int i = strlen( c ); + + for ( c += i; c != arg_rb_filename->name && ( *c != '.' ); --c ) + { + /* Empty */ + } + if ( *c == '.' ) + { + ++c; + } + else + { + c = arg_rb_filename->name; + c += i; + } + return c; +} +/*****/ + +/****f* Filename/RB_Get_Filename + * NAME + * RB_Get_Filename -- + * FUNCTION + * Give the name of this file. That is the name + * of the file without its path but with the + * extension. + * SYNOPSIS + */ +char* RB_Get_Filename( struct RB_Filename *arg_rb_filename ) +/* + * RESULT + * pointer to the extension + * pointer to a '\0' if no extension was found. + * NOTE + * The string returned is owned by this function + * so don't change it. + ****** + */ +{ + return arg_rb_filename->name; +} diff --git a/Source/file.h b/Source/file.h new file mode 100644 index 0000000..ac7d13b --- /dev/null +++ b/Source/file.h @@ -0,0 +1,87 @@ +#ifndef ROBODOC_FILE_H +#define ROBODOC_FILE_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include +#include "path.h" +#include "links.h" + +/****s* Filename/RB_Filename + * NAME + * RB_Filename -- + * ATTRIBUTES + * * next pointer to the next RB_File. + * * name null terminated string with the name of the file, + * (Without the path, but including the extension). + * * fullname + * * path pointer to a RB_Path structure that holds + * the path for this file. + * * link The link used to represent this file while in multidoc + * mode. + * SOURCE + */ + +struct RB_Filename +{ + struct RB_Filename *next; + char *name; + char *docname; + char *fullname; + char *fulldocname; + struct RB_Path *path; + struct RB_link *link; +}; + +/******/ + + +struct RB_Filename *RB_Get_RB_Filename( + char *arg_filename, + struct RB_Path *arg_rb_path ); +void RB_Free_RB_Filename( + struct RB_Filename *arg_rb_filename ); + +/* */ +char *Get_Fullname( + struct RB_Filename *arg_rb_filename ); +void RB_Set_FullDocname( + struct RB_Filename *arg_rb_filename, + char *name ); +char *RB_Get_FullDocname( + struct RB_Filename *arg_rb_filename ); +char *RB_Get_Path( + struct RB_Filename *arg_rb_filename ); +char *RB_Get_Filename( + struct RB_Filename *arg_rb_filename ); +char *RB_Get_Extension( + struct RB_Filename *arg_rb_filename ); +struct RB_Filename *RB_Copy_RB_Filename( + struct RB_Filename *arg_rb_filename ); + +/* */ +void RB_Filename_Dump( + struct RB_Filename *arg_rb_filename ); + + +#endif /* ROBODOC_FILE_H */ diff --git a/Source/generator.c b/Source/generator.c new file mode 100644 index 0000000..491aa22 --- /dev/null +++ b/Source/generator.c @@ -0,0 +1,2845 @@ +// vi: spell ff=unix +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + + +/****h* ROBODoc/Generator + * FUNCTION + * This contains routines to generate the documentation from the + * headers collected from the source code. It contains + * functionality common for all document types (HTML, RTF etc). + * The specifics are handled in the modules for each of the several + * document types. + * + * The behaviour of many of the functions in this module are + * modified by the global output_mode. + * + * The general call sequence is as follows: + * RB_Generate_Documentation + * +> RB_Generate_SingleDoc + * +> RB_Generate_Part + * +> Generate_Header + * +> Generate_Item_Line + * +> Generate_Char + * BUGS + * o Confusing use of doctype and output mode. + * NOTES + * Might be a good idea to replace all the switch statements with + * function pointers. + * So instead of: + * switch (output_mode) + * { + * case HTML: + * RB_HTML_Generate_Doc_Start(dest_doc, src_name, name, toc); + * break; + * case LATEX: + * RB_LaTeX_Generate_Doc_Start(dest_doc, src_name, name, toc); + * break; + * case RTF: + * RB_RTF_Generate_Doc_Start(dest_doc, src_name, name, toc); + * break; + * case ASCII: + * RB_ASCII_Generate_Doc_Start(dest_doc, src_name, name, toc); + * break; + * case TROFF: + * RB_TROFF_Generate_Doc_Start(dest_doc, src_name, name, toc); + * break; + * default: + * break; + * } + * we will have + * (*rb_generate_doc_start)(dest_doc, src_name, name, toc); + * + * were the function pointers are initialized at program start based + * on the output mode. + ******* + * $Id: generator.c,v 1.106 2007/07/10 19:13:51 gumpu Exp $ + */ + +#include +#include +#include +#include +#include + +#include "globals.h" +#include "robodoc.h" +#include "headers.h" +#include "items.h" +#include "util.h" +#include "links.h" +#include "generator.h" +#include "document.h" +#include "part.h" +#include "file.h" +#include "roboconfig.h" + +/* Generators */ +#include "html_generator.h" +#include "latex_generator.h" +#include "xmldocbook_generator.h" +#include "rtf_generator.h" +#include "troff_generator.h" +#include "ascii_generator.h" +#include "test_generator.h" + +/* TODO This should not be here.... */ +#include "analyser.h" + +#ifdef DMALLOC +#include +#endif + + +/* Module functions */ +// static void RB_Generate_Empty_Item( FILE * dest_doc ); + +static void Generate_Item_Line( + FILE *dest_doc, + char *line, + int item_type, + char *docname, + struct RB_header *fnames ); +void Generate_Char( + FILE *dest_doc, + int cur_char ); +static void Generate_Index( + struct RB_Document *document ); + +static void Generate_Header( + FILE *f, + struct RB_Document *document, + struct RB_header *header, + char *docname ); + +static void Generate_Begin_Paragraph( + FILE *dest_doc ); +static void Generate_End_Paragraph( + FILE *dest_doc ); +static void Format_Line( + FILE *dest_doc, + long format ); +static void Generate_Begin_Preformatted( + FILE *dest_doc, + int source ); +static void Generate_End_Preformatted( + FILE *dest_doc ); +static void Generate_Begin_List_Item( + FILE *dest_doc ); +static void Generate_End_List_Item( + FILE *dest_doc ); +static void Generate_Begin_List( + FILE *dest_doc ); +static void Generate_End_List( + FILE *dest_doc ); +static void Pipe_Line( + FILE *dest_doc, + char *arg_line ); + +static char piping = FALSE; + + +/* TODO Documentation */ +void RB_Generate_False_Link( + FILE *dest_doc, + char *name ) +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_False_Link( dest_doc, name ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_False_Link( dest_doc, name ); + break; + case HTML: + RB_HTML_Generate_False_Link( dest_doc, name ); + break; + case LATEX: + RB_LaTeX_Generate_False_Link( dest_doc, name ); + break; + case RTF: + RB_RTF_Generate_False_Link( dest_doc, name ); + break; + case ASCII: + RB_ASCII_Generate_False_Link( dest_doc, name ); + break; + case TROFF: + RB_TROFF_Generate_False_Link( dest_doc, name ); + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + +/****f* Generator/RB_Generate_Item_Begin + * FUNCTION + * Generate the begin of an item. This should switch to some + * preformatted output mode, similar to HTML's

    .
    + * SYNOPSIS
    + */
    +void RB_Generate_Item_Begin(
    +    FILE *dest_doc,
    +    char *name )
    +/*
    + * INPUTS
    + *   dest_doc -- file to be written to
    + *   output_mode -- global with the current output mode
    + * SOURCE
    + */
    +{
    +    switch ( output_mode )
    +    {
    +    case TEST:
    +        RB_TEST_Generate_Item_Begin( dest_doc );
    +        break;
    +    case XMLDOCBOOK:
    +        RB_XMLDB_Generate_Item_Begin( dest_doc );
    +        break;
    +    case HTML:
    +        RB_HTML_Generate_Item_Begin( dest_doc, name );
    +        break;
    +    case LATEX:
    +        RB_LaTeX_Generate_Item_Begin( dest_doc );
    +        break;
    +    case RTF:
    +        RB_RTF_Generate_Item_Begin( dest_doc );
    +        break;
    +    case ASCII:
    +        RB_ASCII_Generate_Item_Begin( dest_doc );
    +        break;
    +    case TROFF:
    +        /* nothing */
    +        break;
    +    case UNKNOWN:
    +    default:
    +        assert( 0 );
    +    }
    +}
    +
    +/******/
    +
    +
    +/****f* Generator/Generate_Label
    + * FUNCTION
    + *   Generate a label that can be used for a link.
    + *   For instance in HTML this is 
    + * SYNOPSIS
    + */
    +void Generate_Label(
    +    FILE *dest_doc,
    +    char *name )
    +/*
    + * INPUTS
    + *   * dest_doc -- file to be written to
    + *   * name -- the label's name.
    + *   * output_mode -- global with the current output mode
    + * SOURCE
    + */
    +{
    +    switch ( output_mode )
    +    {
    +    case TEST:
    +        RB_TEST_Generate_Label( dest_doc, name );
    +        break;
    +    case XMLDOCBOOK:
    +        RB_XMLDB_Generate_Label( dest_doc, name );
    +        break;
    +    case HTML:
    +        RB_HTML_Generate_Label( dest_doc, name );
    +        break;
    +    case LATEX:
    +        /* lowtexx 21.09.2005 11:33 */
    +        RB_LaTeX_Generate_Label( dest_doc, name );
    +        break;
    +    case RTF:
    +        RB_RTF_Generate_Label( dest_doc, name );
    +        break;
    +    case ASCII:
    +        /* Doesn't apply */
    +        break;
    +    case TROFF:
    +        /* Doesn't apply */
    +        break;
    +    case UNKNOWN:
    +    default:
    +        assert( 0 );
    +    }
    +}
    +
    +/******/
    +
    +
    +/****f* Generator/RB_Generate_Item_End
    + * FUNCTION
    + *   Generate the end of an item.  This should switch back from the
    + *   preformatted mode.  So in HTML it generates the 
    of a
    + *   
    pair. + * INPUTS + * * dest_doc -- file to be written to + * * output_mode -- global with the current output mode + * SOURCE + */ + +void RB_Generate_Item_End( + FILE *dest_doc, + char *name ) +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Item_End( dest_doc ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Item_End( dest_doc ); + break; + case HTML: + RB_HTML_Generate_Item_End( dest_doc, name ); + break; + case LATEX: + if ( piping == TRUE ) + { + fprintf( dest_doc, "\\begin{verbatim}\n" ); + piping = FALSE; + } + RB_LaTeX_Generate_Item_End( dest_doc ); + break; + case RTF: + RB_RTF_Generate_Item_End( dest_doc ); + break; + case ASCII: + RB_ASCII_Generate_Item_End( dest_doc ); + break; + case TROFF: + /* Doesn't apply */ break; + case UNKNOWN: + + default: + assert( 0 ); + } +} + +/****/ + + + +/****f Generator/RB_Get_Len_Extension + * FUNCTION + * Compute the length of the filename extension for + * the current document type. + ***** + */ + +size_t RB_Get_Len_Extension( + char *extension ) +{ + size_t size = 0; + + size = strlen( extension ); + if ( *extension != '.' ) + size++; + return size; +} + +/****f* Generator/RB_Add_Extension + * FUNCTION + * Add an extension to the filename base based on on the current + * output mode. + * INPUTS + * * doctype -- output mode + * * name -- the name of the file without extension and with + * enough room left to add the extension. + * OUTPUT + * name -- the name of the file including the extension. + * SOURCE + */ + +void RB_Add_Extension( + char *extension, + char *name ) +{ + if ( *extension != '.' ) + strcat( name, "." ); + strcat( name, extension ); +} + +/******/ + +/*x**f Generator/RB_Default_Len_Extension + * FUNCTION + * Returns default extension for + * the current document type. + ***** + */ + +char *RB_Get_Default_Extension( + T_RB_DocType doctype ) +{ + char *extension = NULL; + + switch ( doctype ) + { + case TEST: + extension = RB_TEST_Get_Default_Extension( ); + break; + case XMLDOCBOOK: + extension = RB_XMLDB_Get_Default_Extension( ); + break; + case HTML: + extension = RB_HTML_Get_Default_Extension( ); + break; + case LATEX: + extension = RB_LaTeX_Get_Default_Extension( ); + break; + case RTF: + extension = RB_RTF_Get_Default_Extension( ); + break; + case ASCII: + extension = RB_ASCII_Get_Default_Extension( ); + break; + case TROFF: + extension = RB_TROFF_Get_Default_Extension( ); + break; + case UNKNOWN: + default: + assert( 0 ); + } + return extension; +} + + +/****f* Generator/RB_Generate_BeginSection + * FUNCTION + * Generate a section of level depth in the current output mode. + * This is used for the --sections option. Where each header is + * placed in a section based on the header hierarchy. + * INPUTS + * * dest_doc -- the destination file. + * * doctype -- document type + * * depth -- the level of the section + * * name -- the name of the section + * * header -- pointer to the header structure + * * output_mode -- global with the current output mode. + * SOURCE + */ + +void RB_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ) +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_BeginSection( dest_doc, depth, name ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_BeginSection( dest_doc, depth, name ); + break; + case HTML: + RB_HTML_Generate_BeginSection( dest_doc, depth, name, header ); + break; + case LATEX: + RB_LaTeX_Generate_BeginSection( dest_doc, depth, name, header ); + break; + case RTF: + RB_RTF_Generate_BeginSection( dest_doc, depth, name ); + break; + case TROFF: +/* RB_TROFF_Generate_BeginSection( dest_doc, depth, name ); */ + break; + case ASCII: + RB_ASCII_Generate_BeginSection( dest_doc, depth, name, header ); + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + +/*******/ + + +/****f* Generator/RB_Generate_EndSection + * FUNCTION + * Generate the end of a section base on the current output mode. + * The functions is used for the --section option. + * It closes a section in the current output mode. + * INPUTS + * * dest_doc -- the destination file. + * * doctype -- + * * depth -- the level of the section + * * name -- the name of the section + * * output_mode -- global with the current output mode. + * SOURCE + */ + +void RB_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ) +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_EndSection( dest_doc, depth, name ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_EndSection( dest_doc, depth, name ); + break; + case HTML: + RB_HTML_Generate_EndSection( dest_doc, depth, name ); + break; + case LATEX: + RB_LaTeX_Generate_EndSection( dest_doc, depth, name ); + break; + case RTF: + RB_RTF_Generate_EndSection( dest_doc, depth, name ); + break; + case TROFF: + /* doesn't apply */ + break; + case ASCII: + RB_HTML_Generate_EndSection( dest_doc, depth, name ); + break; + case UNKNOWN: + + default: + assert( 0 ); + } +} + +/******/ + + +/****f* Generator/RB_Generate_Index_Entry + * FUNCTION + * Generate an entry for an auto generated index. This works only + * for output modes that support this, LaTeX for instance. This + * has nothting to do with the master index. + * SYNOPSIS + */ +void RB_Generate_Index_Entry( + FILE *dest_doc, + T_RB_DocType doctype, + struct RB_header *header ) +/* + * INPUTS + * * dest_doc -- the destination file. + * * header -- pointer to the header the index entry is for. + * * output_mode -- global with the current output mode. + * SOURCE + */ +{ + switch ( doctype ) + { + case TEST: + /* TODO */ + break; + case XMLDOCBOOK: + /* TODO */ + break; + case HTML: + /* TODO */ + break; + case LATEX: + RB_LaTeX_Generate_Index_Entry( dest_doc, header ); + break; + case RTF: + /* TODO */ + break; + case ASCII: + /* No index available */ + break; + case TROFF: + /* No index available */ + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + +/*******/ + + +/****f* Generator/RB_Generate_TOC_2 + * FUNCTION + * Create a Table of Contents based on the headers found in + * _all_ source files. There is also a function to create + * a table of contents based on the headers found in a single + * source file RB_Generate_TOC_1 + * SYNOPSIS + */ +void RB_Generate_TOC_2( + FILE *dest_doc, + struct RB_header **headers, + int count, + struct RB_Part *owner, + char *dest_name ) +/* + * INPUTS + * * dest_doc -- the destination file. + * * headers -- an array of pointers to all the headers. + * * count -- the number of pointers in the array. + * * output_mode -- global with the current output mode. + * * owner -- The owner of the TOC. Only the headers that are owned + * by this owner are included in the TOC. Can be NULL, + * in which case all headers are included. + * SOURCE + */ +{ + switch ( output_mode ) + { + case TEST: + break; + case TROFF: + break; + case XMLDOCBOOK: + break; + case HTML: + RB_HTML_Generate_TOC_2( dest_doc, headers, count, owner, dest_name ); + break; + case LATEX: + /* LaTeX has it's own mechanism for creating + * a table of content */ + break; + case RTF: + RB_RTF_Generate_TOC_2( dest_doc, headers, count ); + break; + case ASCII: + /* TODO: No TOC in ASCII mode */ + break; + case UNKNOWN: + + default: + assert( 0 ); + } +} + +/******/ + + +/****f* Generator/RB_Generate_Doc_Start + * NAME + * RB_Generate_Doc_Start -- Generate document header. + * SYNOPSIS + */ +void RB_Generate_Doc_Start( + struct RB_Document *document, + FILE *dest_doc, + char *src_name, + char *title, + char toc, + char *dest_name, + char *charset ) +/* + * FUNCTION + * Generates for depending on the output_mode the text that + * will be at the start of a document. + * Including the table of contents. + * INPUTS + * o dest_doc - pointer to the file to which the output will + * be written. + * o src_name - the name of the source file or directory. + * o name - the name of this file. + * o output_mode - global variable that indicates the output + * mode. + * o toc - generate table of contens + * SEE ALSO + * RB_Generate_Doc_End + * SOURCE + */ +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Doc_Start( dest_doc, src_name, title, toc ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Doc_Start( document, dest_doc, charset ); + break; + case HTML: + RB_HTML_Generate_Doc_Start( dest_doc, src_name, title, dest_name, + charset ); + break; + case LATEX: + RB_LaTeX_Generate_Doc_Start( dest_doc, src_name, title, charset ); + break; + case RTF: + RB_RTF_Generate_Doc_Start( dest_doc, src_name, title, toc ); + break; + case ASCII: + RB_ASCII_Generate_Doc_Start( dest_doc, src_name, title, toc ); + break; + case TROFF: + /* */ ; + break; + case UNKNOWN: + default: + ; + } +} + +/***************/ + + +/****f* Generator/RB_Generate_Doc_End + * NAME + * RB_Generate_Doc_End -- generate document trailer. + * SYNOPSIS + */ +void RB_Generate_Doc_End( + FILE *dest_doc, + char *name, + char *src_name ) +/* + * FUNCTION + * Generates for depending on the output_mode the text that + * will be at the end of a document. + * INPUTS + * o dest_doc - pointer to the file to which the output will + * be written. + * o name - the name of this file. + * o output_mode - global variable that indicates the output + * mode. + * NOTES + * Doesn't do anything with its arguments, but that might + * change in the future. + * BUGS + * SOURCE + */ +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Doc_End( dest_doc, name ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Doc_End( dest_doc, name ); + break; + case HTML: + RB_HTML_Generate_Doc_End( dest_doc, name, src_name ); + break; + case LATEX: + RB_LaTeX_Generate_Doc_End( dest_doc, name ); + break; + case RTF: + RB_RTF_Generate_Doc_End( dest_doc, name ); + break; + case TROFF: + break; + case ASCII: + break; + case UNKNOWN: + + default: + assert( 0 ); + } +} + +/************/ + + +/****f* Generator/RB_Generate_Header_Start [3.0h] + * NAME + * RB_Generate_Header_Start -- generate header start text. + * SYNOPSIS + */ +FILE *RB_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ) +/* + * FUNCTION + * Generates depending on the output_mode the text that + * will be at the end of each header. + * INPUTS + * o dest_doc - pointer to the file to which the output will + * be written. + * o cur_header - pointer to a RB_header structure. + * SEE ALSO + * RB_Generate_Header_End + * SOURCE + */ +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Header_Start( dest_doc, cur_header ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Header_Start( dest_doc, cur_header ); + break; + case HTML: + RB_HTML_Generate_Header_Start( dest_doc, cur_header ); + break; + case LATEX: + RB_LaTeX_Generate_Header_Start( dest_doc, cur_header ); + break; + case RTF: + RB_RTF_Generate_Header_Start( dest_doc, cur_header ); + break; + case ASCII: + RB_ASCII_Generate_Header_Start( dest_doc, cur_header ); + break; + case TROFF: + dest_doc = RB_TROFF_Generate_Header_Start( dest_doc, cur_header ); + break; + case UNKNOWN: + default: + assert( 0 ); + } + return dest_doc; +} + +/******/ + + +/****f* Generator/RB_Generate_Header_End [3.0h] + * NAME + * RB_Generate_Header_End + * SYNOPSIS + */ +void RB_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ) +/* + * FUNCTION + * Generates for depending on the output_mode the text that + * will be at the end of a header. + * This function is used if the option --section is _not_ + * used. + * INPUTS + * o dest_doc - pointer to the file to which the output will + * be written. + * o cur_header - pointer to a RB_header structure. + * SEE ALSO + * RB_Generate_Header_Start, RB_Generate_EndSection, + * RB_Generate_BeginSection + * SOURCE + */ +{ + switch ( output_mode ) + { /* switch by *koessi */ + case TEST: + RB_TEST_Generate_Header_End( dest_doc, cur_header ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Header_End( dest_doc, cur_header ); + break; + case HTML: + RB_HTML_Generate_Header_End( dest_doc, cur_header ); + break; + case LATEX: + RB_LaTeX_Generate_Header_End( dest_doc, cur_header ); + break; + case RTF: + RB_RTF_Generate_Header_End( dest_doc, cur_header ); + break; + case ASCII: + RB_ASCII_Generate_Header_End( dest_doc, cur_header ); + break; + case TROFF: + RB_TROFF_Generate_Header_End( dest_doc, cur_header ); + break; + case UNKNOWN: + default: + break; + } +} + +/*****/ + + +/****f* Generator/Generate_Item_Name [2.01] + * NAME + * Generate_Item_Name -- fast&easy + * SYNOPSIS + */ +void Generate_Item_Name( + FILE *dest_doc, + int item_type ) +/* + * FUNCTION + * write the item's name to the doc + * INPUTS + * o FILE* dest_doc -- destination file + * o int item_type -- the type of item + * AUTHOR + * Koessi + * NOTES + * uses globals: output_mode + * SOURCE + */ +{ + char *name = configuration.items.names[item_type]; + + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Item_Name( dest_doc, name ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Item_Name( dest_doc, name ); + break; + case HTML: + RB_HTML_Generate_Item_Name( dest_doc, name ); + break; + case LATEX: + RB_LaTeX_Generate_Item_Name( dest_doc, name ); + break; + case RTF: + RB_RTF_Generate_Item_Name( dest_doc, name ); + break; + case ASCII: + RB_ASCII_Generate_Item_Name( dest_doc, name ); + break; + case TROFF: + RB_TROFF_Generate_Item_Name( dest_doc, name, item_type ); + break; + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + +/*********/ + + +void Generate_Begin_Content( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case HTML: + HTML_Generate_Begin_Content( dest_doc ); + break; + default: + break; + } +} + +void Generate_End_Content( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case HTML: + HTML_Generate_End_Content( dest_doc ); + break; + default: + break; + } +} + +void Generate_Begin_Navigation( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case HTML: + HTML_Generate_Begin_Navigation( dest_doc ); + break; + default: + break; + } + +} + +void Generate_End_Navigation( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case HTML: + HTML_Generate_End_Navigation( dest_doc ); + break; + default: + break; + } + +} + +void Generate_IndexMenu( + FILE *dest_doc, + char *filename, + struct RB_Document *document ) +{ + switch ( output_mode ) + { + case HTML: + RB_HTML_Generate_IndexMenu( dest_doc, filename, document, NULL ); + break; + default: + break; + } + +} + +void Generate_Begin_Extra( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case HTML: + HTML_Generate_Begin_Extra( dest_doc ); + break; + default: + break; + } +} + +void Generate_End_Extra( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case HTML: + HTML_Generate_End_Extra( dest_doc ); + break; + default: + break; + } +} + + + + + + +/* TODO Documentation */ +void RB_Generate_Nav_Bar( + struct RB_Document *document, + FILE *current_doc, + struct RB_header *current_header ) +{ + switch ( output_mode ) + { + case TEST: + break; + case XMLDOCBOOK: + break; + case HTML: + if ( course_of_action.do_one_file_per_header ) + { + /* Nothing */ + } + else + { + RB_HTML_Generate_Nav_Bar( document, current_doc, current_header ); + } + break; + case LATEX: + break; + case RTF: + break; + case ASCII: + break; + case TROFF: + break; + case UNKNOWN: + default: + /* Bug */ + assert( 0 ); + } +} + + + +/* TODO Documentation */ +int RB_HTML_Extra( + FILE *dest_doc, + int item_type, + char *cur_char, + char prev_char ) +{ + int res = -1; + + switch ( output_mode ) + { + case TEST: + break; + case XMLDOCBOOK: + break; + case HTML: + res = + RB_HTML_Generate_Extra( dest_doc, item_type, cur_char, + prev_char ); + break; + case LATEX: + /* TODO */ + break; + case RTF: + /* TODO */ + break; + case ASCII: + /* TODO */ + break; + case TROFF: + res = RB_TROFF_Generate_Extra( dest_doc, item_type, cur_char ); + break; + break; + case UNKNOWN: + default: + /* Bug */ + assert( 0 ); + } + return res; +} + + +/****f* Generator/RB_Name_Headers + * FUNCTION + * Give all headers a unique name. This makes sure that if + * two headers have the same name linking to one of the headers + * still works. + * SYNOPSIS + */ +void RB_Name_Headers( + struct RB_header **headers, + long count ) +/* + * SOURCE + */ +#define MAX_UNIQUE_ID_LENGTH 80 +{ + int i; + char id[MAX_UNIQUE_ID_LENGTH + 1]; + + RB_Say( "Assigning headers a unique name.\n", SAY_DEBUG ); + for ( i = 0; i < count; ++i ) + { + struct RB_header *header; + + header = headers[i]; + sprintf( id, "robo%d", i ); + header->unique_name = RB_StrDup( id ); + } +} + +/******/ + +/****f* Generator/RB_Sort_Items + * FUNCTION + * Sort the items in all the headers according to the order + * specified in the 'item order' block in the robodoc.rc + * file. + * SYNOPSIS + */ +static void RB_Sort_Items( + struct RB_header **headers, + long header_count ) +/* + * SOURCE + */ +{ + int n_order = configuration.item_order.number; + + if ( n_order ) + { + int i = 0; + int j = 0; + int max_number_of_items = 0; + struct RB_Item **items = NULL; + struct RB_Item **items_sorted = NULL; + + RB_Say( "Sorting items in %d headers.\n", SAY_DEBUG, header_count ); + + /* Compute the maximum number of items in any given header */ + for ( j = 0; j < header_count; ++j ) + { + struct RB_header *header; + struct RB_Item *item; + int item_count = 0; + + header = headers[j]; + for ( item = header->items; item; item = item->next ) + { + ++item_count; + } + + if ( item_count > max_number_of_items ) + { + max_number_of_items = item_count; + } + } + /* Allocate an array for the items, this makes it easier to + * sort. */ + + RB_Say( "Largest header has %d items.\n", SAY_DEBUG, + max_number_of_items ); + + if ( max_number_of_items == 0 ) + { + /* No items in any of the headers, do nothing */ + } + else + { + items = calloc( max_number_of_items, sizeof( struct RB_Item * ) ); + items_sorted = + calloc( max_number_of_items, sizeof( struct RB_Item * ) ); + + /* Sort items */ + for ( j = 0; j < header_count; ++j ) + { + struct RB_header *header = NULL; + struct RB_Item *item = NULL; + int item_index = 0; + int sorted_item_index = 0; + int item_count = 0; + + header = headers[j]; + + /* Copy item pointers to array */ + for ( item = header->items; item; + item = item->next, ++item_index ) + { + items[item_index] = item; + items_sorted[item_index] = item; + }; + item_count = item_index; + + if ( item_count == 0 ) + { + /* No items in this header, do nothing. */ + } + else + { + assert( item_count <= max_number_of_items ); + + /* First copy the items in the order that is defined in + * item_order[] to sorted_items[] */ + sorted_item_index = 0; + for ( i = 0; i < n_order; ++i ) + { + for ( item_index = 0; item_index < item_count; + ++item_index ) + { + if ( items[item_index] ) + { + if ( strcmp + ( configuration.items. + names[items[item_index]->type], + configuration.item_order.names[i] ) == + 0 ) + { + /* copy to items_sorted */ + items_sorted[sorted_item_index] = + items[item_index]; + ++sorted_item_index; + items[item_index] = NULL; + } + } + } + } + /* Then copy the remaining items to items_sorted[] */ + for ( item_index = 0; item_index < item_count; + ++item_index ) + { + if ( items[item_index] ) + { + /* copy to items_sorted */ + items_sorted[sorted_item_index] = + items[item_index]; + ++sorted_item_index; + items[item_index] = NULL; + } + } + + assert( sorted_item_index == item_count ); + + /* Now copy the items in items_sorted[] back into the linked list in + * the header */ + if ( item_count > 1 ) + { + /* Chain all the items */ + for ( item_index = 0; item_index < item_count - 1; + ++item_index ) + { + items_sorted[item_index]->next = + items_sorted[item_index + 1]; + } + } + + assert( item_count > 0 ); + items_sorted[item_count - 1]->next = NULL; + /* now link the first item to the header. */ + header->items = items_sorted[0]; + } + } + + free( items_sorted ); + free( items ); + } + } + + RB_Say( "Done sorting items in %d headers.\n", SAY_DEBUG, header_count ); +} + +/*******/ + + +/****f* Generator/RB_Generate_Documentation + * FUNCTION + * Generate the documentation for all the information contained in a + * RB_Document structure. + * SYNOPSIS + */ +void RB_Generate_Documentation( + struct RB_Document *document ) +/* + * INPUTS + * document -- pointer to the RB_Document structure. + * SOURCE + */ +{ + RB_SetCurrentFile( NULL ); + + + + if ( document->actions.do_singledoc ) + { + RB_Generate_SingleDoc( document ); + } + else if ( document->actions.do_multidoc ) + { + RB_Generate_MultiDoc( document ); + } + else if ( document->actions.do_singlefile ) + { + RB_Generate_SingleDoc( document ); + } +} + +/*****/ + +/****f* Generator/RB_Generate_MultiDoc + * FUNCTION + * Create documentation by creating a file for each + * individual source file that was scanned. + * SYNOPSIS + */ +void RB_Generate_MultiDoc( + struct RB_Document *document ) +/* + * INPUTS + * document -- pointer to the RB_Document structure. + * SOURCE + */ +{ + struct RB_Part *i_part; + FILE *document_file = NULL; + + RB_Document_Determine_DocFilePaths( document ); + RB_Document_Create_DocFilePaths( document ); + if ( document->actions.do_one_file_per_header ) + { + RB_Document_Split_Parts( document ); + } + RB_Document_Determine_DocFileNames( document ); + RB_Document_Collect_Headers( document ); + if ( document->actions.do_nosort ) + { + /* Nothing */ + } + else + { + RB_Document_Sort_Headers( document ); + } + RB_Document_Link_Headers( document ); + RB_Fill_Header_Filename( document ); + RB_Name_Headers( document->headers, document->no_headers ); + RB_Sort_Items( document->headers, document->no_headers ); + RB_CollectLinks( document, document->headers, document->no_headers ); + if ( output_mode == HTML ) + { + RB_Create_CSS( document ); + } + + + for ( i_part = document->parts; i_part != NULL; i_part = i_part->next ) + { + + char *srcname = Get_Fullname( i_part->filename ); + char *docname = RB_Get_FullDocname( i_part->filename ); + + /* Nothing found in this part, do not generate it */ + if ( i_part->headers == 0 ) + continue; + + + if ( output_mode != TROFF ) + { + document_file = RB_Open_Documentation( i_part ); + RB_Generate_Doc_Start( document, + document_file, srcname, srcname, 1, + docname, document->charset ); + + Generate_Begin_Navigation( document_file ); + if ( document->actions.do_one_file_per_header ) + { + RB_HTML_Generate_Nav_Bar_One_File_Per_Header( document, + document_file, + i_part-> + headers ); + } + else + { + Generate_IndexMenu( document_file, docname, document ); + } + Generate_End_Navigation( document_file ); + + Generate_Begin_Content( document_file ); + + if ( ( document->actions.do_toc ) && document->no_headers ) + { + RB_Generate_TOC_2( document_file, + document->headers, document->no_headers, + i_part, docname ); + } + RB_Generate_Part( document_file, document, i_part ); + Generate_End_Content( document_file ); + + RB_Generate_Doc_End( document_file, docname, srcname ); + fclose( document_file ); + } + else + { + RB_Generate_Part( document_file, document, i_part ); + } + } + + if ( document->actions.do_index ) + { + Generate_Index( document ); + } + + RB_Free_Links( ); +} + +/*****/ + + +/****f* Generator/RB_Generate_SingleDoc + * FUNCTION + * Create documentation by creating a single file for all individual + * source file that were scanned. + * + * This function is called when the option --singledoc is used. + * Based on whether the option --sections is used this function then + * calls RB_Generate_Sections or RB_Generate_Part + * SYNOPSIS + */ +void RB_Generate_SingleDoc( + struct RB_Document *document ) +/* + * INPUTS + * document -- pointer to the RB_Document structure. + * SOURCE + */ +{ + FILE *document_file; + struct RB_Part *i_part; + + RB_Document_Collect_Headers( document ); + if ( document->actions.do_nosort ) + { + /* Nothing */ + } + else + { + RB_Document_Sort_Headers( document ); + } + RB_Document_Link_Headers( document ); + RB_Fill_Header_Filename( document ); + RB_Name_Headers( document->headers, document->no_headers ); + RB_Sort_Items( document->headers, document->no_headers ); + RB_CollectLinks( document, document->headers, document->no_headers ); + + for ( i_part = document->parts; i_part != NULL; i_part = i_part->next ) + { + RB_Set_FullDocname( i_part->filename, document->singledoc_name ); + } + + if ( output_mode == HTML ) + { + RB_Create_CSS( document ); + } + + document_file = RB_Open_SingleDocumentation( document ); + assert( document->parts->filename->name ); + + + RB_Generate_Doc_Start( document, + document_file, + document->srcroot->name, + document->singledoc_name, 1, + document->singledoc_name, document->charset ); + + if ( ( document->actions.do_toc ) && document->no_headers ) + { + RB_Generate_TOC_2( document_file, + document->headers, document->no_headers, NULL, + document->parts->filename->name ); + } + if ( document->actions.do_sections ) + { + RB_Generate_Sections( document_file, document ); + } + else + { + for ( i_part = document->parts; + i_part != NULL; i_part = i_part->next ) + { + RB_Generate_Part( document_file, document, i_part ); + } + } + + RB_Generate_Doc_End( document_file, "singledoc", + document->srcroot->name ); + fclose( document_file ); + + RB_Free_Links( ); +} + +/******/ + + +/****f* Generator/RB_Generate_Sections + * FUNCTION + * Creates the documentation for all headers found in all source + * files. The order in which they are generated depends on the + * header hierarchy. First the top level header's documentation + * is generated then, the documentation for all it's childern, then + * the next top level header's documentation is generated. + * This is a recursive proces. + * The idea is to create something like: + * 1. Parentheader1 + * 1.1 Child1 + * 1.2 Child2 + * 1.2.1 Child's child1 + * 2. Parentheader2 + * etc + * SYNOPSIS + */ +void RB_Generate_Sections( + FILE *document_file, + struct RB_Document *document ) +/* + * INPUTS + * o document_file -- destination file. + * o document -- pointer to the RB_Document structure. + * SOURCE + */ +{ + unsigned long i; + int depth = 1; + struct RB_header *header; + + depth = document->first_section_level; + + RB_Say( "Generating Sections\n", SAY_INFO ); + for ( i = 0; i < document->no_headers; ++i ) + { + header = ( document->headers )[i]; + if ( header->parent ) + { + /* This will be in one of the subsections */ + } + else + { + RB_Generate_Section( document_file, header, document, depth ); + } + } +} + +/******/ + + + +/****f* Generator/RB_Generate_Section + * FUNCTION + * Generate the documentation for a header and all + * its childern. + * INPUTS + * o document_file -- destination file + * o parent -- the parent of the header for which the documentation + * is to be generated. + * o document -- pointer to the RB_Document structure. + * o depth -- level of sectioning ( 1 1.1 1.1.1 etc) + * SYNOPSIS + */ +void RB_Generate_Section( + FILE *document_file, + struct RB_header *parent, + struct RB_Document *document, + int depth ) +/* + * NOTE + * This is a recursive function. + * SEE ALSO + * RB_Generate_Sections + * SOURCE + */ +{ + unsigned long i; + struct RB_header *header; + char *headername; + + // We pass either modulename/name or just the name + if ( course_of_action.do_sectionnameonly ) + { + headername = parent->function_name; + } + else + { + headername = parent->name; + } + + switch ( output_mode ) + { + case XMLDOCBOOK: + { + RB_Generate_BeginSection( document_file, depth, headername, + parent ); + /* Docbook output does not like the labels to be + * generated before the
    part + */ + Generate_Label( document_file, parent->unique_name ); + Generate_Label( document_file, parent->name ); + } + break; + /* lowtexx 21.09.2005 11:37 */ + case LATEX: + { + RB_Generate_BeginSection( document_file, depth, headername, + parent ); + /* We have to start section before labeling in latex */ + Generate_Label( document_file, parent->unique_name ); + Generate_Label( document_file, parent->name ); + } + break; + /* --- */ + default: + { + Generate_Label( document_file, parent->unique_name ); + Generate_Label( document_file, parent->name ); + RB_Generate_BeginSection( document_file, depth, headername, + parent ); + } + break; + } + + RB_Generate_Nav_Bar( document, document_file, parent ); + RB_Generate_Index_Entry( document_file, document->doctype, parent ); + Generate_Header( document_file, document, parent, "dummy" ); + for ( i = 0; i < document->no_headers; ++i ) + { + header = ( document->headers )[i]; + if ( header->parent == parent ) + { + RB_Generate_Section( document_file, header, document, depth + 1 ); + } + else + { + /* Leeg */ + } + } + RB_Generate_EndSection( document_file, depth, parent->name ); +} + +/******/ + + + +/****f* Generator/RB_Generate_Part + * FUNCTION + * Generate the documention for all the headers found in a single + * source file. + * SYNOPSIS + */ +void RB_Generate_Part( + FILE *document_file, + struct RB_Document *document, + struct RB_Part *part ) +/* + * INPUTS + * * document_file -- The file were it stored. + * * document -- All the documentation. + * * part -- pointer to a RB_Part that contains all the headers found + * in a single source file. + * SOURCE + */ +{ + struct RB_header *i_header; + char *docname = NULL; + char *srcname = Get_Fullname( part->filename ); + + RB_Say( "generating documentation for file \"%s\"\n", SAY_INFO, srcname ); + if ( document->actions.do_singledoc ) + { + docname = document->singledoc_name; + } + else if ( document->actions.do_multidoc ) + { + docname = RB_Get_FullDocname( part->filename ); + } + else if ( document->actions.do_singlefile ) + { + docname = document->singledoc_name; + } + else + { + assert( 0 ); + } + + if ( output_mode == TROFF ) + { + RB_TROFF_Set_Param( document->compress, document->section ); + } + + + for ( i_header = part->headers; i_header; i_header = i_header->next ) + { + RB_Say( "generating documentation for header \"%s\"\n", SAY_INFO, + i_header->name ); + document_file = RB_Generate_Header_Start( document_file, i_header ); + RB_Generate_Nav_Bar( document, document_file, i_header ); + RB_Generate_Index_Entry( document_file, document->doctype, i_header ); + Generate_Header( document_file, document, i_header, docname ); + RB_Generate_Header_End( document_file, i_header ); + } +} + +/******/ + + +/****f* Generator/RB_Get_DOT_Type + * FUNCTION + * Returns the type of the DOT file for the given output mode + * SOURCE + */ +char *RB_Get_DOT_Type( + void ) +{ + switch ( output_mode ) + { + case HTML: + return DOT_HTML_TYPE; + break; + + case LATEX: + return DOT_LATEX_TYPE; + break; + + default: + break; + } + + return NULL; +} + +/******/ + + +/****f* Generator/RB_Generate_DOT_Image_Link + * FUNCTION + * Generates the image link for the created dot graphics + * SOURCE + */ +void RB_Generate_DOT_Image_Link( + FILE *f, + int dot_nr, + char *dot_type ) +{ + switch ( output_mode ) + { + case HTML: + fprintf( f, "\n", DOT_GRAPH_NAME, dot_nr, + dot_type ); + break; + + case LATEX: + { + char str[TEMP_BUF_SIZE]; + + // First we need to convert graph to PDF + // (maybe the user is using pdflatex) +#if defined(RB_MSVC) + sprintf( str, "%s %s%d.%s", EPSTOPDF_NAME, + DOT_GRAPH_NAME, dot_nr, dot_type ); +#else + snprintf( str, sizeof( str ), "%s %s%d.%s", EPSTOPDF_NAME, + DOT_GRAPH_NAME, dot_nr, dot_type ); +#endif + system( str ); + + fprintf( f, "\\includegraphics{%s%d}\n", DOT_GRAPH_NAME, dot_nr ); + } + break; + + default: + break; + } +} + +/******/ + +/****f* Generator/Generate_Item + * SYNOPSIS + */ +static void Generate_Item( + FILE *f, + struct RB_Document *document, + struct RB_header *header, + struct RB_Item *cur_item, + char *docname ) + /* + * FUNCTION + * Generate the documentation for a single item. + * SOURCE + */ +{ + static int dot_nr = 1; + int line_nr; + char *dot_type = NULL; + FILE *tool = NULL; // Pipe handler to the tool we use + enum ItemType item_type = cur_item->type; + char *name = configuration.items.names[item_type]; + + + Generate_Item_Name( f, item_type ); + RB_Generate_Item_Begin( f, name ); + for ( line_nr = 0; line_nr < cur_item->no_lines; ++line_nr ) + { + struct RB_Item_Line *item_line = cur_item->lines[line_nr]; + char *line = item_line->line; + + // Plain item lines + if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_PLAIN ) ) + { + Format_Line( f, item_line->format ); + Generate_Item_Line( f, line, item_type, docname, header ); + } + // Last line + else if ( item_line->kind == ITEM_LINE_END ) + { + Format_Line( f, item_line->format ); + } + // Normal Pipes + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_PIPE ) ) + { + Format_Line( f, item_line->format ); + if ( item_line->pipe_mode == output_mode ) + { + Pipe_Line( f, line ); + } + } + // Tool start + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_TOOL_START ) ) + { + Format_Line( f, item_line->format ); + + // Change to docdir + RB_Change_To_Docdir( document ); + + // Open pipe to tool + tool = Open_Pipe( line ); + + // Get back to working dir + RB_Change_Back_To_CWD( ); + } + // Tool (or DOT) body + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_TOOL_BODY ) ) + { + if ( tool != NULL ) + { + fprintf( tool, "%s\n", line ); + } + } + // Tool end + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_TOOL_END ) ) + { + // Close pipe + Close_Pipe( tool ); + tool = NULL; + } + // DOT start + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_DOT_START ) ) + { + Format_Line( f, item_line->format ); + + // Get DOT file type + dot_type = RB_Get_DOT_Type( ); + + if ( dot_type ) + { + char pipe_str[TEMP_BUF_SIZE]; + + // Change to docdir + RB_Change_To_Docdir( document ); +#if defined(RB_MSVC) + sprintf( pipe_str, + "%s -T%s -o%s%d.%s", dot_name, + dot_type, DOT_GRAPH_NAME, dot_nr, dot_type ); +#else + snprintf( pipe_str, sizeof( pipe_str ), + "%s -T%s -o%s%d.%s", dot_name, + dot_type, DOT_GRAPH_NAME, dot_nr, dot_type ); +#endif + tool = Open_Pipe( pipe_str ); + } + } + // DOT end + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_DOT_END ) ) + { + if ( tool ) + { + // Close pipe + Close_Pipe( tool ); + tool = NULL; + + // Generate link to image + RB_Generate_DOT_Image_Link( f, dot_nr, dot_type ); + + // Get back to working dir + RB_Change_Back_To_CWD( ); + + // Increment dot file number + dot_nr++; + } + } + // DOT file include + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_DOT_FILE ) ) + { + Format_Line( f, item_line->format ); + + // Get DOT file type + dot_type = RB_Get_DOT_Type( ); + + if ( dot_type ) + { + char str[TEMP_BUF_SIZE]; + + // Change to docdir + RB_Change_To_Docdir( document ); + +#if defined(RB_MSVC) + sprintf( str, + "%s -T%s \"%s/%s\" -o%s%d.%s", dot_name, + dot_type, RB_Get_Saved_CWD( ), line, + DOT_GRAPH_NAME, dot_nr, dot_type ); +#else + snprintf( str, sizeof( str ), + "%s -T%s \"%s/%s\" -o%s%d.%s", dot_name, + dot_type, RB_Get_Saved_CWD( ), line, + DOT_GRAPH_NAME, dot_nr, dot_type ); +#endif + system( str ); + + // Generate link to image + RB_Generate_DOT_Image_Link( f, dot_nr, dot_type ); + + // Get back to working dir + RB_Change_Back_To_CWD( ); + + // Increment dot file number + dot_nr++; + } + } + // Exec item + else if ( !Works_Like_SourceItem( item_type ) && + ( item_line->kind == ITEM_LINE_EXEC ) ) + { + Format_Line( f, item_line->format ); + + // Change to docdir + RB_Change_To_Docdir( document ); + + // Execute line + system( line ); + + // Get back to working dir + RB_Change_Back_To_CWD( ); + } + // Source lines + else if ( Works_Like_SourceItem( item_type ) ) + { + Format_Line( f, item_line->format ); + Generate_Item_Line( f, line, item_type, docname, header ); + } + else + { + /* This item line is ignored */ + } + } + RB_Generate_Item_End( f, name ); +} + +/******/ + + +/****f* Generator/Generate_Header + * FUNCTION + * Generate the documentation for all the items found in + * a header except for any items specified in + * configuration.ignore_items. + * SYNOPSIS + */ +static void Generate_Header( + FILE *f, + struct RB_Document *document, + struct RB_header *header, + char *docname ) +/* + * INPUTS + * * f -- destination file + * * header -- header to be searched. + * * srcname -- name of the source file the header was found in. + * * document -- name of the documentation file. + * BUGS + * This skips the first item body if the first item name was + * not correctly spelled. + * SOURCE + */ +{ + struct RB_Item *cur_item; + + for ( cur_item = header->items; cur_item; cur_item = cur_item->next ) + { + enum ItemType item_type = cur_item->type; + char *name = configuration.items.names[item_type]; + + if ( Is_Ignore_Item( name ) ) + { + /* User does not want this item */ + } + else if ( Works_Like_SourceItem( item_type ) + && ( course_of_action.do_nosource ) ) + { + /* User does not want source items */ + } + else + { + Generate_Item( f, document, header, cur_item, docname ); + } + } +} + +/******/ + + +static void Pipe_Line( + FILE *dest_doc, + char *arg_line ) +{ + char *cur_char = arg_line; + + for ( ; *cur_char && ( *cur_char == ' ' || *cur_char == '\t' ); + cur_char++ ) + { + fputc( *cur_char, dest_doc ); + } + fprintf( dest_doc, "%s%s", cur_char, + ( output_mode == RTF ? "\\line" : "\n" ) ); +} + + +static void Format_Line( + FILE *dest_doc, + long format ) +{ + if ( format & RBILA_END_LIST_ITEM ) + { + Generate_End_List_Item( dest_doc ); + } + if ( format & RBILA_END_LIST ) + { + Generate_End_List( dest_doc ); + } + if ( format & RBILA_END_PRE ) + { + Generate_End_Preformatted( dest_doc ); + } + if ( format & RBILA_BEGIN_PARAGRAPH ) + { + Generate_Begin_Paragraph( dest_doc ); + } + if ( format & RBILA_END_PARAGRAPH ) + { + Generate_End_Paragraph( dest_doc ); + } + if ( format & RBILA_BEGIN_PRE ) + { + Generate_Begin_Preformatted( dest_doc, + ( format & RBILA_BEGIN_SOURCE ) ); + } + if ( format & RBILA_BEGIN_LIST ) + { + Generate_Begin_List( dest_doc ); + } + if ( format & RBILA_BEGIN_LIST_ITEM ) + { + Generate_Begin_List_Item( dest_doc ); + } +} + + + +static void Generate_Begin_List_Item( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_Begin_List_Item( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_Begin_List_Item( dest_doc ); + break; + case HTML: + HTML_Generate_Begin_List_Item( dest_doc ); + break; + case LATEX: + LaTeX_Generate_Begin_List_Item( dest_doc ); + break; + case RTF: + break; + case TROFF: + TROFF_Generate_Begin_List_Item( dest_doc ); + break; + break; + case ASCII: + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +static void Generate_End_List_Item( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_End_List_Item( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_End_List_Item( dest_doc ); + break; + case HTML: + HTML_Generate_End_List_Item( dest_doc ); + break; + case LATEX: + LaTeX_Generate_End_List_Item( dest_doc ); + break; + case RTF: + break; + case TROFF: + TROFF_Generate_End_List_Item( dest_doc ); + break; + break; + case ASCII: + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +static void Generate_Begin_List( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_Begin_List( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_Begin_List( dest_doc ); + break; + case HTML: + HTML_Generate_Begin_List( dest_doc ); + break; + case LATEX: + LaTeX_Generate_Begin_List( dest_doc ); + break; + + case RTF: + case TROFF: + case ASCII: + break; + + case UNKNOWN: + default: + assert( 0 ); + } +} + +/* TODO FS Document */ + +static void Generate_End_List( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_End_List( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_End_List( dest_doc ); + break; + case HTML: + HTML_Generate_End_List( dest_doc ); + break; + case LATEX: + LaTeX_Generate_End_List( dest_doc ); + break; + + case RTF: + case TROFF: + case ASCII: + break; + + case UNKNOWN: + default: + assert( 0 ); + } +} + + +/* TODO FS Document */ + +static void Generate_Begin_Preformatted( + FILE *dest_doc, + int source ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_Begin_Preformatted( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_Begin_Preformatted( dest_doc ); + break; + case HTML: + HTML_Generate_Begin_Preformatted( dest_doc, source ); + break; + case LATEX: + LaTeX_Generate_Begin_Preformatted( dest_doc ); + break; + case RTF: + break; + case TROFF: + TROFF_Generate_Begin_Preformatted( dest_doc ); + break; + case ASCII: + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +/* TODO FS Document */ +static void Generate_End_Preformatted( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_End_Preformatted( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_End_Preformatted( dest_doc ); + break; + case HTML: + HTML_Generate_End_Preformatted( dest_doc ); + break; + case LATEX: + LaTeX_Generate_End_Preformatted( dest_doc ); + break; + case RTF: + break; + case TROFF: + TROFF_Generate_End_Preformatted( dest_doc ); + break; + case ASCII: + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +/* TODO FS Document */ +static void Generate_End_Paragraph( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_End_Paragraph( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_End_Paragraph( dest_doc ); + break; + case HTML: + HTML_Generate_End_Paragraph( dest_doc ); + break; + case LATEX: + LaTeX_Generate_End_Paragraph( dest_doc ); + break; + case RTF: + break; + case TROFF: + TROFF_Generate_End_Paragraph( dest_doc ); + break; + case ASCII: + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +/* TODO FS Document */ +static void Generate_Begin_Paragraph( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + TEST_Generate_Begin_Paragraph( dest_doc ); + break; + case XMLDOCBOOK: + XMLDB_Generate_Begin_Paragraph( dest_doc ); + break; + case HTML: + HTML_Generate_Begin_Paragraph( dest_doc ); + break; + case LATEX: + LaTeX_Generate_Begin_Paragraph( dest_doc ); + break; + case RTF: + break; + case TROFF: + TROFF_Generate_Begin_Paragraph( dest_doc ); + break; + case ASCII: + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +#if 0 +/*x**f* Generator/RB_Generate_Empty_Item + * FUNCTION + * Generate documentation for an item with an empty body. + * INPUTS + * dest_doc -- destination file. + **** + * TODO Documentation + */ + +static void RB_Generate_Empty_Item( + FILE *dest_doc ) +{ + switch ( output_mode ) + { + case TEST: + break; + case XMLDOCBOOK: + break; + case HTML: + RB_HTML_Generate_Empty_Item( dest_doc ); + break; + case LATEX: + RB_LaTeX_Generate_Empty_Item( dest_doc ); + break; + case RTF: + RB_RTF_Generate_Empty_Item( dest_doc ); + break; + case TROFF: + break; + case ASCII: + RB_ASCII_Generate_Empty_Item( dest_doc ); + break; + case UNKNOWN: + default: + assert( 0 ); + } +} +#endif + + + +static void Generate_Item_Line( + FILE *dest_doc, + char *line, + int item_type, + char *docname, + struct RB_header *fnames ) +{ + char *cur_char = line; + char *object_name = NULL; + char *label_name = NULL; + char *file_name = NULL; + + enum EIL_State + { SKIP_ALPHANUM, SKIP_SPACE, SEARCH_LINK_START_WORD, SEARCH_LINK } + state = SKIP_SPACE; + + for ( ; *cur_char; cur_char++ ) + { + char c = *cur_char; + + /* This is a little statemachine to switch searching for + * links on and off. A link can be found for a word + * or for a word combined with some punctuation + * characters. A word is a string of alpha numeric + * characters (including a '_'), say FunctionAA_10_B + * All other characters are punctuation characters. + * We do not want links to start in the middle of a word, + * but they can start after or on a punctuation character. + * So for a link can start at + * Foo_bar::SnaFu + * ^ ^^^ + * | ||| + * + */ + + /* Move to the next state based on current character. */ + switch ( state ) + { + case SKIP_SPACE: + /* In this state we try to skip of a string of space + * characters until we find something else. + */ + { + if ( utf8_ispunct( c ) ) + { + /* we were in the process of skipping spaces, + * but now we found a non-space character. + * This might be the begin of a link, so + * switch to the search link state. + */ + state = SEARCH_LINK; + } + else if ( utf8_isalnum( c ) || ( c == '_' ) ) + { + state = SEARCH_LINK_START_WORD; + } + else + { + /* Links can only start with a none space character, + * so if the current charater is a space, we skip it. + */ + } + break; + } + case SKIP_ALPHANUM: + /* In this state we skipping a string of alpha + * numeric charaters after that the first + * character in this string did not result in a + * link. + */ + { + if ( utf8_isspace( c ) ) + { + /* We found the end of the string, so we go + * back to the space skipping state + */ + state = SKIP_SPACE; + } + else if ( utf8_ispunct( c ) && ( c != '_' ) ) + { + /* We found a puntuation character, this end + * the string of alpha numeric character, but + * can be the begin of a new link, so we + * switch to the seach link state. + */ + state = SEARCH_LINK; + } + else + { + /* We stay in this state */ + } + } + break; + case SEARCH_LINK_START_WORD: + /* In this state we are at the start of a string + * of alpha numeric characters. + */ + { + if ( utf8_isalnum( c ) || ( c == '_' ) ) + { + /* We are not at the second character of + * a string of alpha numeric characters, + * we can stop searching for links, as a + * link can only start at the begin of + * such a string. + */ + state = SKIP_ALPHANUM; + } + else if ( utf8_ispunct( c ) && ( c != '_' ) ) + { + state = SEARCH_LINK; + } + else if ( utf8_isspace( c ) ) + { + state = SKIP_SPACE; + } + else + { + state = SKIP_SPACE; + } + } + break; + case SEARCH_LINK: + { + /* In this state we search for links. We stop + * searching if we encounter a space because this + * marks end of the word, + */ + if ( utf8_isalnum( c ) || ( c == '_' ) ) + { + /* We are at the start of a word. + */ + state = SEARCH_LINK_START_WORD; + } + else if ( utf8_isspace( c ) ) + { + state = SKIP_SPACE; + } + else + { + /* We stay in this state */ + } + } + break; + default: + assert( 0 ); + break; + } + + if ( ( ( state == SEARCH_LINK ) || + ( state == SEARCH_LINK_START_WORD ) ) && + Find_Link( cur_char, &object_name, &label_name, &file_name ) ) + { + /* We found a link, so we can stop searching for one + * for now. + */ + state = SKIP_SPACE; + + if ( object_name && fnames->no_names > 0 ) + { + extern char *function_name( + char * ); + int i; + + for ( i = 0; i < fnames->no_names; i++ ) + if ( strcmp + ( object_name, + function_name( fnames->names[i] ) ) == 0 ) + break; + if ( i < fnames->no_names ) + { + RB_Generate_False_Link( dest_doc, object_name ); + cur_char += strlen( object_name ) - 1; + } + else + { + Generate_Link( dest_doc, docname, + file_name, label_name, object_name ); + cur_char += strlen( object_name ) - 1; + } + } + else + { + assert( 0 ); + } + } + else + { + int res = + RB_HTML_Extra( dest_doc, item_type, cur_char, + ( cur_char == line ) ? 0 : *( cur_char - 1 ) ); + + if ( res >= 0 ) + { + cur_char += res; + } + else + { + /* convert from signed to unsigned */ + unsigned char c2 = *cur_char; + + Generate_Char( dest_doc, c2 ); + } + } + } + + /* TODO Move to the RTF_Generator */ + switch ( output_mode ) + { + case RTF: + fprintf( dest_doc, "\\line" ); + break; + + case TROFF: + RB_TROFF_Start_New_Line( dest_doc ); + break; + + case HTML: + // Check for source line comment endings + RB_HTML_Generate_Line_Comment_End( dest_doc ); + break; + + case TEST: + case ASCII: + case LATEX: + case XMLDOCBOOK: + case UNKNOWN: + break; + default: + break; + } + + /* For all modes we add a newline. */ + fputc( '\n', dest_doc ); +} + + + +/****f* Generator/Generate_Link + * FUNCTION + * Generate a link to another headers documentation. + * SYNOPSIS + */ +void Generate_Link( + FILE *dest_doc, + char *docname, + char *file_name, + char *label_name, + char *function_name ) +/* + * INPUTS + * * dest_doc -- the output file + * * docname -- the name of the output file + * * file_name -- the name of the file that contains the link's body + * * label_name -- the label for the link + * * function_name -- the name that is shown for the link in the + * documentation + * SOURCE + */ +{ + + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Link( dest_doc, docname, file_name, label_name, + function_name ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Link( dest_doc, docname, file_name, label_name, + function_name ); + break; + case HTML: + RB_HTML_Generate_Link( dest_doc, docname, file_name, label_name, + function_name, NULL ); + break; + case RTF: + RB_RTF_Generate_Link( dest_doc, docname, file_name, label_name, + function_name ); + break; + case LATEX: + RB_LaTeX_Generate_String( dest_doc, function_name ); + /* lowtexx 21.09.2005 11:43 */ + /* generate a simple link here */ + RB_LaTeX_Generate_Link( dest_doc, docname, file_name, label_name, + function_name ); + break; + case UNKNOWN: + case ASCII: + case TROFF: + default: + fprintf( dest_doc, "%s", function_name ); + } +} + +/******/ + + +/****f* Generator/Generate_Char + * FUNCTION + * Generate a single character in the current output mode. + * The individual generators will make sure that special + * characters are escaped. + * SYNOPSIS + */ +void Generate_Char( + FILE *dest_doc, + int cur_char ) +/* + * INPUTS + * * dest_doc -- destination file. + * * cur_char -- character to be generated. + ******* + */ +{ + switch ( output_mode ) + { + case TEST: + RB_TEST_Generate_Char( dest_doc, cur_char ); + break; + case XMLDOCBOOK: + RB_XMLDB_Generate_Char( dest_doc, cur_char ); + break; + case HTML: + RB_HTML_Generate_Char( dest_doc, cur_char ); + break; + case LATEX: + RB_LaTeX_Generate_Char( dest_doc, cur_char ); + break; + case RTF: + RB_RTF_Generate_Char( dest_doc, cur_char ); + break; + case TROFF: + RB_TROFF_Generate_Char( dest_doc, cur_char ); + break; + case ASCII: + RB_ASCII_Generate_Char( dest_doc, cur_char ); + break; + case UNKNOWN: + default: + assert( 0 ); + } +} + + +/****f* Generator/RB_Get_SubIndex_FileName + * FUNCTION + * Get the name of the master index file for a specific + * header_type. + * SYNOPSIS + */ +char *RB_Get_SubIndex_FileName( + char *docroot, + char *extension, + struct RB_HeaderType *header_type ) +/* + * INPUTS + * * docroot -- the path to the documentation directory. + * * extension -- the extension for the file + * * header_type -- the header type + * RESULT + * a pointer to a freshly allocated string. + * NOTES + * Has too many parameters. + * SOURCE + */ +{ + size_t l; + char *filename; + + assert( docroot ); + + l = strlen( docroot ); + + l += RB_Get_Len_Extension( extension ); + l += strlen( docroot ); + l += strlen( header_type->fileName ); + + filename = ( char * ) malloc( l + 2 ); + assert( filename ); + filename[0] = '\0'; + + strcat( filename, docroot ); + strcat( filename, header_type->fileName ); + RB_Add_Extension( extension, filename ); + + return filename; +} + +/*****/ + + +/****f* Generator/Generate_Index + * NAME + * Generate_Index -- generate index file based on xref files. + * SYNOPSIS + */ +static void Generate_Index( + struct RB_Document *document ) +/* + * FUNCTION + * Create a master index file. It contains pointers to the + * documentation generated for each source file, as well as all + * "objects" found in the source files. + * SOURCE + */ +{ + switch ( output_mode ) + { + case TEST: + break; + case XMLDOCBOOK: + break; + case HTML: + RB_HTML_Generate_Index( document ); + break; + case LATEX: + /* RB_LaTeX_Generate_Index(dest, source); */ + /* Latex has a index by default */ + break; + case UNKNOWN: + case ASCII: + case TROFF: + case RTF: + default: + break; + } +} + +/*****/ diff --git a/Source/generator.h b/Source/generator.h new file mode 100644 index 0000000..204825d --- /dev/null +++ b/Source/generator.h @@ -0,0 +1,140 @@ +#ifndef ROBODOC_GENERATOR_H +#define ROBODOC_GENERATOR_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "robodoc.h" +#include "headers.h" +#include "document.h" + +void RB_Generate_Doc_Start( + struct RB_Document *document, + FILE *dest_doc, + char *src_name, + char *title, + char toc, + char *dest_name, + char *charset ); +char *RB_Generate_Item_Body( + FILE *, + char *, + char *, + char *, + char *, + int, + int ); +void RB_Generate_Item_Name( + FILE *, + int ); +void RB_Generate_Doc_End( + FILE *, + char *, + char * ); +FILE *RB_Generate_Header_Start( + FILE *, + struct RB_header * ); +void RB_Generate_Header_End( + FILE *, + struct RB_header * ); +int RB_HTML_Extra( + FILE *dest_doc, + int item_type, + char *cur_char, + char prev_char ); +void RB_Generate_Index_Table( + FILE *dest, + int type, + char *source ); +void RB_Name_Headers( + struct RB_header **headers, + long count ); +void RB_Generate_Documentation( + struct RB_Document * ); +void RB_Generate_Part( + FILE *document_file, + struct RB_Document *document, + struct RB_Part *part ); +void RB_Generate_Header_NG( + FILE *f, + struct RB_Document *document, + struct RB_header *header, + char *srcname, + char *docname ); +char *RB_Get_SubIndex_FileName( + char *docroot, + char *extension, + struct RB_HeaderType *header_type ); +void RB_Add_Extension( + char *extension, + char *name ); +size_t RB_Get_Len_Extension( + char *extension ); +char *RB_Get_Default_Extension( + T_RB_DocType doctype ); +void RB_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ); +void RB_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ); +void RB_Generate_Section( + FILE *document_file, + struct RB_header *parent, + struct RB_Document *document, + int depth ); +void RB_Generate_Sections( + FILE *document_file, + struct RB_Document *document ); +void RB_Generate_SingleDoc( + struct RB_Document *document ); +void RB_Generate_MultiDoc( + struct RB_Document *document ); +void Generate_Link( + FILE *dest_doc, + char *docname, + char *file_name, + char *label_name, + char *function_name ); +void RB_Generate_Item_Begin( + FILE *dest_doc, + char *name ); +void RB_Generate_Item_End( + FILE *dest_doc, + char *name ); +void RB_Generate_Nav_Bar( + struct RB_Document *document, + FILE *current_doc, + struct RB_header *current_header ); +void RB_Generate_TOC_2( + FILE *dest_doc, + struct RB_header **headers, + int count, + struct RB_Part *owner, + char *dest_name ); + + +#endif /* ROBODOC_GENERATOR_H */ diff --git a/Source/globals.c b/Source/globals.c new file mode 100644 index 0000000..9edb766 --- /dev/null +++ b/Source/globals.c @@ -0,0 +1,193 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****h* ROBODoc/Globals + * FUNCTION + * A number of global variables. + * TODO + * Documentation. + ***** + * $Id: globals.c,v 1.22 2007/07/10 19:13:51 gumpu Exp $ + */ + +#include +#include +#include "robodoc.h" +#include "globals.h" +#include "links.h" + +#ifdef DMALLOC +#include +#endif + +int number_of_warnings = 0; + +/* Pointer to the name of the current file that is being analysed, + use by RB_Panic */ + +char *current_file = 0; + +/****v* Globals/document_title + * NAME + * documentat_title -- title for the documentation. + * PURPOSE + * Used as the title for master index files or for latex documentation. + * SOURCE + */ + +char *document_title = NULL; + +/******/ + + +/****v* Globals/output_mode [2.0] + * NAME + * output_mode -- the mode of output + * FUNCTION + * Controls which type of output will be generated. + * SOURCE + */ + +T_RB_DocType output_mode = ASCII; + +/*******/ + + +/****v* Globals/course_of_action [2.0] + * NAME + * course_of_action + * FUNCTION + * Global Variable that defines the course of action. + * SOURCE + */ + +actions_t course_of_action; + +/*******/ + +/****v* Globals/debugmode + * NAME + * debugmode + * FUNCTION + * A bitfield determining the output levels + * SOURCE + */ + +long debugmode = 0; + +/*******/ + + +/****v* Globals/line_buffer [2.0] + * NAME + * line_buffer -- global line buffer + * FUNCTION + * Temporary storage area for lines + * that are read from an input file. + * SOURCE + */ + +char line_buffer[MAX_LINE_LEN]; + +/*******/ + +/****v* Globals/myLine + * NAME + * myLine -- dynamic buffer for current line + * FUNCTION + * Temporary storage area for lines + * that are read from an input file. + * SOURCE + */ + +char *myLine = NULL; + +/*******/ + +/****v* Globals/readChars + * NAME + * readChars -- number of characters in the currently bufferd line + * FUNCTION + * Temporary storage area for lines + * that are read from an input file. + * SOURCE + */ + +int readChars = 0; + +/*******/ + +/****v* Globals/line_number [2.0] + * NAME + * line_number -- global line counter + * PURPOSE + * Keeps track of the number of lines that are read from the source file. + * AUTHOR + * Koessi + * SOURCE + */ + +int line_number = 0; + +/*******/ + +/* + * Global variables + */ +/* TODO Document these. */ + +char *source_file; /* DCD */ +char *whoami = NULL; /* me,myself&i */ +int tab_stops[MAX_TABS]; /* Tab stop positions */ + +// Number of header item names before linebreak +int header_breaks = DEFAULT_HEADER_BREAKS; + + +// Path and filename to dot tool +char *dot_name = DEFAULT_DOT_NAME; + + +/****i* Globals/RB_Close_The_Shop [3.0b] + * NAME + * RB_Close_The_Shop -- free resources. + * SYNOPSIS + * void RB_Close_The_Shop () + * FUNCTION + * Frees all resources used by robodoc. + * SEE ALSO + * RB_Free_Header(), RB_Free_Link() + * SOURCE + */ + +void RB_Close_The_Shop( + void ) +{ +/* TODO if (link_index) { free(link_index); } */ + if ( myLine ) + { + free( myLine ); + } +} + +/******/ diff --git a/Source/globals.h b/Source/globals.h new file mode 100644 index 0000000..c86e17b --- /dev/null +++ b/Source/globals.h @@ -0,0 +1,90 @@ +#ifndef ROBODOC_GLOBALS_H +#define ROBODOC_GLOBALS_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include +#include "robodoc.h" + +/* TODO Try to get rid of as many as these as possible. */ + +#define MAX_LINE_LEN 512 +#define MAX_TABS 256 +#define DEFAULT_TABSIZE 8 +#define TABSIZE_SEPARATOR "," +#define DEFAULT_HEADER_BREAKS 2 +#define MAX_HEADER_BREAKS 255 + +#define TEMP_BUF_SIZE 1024 +#define DEFAULT_DOT_NAME "dot" +#define DOT_GRAPH_NAME "dot_graph_" +#define EPSTOPDF_NAME "epstopdf" +#define DOT_HTML_TYPE "png" +#define DOT_LATEX_TYPE "ps" + +// Class definitions for syntax highlighting +// Note: Should correlate with css file +#define SOURCE_CLASS "source" +#define KEYWORD_CLASS "keyword" +#define COMMENT_CLASS "comment" +#define QUOTE_CLASS "quote" +#define SQUOTE_CLASS "squote" +#define SIGN_CLASS "sign" + +// Default HTML charset +#define DEFAULT_CHARSET "ISO-8859-1" + +// Default document title +#define DEFAULT_DOCTITILE "API Reference" + +// Document title +extern char *document_title; + +extern char *source_file; /* DCD */ + +/* extern T_RB_DocType output_mode; */ +/* extern long course_of_action; */ +/* extern int line_number; */ +void RB_Close_The_Shop( + void ); + +// More ugly globals... Any idea where should we place them? +extern int tab_stops[MAX_TABS]; +extern char *dot_name; +extern int header_breaks; + +/* These are really necessary */ +extern int number_of_warnings; +extern unsigned int link_index_size; +extern struct RB_link **link_index; +extern char *current_file; +extern T_RB_DocType output_mode; +extern actions_t course_of_action; +extern int line_number; +extern char line_buffer[MAX_LINE_LEN]; +extern char *whoami; +extern char *myLine; +extern int readChars; +extern long debugmode; + +#endif /* ROBODOC_GLOBALS_H */ diff --git a/Source/headers.c b/Source/headers.c new file mode 100644 index 0000000..bd2daed --- /dev/null +++ b/Source/headers.c @@ -0,0 +1,720 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* ROBODoc/Headers + * FUNCTION + * This module contains a set of variables that define how headers + * start and how they end in various programming languages. + * NOTES + * Added C++/ACM header option (David White) + * Enables documentation only comments (//!) to be extracted from C++ + * and ACM files, rather than all comments. + ****** + */ + +#include +#include +#include +#include +#include "robodoc.h" +#include "headers.h" +#include "globals.h" +#include "roboconfig.h" +#include "util.h" + +/* This limits the total number of possible markers. */ +/* TODO should be an enum */ +#define NO_MARKER_LOCKED 100000 +#define NO_MARKER 100002 + +static int locked_header_marker = NO_MARKER_LOCKED; +static int locked_end_marker = NO_MARKER_LOCKED; +static int locked_remark_marker = NO_MARKER_LOCKED; + +/****v* Headers/header_markers + * NAME + * header_markers -- strings that mark the begin of a header. + * FUNCTION + * These specify what robodoc recognizes as the beginning + * NOTE + * The numbers at the beginning of the lines make it easier + * to keep them in sync with the src_constants + * of a header. + * SOURCE + */ + +char *header_markers[] = { + "/****", /* 0 C, C++ */ + "//!****", /* 1 C++, ACM */ + "//****", /* 2 C++ */ + "(****", /* 3 Pascal, Modula-2, B52 */ + "{****", /* 4 Pascal */ + ";;!****", /* 5 Aspen Plus */ + ";****", /* 6 M68K assembler */ + "****", /* 7 M68K assembler */ + "C ****", /* 8 Fortran */ + "REM ****", /* 9 BASIC */ + "%****", /* 10 LaTeX, TeX, Postscript */ + "#****", /* 11 Tcl/Tk */ + " ****", /* 12 COBOL */ + "--****", /* 13 Occam */ + "", /* 15 HTML & XML */ + "--->", /* 16 HTML */ + ( char * ) NULL, /* 17 GNU Assembler */ + ( char * ) NULL, /* 18 FORTRAN 90 !! */ + ( char * ) NULL, /* 19 FORTRAN 90 ! */ + ( char * ) NULL, /* 20 VB */ + ( char * ) NULL, /* 21 Aspen Plus */ + ( char * ) NULL /* 22 Forth */ +}; + +/****/ + + +/****v* Headers/robo_end [3.0h] + * NAME + * robo_end[] -- the distinct robodoc end marker - + * alternative to using end_markers + * FUNCTION + * This is an alternative to using end_markers - sometimes ROBODOC + * confuses asterisks commonly used in comments as an end marker. To + * use this footer instead of end_markers use the -rh switch. + * NOTE + * Added by David Druffner. + * SOURCE + */ + +char *robo_end[] = { "/*ROBODOC_END*", "*ROBODOC_END*", NULL }; + +/****/ + + +/***f* Headers/RB_Is_Begin_Marker + * FUNCTION + * Scan a line and see if any of the begin-of-a-header-markers + * defined in header_markers can be found. + * SYNOPSIS + */ +int RB_Is_Begin_Marker( + char *cur_line, + char **type ) +/* + * INPUTS + * cur_line -- line to be searched. + * OUTPUT + * type -- the kind of header + * RESULT + * TRUE -- a begin header was found + * FALSE -- no begin header was found. + * SOURCE + */ +{ + int found = FALSE; + unsigned int marker = NO_MARKER; /* for the assert */ + char *cur_mchar = NULL; + char *cur_char = NULL; + + if ( !( course_of_action.do_robo_head ) + && + ( ( ( course_of_action.do_lockheader ) && + ( locked_header_marker == NO_MARKER_LOCKED ) ) + || !( course_of_action.do_lockheader ) ) ) + { + for ( marker = 0; + ( marker < configuration.header_markers.number ) && !found; + marker++ ) + { + cur_mchar = configuration.header_markers.names[marker]; + for ( found = TRUE, cur_char = RB_Skip_Whitespace( cur_line ); + *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) + { + if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) + found = FALSE; + } + if ( *cur_mchar != '\0' ) + { + /* It is not a complete match */ + found = FALSE; + } + } + } + else if ( ( course_of_action.do_lockheader ) && + ( locked_header_marker != NO_MARKER_LOCKED ) ) + { + cur_mchar = configuration.header_markers.names[locked_header_marker]; + for ( found = TRUE, cur_char = RB_Skip_Whitespace( cur_line ); + *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) + { + if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) + { + found = FALSE; + } + if ( *cur_mchar != '\0' ) + { + /* It is not a complete match */ + found = FALSE; + } + } + } + else + { + assert( 0 ); + } + + + if ( found && cur_char ) + { + *type = cur_char; + ++cur_char; + if ( *cur_char == '*' ) + { + ++cur_char; + found = utf8_isspace( *cur_char ); + } + else if ( *( cur_char + 1 ) == '*' ) + { + ++cur_char; + ++cur_char; + found = utf8_isspace( *cur_char ); + } + else + { + found = FALSE; + } + if ( found ) + { + found = FALSE; + /* It should contain some non * characters. */ + for ( ; *cur_char; ++cur_char ) + { + if ( utf8_isalnum( *cur_char ) ) + { + found = TRUE; + } + } + } + } + + if ( found && + ( course_of_action.do_lockheader ) && + ( locked_header_marker == NO_MARKER_LOCKED ) ) + { + assert( marker != NO_MARKER ); + locked_header_marker = marker - 1; + RB_Say( "header marker locked on %s\n", SAY_INFO, + configuration.header_markers.names[locked_header_marker] ); + } + return found; +} + +/******/ + + +/* Generic function to skip a remark begin or end marker */ + +static char *RB_Skip_Remark_XXX_Marker( + char *cur_line, + struct Parameters *parameters ) +{ + char *cur_char; + char *space_pos; + unsigned int marker; + int found = FALSE; + + cur_char = RB_Skip_Whitespace( cur_line ); + space_pos = strchr( cur_char, ' ' ); + /* Replace the first space on the line with a '\0' + * this makes the comparison with the remark markers + * much easier. + */ + if ( space_pos ) + { + *space_pos = '\0'; + } + + for ( marker = 0; ( marker < parameters->number ) && !found; marker++ ) + { + found = + ( RB_Str_Case_Cmp( cur_char, parameters->names[marker] ) == 0 ); + } + + assert( found ); + + if ( space_pos ) + { + *space_pos = ' '; + return space_pos; + } + else + { + return cur_char + strlen( parameters->names[marker - 1] ); + } +} + + +/* Generic function to see if there is a remark begin or end marker */ + +static int RB_Is_Remark_XXX_Marker( + char *cur_line, + struct Parameters *parameters ) +{ + char *cur_char; + char *space_pos; + unsigned int marker; + int found = FALSE; + + cur_char = RB_Skip_Whitespace( cur_line ); + space_pos = strchr( cur_char, ' ' ); + /* Replace the first space on the line with a '\0' + * this makes the comparison with the remark markers + * much easier. + */ + if ( space_pos ) + { + *space_pos = '\0'; + } + + for ( marker = 0; ( marker < parameters->number ) && !found; marker++ ) + { + found = + ( RB_Str_Case_Cmp( cur_char, parameters->names[marker] ) == 0 ); + } + + if ( space_pos ) + { + *space_pos = ' '; + } + + return found; +} + + +/* TODO Documentation */ +int RB_Is_Remark_End_Marker( + char *cur_line ) +{ + return RB_Is_Remark_XXX_Marker( cur_line, + &( configuration.remark_end_markers ) ); +} + +/* TODO Documentation */ +int RB_Is_Remark_Begin_Marker( + char *cur_line ) +{ + return RB_Is_Remark_XXX_Marker( cur_line, + &( configuration.remark_begin_markers ) ); +} + +char *RB_Skip_Remark_Begin_Marker( + char *cur_line ) +{ + return RB_Skip_Remark_XXX_Marker( cur_line, + &( configuration. + remark_begin_markers ) ); +} + +char *RB_Skip_Remark_End_Marker( + char *cur_line ) +{ + return RB_Skip_Remark_XXX_Marker( cur_line, + &( configuration.remark_end_markers ) ); +} + + +/****f* Headers/RB_Is_End_Marker + * FUNCTION + * Scan a line and see if any of the end of a header markers + * defined in header_markers can be found. + * SYNOPSIS + */ +int RB_Is_End_Marker( + char *cur_line ) +/* + * INPUTS + * cur_line -- line to be searched. + * OUTPUT + * none + * RESULT + * TRUE -- an end header was found + * FALSE -- none was found. + * SOURCE + */ +{ + int found = FALSE; + unsigned int marker = NO_MARKER; /* For the assert */ + char *cur_mchar; + char *cur_char; + + if ( !( course_of_action.do_robo_head ) + && + ( ( ( course_of_action.do_lockheader ) && + ( locked_end_marker == NO_MARKER_LOCKED ) ) + || !( course_of_action.do_lockheader ) ) ) + { + for ( marker = 0; + ( marker < configuration.end_markers.number ) && !found; + marker++ ) + { + cur_mchar = configuration.end_markers.names[marker]; + cur_char = RB_Skip_Whitespace( cur_line ); + if ( *cur_char ) + { + for ( found = TRUE; + *cur_mchar && *cur_char && found; + cur_mchar++, cur_char++ ) + { + if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) + { + found = FALSE; + } + } + } + } + } + else if ( ( course_of_action.do_lockheader ) && + ( locked_end_marker != NO_MARKER_LOCKED ) ) + { + cur_mchar = configuration.end_markers.names[locked_end_marker]; + cur_char = RB_Skip_Whitespace( cur_line ); + if ( *cur_char ) + { + for ( found = TRUE; + *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) + { + if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) + { + found = FALSE; + } + } + } + } + else + { + assert( 0 ); + } + + /* Locking on end markers does not work at the moment, + * because there can be more than one end marker for + * a given language. TODO + */ +#if 0 + if ( found && + ( course_of_action.do_LOCKHEADER ) && + ( locked_end_marker == NO_MARKER_LOCKED ) ) + { + assert( marker != NO_MARKER ); + locked_end_marker = marker - 1; + RB_Say( "end marker locked on %s\n", SAY_INFO, + end_markers[locked_end_marker] ); + } +#endif + return found; +} + +/*****/ + + +/****f* Headers/RB_Has_Remark_Marker + * FUNCTION + * Check if a line starts with a remark marker. This function + * assumes that the remark marker starts on the first character of + * the line. + * SYNOPSIS + */ +int RB_Has_Remark_Marker( + char *lline_buffer ) +/* + * INPUTS + * o lline_buffer -- the line of text. + * RESULT + * o TRUE -- it starts with a remark marker + * o FALSE -- it does not. + * SOURCE + */ +{ + unsigned int marker = 0; + unsigned int marker_found = configuration.remark_markers.number; + int found = FALSE; + char *space_pos = NULL; + + space_pos = strchr( lline_buffer, ' ' ); + + /* Replace the first space on the line with a '\0' + * this makes the comparison with the remark markers + * much easier. + */ + if ( space_pos ) + { + *space_pos = '\0'; + } + + if ( ( ( course_of_action.do_lockheader ) && + ( locked_remark_marker == NO_MARKER_LOCKED ) ) + || !( course_of_action.do_lockheader ) ) + { + for ( marker = 0; marker < configuration.remark_markers.number; + marker++ ) + { + if ( RB_Str_Case_Cmp + ( lline_buffer, + configuration.remark_markers.names[marker] ) == 0 ) + { + marker_found = marker; + found = TRUE; + } + } + } + else + { + if ( RB_Str_Case_Cmp + ( lline_buffer, + configuration.remark_markers.names[locked_remark_marker] ) == + 0 ) + { + marker_found = marker; + found = TRUE; + } + } + + if ( found && + ( locked_remark_marker == NO_MARKER_LOCKED ) + && ( course_of_action.do_lockheader ) ) + { + assert( marker_found < configuration.remark_markers.number ); + locked_remark_marker = marker_found; + RB_Say( "remark marker locked on %s\n", SAY_INFO, + configuration.remark_markers.names[locked_remark_marker] ); + } + + /* Restore the space we replaced with a '\0' */ + if ( space_pos ) + { + *space_pos = ' '; + } + + return found; +} + +/******/ + + +/****f* Headers/RB_Skip_Remark_Marker [2.0e] + * NAME + * RB_Skip_Remark_Marker + * SYNOPSIS + */ +char *RB_Skip_Remark_Marker( + char *lline_buffer ) +/* + * FUNCTION + * Scan and search for a recognized remark marker; skip past the + * marker to the body of the text + * SOURCE + */ +{ + unsigned int marker, found; + char *cur_char, *cur_mchar; + + found = FALSE; + cur_char = NULL; + for ( marker = 0; + ( marker < configuration.remark_markers.number ) && !found; + marker++ ) + { + cur_mchar = configuration.remark_markers.names[marker]; + for ( found = TRUE, cur_char = lline_buffer; + *cur_mchar && *cur_char && found; cur_mchar++, cur_char++ ) + { + if ( tolower( *cur_mchar ) != tolower( *cur_char ) ) + { + found = FALSE; + } + } + } + return ( cur_char ); +} + +/**************/ + + + + +/* TODO Documentation */ +void RB_Header_Lock_Reset( + void ) +{ + locked_header_marker = NO_MARKER_LOCKED; + locked_end_marker = NO_MARKER_LOCKED; +} + +void RB_Item_Lock_Reset( + void ) +{ + locked_remark_marker = NO_MARKER_LOCKED; +} diff --git a/Source/headers.h b/Source/headers.h new file mode 100644 index 0000000..ad3acab --- /dev/null +++ b/Source/headers.h @@ -0,0 +1,215 @@ +#ifndef ROBODOC_HEADERS_H +#define ROBODOC_HEADERS_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****s* Headers/RB_header + * FUNCTION + * This structure is used to store the headers that are extracted + * from the source files. + * MODIFICATION HISTORY + * * 8. August 1995: Koessi changed int version to char *version + * ATTRIBUTES + * * next -- used to store RB_headers in a RB_Part as + * a linked list. + * * parent -- the parent of this header + * * name -- the full name of the header + * modulename/functionname [versioninfo] + * * owner -- the Part that owns this header. + * * htype -- the type of this header. + * * items -- pointers to the items in this header. + * * version -- unused + * * function_name -- the functionname ( a better name would + * be objectname or thingy name, + * it is the name of the thing that is + * being documented ). + * * module_name -- the modulename + * * unique_name -- unique name used for labels. + * * file_name -- documentation file of this header. + * * lines -- content of the header + * * no_lines -- number of lines in the content. + * * line_number -- the line number at which the header was + * found in the source file. + * SOURCE + */ + +struct RB_header +{ + struct RB_header *next; + struct RB_header *parent; + struct RB_Part *owner; + struct RB_HeaderType *htype; + struct RB_Item *items; + int is_internal; + char *name; + char **names; + int no_names; + char *version; + char *function_name; + char *module_name; + char *unique_name; + char *file_name; + char **lines; + int no_lines; + int line_number; +}; + +/*********/ + +/****d* Headers/src_constants + * NAME + * src_constants -- numerals for header_markers + * NOTE + * Most of them seem to be unused at the moment. + * But it's better to keep it up to date for the + * eventuality of a later use by robohdrs. + * SOURCE + */ + +#define SRC_C 0 +#define SRC_ACM 1 /* Added by David White for Aspen Custom Modeller */ +#define SRC_CPP 2 /* All values incremented 1 to allow for ACM */ +#define SRC_PASCAL 3 +#define SRC_PASCAL2 4 +#define SRC_APLUS 5 /* David White for Aspen Plus */ +#define SRC_ASM 6 +#define SRC_ASM2 7 +#define SRC_FORTRAN 8 +#define SRC_BASIC 9 +#define SRC_TEX 10 +#define SRC_SCRIPT 11 +#define SRC_COBOL 12 +#define SRC_OCCAM 13 +#define SRC_HTML 14 +#define SRC_HTML2 15 +#define SRC_GNUASM 16 +#define SRC_F902 17 +#define SRC_F90 18 +#define SRC_VB 20 +#define SRC_DBC 21 + +/*********/ + +/****d* Headers/src_remark_constants + * NAME + * src_remark_constants -- numerals for remark_markers + * NOTE + * Most of them seem to be unused at the moment. + * But it's better to keep it up to date for the + * eventuality of a later use by robohdrs. + * SOURCE + */ + +#define SRC_R_C 0 +#define SRC_R_ACM 1 /* Added by David White for Aspen Custom Modeller */ +#define SRC_R_CPP 2 /* All values incremented 1 to allow for ACM */ +#define SRC_R_PASCAL 3 /* PASCAL and PASCAL2 were 1, should have been 2, incr to 3 */ +#define SRC_R_PASCAL2 3 +#define SRC_R_APLUS 4 /* David White for Aspen Plus */ +#define SRC_R_ASM 5 +#define SRC_R_ASM2 6 +#define SRC_R_FORTRAN 7 +#define SRC_R_BASIC 8 +#define SRC_R_TEX 9 +#define SRC_R_SCRIPT 10 +#define SRC_R_COBOL 11 +#define SRC_R_OCCAM 12 +#define SRC_R_GNUASM 13 +#define SRC_R_F902 14 +#define SRC_R_F90 15 +#define SRC_R_VB 17 +#define SRC_R_DBC 18 +#define SRC_R_HTML 19 /* NULL */ +#define SRC_R_HTML2 19 /* NULL */ + +/*********/ + +/****d* Headers/end_remark_constants [3.0h] + * NAME + * end_remark_constants -- numerals for end_markers + * NOTE + * Most of them seem to be unused at the moment. But it's better to + * keep it up to date for the eventuality of a later use by + * robohdrs. + * SOURCE + */ + +#define SRC_E_C 0 +#define SRC_E_ACM 1 /* Added by David White for Aspen Custom Modeller */ +#define SRC_E_CPP 2 /* All values incremented 1 to allow for ACM */ +#define SRC_E_PASCAL 4 +#define SRC_E_PASCAL2 5 +#define SRC_E_APLUS 6 /* David White for Aspen Plus */ +#define SRC_E_ASM 7 +#define SRC_E_ASM2 8 +#define SRC_E_FORTRAN 9 +#define SRC_E_BASIC 10 +#define SRC_E_TEX 11 +#define SRC_E_SCRIPT 12 +#define SRC_E_COBOL 13 +#define SRC_E_OCCAM 14 +#define SRC_E_HTML 15 +#define SRC_E_HTML2 16 +#define SRC_E_GNUASM 17 +#define SRC_E_F902 18 +#define SRC_E_F90 19 +#define SRC_E_VB 21 +#define SRC_E_DBC 22 + + +/*********/ + +extern char *robo_header; /* Added by DavidCD */ +extern char *robo_end[]; /* Added by DavidCD */ +extern char *header_markers[]; +extern char *remark_markers[]; +extern char *end_markers[]; +extern char *end_remark_markers[]; +extern char *RB_header_type_names[]; +extern char *RB_internal_header_type_names[]; + +int RB_Is_Begin_Marker( + char *cur_line, + char **type ); +int RB_Is_End_Marker( + char *cur_line ); +void RB_Header_Lock_Reset( + void ); +void RB_Item_Lock_Reset( + void ); +char *RB_Skip_Remark_Marker( + char *lline_buffer ); +int RB_Has_Remark_Marker( + char *lline_buffer ); + +int RB_Is_Remark_End_Marker( + char *cur_line ); +int RB_Is_Remark_Begin_Marker( + char *cur_line ); +char *RB_Skip_Remark_Begin_Marker( + char *cur_line ); +char *RB_Skip_Remark_End_Marker( + char *cur_line ); + +#endif /* ROBODOC_HEADERS_H */ diff --git a/Source/headertypes.c b/Source/headertypes.c new file mode 100644 index 0000000..ece8a7a --- /dev/null +++ b/Source/headertypes.c @@ -0,0 +1,318 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + + +/****h* ROBODoc/HeaderTypes + * FUNCTION + * Headers come in different types. This module defines what kind + * of headertypes ROBODoc recognizes, and contains functions to add + * new headertypes and to compare headertypes. All the headertypes + * are stored in an array, header_type_lookup_table. + ****** + */ + +#include +#include +#include +#include "headertypes.h" +#include "util.h" + +/****v* HeaderTypes/header_type_lookup_table + * FUNCTION + * A lookup table for all the header types that ROBODoc recognizes. + * At the moment is has about 127 entries. About as many as there + * are characters in the standard ASCII set. The first 32 entries + * can be used for special purposes. + * + * Two of them are use: + * HT_MASTERINDEXTYPE + * and + * HT_SOURCEHEADERTYPE + * + * HT_MASTERINDEXTYPE is a wildcard type. All headertypes match this + * type. This is used to collect all the headers for the + * masterindex. + * + * HT_SOURCEHEADERTYPE is used to pretend that the name of + * a sourcefile is a kind of header. This makes it possible to + * include the names of the source files in the master index. + * SOURCE + */ + +struct RB_HeaderType header_type_lookup_table[MAX_HEADER_TYPE + 1] = { + {'\0', NULL, NULL, 0}, + {HT_SOURCEHEADERTYPE, "Sourcefiles", "robo_sourcefiles", 0}, + {HT_MASTERINDEXTYPE, "Index", "masterindex", 0}, /* no robo_ prefix for backwards compatibility */ + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {' ', NULL, NULL, 0}, + {'!', NULL, NULL, 0}, + {'"', NULL, NULL, 0}, + {'#', NULL, NULL, 0}, + {'$', NULL, NULL, 0}, + {'%', NULL, NULL, 0}, + {'&', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, + {'(', NULL, NULL, 0}, + {')', NULL, NULL, 0}, + {'*', "Generics", "robo_generics", 0}, + {'+', NULL, NULL, 0}, + {',', NULL, NULL, 0}, + {'-', NULL, NULL, 0}, + {'.', NULL, NULL, 0}, + {'/', NULL, NULL, 0}, + {'0', NULL, NULL, 0}, + {'1', NULL, NULL, 0}, + {'2', NULL, NULL, 0}, + {'3', NULL, NULL, 0}, + {'4', NULL, NULL, 0}, + {'5', NULL, NULL, 0}, + {'6', NULL, NULL, 0}, + {'7', NULL, NULL, 0}, + {'8', NULL, NULL, 0}, + {'9', NULL, NULL, 0}, + {':', NULL, NULL, 0}, + {';', NULL, NULL, 0}, + {'<', NULL, NULL, 0}, + {'=', NULL, NULL, 0}, + {'>', NULL, NULL, 0}, + {'?', NULL, NULL, 0}, + {'@', NULL, NULL, 0}, + {'A', NULL, NULL, 0}, + {'B', "Businessrules", "robo_businessrules", 0}, + {'C', "Contracts", "robo_contracts", 0}, + {'D', "Datasources", "robo_datasources", 0}, + {'E', "Ensure contracts", "robo_ensure_contracts", 0}, + {'F', NULL, NULL, 0}, + {'G', NULL, NULL, 0}, + {'H', NULL, NULL, 0}, + {'I', "Invariants", "robo_invariants", 0}, + {'J', NULL, NULL, 0}, + {'K', NULL, NULL, 0}, + {'L', NULL, NULL, 0}, + {'M', "Metadata", "robo_metadata", 0}, + {'N', NULL, NULL, 0}, + {'O', NULL, NULL, 0}, + {'P', "Process", "robo_processes", 0}, + {'Q', NULL, NULL, 0}, + {'R', "Require contracts", "robo_require_contracts", 0}, + {'S', "Subjects", "robo_subjects", 0}, + {'T', NULL, NULL, 0}, + {'U', NULL, NULL, 0}, + {'V', NULL, NULL, 0}, + {'W', NULL, NULL, 0}, + {'X', NULL, NULL, 0}, + {'Y', NULL, NULL, 0}, + {'Z', NULL, NULL, 0}, + {'[', NULL, NULL, 0}, + {'\0', NULL, NULL, 0}, /* Separator / */ + {']', NULL, NULL, 0}, + {'^', NULL, NULL, 0}, + {'_', NULL, NULL, 0}, + {'`', NULL, NULL, 0}, + {'a', NULL, NULL, 0}, + {'b', NULL, NULL, 0}, + {'c', "Classes", "robo_classes", 0}, + {'d', "Definitions", "robo_definitions", 0}, + {'e', "Exceptions", "robo_exceptions", 0}, + {'f', "Functions", "robo_functions", 0}, + {'g', NULL, NULL, 0}, + {'h', "Modules", "robo_modules", 1}, + {'\0', NULL, NULL, 0}, /* Internal header flag */ + {'j', NULL, NULL, 0}, + {'k', NULL, NULL, 0}, + {'l', NULL, NULL, 0}, + {'m', "Methods", "robo_methods", 0}, + {'n', NULL, NULL, 0}, + {'o', NULL, NULL, 0}, + {'p', "Procedures", "robo_procedures", 0}, + {'q', NULL, NULL, 0}, + {'r', NULL, NULL, 0}, + {'s', "Structures", "robo_strutures", 0}, + {'t', "Types", "robo_types", 0}, + {'u', "Unittest", "robo_unittests", 0}, + {'v', "Variables", "robo_variables", 0}, + {'w', "Warehouses", "robo_warehouses", 0}, + {'x', NULL, NULL, 0}, + {'y', NULL, NULL, 0}, + {'z', NULL, NULL, 0}, + {'{', NULL, NULL, 0}, + {'|', NULL, NULL, 0}, + {'}', NULL, NULL, 0}, + {'~', NULL, NULL, 0}, + {'\0', NULL, NULL, 0} +}; + +/*****/ + + +/****f* HeaderTypes/RB_AddHeaderType + * FUNCTION + * Add a new headertype to the list of header type + * that robodoc recognizes. + * RESULT + * * FALSE -- it is a new header type. + * * TRUE -- header type already existed. + * SOURCE + */ + +int RB_AddHeaderType( + unsigned int typeCharacter, + char *indexName, + char *fileName, + unsigned int priority ) +{ + if ( header_type_lookup_table[typeCharacter].typeCharacter ) + { + header_type_lookup_table[typeCharacter].indexName = indexName; + header_type_lookup_table[typeCharacter].fileName = fileName; + header_type_lookup_table[typeCharacter].priority = priority; + } + else + { + RB_Panic + ( "The character %c is not allowed as a headertype character\n", + typeCharacter ); + } + /* Unused */ + return 0; +} + +/*****/ + + + +/****f* HeaderTypes/RB_CompareHeaderTypes + * FUNCTION + * Compare two header types and check if they are equal. If one of + * the header types is a HT_MASTERINDEXTYPE the comparison is always + * TRUE. (This to make sure that all headers appear in the Index.) + * SYNOPSIS + * int RB_CompareHeaderTypes( + * struct RB_HeaderType* ht1, struct RB_HeaderType* ht2 ) + * INPUTS + * o ht1 and ht2 -- the header types to compare. + * RESULT + * o 0 -- header types are not equal + * o != 0 -- header type are equal + * SOURCE + */ + +int RB_CompareHeaderTypes( + struct RB_HeaderType *ht1, + struct RB_HeaderType *ht2 ) +{ + assert( ht1 ); + assert( ht2 ); + return ( ht1->typeCharacter == HT_MASTERINDEXTYPE ) || + ( ht2->typeCharacter == HT_MASTERINDEXTYPE ) || + ( ht1->typeCharacter == ht2->typeCharacter ); +} + +/******/ + + + +/****f* HeaderTypes/RB_FindHeaderType + * FUNCTION + * Return the header type that corresponds to the type character. + * RESULT + * * 0 -- there is no such header type + * * pointer to the header type otherwise. + * SOURCE + */ + +struct RB_HeaderType *RB_FindHeaderType( + unsigned char typeCharacter ) +{ + struct RB_HeaderType *headertype = 0; + + if ( typeCharacter < MAX_HEADER_TYPE ) + { + headertype = &( header_type_lookup_table[typeCharacter] ); + if ( ( headertype->typeCharacter == typeCharacter ) && + ( headertype->indexName ) ) + { + return headertype; + } + } + return 0; +} + +/*****/ + + +/****f* HeaderTypes/RB_IsInternalHeader + * FUNCTION + * Given the typeCharacter is this an internal header? + * RESULT + * * TRUE -- yes it is + * * FALSE -- no it is not + * SOURCE + */ + +int RB_IsInternalHeader( + unsigned char type_character ) +{ + return ( type_character == 'i' ); +} + +/*****/ + + + +#if 0 +char *RB_GetIndexName( + struct RB_HeaderType *ht1 ) +{ + /* TODO should be used to access indexName */ + return 0; +} +#endif diff --git a/Source/headertypes.h b/Source/headertypes.h new file mode 100644 index 0000000..f3111b4 --- /dev/null +++ b/Source/headertypes.h @@ -0,0 +1,71 @@ +#ifndef ROBODOC_HEADERTYPES_H +#define ROBODOC_HEADERTYPES_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****s* Headers/RB_HeaderType + * NAME + * RB_HeaderType -- Information about a header type + * ATTRIBUTES + * o typeCharacter -- The character used to indicate it + * o indexName -- The name used for the master index + * o fileName -- The name of the file use to store + * the master index for this type of headers. + * o priority -- The sorting priority of this header. + * Higher priorities appear first + * SOURCE + */ + +struct RB_HeaderType +{ + unsigned char typeCharacter; + char *indexName; + char *fileName; + unsigned int priority; +}; + +/*******/ + +#define HT_SOURCEHEADERTYPE ((unsigned char)1) +#define HT_MASTERINDEXTYPE ((unsigned char)2) + +#define MIN_HEADER_TYPE 1 /* ' ' */ +#define MAX_HEADER_TYPE 127 + + +int RB_AddHeaderType( + unsigned int typeCharacter, + char *indexName, + char *indexFile, + unsigned int priority ); +struct RB_HeaderType *RB_FindHeaderType( + unsigned char typeCharacter ); +void RB_InitHeaderTypes( + void ); +int RB_IsInternalHeader( + unsigned char type_character ); +int RB_CompareHeaderTypes( + struct RB_HeaderType *ht1, + struct RB_HeaderType *ht2 ); + +#endif /* ROBODOC_HEADERTYPES_H */ diff --git a/Source/html_generator.c b/Source/html_generator.c new file mode 100644 index 0000000..145d5e6 --- /dev/null +++ b/Source/html_generator.c @@ -0,0 +1,2384 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****h* ROBODoc/HTML_Generator + * FUNCTION + * The generator for HTML output. + * + * The generator supports sections upto 7 levels deep. It supports + * a Table of Contents based on all headers. A masterindex for + * all headertypes and seperate masterindexes for each headertype. + * + * MODIFICATION HISTORY + * 2003-02-03 Frans Slothouber Refactoring + * ????-??-?? Frans Slothouber V1.0 + ******* + * $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $ + */ + + +#include +#include +#include +#include +#include + +#include "html_generator.h" +#include "util.h" +#include "globals.h" +#include "robodoc.h" +#include "links.h" +#include "headers.h" +#include "headertypes.h" +#include "generator.h" +#include "items.h" +#include "string.h" +#include "document.h" +#include "directory.h" +#include "path.h" +#include "part.h" +#include "roboconfig.h" + +#ifdef DMALLOC +#include +#endif + +static char *css_name = NULL; +static int in_linecomment = 0; // are we in a line comment? + +static void RB_HTML_Generate_String( + FILE *dest_doc, + const char *a_string ); + + + +/* TODO Documentation */ +static void HTML_Generate_Div( + FILE *dest_doc, + char *id ) +{ + + fprintf( dest_doc, "
    \n", id ); +} + + +/* TODO Documentation */ +static void HTML_Generate_Div_End( + FILE *dest_doc, + char *id ) +{ + fprintf( dest_doc, "
    \n", id ); +} + + +/* TODO Documentation */ + +char *HTML_TOC_Index_Filename( + struct RB_Document *document ) +{ + char *toc_index_path = NULL; + char *toc_index_name = "toc_index.html"; + + assert( document->docroot->name ); + + toc_index_path = + calloc( strlen( toc_index_name ) + 2 + + strlen( document->docroot->name ), 1 ); + strcpy( toc_index_path, document->docroot->name ); + strcat( toc_index_path, toc_index_name ); + + return toc_index_path; +} + + + +/* TODO Documentation */ +static void RB_HTML_Generate_Source_Tree_Entry( + FILE *dest_doc, + char *dest_name, + struct RB_Path *parent_path, + struct RB_Directory *srctree, + struct RB_Document *document ) +{ + struct RB_Path *cur_path; + struct RB_Filename *cur_filename; + + fprintf( dest_doc, "
    \n" ); +} + +/* TODO Documentation */ +void RB_HTML_Generate_Source_Tree( + FILE *dest_doc, + char *dest_name, + struct RB_Document *document ) +{ + struct RB_Directory *srctree; + + srctree = document->srctree; + RB_HTML_Generate_Source_Tree_Entry( dest_doc, dest_name, NULL, srctree, + document ); +} + + +/****if* HTML_Generator/RB_HTML_Generate_String + * FUNCTION + * Write a string to the destination document, escaping + * characters where necessary. + * SYNOPSIS + */ +static void RB_HTML_Generate_String( + FILE *dest_doc, + const char *a_string ) +/* + * INPUTS + * o dest_doc -- the file the characters are written too + * o a_string -- a nul terminated string. + * SEE ALSO + * RB_HTML_Generate_Char() + * SOURCE + */ +{ + int i; + int l = strlen( a_string ); + unsigned char c; + + for ( i = 0; i < l; ++i ) + { + c = a_string[i]; + RB_HTML_Generate_Char( dest_doc, c ); + } +} + +/*******/ + + +/****if* HTML_Generator/RB_HTML_Generate_False_Link + * FUNCTION + * Create a representation for a link that links an word in + * a header to the header itself. + * SYNOPSIS + */ +void RB_HTML_Generate_False_Link( + FILE *dest_doc, + char *name ) +/* + * INPUTS + * * dest_doc -- the file the representation is written to. + * * name -- the word. + * SOURCE + */ +{ + fprintf( dest_doc, "" ); + RB_HTML_Generate_String( dest_doc, name ); + fprintf( dest_doc, "" ); + +} + +/*******/ + + +/****f* HTML_Generator/RB_HTML_Color_String + * FUNCTION + * Generates various colored strings + * SOURCE + */ + +static void RB_HTML_Color_String( + FILE *dest_doc, + int open, + const char *class, + const char *string ) +{ + switch ( open ) + { + // string, closing + case 0: + RB_HTML_Generate_String( dest_doc, string ); + fprintf( dest_doc, "" ); + break; + + // opening, string + case 1: + fprintf( dest_doc, "", class ); + RB_HTML_Generate_String( dest_doc, string ); + break; + + // opening, string, closing + case 2: + fprintf( dest_doc, "", class ); + RB_HTML_Generate_String( dest_doc, string ); + fprintf( dest_doc, "" ); + break; + + // opening, char, closing + case 3: + fprintf( dest_doc, "", class ); + RB_HTML_Generate_Char( dest_doc, *string ); + fprintf( dest_doc, "" ); + break; + + // Bug + default: + assert( 0 ); + } +} + +/*******/ + + +/****f* HTML_Generator/RB_HTML_Generate_Line_Comment_End + * FUNCTION + * Check if a line comment is active and generate ending sequence for it. + * Should be called at the end of each SOURCE line. + * SYNOPSIS + */ +void RB_HTML_Generate_Line_Comment_End( + FILE *dest_doc ) +{ + // Check if we are in a line comment + if ( in_linecomment ) + { + // and end the line comment + in_linecomment = 0; + RB_HTML_Color_String( dest_doc, in_linecomment, COMMENT_CLASS, "" ); + } +} + +/*******/ + + +/****f* HTML_Generator/RB_HTML_Generate_Extra + * FUNCTION + * Do some additional processing to detect HTML extra's like + * file references and other kind of links for the documentation + * body of an item. + * SYNOPSIS + */ +int RB_HTML_Generate_Extra( + FILE *dest_doc, + enum ItemType item_type, + char *cur_char, + char prev_char ) +/* + * INPUTS + * o dest_doc -- the file to write to. + * o item_type -- the kind of item the body belongs to. + * o cur_char -- pointer to a substring of the item's body + * o prev_char -- the character just before cur char (zero if none) + * RESULTS + * Number of characters produced. + * SOURCE + */ +{ + char link[1024], *str; + int res = -1; + unsigned int i; + static int incomment = 0; /* are we in comment? */ + static int quote = 0; /* double quote */ + static int squote = 0; /* single quote */ + + // Reset comment and quote state machine if not source item + if ( !Works_Like_SourceItem( item_type ) ) + { + quote = 0; + squote = 0; + incomment = 0; + in_linecomment = 0; + } + // else check for quotations and string literals + else if ( !( incomment || in_linecomment ) ) + { + switch ( *cur_char ) + { + // Check for quoted string literals ("string") + case '\"': + if ( !squote && course_of_action.do_quotes ) + { + if ( prev_char != '\\' ) + { + quote = !quote; + RB_HTML_Color_String( dest_doc, quote, + QUOTE_CLASS, "\"" ); + return 0; + } + else if ( quote && *( ( char * ) ( cur_char - 2 ) ) == '\\' ) + { + quote = !quote; /* case "... \\" */ + RB_HTML_Color_String( dest_doc, quote, + QUOTE_CLASS, "\"" ); + return 0; + } + } + break; + + // Check for single quoted string literals ('string') + case '\'': + if ( !quote && course_of_action.do_squotes ) + { + if ( prev_char != '\\' ) + { + squote = !squote; + RB_HTML_Color_String( dest_doc, squote, + SQUOTE_CLASS, "\'" ); + return 0; + } + else if ( squote && *( ( char * ) ( cur_char - 2 ) ) == '\\' ) + { + squote = !squote; /* case '\\' */ + RB_HTML_Color_String( dest_doc, squote, + SQUOTE_CLASS, "\'" ); + return 0; + } + } + break; + + default: + break; + } + } + + // Recognise line comments + if ( Works_Like_SourceItem( item_type ) && !incomment && !quote + && !squote && course_of_action.do_line_comments ) + { + // check for line comment start + if ( !in_linecomment ) + { + str = + Find_Parameter_Partial( & + ( configuration. + source_line_comments ), cur_char ); + if ( str ) + { + in_linecomment = 1; + RB_HTML_Color_String( dest_doc, in_linecomment, + COMMENT_CLASS, str ); + // We found it, so exit + return strlen( str ) - 1; + } + } + // The end of line comments are generated in + // RB_HTML_Generate_Line_Comment_End() + } + + // Recognise block comments + if ( Works_Like_SourceItem( item_type ) && !in_linecomment && !quote + && !squote && course_of_action.do_block_comments ) + { + // Check for block comment start + if ( !incomment ) + { + str = + Find_Parameter_Partial( & + ( configuration. + remark_begin_markers ), cur_char ); + if ( str ) + { + incomment = 1; + RB_HTML_Color_String( dest_doc, incomment, + COMMENT_CLASS, str ); + // We found it, so exit + return strlen( str ) - 1; + } + } + // Check for block comment end + else + { + str = + Find_Parameter_Partial( &( configuration.remark_end_markers ), + cur_char ); + if ( str ) + { + incomment = 0; + RB_HTML_Color_String( dest_doc, incomment, + COMMENT_CLASS, str ); + // We found it, so exit + return strlen( str ) - 1; + } + } + } + + // Do further source formating + if ( Works_Like_SourceItem( item_type ) && + !in_linecomment && !incomment && !quote && !squote ) + { + // Check for keywords + if ( configuration.keywords.number && course_of_action.do_keywords ) + { + char *keyword; + + // Check if we are at the beginning of a word + if ( !utf8_isalnum( prev_char ) && ( prev_char != '_' ) ) + { + // Count word length + for ( i = 1; // A word should have at least one character... + utf8_isalnum( cur_char[i] ) || ( cur_char[i] == '_' ); + i++ ); + // Check if it is a keyword + if ( ( keyword = Find_Keyword( cur_char, i ) ) ) + { + RB_HTML_Color_String( dest_doc, 2, KEYWORD_CLASS, + keyword ); + // Exit function + return i - 1; + } + } + } + + // Do some fancy coloration for non-alphanumeric chars + if ( !utf8_isalnum( *cur_char ) && *cur_char != '_' + && *cur_char != ' ' && course_of_action.do_non_alpha ) + { + RB_HTML_Color_String( dest_doc, 3, SIGN_CLASS, cur_char ); + return 0; + } + } + + // Check for links, etc... + if ( incomment || in_linecomment || !Works_Like_SourceItem( item_type ) ) + { + if ( strncmp( "http://", cur_char, 7 ) == 0 ) + { + sscanf( cur_char, "%s", link ); + RB_Say( "found link %s\n", SAY_DEBUG, link ); + res = ( strlen( link ) - 1 ); + /* [ 697247 ] http://body. does not skip the '.' */ + if ( link[( strlen( link ) - 1 )] == '.' ) + { + link[( strlen( link ) - 1 )] = '\0'; + fprintf( dest_doc, "%s.", link, link ); + } + else + { + fprintf( dest_doc, "%s", link, link ); + } + } + else if ( strncmp( "href:", cur_char, 5 ) == 0 ) + { + /* + * handy in relative hyperlink paths, e.g. + * href:../../modulex/ + */ + sscanf( ( cur_char + 5 ), "%s", link ); + RB_Say( "found link %s\n", SAY_DEBUG, link ); + res = ( strlen( link ) + 4 ); + fprintf( dest_doc, "%s", link, link ); + } + else if ( strncmp( "file:/", cur_char, strlen( "file:/" ) ) == 0 ) + { + sscanf( cur_char, "%s", link ); + RB_Say( "found link %s\n", SAY_DEBUG, link ); + res = ( strlen( link ) - 1 ); + fprintf( dest_doc, "%s", link, link ); + } + else if ( strncmp( "mailto:", cur_char, 7 ) == 0 ) + { + sscanf( ( cur_char + 7 ), "%s", link ); + RB_Say( "found mail to %s\n", SAY_DEBUG, link ); + res = ( strlen( link ) + 6 ); + fprintf( dest_doc, "%s", link, link ); + } + else if ( strncmp( "image:", cur_char, 6 ) == 0 ) + { + sscanf( ( cur_char + 6 ), "%s", link ); + RB_Say( "found image %s\n", SAY_DEBUG, link ); + res = ( strlen( link ) + 5 ); + fprintf( dest_doc, "", link ); + } + + } + return res; +} + +/******/ + + + +void RB_HTML_Generate_Item_Name( + FILE *dest_doc, + char *name ) +{ + fprintf( dest_doc, "

    " ); + RB_HTML_Generate_String( dest_doc, name ); + fprintf( dest_doc, "

    \n" ); +} + +void RB_HTML_Generate_Item_Begin( + FILE *dest_doc, + char *name ) +{ + USE( dest_doc ); + USE( name ); + /* empty */ +} + +void RB_HTML_Generate_Item_End( + FILE *dest_doc, + char *name ) +{ + USE( dest_doc ); + USE( name ); + /* empty */ +} + + +int sectiontoc_counters[MAX_SECTION_DEPTH]; + +/****f* HTML_Generator/RB_HTML_Generate_TOC_Section + * FUNCTION + * Create a table of contents based on the hierarchy of + * the headers starting for a particular point in this + * hierarchy (the parent). + * SYNOPSIS + */ +void RB_HTML_Generate_TOC_Section( + FILE *dest_doc, + char *dest_name, + struct RB_header *parent, + struct RB_header **headers, + int count, + int depth ) +/* + * INPUTS + * o dest_doc -- the file to write to. + * o dest_name -- the name of this file. + * o parent -- the parent of the headers for which the the + * current level(depth) of TOC is created. + * o headers -- an array of headers for which the TOC is created + * o count -- the number of headers in this array + * o depth -- the current depth of the TOC + * NOTES + * This is a recursive function and tricky stuff. + * SOURCE + */ +{ + struct RB_header *header; + int i, n, once = 0; + + ++sectiontoc_counters[depth]; + + for ( i = depth + 1; i < MAX_SECTION_DEPTH; ++i ) + { + sectiontoc_counters[i] = 0; + } + + // List item start + fprintf( dest_doc, "
  2. " ); + + // Do not generate section numbers if sectionnameonly + if ( !( course_of_action.do_sectionnameonly ) ) + { + for ( i = 1; i <= depth; ++i ) + { + fprintf( dest_doc, "%d.", sectiontoc_counters[i] ); + } + fprintf( dest_doc, " " ); + } + + + // Generate Link to first reference name + RB_HTML_Generate_Link( dest_doc, dest_name, parent->file_name, + parent->unique_name, + // only generate function name if sectionnameonly + ( course_of_action.do_sectionnameonly ) ? + parent->function_name : parent->name, 0 ); + + // Generate links to further reference names + for ( n = 1; n < parent->no_names; n++ ) + { + RB_HTML_Generate_String( dest_doc, ", " ); + RB_HTML_Generate_Link( dest_doc, dest_name, parent->file_name, + parent->unique_name, parent->names[n], 0 ); + } + + // List item end + fprintf( dest_doc, "
  3. \n" ); + + for ( i = 0; i < count; ++i ) + { + header = headers[i]; + if ( header->parent == parent ) + { + // Generate better TOC level hiearchy (Thuffir) + // We only generate
      once for a level + if ( !once ) + { + once = 1; + fprintf( dest_doc, "
        \n" ); + } + RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header, + headers, count, depth + 1 ); + } + else + { + /* Empty */ + } + } + // If we have generated an
          before, generate the closing one too. + if ( once ) + fprintf( dest_doc, "
        \n" ); +} + +/*******/ + + +void RB_HTML_Generate_TOC_2( + FILE *dest_doc, + struct RB_header **headers, + int count, + struct RB_Part *owner, + char *dest_name ) +{ + struct RB_header *header; + int i, j; + int depth = 1; + + for ( i = 0; i < MAX_SECTION_DEPTH; ++i ) + { + sectiontoc_counters[i] = 0; + } + fprintf( dest_doc, "

        TABLE OF CONTENTS

        \n" ); + if ( course_of_action.do_sections ) + { + /* --sections was specified, create a TOC based on the + * hierarchy of the headers. + */ + fprintf( dest_doc, "
          \n" ); + for ( i = 0; i < count; ++i ) + { + header = headers[i]; + if ( owner == NULL ) + { + if ( header->parent ) + { + /* Will be done in the subfunction */ + } + else + { + RB_HTML_Generate_TOC_Section( dest_doc, dest_name, header, + headers, count, depth ); + } + } + else + { + /* This is the TOC for a specific RB_Part (MultiDoc + * documentation). We only include the headers that + * are part of the subtree. That is, headers that are + * parth the RB_Part, or that are childern of the + * headers in the RB_Part. + */ + if ( header->owner == owner ) + { + /* BUG 721690 */ + /* Any of the parents of this header should not + * have the same owner as this header, otherwise + * this header will be part of the TOC multiple times. + */ + int no_bad_parent = TRUE; + struct RB_header *parent = header->parent; + + for ( ; parent; parent = parent->parent ) + { + if ( parent->owner == owner ) + { + no_bad_parent = FALSE; + break; + } + } + if ( no_bad_parent ) + { + RB_HTML_Generate_TOC_Section( dest_doc, dest_name, + header, headers, count, + depth ); + } + } + } + } + fprintf( dest_doc, "
        \n" ); + } + else + { + /* No --section option, generate a plain, one-level + * TOC + */ + fprintf( dest_doc, "
          \n" ); + + for ( i = 0; i < count; ++i ) + { + header = headers[i]; + if ( header->name && header->function_name && + ( ( owner == NULL ) || ( header->owner == owner ) ) ) + { + for ( j = 0; j < header->no_names; j++ ) + { + fprintf( dest_doc, "
        • " ); + + RB_HTML_Generate_Link( dest_doc, dest_name, + header->file_name, + header->unique_name, + header->names[j], 0 ); + fprintf( dest_doc, "
        • \n" ); + } + } + } + fprintf( dest_doc, "
        \n" ); + } +} + + + +/****f* HTML_Generator/RB_HTML_Generate_Label + * FUNCTION + * Generate a label (name) that can be refered too. + * A label should consist of only alphanumeric characters so + * all 'odd' characters are replaced with their ASCII code in + * hex format. + * SYNOPSIS + */ +void RB_HTML_Generate_Label( + FILE *dest_doc, + char *name ) +/* + * INPUTS + * o dest_doc -- the file to write it to. + * o name -- the name of the label. + * SOURCE + */ +{ + int i; + int l = strlen( name ); + unsigned char c; + + fprintf( dest_doc, "\n" ); +} + +/********/ + + + +static int section_counters[MAX_SECTION_DEPTH]; + + +/* TODO Documentation */ + +void RB_HTML_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ) +{ + int i; + + ++section_counters[depth]; + for ( i = depth + 1; i < MAX_SECTION_DEPTH; ++i ) + { + section_counters[i] = 0; + } + switch ( depth ) + { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + fprintf( dest_doc, "", depth ); + // Only generate section numbers if no sectionnameonly + if ( !( course_of_action.do_sectionnameonly ) ) + { + for ( i = 1; i <= depth; ++i ) + { + fprintf( dest_doc, "%d.", section_counters[i] ); + } + fprintf( dest_doc, " " ); + } + + // Print Header "first" name + RB_HTML_Generate_String( dest_doc, name ); + + // Print further names + for ( i = 1; i < header->no_names; i++ ) + { + fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",
        " ); + RB_HTML_Generate_String( dest_doc, header->names[i] ); + } + + // Include module name if not sectionnameonly + if ( !( course_of_action.do_sectionnameonly ) ) + { + fprintf( dest_doc, " [ " ); + RB_HTML_Generate_String( dest_doc, header->htype->indexName ); + fprintf( dest_doc, " ]" ); + } + + fprintf( dest_doc, "
        \n", depth ); + break; + default: + /* too deep, don't do anything. */ + assert( 0 ); + } +} + +void RB_HTML_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ) +{ + USE( dest_doc ); + USE( name ); + USE( depth ); + /* Empty */ +} + + +char *RB_HTML_Get_Default_Extension( + void ) +{ + return ( ".html" ); +} + +/****f* HTML_Generator/RB_HTML_Generate_Doc_Start + * NAME + * RB_HTML_Generate_Doc_Start -- + * FUNCTION + * Generate the first part of a HTML document. + * As far as ROBODoc is concerned a HTML document + * consists of three parts: + * * The start of a document + * * The body of a document + * * The end of a document + * SYNOPSIS + */ +void RB_HTML_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char *dest_name, + char *charset ) +/* + * INPUTS + * o dest_doc -- the output file. + * o src_name -- The file or directoryname from which + * this document is generated. + * o name -- The title for this document + * o dest_name -- the name of the output file. + * o charset -- the charset to be used for the file. + * SOURCE + */ +{ + + if ( course_of_action.do_headless ) + { + /* The user wants a headless document, so we skip everything + * upto and until + */ + } + else + { + /* Append document type and title */ + fprintf( dest_doc, "\n", + charset ? charset : DEFAULT_CHARSET ); + fprintf( dest_doc, + "\n" ); + + fprintf( dest_doc, + "\n" ); + fprintf( dest_doc, "\n" ); + fprintf( dest_doc, + "\n" ); + /* TODO is charset still needed?? */ + fprintf( dest_doc, + "\n", + charset ? charset : DEFAULT_CHARSET ); + RB_InsertCSS( dest_doc, dest_name ); + fprintf( dest_doc, "%s\n", name ); + + /* append SGML-comment with document- and copyright-info. This code + * ensures that every line has an own comment to avoid problems with + * buggy browsers */ + fprintf( dest_doc, "\n", src_name ); + if ( course_of_action.do_nogenwith ) + { + + } + else + { + static const char copyright_text[] + = COMMENT_ROBODOC /* COMMENT_COPYRIGHT */ ; + size_t i = 0; + char previous_char = '\n'; + char current_char = copyright_text[i]; + + while ( current_char ) + { + if ( previous_char == '\n' ) + { + fprintf( dest_doc, "" ); + } + else if ( ( current_char == '-' ) + && ( previous_char == '-' ) ) + { + /* avoid "--" inside SGML-comment, and use "-_" instead; this + * looks a bit strange, but one should still be able to figure + * out what is meant when reading the output */ + current_char = '_'; + } + fputc( current_char, dest_doc ); + i += 1; + previous_char = current_char; + current_char = copyright_text[i]; + } + } + + /* append heading and start list of links to functions */ + fprintf( dest_doc, "\n" ); + fprintf( dest_doc, "\n" ); + } + +// HTML_Generate_Div( dest_doc, "container" ); + + /* Generate document title if available (Thuffir) */ + HTML_Generate_Div( dest_doc, "logo" ); + fprintf( dest_doc, "
        " ); + if ( document_title ) + RB_HTML_Generate_String( dest_doc, document_title ); + fprintf( dest_doc, "\n" ); + HTML_Generate_Div_End( dest_doc, "logo" ); + + + +} + +/******/ + + +/* TODO */ +/*x**if* HTML_Generator/RB_HTML_Generate_Doc_End + * NAME + * RB_HTML_Generate_Doc_End -- + * FUNCTION + * Close of the document with the proper end tags. + ****** + */ + +void RB_HTML_Generate_Doc_End( + FILE *dest_doc, + char *name, + char *src_name ) +{ + + USE( name ); + + + HTML_Generate_Div( dest_doc, "footer" ); + /* TODO This should be done with + * RB_Generate_Label() + */ + if ( course_of_action.do_nogenwith ) + { + fprintf( dest_doc, "

        Generated from %s on ", src_name ); + RB_TimeStamp( dest_doc ); + fprintf( dest_doc, "

        \n" ); + } + else + { + fprintf( dest_doc, + "

        Generated from %s with ROBODoc V%s on ", + src_name, VERSION ); + RB_TimeStamp( dest_doc ); + fprintf( dest_doc, "

        \n" ); + } + HTML_Generate_Div_End( dest_doc, "footer" ); + +// HTML_Generate_Div_End( dest_doc, "container" ); + + if ( course_of_action.do_footless ) + { + /* The user does not want the foot of the + * document. + */ + } + else + { + fprintf( dest_doc, "\n\n" ); + } +} + + +void RB_HTML_Generate_Nav_Bar( + struct RB_Document *document, + FILE *current_doc, + struct RB_header *current_header ) +{ + char *current_filename = NULL; + char *target_filename = NULL; + char *label = NULL; + char *label_name = NULL; + + current_filename = RB_Get_FullDocname( current_header->owner->filename ); + target_filename = RB_Get_FullDocname( current_header->owner->filename ); + label = Get_Fullname( current_header->owner->filename ); + /* The navigation bar */ + fprintf( current_doc, "

        " ); + + // [ Top ] + fprintf( current_doc, "[ " ); + RB_HTML_Generate_Link( current_doc, current_filename, NULL, + "robo_top_of_doc", "Top", 0 ); + fprintf( current_doc, " ] " ); + + // [ "Parentname" ] + if ( current_header->parent ) + { + fprintf( current_doc, "[ " ); + target_filename = + RB_Get_FullDocname( current_header->parent->owner->filename ); + label = current_header->parent->unique_name; + label_name = current_header->parent->function_name; + RB_HTML_Generate_Link( current_doc, current_filename, target_filename, + label, label_name, 0 ); + fprintf( current_doc, " ] " ); + } + + // [ "Modulename" ] + fprintf( current_doc, "[ " ); + label_name = current_header->htype->indexName; + if ( ( course_of_action.do_index ) && ( course_of_action.do_multidoc ) ) + { + target_filename = RB_Get_SubIndex_FileName( document->docroot->name, + document->extension, + current_header->htype ); + RB_HTML_Generate_Link( current_doc, current_filename, target_filename, + "robo_top_of_doc", label_name, 0 ); + free( target_filename ); + } + else + { + RB_HTML_Generate_String( current_doc, label_name ); + } + fprintf( current_doc, " ]

        \n" ); +} + + + +/* TODO Documentation */ + +void RB_HTML_Generate_Nav_Bar_One_File_Per_Header( + struct RB_Document *document, + FILE *current_doc, + struct RB_header *current_header ) +{ + char *current_filename = NULL; + char *target_filename = NULL; + char *label = NULL; + char *label_name = NULL; + + current_filename = RB_Get_FullDocname( current_header->owner->filename ); + target_filename = RB_Get_FullDocname( current_header->owner->filename ); + label = Get_Fullname( current_header->owner->filename ); + /* The navigation bar */ + if ( current_header->parent ) + { + target_filename = + RB_Get_FullDocname( current_header->parent->owner->filename ); + label = current_header->parent->unique_name; + label_name = current_header->parent->function_name; + RB_HTML_Generate_Link( current_doc, current_filename, target_filename, + label, label_name, "menuitem" ); + } + /* FS TODO one_file_per_header without index is not logical */ + if ( ( course_of_action.do_index ) && ( course_of_action.do_multidoc ) ) + { + target_filename = RB_Get_SubIndex_FileName( document->docroot->name, + document->extension, + current_header->htype ); + label_name = current_header->htype->indexName; + RB_HTML_Generate_Link( current_doc, current_filename, target_filename, + "robo_top_of_doc", label_name, "menuitem" ); + free( target_filename ); + } +} + + + + + +/* TODO Documentation */ +/*x**if* HTML_Generator/RB_HTML_Generate_Header_Start + * NAME + * RB_HTML_Generate_Header_Start -- + ****** + */ + +void RB_HTML_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + struct RB_HeaderType *header_type; + int i; + + if ( cur_header->name && cur_header->function_name ) + { + fprintf( dest_doc, "
        \n" ); + RB_HTML_Generate_Label( dest_doc, cur_header->name ); + fprintf( dest_doc, "

        ", + cur_header->unique_name ); + + header_type = RB_FindHeaderType( cur_header->htype->typeCharacter ); + + for ( i = 1; i <= cur_header->no_names; i++ ) + { + // If Section names only, do not print module name + if ( i == 1 && ( course_of_action.do_sectionnameonly ) ) + RB_HTML_Generate_String( dest_doc, + cur_header->function_name ); + else + RB_HTML_Generate_String( dest_doc, cur_header->names[i - 1] ); + + // Break lines after a predefined number of header names + if ( i < cur_header->no_names ) + fprintf( dest_doc, ( i % header_breaks ) ? ", " : ",
        " ); + } + + // Print header type (if available and not Section names only) + if ( header_type && !( course_of_action.do_sectionnameonly ) ) + { + fprintf( dest_doc, " [ " ); + RB_HTML_Generate_String( dest_doc, header_type->indexName ); + fprintf( dest_doc, " ]" ); + } + + fprintf( dest_doc, "

        \n\n" ); + } +} + +/* TODO */ +/*x**f* HTML_Generator/RB_HTML_Generate_Header_End + * NAME + * RB_HTML_Generate_Header_End -- + ****** + */ + +void RB_HTML_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + USE( cur_header ); + fprintf( dest_doc, "\n" ); +} + + +/****f* HTML_Generator/RB_HTML_Generate_IndexMenu + * FUNCTION + * Generates a menu to jump to the various master index files for + * the various header types. The menu is generated for each of the + * master index files. The current header type is highlighted. + * SYNOPSIS + */ +void RB_HTML_Generate_IndexMenu( + FILE *dest_doc, + char *filename, + struct RB_Document *document, + struct RB_HeaderType *cur_type ) + /* TODO Use cur_type */ +/* + * INPUTS + * * dest_doc -- the output file. + * * filename -- the name of the output file + * * document -- the gathered documention. + * * cur_headertype -- the header type that is to be highlighted. + ****** + */ +{ + unsigned char type_char; + char *toc_index_path = NULL; + + USE( cur_type ); /* TODO FS make use of this */ + assert( dest_doc ); + assert( filename ); + assert( document ); + + toc_index_path = HTML_TOC_Index_Filename( document ); + RB_HTML_Generate_Link( dest_doc, + filename, + toc_index_path, + "top", "Table of Contents", "menuitem" ); + free( toc_index_path ); + fprintf( dest_doc, "\n" ); + + for ( type_char = MIN_HEADER_TYPE; + type_char < MAX_HEADER_TYPE; ++type_char ) + { + struct RB_HeaderType *header_type; + int n; + + header_type = RB_FindHeaderType( type_char ); + if ( header_type ) + { + n = RB_Number_Of_Links( header_type, NULL, FALSE ) + + RB_Number_Of_Links( header_type, NULL, TRUE ); + + if ( n ) + { + char *targetfilename = 0; + + targetfilename = + RB_Get_SubIndex_FileName( document->docroot->name, + document->extension, + header_type ); + assert( targetfilename ); + + RB_HTML_Generate_Link( dest_doc, + filename, + targetfilename, + "top", + header_type->indexName, "menuitem" ); + free( targetfilename ); + fprintf( dest_doc, "\n" ); + } + } + } +} + +/****f* HTML_Generator/RB_HTML_Generate_Index_Page + * FUNCTION + * Generate a single file with a index table for headers + * of one specific type of headers + * SYNOPSIS + */ +void RB_HTML_Generate_Index_Page( + struct RB_Document *document, + struct RB_HeaderType *header_type ) +/* + * INPUTS + * o document -- the document + * o header_type -- the type for which the table is to + * be generated. + ****** + */ +{ + char *filename = 0; + FILE *file; + + assert( document ); + assert( header_type ); + + filename = RB_Get_SubIndex_FileName( document->docroot->name, + document->extension, header_type ); + assert( filename ); + + file = fopen( filename, "w" ); + if ( !file ) + { + RB_Panic( "can't open (%s)!\n", filename ); + } + else + { + /* File opened, now we generate an index + * for the specified header type + */ + RB_HTML_Generate_Doc_Start( file, + document->srcroot->name, + header_type->indexName, + filename, document->charset ); + + /* breadcrumbtrail */ + HTML_Generate_Begin_Extra( file ); + /* No content for extra section yet... */ + HTML_Generate_End_Extra( file ); + + /* Menu for navigation */ + HTML_Generate_Begin_Navigation( file ); + RB_HTML_Generate_IndexMenu( file, filename, document, header_type ); + HTML_Generate_End_Navigation( file ); + + /* Content */ + HTML_Generate_Begin_Content( file ); + if ( RB_CompareHeaderTypes + ( header_type, RB_FindHeaderType( HT_SOURCEHEADERTYPE ) ) + && ( header_type->typeCharacter != HT_MASTERINDEXTYPE ) ) + { + RB_HTML_Generate_Source_Tree( file, filename, document ); + } + else + { + RB_HTML_Generate_Index_Table( file, + filename, + header_type, + header_type->indexName ); + } + HTML_Generate_End_Content( file ); + RB_HTML_Generate_Doc_End( file, filename, document->srcroot->name ); + fclose( file ); + } + + free( filename ); +} + + +/* Create an index page that contains only the table of content */ + +void HTML_Generate_TOC_Index_Page( + struct RB_Document *document ) +{ + FILE *file = NULL; + char *toc_index_path = HTML_TOC_Index_Filename( document ); + + file = fopen( toc_index_path, "w" ); + if ( !file ) + { + RB_Panic( "can't open (%s)!\n", toc_index_path ); + } + else + { + RB_HTML_Generate_Doc_Start( file, document->srcroot->name, + "Table of Contents", + toc_index_path, document->charset ); + + /* breadcrumbtrail */ + HTML_Generate_Begin_Extra( file ); + /* No content for extra section yet... */ + HTML_Generate_End_Extra( file ); + + /* Menu for navigation */ + HTML_Generate_Begin_Navigation( file ); + RB_HTML_Generate_IndexMenu( file, toc_index_path, document, NULL ); + HTML_Generate_End_Navigation( file ); + + /* Content */ + HTML_Generate_Begin_Content( file ); + RB_Generate_TOC_2( file, document->headers, + document->no_headers, NULL, toc_index_path ); + HTML_Generate_End_Content( file ); + + /* End part */ + RB_HTML_Generate_Doc_End( file, toc_index_path, + document->srcroot->name ); + fclose( file ); + } + + free( toc_index_path ); +} + + + + + +/* TODO */ +/*x**if* HTML_Generator/RB_HTML_Generate_Index + * NAME + * RB_HTML_Generate_Index -- + ****** + */ + + +/* Should be called indexes */ +void RB_HTML_Generate_Index( + struct RB_Document *document ) +{ + unsigned char type_char = 0; + + assert( document ); + + for ( type_char = MIN_HEADER_TYPE; + type_char < MAX_HEADER_TYPE; ++type_char ) + { + struct RB_HeaderType *header_type; + int n; + + header_type = RB_FindHeaderType( type_char ); + if ( header_type ) + { + n = RB_Number_Of_Links( header_type, NULL, FALSE ) + + RB_Number_Of_Links( header_type, NULL, TRUE ); + if ( n ) + { + /* There are headers of this type, so create an index page + * for them + */ + RB_HTML_Generate_Index_Page( document, header_type ); + } + } + } + + RB_HTML_Generate_Index_Page( document, + RB_FindHeaderType( HT_MASTERINDEXTYPE ) ); + + HTML_Generate_TOC_Index_Page( document ); +} + + + + + + +void RB_HTML_Generate_Table_Body( + FILE *dest, + char *dest_name, + struct RB_HeaderType *type, + int internal ) +{ + struct RB_link *cur_link; + unsigned int i; + char first_char = ' '; + int found = FALSE; + + /* Compute the number of columns we need for + * this type of header. + */ + for ( i = 0; i < link_index_size; ++i ) + { + cur_link = link_index[i]; + if ( cur_link->htype && + RB_CompareHeaderTypes( cur_link->htype, type ) && + ( ( cur_link->is_internal && internal ) || + ( !cur_link->is_internal && !internal ) ) ) + { + char *r = 0; + + r = RB_HTML_RelativeAddress( dest_name, cur_link->file_name ); + if ( toupper( cur_link->object_name[0] ) != first_char ) + { + first_char = toupper( cur_link->object_name[0] ); + if ( found ) + { +// fprintf( dest, "\n" ); + } + fprintf( dest, "

        ", first_char ); + RB_HTML_Generate_Char( dest, first_char ); + fprintf( dest, "

        " ); +// fprintf( dest, "
        \n" ); + found = TRUE; + } + fprintf( dest, "", r, + cur_link->label_name ); + RB_HTML_Generate_String( dest, cur_link->object_name ); + fprintf( dest, "\n" ); + } + } + if ( found ) + { +// fprintf( dest, "
        \n" ); + } +} + + +/****if* HTML_Generator/RB_HTML_Generate_Index_Shortcuts + * NAME + * RB_HTML_Generate_Index_Shortcuts + * FUNCTION + * Generates alphabetic shortcuts to index entries. + * SYNOPSIS + */ +static void RB_HTML_Generate_Index_Shortcuts( + FILE *dest ) +/* + * INPUTS + * o dest -- the file to write to + * TODO + * - Only list used letters. + * - List all letters (accented, signs, etc), not just the common ones. + * - Should be better to implement it as a
        ? + * SOURCE + */ +{ + unsigned char c; + + fprintf( dest, "

        " ); + + // Generate A - Z + for ( c = 'A'; c <= 'Z'; c++ ) + { + fprintf( dest, "", c ); + RB_HTML_Generate_Char( dest, c ); + fprintf( dest, " - " ); + } + + // Generate 0 - 9 + for ( c = '0'; c <= '9'; c++ ) + { + fprintf( dest, "", c ); + RB_HTML_Generate_Char( dest, c ); + fprintf( dest, "" ); + + // Do not generate separator for the last char + if ( c != '9' ) + { + fprintf( dest, " - " ); + } + } + + fprintf( dest, "

        \n" ); +} + +/********/ + +/****if* HTML_Generator/RB_HTML_Generate_Index_Table + * NAME + * RB_HTML_Generate_Index_Table -- + * FUNCTION + * Create a HTML TABLE containing links to headers of a particular + * type. This creates two tables, a table for normal headers as + * well as one for internal headers. + * SYNOPSIS + */ +void RB_HTML_Generate_Index_Table( + FILE *dest, + char *dest_name, + struct RB_HeaderType *type, + char *title ) +/* + * INPUTS + * o dest -- the file in which to write the table + * o dest_name -- the name of this file + * o type -- the type of header for which to generate + * the table + * o title -- the title of the table. + * SOURCE + */ +{ + /* Compute the number of columns we need for + * this type of header. + */ + + // Generate Index Title + fprintf( dest, "

        " ); + RB_HTML_Generate_String( dest, title ); + fprintf( dest, "

        \n" ); + + // Generate Shortcuts at the begining + RB_HTML_Generate_Index_Shortcuts( dest ); + + if ( RB_Number_Of_Links( type, NULL, FALSE ) ) + { + if ( RB_Number_Of_Links( type, NULL, TRUE ) ) + { + /* only print a title if there are two tables. */ + fprintf( dest, "

        Normal

        " ); + } + RB_HTML_Generate_Table_Body( dest, dest_name, type, FALSE ); + } + + if ( RB_Number_Of_Links( type, NULL, TRUE ) ) + { + /* Always print the Internal title, since + * these headers are special and the user should know + * he is looking at something special. + */ + fprintf( dest, "

        Internal

        " ); + RB_HTML_Generate_Table_Body( dest, dest_name, type, TRUE ); + } + + // Generate Shortcuts at the end + RB_HTML_Generate_Index_Shortcuts( dest ); +} + +/********/ + + + +/* TODO */ +/*x**if* HTML_Generator/RB_HTML_Generate_Empty_Item + * NAME + * RB_HTML_Generate_Empty_Item -- + ****** + */ + +void RB_HTML_Generate_Empty_Item( + FILE *dest_doc ) +{ + fprintf( dest_doc, "
        \n" ); +} + + + + +/****f* HTML_Generator/RB_HTML_Generate_Link + * NAME + * RB_HTML_Generate_Link -- + * SYNOPSIS + */ +void RB_HTML_Generate_Link( + FILE *cur_doc, + char *cur_name, + char *filename, + char *labelname, + char *linkname, + char *classname ) +/* + * INPUTS + * cur_doc -- the file to which the text is written + * cur_name -- the name of the destination file + * (the file from which we link) + * filename -- the name of the file that contains the link + * (the file we link to) + * labelname-- the name of the unique label of the link. + * linkname -- the name of the link as shown to the user. + * SOURCE + */ +{ + if ( classname ) + { + fprintf( cur_doc, "", r, labelname ); + RB_HTML_Generate_String( cur_doc, linkname ); + fprintf( cur_doc, "" ); + + } + else + { + fprintf( cur_doc, "href=\"#%s\">", labelname ); + RB_HTML_Generate_String( cur_doc, linkname ); + fprintf( cur_doc, "" ); + } +} + +/******/ + + +/****f* HTML_Generator/RB_HTML_RelativeAddress + * FUNCTION + * Link to 'that' from 'this' computing the relative path. Here + * 'this' and 'that' are both paths. This function is used to + * create links from one document to another document that might be + * in a completely different directory. + * SYNOPSIS + */ +char *RB_HTML_RelativeAddress( + char *thisname, + char *thatname ) +/* + * EXAMPLE + * The following two + * this /sub1/sub2/sub3/f.html + * that /sub1/sub2/g.html + * result in + * ../g.html + * + * this /sub1/f.html + * that /sub1/sub2/g.html + * == + * ./sub2/g.html + * + * this /sub1/f.html + * that /sub1/g.html + * == + * ./g.html + * + * this /sub1/doc3/doc1/tt.html + * that /sub1/doc5/doc2/qq.html + * == + * ../../doc5/doc2/qq.html + * + * NOTES + * Notice the execelent docmentation. + * SOURCE + */ +#define MAX_RELATIVE_SIZE 1024 +{ + static char relative[MAX_RELATIVE_SIZE + 1]; + char *i_this; + char *i_that; + char *i_this_slash = NULL; + char *i_that_slash = NULL; + + relative[0] = '\0'; + + assert( thisname ); + assert( thatname ); + + for ( i_this = thisname, i_that = thatname; + ( *i_this && *i_that ) && ( *i_this == *i_that ); + ++i_this, ++i_that ) + { + if ( *i_this == '/' ) + { + i_this_slash = i_this; + } + if ( *i_that == '/' ) + { + i_that_slash = i_that; + } + } + + if ( i_this_slash && i_that_slash ) + { + int this_slashes_left = 0; + int that_slashes_left = 0; + char *i_c; + + for ( i_c = i_this_slash + 1; *i_c; ++i_c ) + { + if ( *i_c == '/' ) + { + ++this_slashes_left; + } + } + + for ( i_c = i_that_slash + 1; *i_c; ++i_c ) + { + if ( *i_c == '/' ) + { + ++that_slashes_left; + } + } + + if ( this_slashes_left ) + { + int i; + + for ( i = 0; i < this_slashes_left; ++i ) + { + strcat( relative, "../" ); + } + strcat( relative, i_that_slash + 1 ); + } + else if ( that_slashes_left ) + { + /* !this_slashes_left && that_slashes_left */ + strcat( relative, "./" ); + strcat( relative, i_that_slash + 1 ); + } + else + { + /* !this_slashes_left && !that_slashes_left */ + strcat( relative, "./" ); + strcat( relative, i_that_slash + 1 ); + } + } + return relative; +} + +/******/ + + + +/****f* HTML_Generator/RB_HTML_Generate_Char + * NAME + * RB_HTML_Generate_Char -- generate a single character for an item. + * SYNOPSIS + */ +void RB_HTML_Generate_Char( + FILE *dest_doc, + int c ) +/* + * FUNCTION + * This function is called for every character that goes + * into an item's body. This escapes all the reserved + * HTML characters such as '&', '<', '>', '"'. + * SOURCE + */ +{ + switch ( c ) + { + case '\n': + assert( 0 ); + break; + case '\t': + assert( 0 ); + break; + case '<': + fprintf( dest_doc, "<" ); + break; + case '>': + fprintf( dest_doc, ">" ); + break; + case '&': + fprintf( dest_doc, "&" ); + break; + default: + // All others are printed literally + fputc( c, dest_doc ); + } +} + +/*******/ + + +void HTML_Generate_Begin_Content( + FILE *dest_doc ) +{ + HTML_Generate_Div( dest_doc, "content" ); +} + +void HTML_Generate_End_Content( + FILE *dest_doc ) +{ + HTML_Generate_Div_End( dest_doc, "content" ); +} + +void HTML_Generate_Begin_Navigation( + FILE *dest_doc ) +{ + HTML_Generate_Div( dest_doc, "navigation" ); +} + +void HTML_Generate_End_Navigation( + FILE *dest_doc ) +{ + + HTML_Generate_Div_End( dest_doc, "navigation" ); +} + +void HTML_Generate_Begin_Extra( + FILE *dest_doc ) +{ + HTML_Generate_Div( dest_doc, "extra" ); +} + +void HTML_Generate_End_Extra( + FILE *dest_doc ) +{ + HTML_Generate_Div_End( dest_doc, "extra" ); +} + + + + +/****f* HTML_Generator/RB_Create_CSS + * FUNCTION + * Create the .css file. Unless the user specified it's own css + * file robodoc creates a default one. + * + * For multidoc mode the name of the .css file is + * robodoc.css + * For singledoc mode the name of the .css file is equal + * to the name of the documentation file. + * SYNOPSIS + */ +void RB_Create_CSS( + struct RB_Document *document ) +/* + * INPUTS + * o document -- the document for which to create the file. + * SOURCE + */ +{ + size_t l = 0; + FILE *css_file; + + /* compute the complete path to the css file */ + if ( ( document->actions.do_singledoc ) || + ( document->actions.do_singlefile ) ) + { + char *extension = ".css"; + + l += strlen( document->singledoc_name ); + l += strlen( extension ); + ++l; + css_name = malloc( l ); + strcpy( css_name, document->singledoc_name ); + strcat( css_name, extension ); + } + else + { + struct RB_Path *docroot = document->docroot; + char *docrootname = docroot->name; + char *filename = "robodoc.css"; + + l = strlen( filename ); + l += strlen( docrootname ); + ++l; + css_name = malloc( l ); + strcpy( css_name, docrootname ); + strcat( css_name, filename ); + } + + RB_Say( "Creating CSS file %s\n", SAY_DEBUG, css_name ); + if ( document->css ) + { + /* The user specified its own css file, + * so we use the content of that. + */ + RB_CopyFile( document->css, css_name ); + } + else + { + css_file = fopen( css_name, "w" ); + if ( css_file ) + { + /** BEGIN BEGIN BEGIN Don't remove */ + fprintf( css_file, + "/****h* ROBODoc/ROBODoc Cascading Style Sheet\n" + " * FUNCTION\n" + " * This is the default cascading style sheet for documentation\n" + " * generated with ROBODoc.\n" + " * You can edit this file to your own liking and then use\n" + " * it with the option\n" + " * --css \n" + " *\n" + " * This style-sheet defines the following layout\n" + " * +----------------------------------------+\n" + " * | logo |\n" + " * +----------------------------------------+\n" + " * | extra |\n" + " * +----------------------------------------+\n" + " * | | navi- |\n" + " * | | gation |\n" + " * | content | |\n" + " * | | |\n" + " * +----------------------------------------+\n" + " * | footer |\n" + " * +----------------------------------------+\n" + " *\n" + " * This style-sheet is based on a style-sheet that was automatically\n" + " * generated with the Strange Banana stylesheet generator.\n" + " * See http://www.strangebanana.com/generator.aspx\n" + " *\n" + " ******\n" + " * $Id: html_generator.c,v 1.91 2007/07/10 19:13:51 gumpu Exp $\n" + " */\n" + "\n" + "body\n" + "{\n" + " background-color: rgb(255,255,255);\n" + " color: rgb(98,84,55);\n" + " font-family: Arial, serif;\n" + " border-color: rgb(226,199,143);\n" + "}\n" + "\n" + "pre\n" + "{\n" + " font-family: monospace;\n" + " margin: 15px;\n" + " padding: 5px;\n" + " white-space: pre;\n" + " color: #000;\n" + "}\n" + "\n" + "pre.source\n" + "{\n" + " background-color: #ffe;\n" + " border: dashed #aa9 1px;\n" + "}\n" + "\n" + "p\n" + "{\n" + " margin:15px;\n" + "}\n" + "\n" + "p.item_name \n" + "{\n" + " font-weight: bolder;\n" + " margin:5px;\n" + " font-size: 120%%;\n" + "}\n" + "\n" + "#content\n" "{\n" " font-size: 100%%;\n" ); + fprintf( css_file, + " color: rgb(0,0,0);\n" + " background-color: rgb(255,255,255);\n" + " border-left-width: 0px; \n" + " border-right-width: 0px; \n" + " border-top-width: 0px; \n" + " border-bottom-width: 0px;\n" + " border-left-style: none; \n" + " border-right-style: none; \n" + " border-top-style: none; \n" + " border-bottom-style: none;\n" + " padding: 40px 31px 14px 17px;\n" + " border-color: rgb(0,0,0);\n" + " text-align: justify;\n" + "}\n" + "\n" + "#navigation\n" + "{\n" + " background-color: rgb(98,84,55);\n" + " color: rgb(230,221,202);\n" + " font-family: \"Times New Roman\", serif;\n" + " font-style: normal;\n" + " border-color: rgb(0,0,0);\n" + "}\n" + "\n" + "a.menuitem\n" + "{\n" + " font-size: 120%%;\n" + " background-color: rgb(0,0,0);\n" + " color: rgb(195,165,100);\n" + " font-variant: normal;\n" + " text-transform: none;\n" + " font-weight: normal;\n" + " padding: 1px 8px 3px 1px;\n" + " margin-left: 5px; \n" + " margin-right: 5px; \n" + " margin-top: 5px; \n" + " margin-bottom: 5px;\n" + " border-color: rgb(159,126,57);\n" + " text-align: right;\n" + "}\n" + "\n" + "#logo, #logo a\n" + "{\n" + " font-size: 130%%;\n" + " background-color: rgb(198,178,135);\n" + " color: rgb(98,84,55);\n" + " font-family: Georgia, serif;\n" + " font-style: normal;\n" + " font-variant: normal;\n" + " text-transform: none;\n" + " font-weight: bold;\n" + " padding: 20px 18px 20px 18px;\n" + " border-color: rgb(255,255,255);\n" + " text-align: right;\n" + "}\n" + "\n" + "#extra, #extra a\n" + "{\n" + " font-size: 128%%;\n" + " background-color: rgb(0,0,0);\n" + " color: rgb(230,221,202);\n" + " font-style: normal;\n" + " font-variant: normal;\n" + " text-transform: none;\n" + " font-weight: normal;\n" ); + fprintf( css_file, + " border-left-width: 0px; \n" + " border-right-width: 0px; \n" + " border-top-width: 0px; \n" + " border-bottom-width: 0px;\n" + " border-left-style: none; \n" + " border-right-style: none; \n" + " border-top-style: none; \n" + " border-bottom-style: none;\n" + " padding: 12px 12px 12px 12px;\n" + " border-color: rgb(195,165,100);\n" + " text-align: center;\n" + "}\n" + "\n" + "#content a\n" + "{\n" + " color: rgb(159,126,57);\n" + " text-decoration: none;\n" + "}\n" + "\n" + "#content a:hover, #content a:active\n" + "{\n" + " color: rgb(255,255,255);\n" + " background-color: rgb(159,126,57);\n" + "}\n" + "\n" + "a.indexitem\n" + "{\n" + " display: block;\n" + "}\n" + "\n" + "h1, h2, h3, h4, h5, h6\n" + "{\n" + " background-color: rgb(221,221,221);\n" + " font-family: Arial, serif;\n" + " font-style: normal;\n" + " font-variant: normal;\n" + " text-transform: none;\n" + " font-weight: normal;\n" + "}\n" + "\n" + "h1\n" + "{\n" + " font-size: 151%%;\n" + "}\n" + "\n" + "h2\n" + "{\n" + " font-size: 142%%;\n" + "}\n" + "\n" + "h3\n" + "{\n" + " font-size: 133%%;\n" + "}\n" + "\n" + "h4\n" + "{\n" + " font-size: 124%%;\n" + "}\n" + "\n" + "h5\n" + "{\n" + " font-size: 115%%;\n" + "}\n" + "\n" + "h6\n" + "{\n" + " font-size: 106%%;\n" + "}\n" + "\n" + "#navigation a\n" + "{\n" + " text-decoration: none;\n" + "}\n" + "\n" + ".menuitem:hover\n" + "{\n" + " background-color: rgb(195,165,100);\n" + " color: rgb(0,0,0);\n" + "}\n" + "\n" + "#extra a\n" + "{\n" + " text-decoration: none;\n" + "}\n" + "\n" + "#logo a\n" + "{\n" + " text-decoration: none;\n" + "}\n" + "\n" + "#extra a:hover\n" + "{\n" + "}\n" + "\n" + "/* layout */\n" + "#navigation\n" + "{\n" + " width: 22%%; \n" + " position: relative; \n" + " top: 0; \n" + " right: 0; \n" + " float: right; \n" + " text-align: center;\n" + " margin-left: 10px;\n" + "}\n" + "\n" + ".menuitem {width: auto;}\n" + "#content {width: auto;}\n" + ".menuitem {display: block;}\n" "\n" "\n" ); + fprintf( css_file, + "div#footer\n" + "{\n" + " background-color: rgb(198,178,135);\n" + " color: rgb(98,84,55);\n" + " clear: left;\n" + " width: 100%%;\n" + " font-size: 71%%;\n" + "}\n" + "\n" + "div#footer a\n" + "{\n" + " background-color: rgb(198,178,135);\n" + " color: rgb(98,84,55);\n" + "}\n" + "\n" + "div#footer p\n" + "{\n" + " margin:0;\n" + " padding:5px 10px\n" + "}\n" + "\n" + "span.keyword\n" + "{\n" + " color: #00F;\n" + "}\n" + "\n" + "span.comment\n" + "{\n" + " color: #080;\n" + "}\n" + "\n" + "span.quote\n" + "{\n" + " color: #F00;\n" + "}\n" + "\n" + "span.squote\n" + "{\n" + " color: #F0F;\n" + "}\n" + "\n" + "span.sign\n" + "{\n" + " color: #008B8B;\n" + "}\n" + "\n" + "\n" + "@media print\n" + "{\n" + " #navigation {display: none;}\n" + " #content {padding: 0px;}\n" + " #content a {text-decoration: underline;}\n" + "}\n" ); + /** END END END Don't remove */ + fclose( css_file ); + } + else + { + RB_Panic( "Can't open %s for writing\n", css_name ); + } + } +} + +/*******/ + + +void RB_InsertCSS( + FILE *dest_doc, + char *filename ) +{ + if ( css_name ) + { + char *r = RB_HTML_RelativeAddress( filename, css_name ); + + assert( r ); + assert( strlen( r ) ); + fprintf( dest_doc, + "\n", + r ); + } +} + + + +void HTML_Generate_Begin_Paragraph( + FILE *dest_doc ) +{ + fprintf( dest_doc, "

        " ); +} + +void HTML_Generate_End_Paragraph( + FILE *dest_doc ) +{ + fprintf( dest_doc, "

        \n" ); +} + + +void HTML_Generate_Begin_Preformatted( + FILE *dest_doc, + int source ) +{ + // Check if we are preformatting a SOURCE item + if ( source ) + { + // SOURCE items have their own class in the CSS + fprintf( dest_doc, "
        ", SOURCE_CLASS );
        +    }
        +    else
        +    {
        +        fprintf( dest_doc, "
        " );
        +    }
        +}
        +
        +void HTML_Generate_End_Preformatted(
        +    FILE *dest_doc )
        +{
        +    fprintf( dest_doc, "
        \n" ); +} + + +void HTML_Generate_Begin_List( + FILE *dest_doc ) +{ + fprintf( dest_doc, "
          " ); +} + +void HTML_Generate_End_List( + FILE *dest_doc ) +{ + fprintf( dest_doc, "
        \n" ); +} + +void HTML_Generate_Begin_List_Item( + FILE *dest_doc ) +{ + fprintf( dest_doc, "
      • " ); +} + +void HTML_Generate_End_List_Item( + FILE *dest_doc ) +{ + fprintf( dest_doc, "
      • \n" ); +} diff --git a/Source/html_generator.h b/Source/html_generator.h new file mode 100644 index 0000000..f9b752e --- /dev/null +++ b/Source/html_generator.h @@ -0,0 +1,167 @@ +#ifndef ROBODOC_HTML_GENERATOR_H +#define ROBODOC_HTML_GENERATOR_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "headers.h" +#include "items.h" +#include "document.h" + +#define MAX_SECTION_DEPTH 7 + +void RB_HTML_Generate_Label( + FILE *dest_doc, + char *name ); +void RB_HTML_Generate_Item_Begin( + FILE *dest_doc, + char *name ); +void RB_HTML_Generate_Item_End( + FILE *dest_doc, + char *name ); +void RB_HTML_Generate_TOC_2( + FILE *dest_doc, + struct RB_header **headers, + int count, + struct RB_Part *owner, + char *dest_name ); +void RB_HTML_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ); +void RB_HTML_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ); +char *RB_HTML_Get_Default_Extension( + void ); +void RB_HTML_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char *dest_name, + char *charset ); +void RB_HTML_Generate_Doc_End( + FILE *dest_doc, + char *name, + char *src_name ); +void RB_HTML_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_HTML_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ); + +void RB_HTML_Generate_Index( + struct RB_Document *document ); + +void RB_HTML_Generate_Index_Table( + FILE *dest, + char *dest_name, + struct RB_HeaderType *type, + char *title ); + +void RB_HTML_Generate_Empty_Item( + FILE *dest ); +void RB_HTML_Generate_Link( + FILE *cur_doc, + char *cur_name, + char *filename, + char *labelname, + char *linkname, + char *classname ); +void RB_HTML_Generate_Char( + FILE *dest_doc, + int c ); +void RB_HTML_Generate_Item_Name( + FILE *dest_doc, + char *name ); +char *RB_HTML_RelativeAddress( + char *thisname, + char *thatname ); + +int RB_HTML_Generate_Extra( + FILE *dest_doc, + enum ItemType item_type, + char *cur_char, + char prev_char ); + +void RB_HTML_Generate_False_Link( + FILE *dest_doc, + char *name ); +void RB_Create_CSS( + struct RB_Document *document ); +void RB_InsertCSS( + FILE *dest_doc, + char *filename ); +void RB_HTML_Generate_Nav_Bar( + struct RB_Document *document, + FILE *current_doc, + struct RB_header *current_header ); + +void RB_HTML_Generate_Nav_Bar_One_File_Per_Header( + struct RB_Document *document, + FILE *current_doc, + struct RB_header *current_header ); + +void HTML_Generate_Begin_Paragraph( + FILE *dest_doc ); +void HTML_Generate_End_Paragraph( + FILE *dest_doc ); + +void HTML_Generate_Begin_Preformatted( + FILE *dest_doc, + int source ); +void HTML_Generate_End_Preformatted( + FILE *dest_doc ); + +void HTML_Generate_Begin_List( + FILE *dest_doc ); +void HTML_Generate_End_List( + FILE *dest_doc ); +void HTML_Generate_Begin_List_Item( + FILE *dest_doc ); +void HTML_Generate_End_List_Item( + FILE *dest_doc ); + +void HTML_Generate_Begin_Content( + FILE *dest_doc ); +void HTML_Generate_End_Content( + FILE *dest_doc ); +void HTML_Generate_Begin_Navigation( + FILE *dest_doc ); +void HTML_Generate_End_Navigation( + FILE *dest_doc ); +void HTML_Generate_Begin_Extra( + FILE *dest_doc ); +void HTML_Generate_End_Extra( + FILE *dest_doc ); +void RB_HTML_Generate_Line_Comment_End( + FILE *dest_doc ); +void RB_HTML_Generate_IndexMenu( + FILE *dest_doc, + char *filename, + struct RB_Document *document, + struct RB_HeaderType *cur_type ); + +#endif /* ROBODOC_HTML_GENERATOR_H */ diff --git a/Source/items.c b/Source/items.c new file mode 100644 index 0000000..f9598f2 --- /dev/null +++ b/Source/items.c @@ -0,0 +1,340 @@ +// vi: ff=unix spell + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****h* ROBODoc/Items + * FUNCTION + * This module contains functions that deal with items. The + * documentation consists of headers, and headers contains one of + * more items. Each item has a name and a body. All possible items + * are listed in configuration.items. A uses can specify that + * certain items are not to be added to the documentation. These + * items are listed in configuration.ignore_items. + * AUTHOR + * Frans Slothouber + ******* + */ + +#include +#include +#include +#include +#include +#include + +#include "globals.h" +#include "robodoc.h" +#include "items.h" +#include "roboconfig.h" +#include "util.h" + +/****v* Items/item_name_buffer + * FUNCTION + * Stores the name of the last item that was found. + * SOURCE + */ + +#define MAX_ITEM_NAME_LENGTH 1024 +char item_name_buffer[MAX_ITEM_NAME_LENGTH]; + +/*****/ + +/* TODO Documentation */ +char *RB_Get_Item_Name( + void ) +{ + return item_name_buffer; +} + +/****f* Items/RB_Create_Item + * + * SOURCE + */ + +struct RB_Item *RB_Create_Item( + enum ItemType arg_item_type ) +{ + struct RB_Item *item = malloc( sizeof( struct RB_Item ) ); + + assert( item ); + + item->next = 0; + item->type = arg_item_type; + item->begin_index = 0; + item->end_index = 0; + + return item; +} + +/*****/ + +/****f* Items/RB_Get_Item_Type [3.0b] + * FUNCTION + * return the item_type represented by the given string. + * SYNOPSIS + * int RB_Get_Item_Type( char *cmp_name ) + * INPUTS + * char *cmp_name -- item_name to evaluate + * RESULT + * int -- the right item_type or NO_ITEM + * SOURCE + */ + +int RB_Get_Item_Type( + char *cmp_name ) +{ + unsigned int item_type; + + assert( configuration.items.number ); + for ( item_type = 0; item_type < configuration.items.number; ++item_type ) + { + char *item = configuration.items.names[item_type]; + + /* Skip preformat mark */ + if ( *item == '-' ) + item++; + if ( !strcmp( item, cmp_name ) ) + { + return ( item_type ); + } + } + return ( NO_ITEM ); +} + +/*** RB_Get_Item_Type ***/ + + + +/****f* Items/RB_Is_ItemName + * FUNCTION + * Is there an itemname in the line. Ignores leading spaces and + * remark markers. + * INPUTS + * line -- line to be searched. + * RESULT + * The kind of item that was found or NO_ITEM if no item could be found. + * The name of the item will be stored in item_name_buffer. + * NOTES + * We used to check for misspelled items names by testing if + * the item name buffer consists of only upper case characters. + * However checking for a misspelled item name this way results in + * many false positives. For instance many warnings are given for + * FORTRAN code as all the keywords are in uppercase. We need to + * find a better method for this. + * SOURCE + */ + +enum ItemType RB_Is_ItemName( + char *line ) +{ + char *cur_char = line; + int i = 0; + + cur_char = RB_Skip_Whitespace( cur_char ); + if ( RB_Has_Remark_Marker( cur_char ) ) + { + cur_char = RB_Skip_Remark_Marker( cur_char ); + cur_char = RB_Skip_Whitespace( cur_char ); + /* It there anything left? */ + if ( strlen( cur_char ) ) + { + enum ItemType item_type = NO_ITEM; + + /* Copy the name */ + strcpy( item_name_buffer, cur_char ); + /* remove any trailing spaces */ + for ( i = strlen( item_name_buffer ) - 1; + i >= 0 && utf8_isspace( item_name_buffer[i] ); --i ) + { + item_name_buffer[i] = '\0'; + } + /* No check and see if this is an item name */ + if ( strlen( item_name_buffer ) ) + { + item_type = RB_Get_Item_Type( item_name_buffer ); +#if 0 /* Until we find a better method */ + if ( item_type == NO_ITEM ) + { + /* Check if it is a misspelled item name */ + item_type = POSSIBLE_ITEM; + for ( i = 0; i < strlen( item_name_buffer ); ++i ) + { + if ( !( utf8_isupper( item_name_buffer[i] ) || + utf8_isspace( item_name_buffer[i] ) ) ) + { + /* No it is not */ + item_type = NO_ITEM; + break; + } + } + } +#endif + } + return item_type; + } + else + { + return NO_ITEM; + } + } + else + { + return NO_ITEM; + } +} + +/******/ + +/* TODO Documentation */ +int Is_Ignore_Item( + char *name ) +{ + unsigned int i; + + for ( i = 0; i < configuration.ignore_items.number; ++i ) + { + if ( !strcmp( configuration.ignore_items.names[i], name ) ) + { + return TRUE; + } + } + return FALSE; +} + + +/****f* HeaderTypes/Works_Like_SourceItem + * FUNCTION + * Tells wether this item works similar to the + * source item, that is weather it copies it's + * content verbatim to the output document. + * SYNPOPSIS + */ +int Works_Like_SourceItem( + enum ItemType item_type ) +/* + * INPUTS + * item_type -- Type of item (also the index to the item name) + * RESULT + * TRUE -- Item works like a SOURCE item + * FALSE -- Item does NOT work like a SOURCE item + * SOURCE + */ +{ + unsigned int i; + + // Check if it is a SOURCE item + if ( item_type == SOURCECODE_ITEM ) + { + return TRUE; + } + + // Lookup if it works like a SOURCE item + for ( i = 0; i < configuration.source_items.number; ++i ) + { + if ( !strcmp + ( configuration.source_items.names[i], + configuration.items.names[item_type] ) ) + { + return TRUE; + } + } + + // Neither SOURCE item, nor works like it + return FALSE; +} + +/******/ + +/****f* HeaderTypes/Is_Preformatted_Item + * FUNCTION + * Tells wether this item should be automatically preformatted in the + * output. + * SYNPOPSIS + */ +int Is_Preformatted_Item( + enum ItemType item_type ) +/* + * INPUTS + * item_type -- Type of item (also the index to the item name) + * RESULT + * TRUE -- Item should be automatically preformatted + * FALSE -- Item should NOT be automatically preformatted + * SOURCE + */ +{ + unsigned int i; + + // Lookup if item should be preformatted + for ( i = 0; i < configuration.preformatted_items.number; ++i ) + { + if ( !strcmp + ( configuration.preformatted_items.names[i], + configuration.items.names[item_type] ) ) + { + // Item name match, it sould be preformatted + return TRUE; + } + } + + // Do not automatically preformat item + return FALSE; +} + +/******/ + +/****f* HeaderTypes/Is_Format_Item + * FUNCTION + * Tells wether this item should be formatted by the browser + * SYNPOPSIS + */ +int Is_Format_Item( + enum ItemType item_type ) +/* + * INPUTS + * item_type -- Type of item (also the index to the item name) + * RESULT + * TRUE -- Item should be formatted by the browser + * FALSE -- Item should be left alone + * SOURCE + */ +{ + unsigned int i; + + // Lookup if item should be formatted by the browser + for ( i = 0; i < configuration.format_items.number; ++i ) + { + if ( !strcmp + ( configuration.format_items.names[i], + configuration.items.names[item_type] ) ) + { + // Item name match, it sould be formatted by the browser + return TRUE; + } + } + + // Leave item alone + return FALSE; +} + +/******/ diff --git a/Source/items.h b/Source/items.h new file mode 100644 index 0000000..85606f8 --- /dev/null +++ b/Source/items.h @@ -0,0 +1,130 @@ +#ifndef ROBODOC_ITEMS_H +#define ROBODOC_ITEMS_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "robodoc.h" + +/****t* Items/ItemTypes + * NAME + * ItemTypes -- enumeration of item types + * FUNCTION + * Defines a number of item types. There are two kind of items: + * * the SOURCE item which is always available, + * * and items defined by the user (or through the default items). + * NOTES + * Never check an item type against SOURCECODE_ITEM directily! + * Use Works_Like_SourceItem() function instead. + * SOURCE + */ + +enum ItemType +{ POSSIBLE_ITEM = -2, NO_ITEM = -1, SOURCECODE_ITEM = 0, OTHER_ITEM }; + +/*****/ + + +#define RBILA_BEGIN_PARAGRAPH ( 1 << 1 ) +#define RBILA_END_PARAGRAPH ( 1 << 2 ) +#define RBILA_BEGIN_LIST ( 1 << 3 ) +#define RBILA_END_LIST ( 1 << 4 ) +#define RBILA_BEGIN_LIST_ITEM ( 1 << 5 ) +#define RBILA_END_LIST_ITEM ( 1 << 6 ) +#define RBILA_BEGIN_PRE ( 1 << 7 ) +#define RBILA_END_PRE ( 1 << 8 ) +#define RBILA_BEGIN_SOURCE ( 1 << 9 ) +#define RBILA_END_SOURCE ( 1 << 10 ) + +enum ItemLineKind +{ + ITEM_LINE_RAW, /* A line that does not start with a remark marker */ + ITEM_LINE_PLAIN, /* A line that starts with a remark marker */ + ITEM_LINE_PIPE, /* A line that starts with a remark marked and is + followed by a pipe marker. */ + ITEM_LINE_END, /* The last line of an item */ + + ITEM_LINE_TOOL_START, // Start line of a tool item + ITEM_LINE_TOOL_BODY, // Body of a tool item + ITEM_LINE_TOOL_END, // End line of a tool item + ITEM_LINE_EXEC, // Exec item + ITEM_LINE_DOT_START, // Similar to TOOL_START but use DOT tool + ITEM_LINE_DOT_END, // End line of a DOT item + ITEM_LINE_DOT_FILE // DOT file to include +}; + + +struct RB_Item_Line +{ + char *line; + enum ItemLineKind kind; + long format; + T_RB_DocType pipe_mode; +}; + +/****s* Items/RB_Item + * FUNCTION + * Keeps track of where items start end end in the header. + * The index numbers point to the lines array in + * RB_header. + * SOURCE + */ + +struct RB_Item +{ + struct RB_Item *next; + enum ItemType type; + int no_lines; + struct RB_Item_Line **lines; + int begin_index; + int end_index; +}; + +/******/ + + + +int RB_Get_Item_Type( + char * ); +int RB_Get_Item_Attr( + char *cmp_name ); +enum ItemType RB_Is_ItemName( + char *line ); +int RB_Ignore_Last_Item( + void ); +char *RB_Get_Item_Name( + void ); +struct RB_Item *RB_Create_Item( + enum ItemType arg_item_type ); +int Is_Ignore_Item( + char *name ); +int Works_Like_SourceItem( + enum ItemType item_type ); + +int Is_Preformatted_Item( + enum ItemType item_type ); + +int Is_Format_Item( + enum ItemType item_type ); + +#endif /* ROBODOC_ITEMS_H */ diff --git a/Source/latex_generator.c b/Source/latex_generator.c new file mode 100644 index 0000000..fb60b5b --- /dev/null +++ b/Source/latex_generator.c @@ -0,0 +1,710 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* ROBODoc/LaTeX_Generator + * FUNCTION + * Generator for LaTeX output. Supports singledoc mode. + * + ******* + * TODO More documentation. + */ + +#include +#include +#include +#include + +#include "generator.h" +#include "util.h" +#include "links.h" +#include "latex_generator.h" +#include "globals.h" +#include "robodoc.h" + +#ifdef DMALLOC +#include +#endif + +static int verbatim = FALSE; + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_String + * FUNCTION + * Write a string to the destination document, escaping + * characters where necessary. + ****** + */ + +void RB_LaTeX_Generate_String( + FILE *dest_doc, + char *a_string ) +{ + int i; + int l = strlen( a_string ); + unsigned char c; + + for ( i = 0; i < l; i++ ) + { + c = a_string[i]; + RB_LaTeX_Generate_Char( dest_doc, c ); + } +} + + +void RB_LaTeX_Generate_False_Link( + FILE *dest_doc, + char *name ) +{ + RB_LaTeX_Generate_String( dest_doc, name ); +} + +void RB_LaTeX_Generate_Item_Begin( + FILE *dest_doc ) +{ + USE( dest_doc ); + /* Empty */ +} + +void RB_LaTeX_Generate_Item_End( + FILE *dest_doc ) +{ + USE( dest_doc ); + /* Empty */ +} + +/* void */ +/* RB_LaTeX_Generate_Item_Name( FILE* dest_doc, char *name ) */ +/* { */ +/* RB_LaTeX_Generate_String( dest_doc, name ); */ +/* fprintf( dest_doc, "\n" ); */ +/* } */ + + +/* Lowtexx 21.09.2005 11:02 */ +/* I think it looks better like this. This wastes less space in pdf-document. */ +void RB_LaTeX_Generate_Item_Name( + FILE *dest_doc, + char *name ) +{ + fprintf( dest_doc, "\\textbf{" ); + RB_LaTeX_Generate_String( dest_doc, name ); + + // In alternate format, item names stand alone (Thuffir) + if ( course_of_action.do_altlatex ) + fprintf( dest_doc, "}\n" ); + else + fprintf( dest_doc, ":}\\hspace{0.08in}" ); +} + + +void RB_LaTeX_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ) +{ + int i; + + // Generate a new page for every section in alternate format + if ( course_of_action.do_altlatex ) + fprintf( dest_doc, "\\newpage\n" ); + + // If \part enabled, we have a level deeper + // So enable the level '0' + if ( course_of_action.do_latexparts ) + depth--; + + switch ( depth ) + { + case 0: + fprintf( dest_doc, "\\part{" ); + break; + case 1: + fprintf( dest_doc, "\\section{" ); + break; + case 2: + fprintf( dest_doc, "\\subsection{" ); + break; + case 3: + fprintf( dest_doc, "\\subsubsection{" ); + break; + default: + /* Too deep so just make it a subsubsection */ + fprintf( dest_doc, "\\subsubsection{" ); + } + + // Print Header "First" name + RB_LaTeX_Generate_String( dest_doc, name ); + // Print other names + for ( i = 1; i < header->no_names; i++ ) + { + RB_LaTeX_Generate_String( dest_doc, ", " ); + RB_LaTeX_Generate_String( dest_doc, header->names[i] ); + } + fprintf( dest_doc, "}\n" ); + + // Print Parent if any + if ( header->parent ) + { + fprintf( dest_doc, "\\textsl{[ " ); + RB_LaTeX_Generate_String( dest_doc, header->parent->function_name ); + fprintf( dest_doc, " ]}\n" ); + } + + // Print Header Type + fprintf( dest_doc, "\\textsl{[ " ); + RB_LaTeX_Generate_String( dest_doc, header->htype->indexName ); + fprintf( dest_doc, " ]}\n\n" ); +} + +void RB_LaTeX_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ) +{ + USE( dest_doc ); + USE( depth ); + USE( name ); + /* Empty */ +} + +char *RB_LaTeX_Get_Default_Extension( + void ) +{ + return ".tex"; +} + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Doc_Start + * NAME + * RB_LaTeX_Generate_Doc_Start -- + ***** + */ + +void RB_LaTeX_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char *charset ) +{ + fprintf( dest_doc, "%% Document: %s\n", name ); + fprintf( dest_doc, "%% Source: %s\n", src_name ); + + if ( course_of_action.do_nogenwith ) + { + + } + else + { + fprintf( dest_doc, "%% " COMMENT_ROBODOC ); +/* Documentation is the users not ours fprintf( dest_doc, "%% " COMMENT_COPYRIGHT ); */ + } + + if ( course_of_action.do_headless ) + { + /* The user wants a headless document, so we skip all + * initialization. It is up to the user to put this in. + */ + } + else + { + fprintf( dest_doc, "\\documentclass{article}\n" ); + fprintf( dest_doc, "\\usepackage{makeidx}\n" ); + fprintf( dest_doc, "\\usepackage{graphicx}\n" ); + + // Check if we have to use the inputenc package + if ( charset ) + { + fprintf( dest_doc, "\\usepackage[%s]{inputenc}\n", charset ); + } + + // Alternate mode, works better with pdflatex and DIN A4 sheets + // At least for me :) (Thuffir) + if ( course_of_action.do_altlatex ) + { + fprintf( dest_doc, "\\oddsidemargin 0 cm\n" ); + fprintf( dest_doc, "\\evensidemargin 0 cm\n" ); + fprintf( dest_doc, "\\topmargin 0 cm\n" ); + fprintf( dest_doc, "\\textwidth 16 cm\n" ); + fprintf( dest_doc, "\\textheight 22 cm\n" ); + } + else + { + /* I guess this is unecessarry (same definitions twice ?) + fprintf( dest_doc, "\\oddsidemargin 0.15 in\n" ); + fprintf( dest_doc, "\\evensidemargin 0.35 in\n" ); + fprintf( dest_doc, "\\marginparwidth 1 in \n" ); + */ + + fprintf( dest_doc, "\\oddsidemargin 0.25 in \n" ); + fprintf( dest_doc, "\\evensidemargin 0.25 in\n" ); + fprintf( dest_doc, "\\marginparwidth 0.75 in\n" ); + fprintf( dest_doc, "\\textwidth 5.875 in\n" ); + } + + + fprintf( dest_doc, "\\setlength{\\parindent}{0in}\n" ); + fprintf( dest_doc, "\\setlength{\\parskip}{.08in}\n\n" ); + + /* changed default header to use boldface (vs slant) */ + fprintf( dest_doc, "\\pagestyle{headings}\n" ); + + // Set document title + fprintf( dest_doc, "\\title{%s}\n", + document_title ? document_title : DEFAULT_DOCTITILE ); + + if ( course_of_action.do_nogenwith ) + { + fprintf( dest_doc, "\\author{Documentation Generator}\n" ); + } + else + { + fprintf( dest_doc, "\\author{%s}\n", COMMENT_ROBODOC ); + } + + fprintf( dest_doc, "\\makeindex\n" ); + fprintf( dest_doc, "\\begin{document}\n" ); + fprintf( dest_doc, "\\maketitle\n" ); + + // In alternate mode, we generate INDEX at the end of document + if ( course_of_action.do_altlatex ) + { + fprintf( dest_doc, "\\newpage\n" ); + } + else + { + fprintf( dest_doc, "\\printindex\n" ); + } + + /* autogenerate table of contents! */ + fprintf( dest_doc, "\\tableofcontents\n" ); + + // We don't need this in alternate format, since every section begins + // with a \newpage (Thuffir) + if ( !( course_of_action.do_altlatex ) ) + fprintf( dest_doc, "\\newpage\n" ); + + /* trick to disable the autogenerated \newpage */ + fprintf( dest_doc, "\n" ); + } +} + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Doc_End + * NAME + * RB_LaTeX_Generate_Doc_End -- + ***** + */ + +void RB_LaTeX_Generate_Doc_End( + FILE *dest_doc, + char *name ) +{ + USE( name ); + + // In alternate mode, we generate INDEX at the end of document + if ( course_of_action.do_altlatex ) + { + fprintf( dest_doc, "\\printindex\n" ); + } + + if ( course_of_action.do_footless ) + { + /* The user does not want the foot of the + * document + */ + } + else + { + fprintf( dest_doc, "\\end{document}\n" ); + } +} + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Index_Entry + * FUNCTION + * Creates a entry for the index. + * + ******* + */ + +void RB_LaTeX_Generate_Index_Entry( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + assert( cur_header->function_name ); + + fprintf( dest_doc, "\\index{unsorted!" ); + RB_LaTeX_Generate_String( dest_doc, cur_header->function_name ); + if ( cur_header->is_internal ) + { + fprintf( dest_doc, "}\\index{internal\\_%s!", + cur_header->htype->indexName ); + } + else + { + fprintf( dest_doc, "}\\index{%s!", cur_header->htype->indexName ); + } + RB_LaTeX_Generate_String( dest_doc, cur_header->function_name ); + fprintf( dest_doc, "}\n" ); +} + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Header_Start + * NAME + * RB_LaTeX_Generate_Header_Start -- + ***** + */ + +void RB_LaTeX_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + fprintf( dest_doc, "\\subsection{" ); + RB_LaTeX_Generate_String( dest_doc, cur_header->name ); + fprintf( dest_doc, "}\n" ); +} + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Header_End + * NAME + * RB_LaTeX_Generate_Header_End -- + ***** + */ + +void RB_LaTeX_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + USE( cur_header ); + fputc( '\n', dest_doc ); +} + + +/*x**f* LaTeX_Generator/RB_LaTeX_Generate_Index + * NAME + * RB_LaTeX_Generate_Index -- + ***** + */ + +void RB_LaTeX_Generate_Index( + FILE *dest, + char *source ) +{ + /* TODO REMOVE */ + USE( dest ); + USE( source ); + assert( 0 ); +#if 0 + RB_Generate_Doc_Start( dest, source, "Master File", 0 ); + RB_Generate_LaTeX_Includes( dest ); + RB_Generate_Doc_End( dest, source ); +#endif +} + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Index_Table + * NAME + * RB_LaTeX_Generate_Index_Table -- + ***** + */ + +void RB_LaTeX_Generate_Index_Table( + FILE *dest, + int type, + char *title ) +{ + USE( dest ); + USE( type ); + USE( title ); + + /* Empty */ +} + +/****f* LaTeX_Generator/Generate_LaTeX_Includes + * NAME + * Generate_LaTeX_Includes -- generate include commands + * SYNOPSIS + * void RB_Generate_LaTeX_Includes (FILE *dest) + * FUNCTION + * Generates a series of \include commands to include the + * documentation generated for each source file into one + * big file. + **** + */ + +void RB_Generate_LaTeX_Includes( + FILE *dest ) +{ + USE( dest ); + /* TODO REMOVE ?? */ +#if 0 + struct RB_link *cur_link; + + for ( cur_link = first_link; cur_link; cur_link = cur_link->next_link ) + { + { + if ( cur_link->type == NO_HEADER ) + fprintf( dest, "\\include{%s}\n", cur_link->label_name ); + } + } +#endif +} + + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Empty_Item + * NAME + * RB_LaTeX_Generate_Empty_Item -- + ***** + */ + +void RB_LaTeX_Generate_Empty_Item( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\\\\\n" ); +} + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_EscapedChar + * FUNCTION + * Generate a single character. These characters are outside + * a begin{verbatim} end{verbatim} block. So we need to escape is + * special characters. + * These are + * _ => \_ + * % => \% + * $ => \$ + * < => \textless + * > => \textgreater + * \ => $\backslash$ + * SYNOPSIS + * void RB_LaTeX_Generate_EscapedChar( FILE* dest_doc, int c ) + * SEE ALSO + * RB_LaTeX_Generate_Char() + ***** + */ + +void RB_LaTeX_Generate_EscapedChar( + FILE *dest_doc, + int c ) +{ + switch ( c ) + { + case '&': + case '~': + case '_': + case '%': + case '^': + case '{': + case '}': + case '$': + case '#': + fputc( '\\', dest_doc ); + fputc( c, dest_doc ); + break; +/* lowtexx 21.09.2005 11:12 */ +/* Replace these characters by the correct latex-code */ + case '\\': + fprintf( dest_doc, "$\\backslash$" ); + break; + case '<': + fprintf( dest_doc, "\\textless " ); + break; + case '>': + fprintf( dest_doc, "\\textgreater " ); + break; +/* --- */ + default: + fputc( c, dest_doc ); + break; + } +} + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Char + * FUNCTION + * Generate a single character. These characters are generated + * within a begin{verbatim} end{verbatim} block So no escaping is + * necessary. + * SYNOPSIS + * void RB_LaTeX_Generate_Char( FILE* dest_doc, int c ) + ***** + */ + +void RB_LaTeX_Generate_Char( + FILE *dest_doc, + int c ) +{ + if ( verbatim ) + { + switch ( c ) + { + case '\n': + assert( 0 ); + break; + case '\t': + assert( 0 ); + break; + default: + fputc( c, dest_doc ); + } + } + else + { + RB_LaTeX_Generate_EscapedChar( dest_doc, c ); + } +} + + +void LaTeX_Generate_Begin_Paragraph( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\n" ); +} + +void LaTeX_Generate_End_Paragraph( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\n" ); +} + + +void LaTeX_Generate_Begin_Preformatted( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\\begin{verbatim}\n" ); + verbatim = TRUE; +} + +void LaTeX_Generate_End_Preformatted( + FILE *dest_doc ) +{ + verbatim = FALSE; + fprintf( dest_doc, "\\end{verbatim}\n" ); +} + + +void LaTeX_Generate_Begin_List( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\\begin{itemize}\n" ); +} + +void LaTeX_Generate_End_List( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\\end{itemize}\n" ); +} + +void LaTeX_Generate_Begin_List_Item( + FILE *dest_doc ) +{ + fprintf( dest_doc, " \\item " ); +} + +void LaTeX_Generate_End_List_Item( + FILE *dest_doc ) +{ + USE( dest_doc ); +// fprintf( dest_doc, "" ); +} + + + +/* lowtexx 21.09.2005 11:23 */ +/* added some functions to create links in latex documents */ + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Label + * NAME + * RB_LaTeX_Generate_Label -- + * SYNOPSIS + * void RB_LaTeX_Generate_Label( FILE* dest_doc, char* name) + * INPUTS + * dest_doc -- the file to which the text is written + * name -- the unique name of the label to create + * SOURCE + */ + +void RB_LaTeX_Generate_Label( + FILE *dest_doc, + char *name ) +{ + int i; + int l = strlen( name ); + unsigned char c; + + fprintf( dest_doc, "\\label{ch:" ); + for ( i = 0; i < l; ++i ) + { + c = name[i]; + if ( utf8_isalnum( c ) ) + { + RB_LaTeX_Generate_Char( dest_doc, c ); + } + else + { + // think about this + // replaced by underscore + fputc( '_', dest_doc ); + } + } + fprintf( dest_doc, "}\n" ); +} + +/******/ + + +/****f* LaTeX_Generator/RB_LaTeX_Generate_Link + * NAME + * RB_LaTeX_Generate_Link -- + * SYNOPSIS + * void RB_LaTeX_Generate_Link( FILE *cur_doc, char *cur_name, + * char *filename, char *labelname, + * char *linkname ) + * INPUTS + * cur_doc -- the file to which the text is written + * cur_name -- the name of the destination file (unused) + * (the file from which we link) + * filename -- the name of the file that contains the link + * (the file we link to) (unused) + * labelname-- the name of the unique label of the link. + * linkname -- the name of the link as shown to the user (unused). + * SOURCE + */ + +void RB_LaTeX_Generate_Link( + FILE *cur_doc, + char *cur_name, + char *filename, + char *labelname, + char *linkname ) +{ + USE( cur_name ); + USE( filename ); + USE( linkname ); + + // Only generate links outside the verbatim sections + // LaTeX does not seem to recognise them inside (Thuffir) + if ( verbatim == FALSE ) + fprintf( cur_doc, " (\\ref{ch:%s})", labelname ); +} + +/******/ diff --git a/Source/latex_generator.h b/Source/latex_generator.h new file mode 100644 index 0000000..804a3fb --- /dev/null +++ b/Source/latex_generator.h @@ -0,0 +1,125 @@ +#ifndef ROBODOC_LATEX_GENERATOR_H +#define ROBODOC_LATEX_GENERATOR_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "headers.h" + +void RB_LaTeX_Generate_Index_Entry( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_LaTeX_Generate_Item_Begin( + FILE *dest_doc ); +void RB_LaTeX_Generate_Item_End( + FILE *dest_doc ); +void RB_LaTeX_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name, + struct RB_header *header ); +void RB_LaTeX_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ); + +/* size_t RB_LaTeX_Get_Len_Extension(); */ +/* void RB_LaTeX_Add_Extension(char* name); */ +char *RB_LaTeX_Get_Default_Extension( + void ); +void RB_LaTeX_Generate_Item_Name( + FILE *dest_doc, + char *name ); +void RB_LaTeX_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char *charset ); +void RB_LaTeX_Generate_Doc_End( + FILE *dest_doc, + char *name ); +void RB_LaTeX_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_LaTeX_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_LaTeX_Generate_Index( + FILE *dest, + char *source ); +void RB_Generate_LaTeX_Includes( + FILE *dest ); +void RB_LaTeX_Generate_Index_Table( + FILE *dest, + int type, + char *title ); +void RB_LaTeX_Generate_Item_Doc( + FILE *dest_doc, + char *dest_name, + char *begin_of_item, + char *end_of_item, + char *function_name, + int item_type ); +void RB_LaTeX_Generate_Empty_Item( + FILE *dest ); +void RB_LaTeX_Generate_Char( + FILE *dest_doc, + int c ); +void RB_LaTeX_Generate_False_Link( + FILE *dest_doc, + char *name ); + +void RB_LaTeX_Generate_String( + FILE *dest_doc, + char *a_string ); +void RB_LaTeX_Generate_EscapedChar( + FILE *dest_doc, + int c ); + +void LaTeX_Generate_Begin_Paragraph( + FILE *dest_doc ); +void LaTeX_Generate_End_Paragraph( + FILE *dest_doc ); +void LaTeX_Generate_Begin_Preformatted( + FILE *dest_doc ); +void LaTeX_Generate_End_Preformatted( + FILE *dest_doc ); +void LaTeX_Generate_Begin_List( + FILE *dest_doc ); +void LaTeX_Generate_End_List( + FILE *dest_doc ); +void LaTeX_Generate_Begin_List_Item( + FILE *dest_doc ); +void LaTeX_Generate_End_List_Item( + FILE *dest_doc ); + +void RB_LaTeX_Generate_Label( + FILE *dest_doc, + char *name ); +void RB_LaTeX_Generate_Link( + FILE *cur_doc, + char *cur_name, + char *filename, + char *labelname, + char *linkname ); + +#endif /* ROBODOC_LATEX_GENERATOR_H */ diff --git a/Source/links.c b/Source/links.c new file mode 100644 index 0000000..db8b7e3 --- /dev/null +++ b/Source/links.c @@ -0,0 +1,511 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* ROBODoc/Links + * FUNCTION + * This module contains functions to manipulate links. + * Links are derived from headers. They are used to create + * links in the documentation between a word and the part of + * the documentation that explains something about that word. + * (For instance a function name or variable name). + * In addition to the links derived from the headers links are + * also derived from the names of all the sourcefiles. + * MODIFICATION HISTORY + * ????-??-?? Frans Slothouber V1.0 + * 2003-02-03 Frans Slothouber Refactoring + ******* + * $Header: /cvsroot/robodoc/robo/Source/links.c,v 1.43 2007/07/10 19:13:52 gumpu Exp $ + */ + +#include +#include +#include +#include +#include + +#include "globals.h" +#include "robodoc.h" +#include "headers.h" +#include "util.h" +#include "links.h" +#include "document.h" +#include "part.h" +#include "file.h" + +#ifdef DMALLOC +#include +#endif + +/* TODO Documentation */ +unsigned int link_index_size = 0; +struct RB_link **link_index = NULL; +struct RB_link **case_sensitive_link_index = NULL; + + +/* Local functions */ + +static struct RB_link *RB_Alloc_Link( char *label_name, char *object_name, + char *file_name ); + +/* TODO Documentation */ +int link_cmp( void *l1, void *l2 ) +{ + struct RB_link *link1 = l1; + struct RB_link *link2 = l2; + + return RB_Str_Case_Cmp( link1->object_name, link2->object_name ); +} + + +int case_sensitive_link_cmp( void *l1, void *l2 ) +{ + struct RB_link *link1 = l1; + struct RB_link *link2 = l2; + + return strcmp( link1->object_name, link2->object_name ); +} + +char * function_name( char * full_name ) +{ + char * name = strchr( full_name, '/' ); + + if( name ) return name + 1; + else return full_name; +} + +/****f* Links/RB_CollectLinks + * FUNCTION + * Convert header information into link information. + * RB_header -> RB_link conversion + * SYNOPSIS + */ +void +RB_CollectLinks( struct RB_Document *document, + struct RB_header **headers, + unsigned long count ) +/* + * INPUTS + * * document -- + * * headers -- the array with headers. + * * count -- number of headers in the array + * OUTPUT + * * link_index -- an array with links + * * link_index_size -- the number of links in the array. + * SOURCE + */ + +{ + unsigned long i, j; + int k; + struct RB_Part *i_part; + + for ( i = j = 0; i < count; ++i ) + { + j += headers[i]->no_names - 1; + } + + link_index_size = count + j; + + if ( ( document->actions.do_multidoc ) && + ! ( document->actions.do_one_file_per_header ) + ) + { + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + if ( i_part->headers ) + { + link_index_size++; + } + } + } + + link_index = + ( struct RB_link ** ) calloc( link_index_size, + sizeof( struct RB_link ** ) ); + case_sensitive_link_index = + ( struct RB_link ** ) calloc( link_index_size, + sizeof( struct RB_link ** ) ); + + for ( i = j = 0; i < count; ++i ) + { + struct RB_link *link; + struct RB_header *header; + + header = headers[i]; + assert( header->unique_name ); + assert( header->file_name ); + for( k = 0; k < header->no_names; j++, k++ ) + { + link = RB_Alloc_Link( header->unique_name, function_name(header->names[k]), + header->file_name ); + link->htype = header->htype; + link->is_internal = header->is_internal; + link_index[j] = link; + case_sensitive_link_index[j] = link; + } + } + + /* If we are in multidoc mode, we also create links + * for all the source files. + */ + + if ( ( document->actions.do_multidoc ) && + /* but not for one file per header multidocs */ + ! ( document->actions.do_one_file_per_header ) + ) + { + for ( i_part = document->parts; i_part; i_part = i_part->next ) + { + if ( i_part->headers ) + { + struct RB_link *link; + + link = + RB_Alloc_Link( "robo_top_of_doc", i_part->filename->name, + RB_Get_FullDocname( i_part->filename ) ); + i_part->filename->link = link; + link->htype = RB_FindHeaderType( HT_SOURCEHEADERTYPE ); + link_index[j] = link; + case_sensitive_link_index[j] = link; + ++j; + } + else + { + i_part->filename->link = NULL; + } + } + } + + /* Sort all the links so we can use a binary search */ + RB_QuickSort( (void **)link_index, 0, link_index_size - 1, link_cmp ); + RB_QuickSort( (void **)case_sensitive_link_index, 0, link_index_size - 1, case_sensitive_link_cmp ); +} + +/*****/ + + +/****f* Links/RB_Free_Links + * FUNCTION + * Deallocate all the memory used to store the links. + * SYNOPSIS + */ +void RB_Free_Links( void ) +/* + * INPUTS + * o link_index_size + * o link_index[] + * BUGS + * Should use RB_Free_Link instead of doing + * everything by it self. + * SOURCE + */ +{ + struct RB_link *cur_link; + unsigned int i; + + for ( i = 0; i < link_index_size; ++i ) + { + cur_link = link_index[i]; + free( cur_link->object_name ); + free( cur_link->label_name ); + free( cur_link->file_name ); + free( cur_link ); + } + free( link_index ); +} + +/*******/ + +/* TODO Documentation */ + +int RB_Number_Of_Links( struct RB_HeaderType* header_type, char* file_name, int internal ) +{ + struct RB_link *cur_link; + int n = 0; + unsigned int i; + + for ( i = 0; i < link_index_size; ++i ) + { + cur_link = link_index[i]; + if ( RB_CompareHeaderTypes( cur_link->htype, header_type ) && + ( ( cur_link->is_internal && internal ) || + ( !cur_link->is_internal && !internal ) ) ) + { + if ( file_name ) + { + if ( strcmp( file_name, cur_link->file_name ) == 0 ) + { + n++; + } + } + else + { + n++; + } + } + } + return n; +} + +/****f* Links/Find_Link [3.0h] + * NAME + * Find_Link -- try to match word with a link + * FUNCTION + * Searches for the given word in the list of links and + * headers. There are three passes (or four, when the C option + * is selected). Each pass uses a different definition of "word": + * o In the first pass it is any thing that ends with a 'space', a '.' + * or a ','. + * o In the second pass it is any string that consists of alpha + * numerics, '_', ':', '.', or '-'. + * o In the third pass (for C) it is any string that consists + * of alpha numerics or '_'. + * SYNOPSIS + */ + +int +Find_Link( char *word_begin, + char **object_name, + char **label_name, + char **file_name ) +/* + * INPUTS + * o word_begin - pointer to a word (a string). + * o object_name - pointer to a pointer to a string + * o file_name - pointer to a pointer to a string + * SIDE EFFECTS + * label_name & file_name are modified + * RESULT + * o object_name -- points to the object if a match was found, + * NULL otherwise. + * o file_name -- points to the file name if a match was found, + * NULL otherwise. + * o label_name -- points to the labelname if a match was found, + * o TRUE -- a match was found. + * o FALSE -- no match was found. + * NOTES + * This is a rather sensitive algorithm. Don't mess with it + * too much. + * SOURCE + */ + +{ + char *cur_char = NULL, old_char; + int low_index, high_index, cur_index, state, pass; + unsigned int length = 0; + + for ( pass = 0; pass < 3; pass++ ) + { + switch ( pass ) + { + case 0: + { + for ( cur_char = word_begin; + ( *cur_char == '_' ) || utf8_isalnum( *cur_char ) || utf8_ispunct( *cur_char ); + cur_char++ ); + break; + } + case 1: + { + for ( cur_char = word_begin; + utf8_isalnum( *cur_char ) || ( *cur_char == '_' ) || + ( *cur_char == '-' ) || ( *cur_char == '.' ) || + ( *cur_char == ':' ); cur_char++ ); + break; + } + case 2: + { + for ( cur_char = word_begin; + utf8_isalnum( *cur_char ) || ( *cur_char == '_'); + cur_char++ ); + break; + } + } + + if ( ( ( *( cur_char - 1 ) ) == ',' ) || ( ( *( cur_char - 1 ) ) == '.' ) ) + { + cur_char--; + } + + old_char = *cur_char; + *cur_char = '\0'; /* + * End the word with a '\0' + */ + if ( strlen( word_begin ) == length ) + { + /* Do not test the same word over and over. If + * the current string and the string of the previous + * pass are the same length, they are the same. */ + + /* RB_Say ("Skipping (pass %d) \"%s\"\n", SAY_INFO, pass, word_begin); */ + } + else + { + length = strlen( word_begin ); + /* RB_Say ("Testing (pass %d) \"%s\"\n", SAY_INFO, pass, word_begin); */ + /* + * Search case sensitive for a link + */ + for ( cur_index = 0, low_index = 0, high_index = + link_index_size - 1; high_index >= low_index; ) + { + cur_index = ( high_index - low_index ) / 2 + low_index; + state = strcmp( word_begin, case_sensitive_link_index[cur_index]->object_name ); + if ( state < 0 ) + { + high_index = cur_index - 1; + } + else if ( state == 0 ) + { + *object_name = case_sensitive_link_index[cur_index]->object_name; + *label_name = case_sensitive_link_index[cur_index]->label_name; + *file_name = case_sensitive_link_index[cur_index]->file_name; + RB_Say( "linking \"%s\"->\"%s\" from \"%s\"\n", SAY_DEBUG, + word_begin, *object_name, *file_name ); + *cur_char = old_char; + return ( TRUE ); + } + else if ( state > 0 ) + { + low_index = cur_index + 1; + } + } + + /* + * Search case insensitive for a link. + * But only when the user asks for this. + */ + if ( course_of_action.do_ignore_case_when_linking ) + { + + for ( cur_index = 0, low_index = 0, high_index = + link_index_size - 1; high_index >= low_index; ) + { + cur_index = ( high_index - low_index ) / 2 + low_index; + state = RB_Str_Case_Cmp( word_begin, link_index[cur_index]->object_name ); + if ( state < 0 ) + { + high_index = cur_index - 1; + } + else if ( state == 0 ) + { + *object_name = link_index[cur_index]->object_name; + *label_name = link_index[cur_index]->label_name; + *file_name = link_index[cur_index]->file_name; + RB_Say( "linking \"%s\"->\"%s\" from \"%s\"\n", SAY_DEBUG, + word_begin, *object_name, *file_name ); + *cur_char = old_char; + return ( TRUE ); + } + else if ( state > 0 ) + { + low_index = cur_index + 1; + } + } + } + } + *cur_char = old_char; + *file_name = NULL; + *object_name = NULL; + *label_name = NULL; + } + return ( FALSE ); +} + +/*****/ + + +/****f* Links/RB_Alloc_Link [2.01] + * NAME + * RB_Alloc_Link -- oop + * FUNCTION + * allocate struct + strings + * SYNOPSIS + */ +static struct RB_link * +RB_Alloc_Link( char *label_name, char *object_name, char *file_name ) +/* + * INPUTS + * char *label_name -- strings to copy into the link + * char *file_name + * RESULT + * struct RB_link * -- ready-to-use + * AUTHOR + * Koessi + * SEE ALSO + * RB_StrDup(), RB_Free_Link() + * SOURCE + */ + +{ + struct RB_link *new_link; + + assert( object_name ); + assert( label_name ); + assert( file_name ); + RB_Say( "Allocating a link (%s %s %s)\n", SAY_DEBUG, object_name, label_name, file_name ); + new_link = malloc( sizeof( struct RB_link ) ); + memset( new_link, 0, sizeof( struct RB_link ) ); + + new_link->file_name = RB_StrDup( file_name ); + new_link->object_name = RB_StrDup( object_name ); + new_link->label_name = RB_StrDup( label_name ); + return ( new_link ); +} + +/*****/ + +/****f* Links/RB_Free_Link + * NAME + * RB_Free_Link -- oop + * FUNCTION + * free struct + strings + * SYNOPSIS + */ +void RB_Free_Link( struct RB_link *arg_link ) +/* + * INPUTS + * struct RB_link *link + * AUTHOR + * Koessi + * SEE ALSO + * RB_Alloc_Link(), RB_Close_The_Shop() + * SOURCE + */ + +{ + if ( arg_link ) + { + if ( arg_link->label_name ) + { + free( arg_link->label_name ); + } + if ( arg_link->file_name ) + { + free( arg_link->file_name ); + } + free( arg_link ); + } +} + +/******/ + diff --git a/Source/links.h b/Source/links.h new file mode 100644 index 0000000..ca50cbb --- /dev/null +++ b/Source/links.h @@ -0,0 +1,76 @@ +#ifndef ROBODOC_LINKS_H +#define ROBODOC_LINKS_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "headertypes.h" +#include "headers.h" +#include "document.h" + +/****s* Links/RB_link + * NAME + * RB_link -- link data structure + * PURPOSE + * Structure to store links to the documentation of an component. + * ATTRIBUTES + * * label_name -- the label under which the component can be found. + * this should be a unique name. + * * object_name -- the proper name of the object + * * file_name -- the file the component can be found in. + * * type -- the type of component (the header type). + * * is_internal -- is the header an internal header? + * SOURCE + */ + +struct RB_link +{ + char *label_name; + char *object_name; + char *file_name; + struct RB_HeaderType *htype; + int is_internal; +}; + +/*********/ + +int Find_Link( + char *word_begin, + char **object_name, + char **unique_name, + char **file_name ); +void RB_CollectLinks( + struct RB_Document *document, + struct RB_header **headers, + unsigned long count ); +void RB_Free_Links( + void ); +void RB_Free_Link( + struct RB_link *arg_link ); + +int RB_Number_Of_Links( + struct RB_HeaderType *header_type, + char *file_name, + int internal ); + +#endif /* ROBODOC_LINKS_H */ diff --git a/Source/lua_generator.c b/Source/lua_generator.c new file mode 100644 index 0000000..29f1d8f --- /dev/null +++ b/Source/lua_generator.c @@ -0,0 +1,56 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +#ifdef USE_LUA + +/****m* ROBODoc/Lua_Generator + * FUNCTION + * Shell generator that actually gives data to a Lua script. + * Supports singledoc mode. + * + * AUTHOR + * Jeremy Cowgar + * + * NOTES + * No code defined yet. This is just a shell. + ******* + */ + +#include +#include +#include +#include + +#include "generator.h" +#include "util.h" +#include "links.h" +#include "lua_generator.h" +#include "globals.h" +#include "robodoc.h" + +#ifdef DMALLOC +#include +#endif + +/* Source to come soon */ + +#endif diff --git a/Source/lua_generator.h b/Source/lua_generator.h new file mode 100644 index 0000000..8161187 --- /dev/null +++ b/Source/lua_generator.h @@ -0,0 +1,28 @@ +#ifdef USE_LUA +#ifndef ROBODOC_LUA_GENERATOR_H +#define ROBODOC_LUA_GENERATOR_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#endif /* ROBODOC_LUA_GENERATOR_H */ +#endif /* USE_LUA */ diff --git a/Source/makefile.am b/Source/makefile.am new file mode 100644 index 0000000..1f16f57 --- /dev/null +++ b/Source/makefile.am @@ -0,0 +1,38 @@ +# vi: ff=unix +# $Id: makefile.am,v 1.24 2007/01/13 11:43:10 gumpu Exp $ +# Process this file with automake to produce Makefile.in + +bin_PROGRAMS = robodoc robohdrs + +robohdrs_SOURCES = \ + robohdrs.c headers.c util.c globals.c roboconfig.c \ + headertypes.c + +robohdrs_DEPENDENCIES = headers.h + +robodoc_SOURCES = \ + optioncheck.c optioncheck.h \ + analyser.c analyser.h \ + config.h \ + generator.c generator.h \ + headers.c headers.h \ + headertypes.c headertypes.h \ + items.c items.h \ + links.c links.h \ + globals.c globals.h \ + robodoc.c robodoc.h \ + util.c util.h \ + html_generator.c html_generator.h \ + xmldocbook_generator.c xmldocbook_generator.h \ + latex_generator.c latex_generator.h \ + rtf_generator.c rtf_generator.h \ + test_generator.c test_generator.h \ + ascii_generator.c ascii_generator.h \ + troff_generator.c troff_generator.h \ + lua_generator.c lua_generator.h \ + document.c document.h \ + directory.c directory.h \ + file.c file.h \ + part.c part.h \ + path.c path.h \ + roboconfig.c roboconfig.h diff --git a/Source/makefile.bcc b/Source/makefile.bcc new file mode 100644 index 0000000..0ccbdaa --- /dev/null +++ b/Source/makefile.bcc @@ -0,0 +1,182 @@ +#****h* ROBODoc/Makefile.bcc +# NAME +# Makefile.bcc -- Makefile for Borland C++ Compiler 5.5 +# Adapted from Makefile.plain +# +# SYNOPSIS +# make -f makefile.bcc robodoc +# PURPOSE +# The following targets are the most useful for the user. +# robodoc - makes the robodc executable. +# +#**** +# +# $Id: makefile.bcc,v 1.7 2007/05/04 13:31:31 petterik Exp $ +# + +SHELL = /bin/sh +.SUFFIXES: +.SUFFIXES: .c .obj + +#-------------------------------------- + +CC = bcc32 +CFLAGS = -DRB_BCC -DIGNORE_CASE_FILENAMES +LIBS= + +# +# +# + +BROWSER=netscape +ROBODOC=./robodoc +ETAGS=/usr/bin/etags +EGREP=/bin/egrep +RM=/bin/rm +VERS=4.99.1 +RELEASE=1 + +#-------------------------------------- +# sources for the robodoc executable +#-------------------------------------- + +# BCC -e filename.exe wouldn't work +# so list robodoc.c first to ensure correct .exe name +# + +SOURCES = analyser.c \ + ascii_generator.c \ + directory.c \ + generator.c \ + document.c \ + globals.c \ + headers.c \ + headertypes.c \ + html_generator.c \ + items.c \ + links.c \ + file.c \ + latex_generator.c \ + part.c \ + path.c \ + roboconfig.c \ + robodoc.c \ + rtf_generator.c \ + sgmldocbook_generator.c \ + test_generator.c \ + troff_generator.c \ + util.c \ + xmldocbook_generator.c + +HEADERS= analyser.h \ + ascii_generator.h \ + directory.h \ + dirwalk.h \ + document.h \ + file.h \ + generator.h \ + globals.h \ + headers.h \ + headertypes.h \ + html_generator.h \ + items.h \ + latex_generator.h \ + links.h \ + part.h \ + path.h \ + roboconfig.h \ + robodoc.h \ + rtf_generator.h \ + sgmldocbook_generator.h \ + test_generator.h \ + troff_generator.h \ + unittest.h \ + util.h \ + xmldocbook_generator.h + +OBJECTS= robodoc.obj \ + analyser.obj \ + ascii_generator.obj \ + directory.obj \ + generator.obj \ + document.obj \ + globals.obj \ + headers.obj \ + headertypes.obj \ + html_generator.obj \ + items.obj \ + links.obj \ + file.obj \ + latex_generator.obj \ + part.obj \ + path.obj \ + roboconfig.obj \ + rtf_generator.obj \ + sgmldocbook_generator.obj \ + test_generator.obj \ + troff_generator.obj \ + util.obj \ + xmldocbook_generator.obj + +#****e* Makefile.bcc/robodoc +# NAME +# robodoc -- +# NOTE +# This assumes that you version of make knows how to make an .obj file +# out of an .c file. +# SOURCE +# + +robodoc : $(OBJECTS) + $(CC) $(OBJECTS) $(LIBS) + +#**** +#------------------------------ +# Construction of the makefile +#------------------------------ + +depend : + makedepend -Y"" -f makefile.bcc $(SOURCES) $(HEADERS) + +depend2: + $(CC) -MM $(SOURCES) + +# DO NOT DELETE + +analyser.o : robodoc.h globals.h headers.h items.h util.h links.h \ + analyser.h document.h file.h path.h part.h +ascii_generator.o : ascii_generator.h headers.h util.h robodoc.h globals.h \ + items.h generator.h document.h +directory.o : robodoc.h directory.h file.h path.h +generator.o : globals.h robodoc.h headers.h items.h util.h links.h \ + generator.h document.h part.h file.h path.h roboconfig.h \ + html_generator.h latex_generator.h sgmldocbook_generator.h \ + rtf_generator.h troff_generator.h ascii_generator.h analyser.h +document.o : robodoc.h document.h part.h path.h directory.h file.h \ + headers.h links.h util.h generator.h +globals.o : robodoc.h globals.h headers.h util.h +headers.o : robodoc.h headers.h +headertypes.o : robodoc.h headertypes.h +html_generator.o : html_generator.h headers.h util.h globals.h robodoc.h \ + links.h generator.h document.h items.h +items.o : globals.h robodoc.h items.h roboconfig.h +links.o : globals.h robodoc.h headers.h util.h links.h +file.o : file.h path.h headers.h util.h +latex_generator.o : generator.h robodoc.h headers.h document.h util.h \ + links.h latex_generator.h globals.h +part.o : headers.h file.h path.h part.h util.h +path.o : path.h robodoc.h headers.h util.h +roboconfig.o : util.h roboconfig.h +robodoc.o : robodoc.h globals.h headers.h items.h util.h links.h \ + part.h analyser.h document.h generator.h directory.h file.h path.h \ + roboconfig.h +rtf_generator.o : rtf_generator.h headers.h util.h robodoc.h globals.h \ + generator.h document.h items.h +sgmldocbook_generator.o : sgmldocbook_generator.h headers.h util.h \ + robodoc.h globals.h links.h generator.h document.h items.h +test_generator.o : test_generator.h globals.h util.h +troff_generator.o : troff_generator.h headers.h util.h robodoc.h items.h \ + generator.h document.h +util.o : robodoc.h globals.h links.h headers.h items.h util.h +xmldocbook_generator.o : xmldocbook_generator.h globals.h util.h + diff --git a/Source/makefile.mingw b/Source/makefile.mingw new file mode 100644 index 0000000..f0e9907 --- /dev/null +++ b/Source/makefile.mingw @@ -0,0 +1,255 @@ +#****h* ROBODoc/Makefile.mingw +# NAME +# Makefile.mingw -- Plain makefile that does not need autoconf +# SYNOPSIS +# make -f makefile.mingw robodoc +# make -f makefile.mingw count +# make -f makefile.mingw test +# make -f makefile.mingw clean +# PURPOSE +# The makefile for MingW Minimalist GNU for Windows +# See http://www.mingw.org +# +# You can use it if you are on a win32 system. +# +# The following targets are the most useful for the user. +# +# robodoc - makes the robodoc executable. +# +# Developers might try: +# test - +# count - +# clean - +# +#**** +# +# $Id: makefile.mingw,v 1.7 2007/05/14 15:41:19 petterik Exp $ +# + +.SUFFIXES: +.SUFFIXES: .c .o + +#-------------------------------------- +# use gcc (generic) +#-------------------------------------- + +CC = gcc +CFLAGS = -pedantic -O3 -Wall -W -std=c99 # -ansi +LIBS= + +# +# +# + +ROBODOC=robodoc.exe +RM=rm -f +all: robodoc.exe + +# currently does not compile: robohdrs + +#-------------------------------------- +# sources for the robodoc executable +#-------------------------------------- + +SOURCES = analyser.c \ + ascii_generator.c \ + directory.c \ + generator.c \ + document.c \ + globals.c \ + headertypes.c \ + headers.c \ + html_generator.c \ + items.c \ + links.c \ + file.c \ + latex_generator.c \ + part.c \ + path.c \ + roboconfig.c \ + robodoc.c \ + optioncheck.c \ + rtf_generator.c \ + sgmldocbook_generator.c \ + troff_generator.c \ + util.c \ + test_generator.c \ + xmldocbook_generator.c + +HEADERS= analyser.h \ + ascii_generator.h \ + directory.h \ + dirwalk.h \ + document.h \ + file.h \ + generator.h \ + globals.h \ + headertypes.h \ + headers.h \ + html_generator.h \ + items.h \ + latex_generator.h \ + links.h \ + optioncheck.h \ + part.h \ + path.h \ + roboconfig.h \ + robodoc.h \ + rtf_generator.h \ + sgmldocbook_generator.h \ + troff_generator.h \ + unittest.h \ + util.h \ + test_generator.h \ + xmldocbook_generator.h + +OBJECTS= $(SOURCES:.c=.o) + +#****e* Makefile.mingw/robodoc +# NAME +# robodoc -- +# NOTE +# This assumes that you version of make knows how to make an .o file +# out of an .c file. +# SOURCE +# + +$(ROBODOC) : $(OBJECTS) + $(CC) $(OBJECTS) -o robodoc $(LIBS) + +#**** + +#****e* Makefile.mingw/robohdrs +# NAME +# robohdrs -- +# SOURCE +# + +robohdrs : robohdrs.o headers.o + $(CC) robohdrs.o headers.o -o robohdrs + +#**** + +html : robodoc.html + +robodoc.html : $(ROBODOC) + ./$(ROBODOC) --src ./ --doc robodoc --singledoc --html --sections --toc + +#---------------------------- +# Development +#---------------------------- + + +#****e* Makefile.mingw/test +# NAME +# test -- run some tests +# FUNCTION +# Runs robodoc on file with a number of different headers. +# HISTORY +# 2002-05-19/PetteriK: test cases in Test directory run with this rule +# +#**** + +test : $(ROBODOC) + (cd Test; $(MAKE)) + +#****e* Makefile.mingw/clean +# NAME +# clean -- Clean up the mess we made. +# FUNCTION +# Cleans up the mess we made. +#***** + +clean : + $(RM) $(OBJECTS) + $(RM) robodoc + $(RM) robohdrs + $(RM) *~ + $(RM) *.o + $(RM) *.tex + $(RM) *.toc + $(RM) *.dvi + $(RM) *.aux + $(RM) *.log + $(RM) *.ps + $(RM) robodoc.html + $(RM) testheaders.html + $(RM) stamp-h* + $(RM) makefile.in + $(RM) config.h + + +#------------------------------ +# Construction of the makefile +#------------------------------ + +depend : + makedepend -Y"" -f makefile.mingw $(SOURCES) $(HEADERS) + +depend2: + $(CC) -MM $(SOURCES) + +# DO NOT DELETE + +analyser.o: robodoc.h globals.h headers.h headertypes.h items.h util.h +analyser.o: links.h document.h analyser.h file.h path.h part.h +ascii_generator.o: ascii_generator.h headers.h util.h robodoc.h globals.h +ascii_generator.o: items.h generator.h document.h +directory.o: robodoc.h directory.h file.h path.h links.h headertypes.h +directory.o: headers.h document.h util.h globals.h roboconfig.h +generator.o: globals.h robodoc.h headers.h items.h util.h links.h +generator.o: headertypes.h document.h generator.h part.h file.h path.h +generator.o: roboconfig.h html_generator.h latex_generator.h +generator.o: sgmldocbook_generator.h xmldocbook_generator.h rtf_generator.h +generator.o: troff_generator.h ascii_generator.h test_generator.h analyser.h +document.o: robodoc.h document.h part.h path.h directory.h file.h links.h +document.o: headertypes.h headers.h util.h generator.h +globals.o: robodoc.h globals.h links.h headertypes.h headers.h document.h +headertypes.o: headertypes.h util.h headers.h +headers.o: robodoc.h headers.h globals.h roboconfig.h util.h +html_generator.o: html_generator.h headers.h items.h document.h robodoc.h +html_generator.o: util.h globals.h links.h headertypes.h generator.h +html_generator.o: directory.h file.h path.h part.h +items.o: globals.h robodoc.h items.h roboconfig.h util.h headers.h +links.o: globals.h robodoc.h headers.h util.h links.h headertypes.h +links.o: document.h part.h file.h path.h +file.o: file.h path.h links.h headertypes.h headers.h document.h robodoc.h +file.o: util.h +latex_generator.o: generator.h robodoc.h headers.h document.h util.h links.h +latex_generator.o: headertypes.h latex_generator.h globals.h +part.o: headers.h file.h path.h links.h headertypes.h document.h robodoc.h +part.o: part.h util.h +path.o: path.h robodoc.h headers.h util.h +roboconfig.o: headertypes.h util.h headers.h roboconfig.h +robodoc.o: robodoc.h globals.h headers.h util.h links.h headertypes.h +robodoc.o: document.h part.h analyser.h generator.h directory.h file.h path.h +robodoc.o: roboconfig.h +rtf_generator.o: rtf_generator.h headers.h util.h robodoc.h globals.h +rtf_generator.o: generator.h document.h +sgmldocbook_generator.o: sgmldocbook_generator.h headers.h +sgmldocbook_generator.o: xmldocbook_generator.h document.h robodoc.h util.h +sgmldocbook_generator.o: globals.h links.h headertypes.h generator.h items.h +troff_generator.o: troff_generator.h headers.h util.h robodoc.h items.h +troff_generator.o: generator.h document.h +util.o: robodoc.h globals.h links.h headertypes.h headers.h document.h util.h +test_generator.o: test_generator.h headers.h document.h robodoc.h globals.h +test_generator.o: util.h +xmldocbook_generator.o: xmldocbook_generator.h headers.h document.h robodoc.h +xmldocbook_generator.o: globals.h util.h +analyser.o: document.h robodoc.h +ascii_generator.o: headers.h +directory.o: file.h path.h links.h headertypes.h headers.h document.h +directory.o: robodoc.h +document.o: robodoc.h +file.o: path.h links.h headertypes.h headers.h document.h robodoc.h +generator.o: robodoc.h headers.h document.h +globals.o: robodoc.h +html_generator.o: headers.h items.h document.h robodoc.h +latex_generator.o: headers.h +links.o: headertypes.h headers.h document.h robodoc.h +rtf_generator.o: headers.h +sgmldocbook_generator.o: headers.h +troff_generator.o: headers.h +util.o: headers.h +test_generator.o: headers.h document.h robodoc.h +xmldocbook_generator.o: headers.h document.h robodoc.h diff --git a/Source/makefile.mingw-cygwin b/Source/makefile.mingw-cygwin new file mode 100644 index 0000000..91797f9 --- /dev/null +++ b/Source/makefile.mingw-cygwin @@ -0,0 +1,279 @@ +# vi: spell ff=unix +#****h* ROBODoc/makefile.mingw-cygwin +# NAME +# makefile.mingw-cygwin -- Plain makefile that does not need autoconf +# PURPOSE +# The makefile for MingW Minimalist GNU for Windows under the Cygwin +# environment, See: +# * http://www.mingw.org, +# * http://www.cygwin.com +# +# You can use it if you are on a win32 system. +# +# The following targets are the most useful for the user: +# * robodoc - makes the robodoc executable. +# +# Developers might try: +# * test - run system tests +# * clean - clean all results. +# +# EXAMPLES +# make -f makefile.mingw-cygwin robodoc +# make -f makefile.mingw-cygwin test +# make -f makefile.mingw-cygwin clean +# +#**** +# +# $Id: makefile.mingw-cygwin,v 1.17 2007/05/14 15:41:19 petterik Exp $ +# + +.SUFFIXES: +.SUFFIXES: .c .o + +#-------------------------------------- +# use gcc (generic) +#-------------------------------------- + +CC = gcc +#DEBUG = 1 + +#****v* makefile.mingw-cygwin/CFLAGS +# FUNCTION +# Defined the flags used for the C compiler: +# * -W, -Wall and -std=gnu99 -- +# This turns on all warnings based on the C99 standard. +# Making the source warning free for an earlier standard is +# not necessary as this code is compiled on Unix, Windows, and +# Mac systems that all have C99 compliant C compilers. +# It also allows some gnu extensions. +# Using -std=c99 gives some spurious warnings about popen() +# * -O3 -- optimize, turning optimization on finds more errors and +# warnings. +# * -mno-cygwin -- Tells gcc not to link with cygwin1.dll but use the +# windows standard C library. (make mingw windows native executable +# under cygwin) +# * -s -- Strip debug info out from objects, making the executable smaller +# * -g -- Include all debugger info for GDB +# SOURCE + +ifdef DEBUG +CFLAGS = -g -mno-cygwin -W -Wall -std=gnu99 +else +CFLAGS = -s -mno-cygwin -O3 -W -Wall -std=gnu99 +endif + +#***** + +LIBS= + +# +# +# + +ROBODOC=robodoc.exe +RM=rm -f +all: robodoc.exe + +# currently does not compile: robohdrs + +#****v* makefile.mingw-cygwin/SOURCES, HEADERS +# FUNCTION +# All source files needed to compile ROBODoc +# SOURCE +# +SOURCES = \ + analyser.c \ + ascii_generator.c \ + directory.c \ + document.c \ + file.c \ + generator.c \ + globals.c \ + headers.c \ + headertypes.c \ + html_generator.c \ + items.c \ + latex_generator.c \ + links.c \ + optioncheck.c \ + part.c \ + path.c \ + roboconfig.c \ + robodoc.c \ + rtf_generator.c \ + test_generator.c \ + troff_generator.c \ + util.c \ + xmldocbook_generator.c + +HEADERS= analyser.h \ + ascii_generator.h \ + directory.h \ + dirwalk.h \ + document.h \ + file.h \ + generator.h \ + globals.h \ + headertypes.h \ + headers.h \ + html_generator.h \ + items.h \ + latex_generator.h \ + links.h \ + optioncheck.h \ + part.h \ + path.h \ + roboconfig.h \ + robodoc.h \ + rtf_generator.h \ + troff_generator.h \ + unittest.h \ + util.h \ + test_generator.h \ + xmldocbook_generator.h + +#***** + +OBJECTS= $(SOURCES:.c=.o) + +#****e* makefile.mingw-cygwin/robodoc +# NAME +# robodoc -- +# NOTE +# This assumes that your version of make knows how to make an .o file +# out of an .c file. +# SOURCE +# + +$(ROBODOC) : $(OBJECTS) + $(CC) $(CFLAGS) $(OBJECTS) -o $(ROBODOC) $(LIBS) + +#**** + +#****e* makefile.mingw-cygwin/robohdrs +# NAME +# robohdrs -- +# SOURCE +# + +robohdrs : robohdrs.o headers.o + $(CC) robohdrs.o headers.o -o robohdrs + +#**** + +html : robodoc.html + +robodoc.html : $(ROBODOC) + ./$(ROBODOC) --src ./ --doc robodoc --singledoc --html --sections --toc + +#---------------------------- +# Development +#---------------------------- + + +#****e* makefile.mingw-cygwin/test +# NAME +# test -- run some tests +# FUNCTION +# Runs robodoc on file with a number of different headers. +# HISTORY +# 2002-05-19/PetteriK: test cases in Test directory run with this rule +# +#**** + +test : $(ROBODOC) + (cd Test; $(MAKE)) + +#****e* makefile.mingw-cygwin/clean +# NAME +# clean -- Clean up the mess we made. +# FUNCTION +# Cleans up the mess we made. +#***** + +clean : + $(RM) \ + $(OBJECTS) \ + $(ROBODOC) \ + robohdrs \ + *~ \ + *.o \ + *.tex \ + *.toc \ + *.dvi \ + *.aux \ + *.log \ + *.ps \ + robodoc.html \ + testheaders.html \ + stamp-h* \ + makefile.in \ + config.h \ + + +#------------------------------ +# Construction of the makefile +#------------------------------ + +# TODO Figure out how to get rid of all the warnings about +# standard includes such as etc +depend : + makedepend -Y"" -f makefile.mingw-cygwin $(SOURCES) $(HEADERS) + +depend2: + $(CC) -MM $(SOURCES) + +# DO NOT DELETE + +analyser.o: analyser.c robodoc.h globals.h headers.h headertypes.h \ + items.h util.h document.h links.h analyser.h file.h path.h part.h \ + roboconfig.h +ascii_generator.o: ascii_generator.c ascii_generator.h headers.h util.h \ + document.h robodoc.h globals.h items.h headertypes.h generator.h +directory.o: directory.c robodoc.h directory.h file.h path.h links.h \ + headertypes.h headers.h document.h util.h globals.h roboconfig.h +document.o: document.c robodoc.h document.h part.h path.h directory.h \ + file.h links.h headertypes.h headers.h util.h generator.h globals.h +file.o: file.c file.h path.h links.h headertypes.h headers.h document.h \ + robodoc.h util.h +generator.o: generator.c globals.h robodoc.h headers.h items.h util.h \ + document.h links.h headertypes.h generator.h part.h file.h path.h \ + roboconfig.h html_generator.h latex_generator.h xmldocbook_generator.h \ + rtf_generator.h troff_generator.h ascii_generator.h test_generator.h \ + analyser.h +globals.o: globals.c robodoc.h globals.h links.h headertypes.h headers.h \ + document.h +headers.o: headers.c robodoc.h headers.h globals.h roboconfig.h util.h \ + document.h +headertypes.o: headertypes.c headertypes.h util.h headers.h document.h \ + robodoc.h +html_generator.o: html_generator.c html_generator.h headers.h items.h \ + robodoc.h document.h util.h globals.h links.h headertypes.h generator.h \ + directory.h file.h path.h part.h roboconfig.h +items.o: items.c globals.h robodoc.h items.h roboconfig.h util.h \ + headers.h document.h +latex_generator.o: latex_generator.c generator.h robodoc.h headers.h \ + document.h util.h links.h headertypes.h latex_generator.h globals.h +links.o: links.c globals.h robodoc.h headers.h util.h document.h links.h \ + headertypes.h part.h file.h path.h +optioncheck.o: optioncheck.c robodoc.h optioncheck.h roboconfig.h util.h \ + headers.h document.h +part.o: part.c headers.h file.h path.h links.h headertypes.h document.h \ + robodoc.h part.h util.h +path.o: path.c path.h robodoc.h headers.h util.h document.h +roboconfig.o: roboconfig.c headertypes.h util.h headers.h document.h \ + robodoc.h roboconfig.h globals.h optioncheck.h +robodoc.o: robodoc.c robodoc.h globals.h headers.h util.h document.h \ + links.h headertypes.h part.h analyser.h generator.h directory.h file.h \ + path.h roboconfig.h optioncheck.h +rtf_generator.o: rtf_generator.c rtf_generator.h headers.h util.h \ + document.h robodoc.h globals.h generator.h +test_generator.o: test_generator.c test_generator.h headers.h document.h \ + robodoc.h globals.h util.h +troff_generator.o: troff_generator.c troff_generator.h headers.h items.h \ + robodoc.h util.h document.h generator.h file.h path.h links.h \ + headertypes.h part.h +util.o: util.c robodoc.h globals.h links.h headertypes.h headers.h \ + document.h path.h util.h +xmldocbook_generator.o: xmldocbook_generator.c xmldocbook_generator.h \ + headers.h document.h robodoc.h globals.h util.h diff --git a/Source/makefile.plain b/Source/makefile.plain new file mode 100644 index 0000000..0e370fb --- /dev/null +++ b/Source/makefile.plain @@ -0,0 +1,262 @@ +# -*-makefile-*- +# vi: ff=unix +# +#****h* ROBODoc/Makefile.plain +# NAME +# Makefile.plain -- Plain makefile that does not need autoconf +# SYNOPSIS +# * make -f makefile.plain robodoc +# * make -f makefile.plain html +# * make -f makefile.plain count +# * make -f makefile.plain test +# * make -f makefile.plain clean +# * make -f makefile.plain xcompile +# +# PURPOSE +# The makefile GCC. +# You can use it if you are on a non Unix system or a system +# that does not support autoconfiguration. +# +# The following targets are the most useful for the user: +# * robodoc - makes the robodc executable. +# * example - makes robodoc and shows you the autodocs +# generated from the ROBODoc source code +# using browser. +# * html - makes autodocs for robodoc in html format. +# +# To build robodoc use: +# * make -f makefile.plain robodoc +# +# Developers might try: +# * depend - create dependencies +# * test - +# * count - +# * clean - +# +# NOTES +# This documentation is not complete. It is just a test to see +# how to best use ROBODoc with makefiles. +# +#**** +# +# $Id: makefile.plain,v 1.63 2007/07/10 19:13:52 gumpu Exp $ +# + +SHELL = /bin/sh +.SUFFIXES: +.SUFFIXES: .c .o + +#-------------------------------------- +# use gcc (generic) +#-------------------------------------- + +CC = gcc +# CFLAGS = -g -Wall -Wshadow -Wbad-function-cast -Wconversion -Wredundant-decls +# -Wunreachable-code +# TODO try to get this to compile with -Wconversion + +CFLAGS = -g -Wall -Wshadow -Wbad-function-cast -Wredundant-decls +LIBS= + +# + +BROWSER=netscape +ROBODOC=./robodoc +ETAGS=/usr/bin/etags +EGREP=/bin/egrep +RM=/bin/rm +MINGW_CC=/usr/bin/i586-mingw32msvc-gcc +VERS=4.99.36 +RELEASE=1 +all: robodoc robohdrs + +#-------------------------------------- +# sources for the robodoc executable +#-------------------------------------- + +SOURCES = \ + analyser.c \ + ascii_generator.c \ + directory.c \ + generator.c \ + document.c \ + globals.c \ + headers.c \ + headertypes.c \ + html_generator.c \ + items.c \ + links.c \ + file.c \ + latex_generator.c \ + optioncheck.c \ + part.c \ + path.c \ + roboconfig.c \ + robodoc.c \ + rtf_generator.c \ + test_generator.c \ + troff_generator.c \ + util.c \ + xmldocbook_generator.c + +HEADERS= \ + analyser.h \ + ascii_generator.h \ + directory.h \ + dirwalk.h \ + document.h \ + file.h \ + generator.h \ + globals.h \ + headers.h \ + headertypes.h \ + html_generator.h \ + items.h \ + latex_generator.h \ + links.h \ + optioncheck.h \ + part.h \ + path.h \ + roboconfig.h \ + robodoc.h \ + rtf_generator.h \ + test_generator.h \ + troff_generator.h \ + unittest.h \ + util.h \ + xmldocbook_generator.h + +OBJECTS = $(SOURCES:.c=.o) +DEPENDS = $(OBJECTS:.o=.d) + +#****e* Makefile.plain/robodoc +# NAME +# robodoc -- +# NOTE +# This assumes that you version of make knows how to make an .o file +# out of an .c file. +# SOURCE +# + +robodoc : $(OBJECTS) + $(CC) $(OBJECTS) -o robodoc$(EXE) $(LIBS) + +#**** + +#****e* Makefile.plain/robohdrs +# NAME +# robohdrs -- +# SOURCE +# + +robohdrs : robodoc robohdrs.o headers.o + $(CC) $(CFLAGS) util.o globals.o robohdrs.o headers.o roboconfig.o headertypes.o -o robohdrs$(EXE) + +#**** + +html : robodoc.html + +robodoc.html : robodoc + ./robodoc --src ./ --doc robodoc --singledoc --html --sections --toc + +#****e* Makefile.plain/example +# NAME +# example -- create and show autodocs extracted from ROBODoc source. +# FUNCTION +# +#**** + +example : html + $(BROWSER) robodoc.html + +#---------------------------- +# Development +#---------------------------- + +tags : + $(ETAGS) *.c *.h + +#****e* Makefile.plain/count +# NAME +# count -- count the number of lines of the ROBODoc source. +#**** + +count : + $(EGREP) -v -G "^ \*" *.c *.h | egrep -v -G "/\*" | wc + + +#****e* Makefile.plain/test +# NAME +# test -- run some tests +# FUNCTION +# Runs robodoc on file with a number of different headers. +# HISTORY +# 2002-05-19/PetteriK: test cases in Test directory run with this rule +# +#**** + +test : $(ROBODOC) + (cd Test; $(MAKE)) + +#****e* Makefile.plain/clean +# NAME +# clean -- Clean up the mess we made. +# FUNCTION +# Cleans up the mess we made. +#***** + +clean : + $(RM) -f $(DOCS) $(XREF) + $(RM) -f robodoc robohdrs + $(RM) -f *~ + $(RM) -f *.o *.tex *.toc *.dvi *.aux *.log *.ps *.exe + $(RM) -f robodoc.html + $(RM) -f testheaders.html + $(RM) -f stamp-h* makefile.in config.h + +#****e* Makefile.plain/xcompiler-test +# NAME +# xcompiler-test +# SYNOPSIS +# make -f makefile.plain xcompiler-test +# NOTE +# Used by do.sh. +# RESULT +# Exit status 0 if cross-compiler is found. +# SOURCE +# + +xcompiler-test: + test -x $(MINGW_CC) + zip -h > /dev/null 2>&1 + +#***** + +#****e* Makefile.plain/xcompile +# NAME +# xcompile +# SYNOPSIS +# make -f makefile.plain xcompile +# make -f makefile.plain MINGW_CC=/path/to/mingwcc xcompile +# NOTE +# Cross-compile Wintel binary. +# Consider `apt-get install mingw32' before running this. +# RESULT +# Excutable `robodoc.exe' is created. +# SOURCE +# + +xcompile: + $(MAKE) -f makefile.plain CC=$(MINGW_CC) EXE=.exe robodoc + +#***** end xcompile + +#------------------------------ +# Construction of the makefile +#------------------------------ + +-include $(DEPENDS) + +depend: + $(CC) -MMD -E $(SOURCES) > /dev/null + diff --git a/Source/makefile.win32 b/Source/makefile.win32 new file mode 100644 index 0000000..9d1efd7 --- /dev/null +++ b/Source/makefile.win32 @@ -0,0 +1,105 @@ +#****h* ROBODoc/Makefile.win32 +# FUNCTION +# A makefile for win32. +# Well it is not really a proper makefile since the dependencies are +# missing, but it will compile robodoc using VC++ +# USAGE +# nmake -f makefile.win32 +# nmake -f makefile.win32 clean +# NOTES +# run vcvars32.bat (part of VC++) +# before using this file. +#***** + +.SUFFIXES : +.SUFFIXES : .obj .c +.c.obj: + $(CC) $(CFLAGS) -c $< + +CC = cl + +#****v* Makefile.win32/CFLAGS +# FUNCTION +# The flags feeded to the compiler to compile a .c file. +# +# -I. look for include files in the current directory +# -Zi enable debugging information. +# -W3 turns on warnings, +# -D RB_MSVC defines the symbol RB_MSVC which is needed +# to compile the OS dependend parts of robodoc. +# SOURCE +# + +CFLAGS = -c -I. -nologo -Zi -W3 -D RB_MSVC -D IGNORE_CASE_FILENAMES + +#****** + +CLINK = link +CLINKFLAGS = /nologo /debug + +#****v* Makefile.win32/SOURCES +# FUNCTION +# List of all the sources needed to compile ROBODoc. +# SOURCE +SOURCES=analyser.c generator.c items.c util.c folds.c headers.c \ + headertypes.c links.c robodoc.c directory.c part.c file.c path.c \ + html_generator.c latex_generator.c rtf_generator.c \ + troff_generator.c sgmldocbook_generator.c ascii_generator.c \ + globals.c document.c roboconfig.c xmldocbook_generator.c \ + test_generator.c +#***** + +OBJECTS=$(SOURCES:.c=.obj) + + +#****e* Makefile.win32/robodoc.trg +# FUNCTION +# Compile the robodoc executable. This makefile is +# missing a dependencies sections, so use this target +# only once. +# SOURCE +# +robodoc.trg : $(OBJECTS) + $(CLINK) $(CLINKFLAGS) $(OBJECTS) /out:robodoc.exe +#****** + +#****v* Makefile.win32/clean +# FUNCTION +# Delete all the files created in the build process. +# SOURCE +# +clean: + del $(OBJECTS) + del robodoc.exe + del *.pdb *.ilk + del tags +#***** + + +frans: robodoc.trg + copy robodoc.exe c:\pws\bin + +LINTOPT = -ic:\pclint8\lnt -u std.lnt env-vc6.lnt -e715 +dRB_MSVC + +# LINTOPT = -ic:\pclint8\lnt -u std.lnt env-vc6.lnt -e715 -e613 -e550 -e740 -e732 -e713 -e737 -e818 -e830 -e641 +dRB_MSVC + +#****ie* Makefile.win32/lint +# FUNCTION +# Runs lint on all the robodoc sources. +# SOURCE +# +lint: + -c:\pclint8\lint-nt $(LINTOPT) globals.c + -c:\pclint8\lint-nt $(LINTOPT) latex_generator.c + -c:\pclint8\lint-nt $(LINTOPT) rtf_generator.c + -c:\pclint8\lint-nt $(LINTOPT) document.c + -c:\pclint8\lint-nt $(LINTOPT) file.c + -c:\pclint8\lint-nt $(LINTOPT) headers.c + -c:\pclint8\lint-nt $(LINTOPT) directory.c + -c:\pclint8\lint-nt $(LINTOPT) headertypes.c + -c:\pclint8\lint-nt $(LINTOPT) util.c + -c:\pclint8\lint-nt $(LINTOPT) roboconfig.c + -c:\pclint8\lint-nt $(LINTOPT) robodoc.c + -c:\pclint8\lint-nt $(LINTOPT) generator.c + -c:\pclint8\lint-nt $(LINTOPT) html_generator.c +#****** diff --git a/Source/makefile.wingcc b/Source/makefile.wingcc new file mode 100644 index 0000000..a17945c --- /dev/null +++ b/Source/makefile.wingcc @@ -0,0 +1 @@ +# Obsolete diff --git a/Source/optioncheck.c b/Source/optioncheck.c new file mode 100644 index 0000000..6067211 --- /dev/null +++ b/Source/optioncheck.c @@ -0,0 +1,667 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/* $Id: optioncheck.c,v 1.19 2007/07/10 19:13:52 gumpu Exp $*/ + +#include +#include +#include +#include +#include "robodoc.h" +#include "optioncheck.h" +#include "roboconfig.h" +#include "util.h" + + +char short_use[] = + "Usage:\n" + " robodoc --src --doc --multidoc [type] [options]\n" + " robodoc --src --doc --singledoc [type] [options]\n" + " robodoc --src --doc --singlefile [type] [options]\n" + "\n" "Use robodoc --help for more information\n"; + + +void Print_Short_Use( + void ) +{ + fprintf( stdout, "%s\n", short_use ); +} + +/****t* UserInterface/Option_Test_Kind + * FUNCTION + * Enumeration for the kind of tests that are carried out on the + * options that the user specifies. + * SOURCE + */ +typedef enum +{ + TEST_INVALID = 0, + TEST_MUTUAL_EXCLUDE = 1, + TEST_SHOULD_EXISTS, /* TODO Create this kind of test */ + TEST_NO_EFFECT, /* TODO Create this kind of test */ + TEST_COUNT, /* TODO Create this kind of test */ + TEST_SPELLING /* TODO Create this kind of test */ +} Option_Test_Kind; + +/*****/ + +typedef enum +{ + OPTION_FATAL = 1, + OPTION_WARNING +} Option_Error_Severity; + +/****s* UserInterface/RB_Option_Name + * FUNCTION + * Element in a list of option names. + * Used in a RB_Option_Test to specify to what + * options a test applies. + * SOURCE + */ + +struct RB_Option_Name +{ + /* linked list administration */ + struct RB_Option_Name *next; + /* name of the option */ + char *name; + /* use by the Count test */ + int count; +}; + +/*****/ + +/****s* UserInterface/RB_Option_Test + * FUNCTION + * A test specification for options. This + * stores information about the kind of test and + * the options it applies to, and the message that + * is given to the user. + * SOURCE + */ + +struct RB_Option_Test +{ + /* tests are stored in a linked list */ + struct RB_Option_Test *next; + /* the group of options the test applies to. */ + struct RB_Option_Name *option_group; + /* the kind of test */ + Option_Test_Kind kind; + /* More information for the user */ + char *more_information; /* TODO Fill and use */ + + Option_Error_Severity severity; +}; + +/******/ + +/****v* UserInterface/ok_options + * FUNCTION + * An list of all allowed command-line options. If you add any + * options add its name here too. This list is used to verify + * the options specified by the user. + * SOURCE + */ + +static char *ok_options[] = { + "--rc", + "--src", + "--doc", + "--html", + "--latex", + "--ascii", + "--rtf", + "--troff", + "--dbxml", + "--doctype_name", + "--doctype_location", + "--singledoc", + "--singlefile", + "--multidoc", + "--one_file_per_header", + "--first_section_level", + "--sections", + "--internal", + "--internalonly", + "--ignore_case_when_linking", + "--toc", + "--index", + "--nosource", + "--tabsize", + "--tell", + "--debug", + "--test", /* Special output mode for testing */ + "--nodesc", + "--nopre", + "--nogeneratedwith", + "--no_subdirectories", + "--cmode", + "--charset", + "--ext", + "--help", + "--css", + "--version", + "-c", + "--lock", + "--nosort", + "--headless", + "--footless", + "--sectionnameonly", + "--compress", + "--mansection", + "--verbal", /*FS TODO */ + "--ms_errors", /* TODO is this documented?? */ + "--documenttitle", + "--altlatex", + "--latexparts", + "--tabstops", + "--syntaxcolors", + "--syntaxcolors_enable", + "--dotname", + "--masterindex", + "--sourceindex", + "--header_breaks", + ( char * ) NULL +}; + +/*****/ + + +/****v* UserInterface/option_tests + * FUNCTION + * A linked lists of tests that check the options specified + * by the user. + * SOURCE + */ +static struct RB_Option_Test *option_tests = NULL; + +/*****/ + + +/****f* UserInterface/Add_Option_Test + * FUNCTION + * Add a test to the linked list of options tests. + * SYNOPSIS + */ +static void Add_Option_Test( + struct RB_Option_Test *option_test ) +/* + * INPUTS + * option_test -- the test to be added. + * SOURCE + */ +{ + option_test->next = option_tests; + option_tests = option_test; +} + +/*****/ + +/****f* UserInterface/Add_Option_Name + * FUNCTION + * Add the name of an option to the group of option names an option + * test applies to. + * SYNOPSIS + */ +static void Add_Option_Name( + struct RB_Option_Test *option_test, + char *name ) +/* + * INPUTS + * option_test -- the option test + * name -- the name of the option + * SOURCE + */ +{ + struct RB_Option_Name *new_option_name = + malloc( sizeof( struct RB_Option_Name ) ); + new_option_name->name = RB_StrDup( name ); + new_option_name->next = option_test->option_group; + new_option_name->count = 0; + option_test->option_group = new_option_name; +} + +/****/ + +/****f* UserInterface/Create_New_Option_Test + * FUNCTION + * Allocate and initialize a new option test. + * SYNOPSIS + */ +static struct RB_Option_Test *Create_New_Option_Test( + Option_Test_Kind kind, + Option_Error_Severity severity ) +/* + * INPUTS + * kind -- the kind of test that has to be created. + * SOURCE + */ +{ + struct RB_Option_Test *new_option_test = + malloc( sizeof( struct RB_Option_Test ) ); + new_option_test->next = NULL; + new_option_test->option_group = NULL; + new_option_test->kind = kind; + new_option_test->severity = severity; + return new_option_test; +} + +/*****/ + +/****f* UserInterface/Create_Test_Data + * FUNCTION + * Create a linked list of tests. + * SYNOPSIS + */ +static void Create_Test_Data( + void ) +/* + * TODO + * Generate this code automatically from a set + * of high-level specifications. + * SOURCE + */ +{ + struct RB_Option_Test *cur_option_test = NULL; + int i; + + cur_option_test = + Create_New_Option_Test( TEST_MUTUAL_EXCLUDE, OPTION_FATAL ); + Add_Option_Name( cur_option_test, "--singledoc" ); + Add_Option_Name( cur_option_test, "--multidoc" ); + Add_Option_Name( cur_option_test, "--singlefile" ); + Add_Option_Test( cur_option_test ); + + cur_option_test = + Create_New_Option_Test( TEST_MUTUAL_EXCLUDE, OPTION_FATAL ); + Add_Option_Name( cur_option_test, "--html" ); + Add_Option_Name( cur_option_test, "--rtf" ); + Add_Option_Name( cur_option_test, "--ascii" ); + Add_Option_Name( cur_option_test, "--dbxml" ); + Add_Option_Name( cur_option_test, "--troff" ); + Add_Option_Name( cur_option_test, "--latex" ); + Add_Option_Name( cur_option_test, "--test" ); + Add_Option_Test( cur_option_test ); + + /* Order is important here */ + cur_option_test = Create_New_Option_Test( TEST_COUNT, OPTION_FATAL ); + for ( i = 0; ok_options[i]; i++ ) + { + Add_Option_Name( cur_option_test, ok_options[i] ); + } + Add_Option_Test( cur_option_test ); + +} + +/******/ + +static int Do_Count_Test( + struct RB_Option_Test *cur_option_test ) +{ + unsigned int parameter_nr = 0; + int result = EXIT_SUCCESS; + struct RB_Option_Name *option_name; + + assert( cur_option_test ); + + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + for ( option_name = cur_option_test->option_group; + option_name; option_name = option_name->next ) + { + if ( RB_Str_Case_Cmp + ( configuration.options.names[parameter_nr], + option_name->name ) == 0 ) + { + ( option_name->count )++; + } + } + } + + for ( option_name = cur_option_test->option_group; + option_name; option_name = option_name->next ) + { + if ( option_name->count > 1 ) + { + fprintf( stderr, "The option %s is used more than once.\n", + option_name->name ); + result = EXIT_FAILURE; + } + } + + return result; +} + + +/****f* UserInterface/Do_Mutual_Exlcude_Test + * FUNCTION + * Check all the options to see if combinations of options + * are used that mutually exclude each other, such as + * --singledoc and --multidoc. + * SYNOPSIS + */ +static int Do_Mutual_Exlcude_Test( + struct RB_Option_Test *cur_option_test ) + /* + * INPUTS + * * cur_option_test -- the test to be carried out. + * SOURCE + */ +{ + int n = 0; + unsigned int parameter_nr = 0; + int result = EXIT_SUCCESS; + + assert( cur_option_test ); + + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + struct RB_Option_Name *option_name = cur_option_test->option_group; + + for ( ; option_name; option_name = option_name->next ) + { + if ( RB_Str_Case_Cmp + ( configuration.options.names[parameter_nr], + option_name->name ) == 0 ) + { + ++n; + } + } + } + + /* Only one of the options in the group may be used */ + if ( n > 1 ) + { + fprintf( stderr, "The options: " ); + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + struct RB_Option_Name *option_name = + cur_option_test->option_group; + for ( ; option_name; option_name = option_name->next ) + { + if ( RB_Str_Case_Cmp + ( configuration.options.names[parameter_nr], + option_name->name ) == 0 ) + { + + fprintf( stderr, "%s ", + configuration.options.names[parameter_nr] ); + } + } + } + fprintf( stderr, "cannot be used together.\n" ); + result = EXIT_FAILURE; + } + + return result; +} + +/*****/ + + +/****f* UserInterface/Do_Option_Tests + * FUNCTION + * Run a series of tests on the options that the user + * specified. These tests are specified in + * option_tests. + * SYNOPSIS + */ +static int Do_Option_Tests( + void ) +/* + * RESULT + * * EXIT_FAILURE -- one of the tests failed. + * * EXIT_SUCCESS -- all test completed successfully + * SOURCE + */ +{ + struct RB_Option_Test *cur_option_test = NULL; + int result = EXIT_SUCCESS; + int final_result = EXIT_SUCCESS; + + RB_Say( "Checking the option semantics.\n", SAY_INFO ); + Create_Test_Data( ); + cur_option_test = option_tests; + + assert( cur_option_test ); + + for ( ; cur_option_test; cur_option_test = cur_option_test->next ) + { + switch ( cur_option_test->kind ) + { + case TEST_MUTUAL_EXCLUDE: + RB_Say( "Checking for mutual excluding options.\n", SAY_INFO ); + result = Do_Mutual_Exlcude_Test( cur_option_test ); + break; + case TEST_COUNT: /* TODO Create */ + RB_Say( "Checking for duplicate options.\n", SAY_INFO ); + result = Do_Count_Test( cur_option_test ); + break; + case TEST_SHOULD_EXISTS: /* TODO Create */ + case TEST_NO_EFFECT: /* TODO Create */ + case TEST_SPELLING: /* TODO Create */ + default: + assert( 0 ); + } + /* If one of the tests fails the final result is a fail. */ + if ( result == EXIT_FAILURE ) + { + final_result = EXIT_FAILURE; + if ( cur_option_test->severity == OPTION_FATAL ) + { + break; + } + } + } + + return final_result; +} + +/****/ + +/****f* UserInterface/Check_Option_Spelling + * FUNCTION + * Check for misspelled options specified by the user. + * SYNOPSIS + */ + +int Check_Option_Spelling( + void ) +/* + * RESULT + * * EXIT_SUCCESS -- all options are correctly spelled. + * * EXIT_FAILURE -- one of more options are misspelled. + * SOURCE + */ +{ + char ok; + char *arg; + char **opts; + unsigned int parameter_nr; + + RB_Say( "Checking the option syntax.\n", SAY_INFO ); + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + arg = configuration.options.names[parameter_nr]; + if ( ( arg[0] == '-' ) && ( arg[1] == '-' ) ) + { + /* this arg is an option */ + ok = 0; + opts = ok_options; + while ( *opts ) + { + if ( strcmp( arg, *opts ) == 0 ) + { + ok = 1; + break; + } + opts++; + } + if ( !ok ) + { + fprintf( stderr, "Invalid argument: %s\n", arg ); + fprintf( stderr, + "This might also be in your robodoc.rc file\n" ); + return EXIT_FAILURE; + } + } + } + return EXIT_SUCCESS; +} + +/******/ + + +static int Check_Item_Names( + struct Parameters *arg_parameters, + char *block_name ) +{ + unsigned int parameter_nr_1; + unsigned int parameter_nr_2; + int name_is_ok = TRUE; + + RB_Say( "Checking the item names for %s block.\n", SAY_INFO, block_name ); + for ( parameter_nr_1 = 0; + parameter_nr_1 < arg_parameters->number; parameter_nr_1++ ) + { + name_is_ok = FALSE; + for ( parameter_nr_2 = 0; + parameter_nr_2 < configuration.items.number; parameter_nr_2++ ) + { + if ( strcmp( configuration.items.names[parameter_nr_2], + arg_parameters->names[parameter_nr_1] ) == 0 ) + { + name_is_ok = TRUE; + } + } + if ( !name_is_ok ) + { + RB_Say( "!! block.\n", SAY_INFO ); + fprintf( stderr, "Unknown item %s found in the\n", + arg_parameters->names[parameter_nr_1] ); + fprintf( stderr, " %s block\nof your configuration file.\n", + block_name ); + break; + } + } + + RB_Say( "Is %d block.\n", SAY_INFO, name_is_ok ); + return name_is_ok; +} + +/****f* UserInterface/Check_Item_Options + * FUNCTION + * Check the validity of the item options. Users can specify their + * own items, item order, and items that ar to be ignored. This all + * should be consistent. + * SYNOPSIS + */ +static int Check_Item_Options( + void ) +/* + * RESULT + * * EXIT_SUCCESS -- all options are correct. + * * EXIT_FAILURE -- one of more options incorrect. + * SOURCE + */ +{ + int item_OK = TRUE; + int result = TRUE; + + RB_Say( "Checking the item names.\n", SAY_INFO ); + result = item_OK + && Check_Item_Names( &( configuration.ignore_items ), + "ignore items:" ); + item_OK = item_OK && result; + result = + Check_Item_Names( &( configuration.source_items ), "source items:" ); + item_OK = item_OK && result; + result = + Check_Item_Names( &( configuration.preformatted_items ), + "preformatted items:" ); + item_OK = item_OK && result; + result = + Check_Item_Names( &( configuration.format_items ), "format items:" ); + item_OK = item_OK && result; + result = Check_Item_Names( &( configuration.item_order ), "item order:" ); + item_OK = item_OK && result; + if ( item_OK ) + { + return EXIT_SUCCESS; + } + else + { + return EXIT_FAILURE; + } +} + +/*****/ + + +/****f* UserInterface/Check_Options + * FUNCTION + * Check the validity of all the options in configuration.options[]. + * This runs a number of checks. + * SYNOPSIS + */ + +int Check_Options( + void ) +/* + * RESULT + * * EXIT_SUCCESS -- all options are correct. + * * EXIT_FAILURE -- one of more options incorrect. + * SOURCE + */ +{ + int status; + + RB_Say( "Checking the options.\n", SAY_INFO ); + status = Check_Option_Spelling( ); + if ( status == EXIT_SUCCESS ) + { + status = Do_Option_Tests( ); + if ( status == EXIT_SUCCESS ) + { + status = Check_Item_Options( ); + } + else + { + Print_Short_Use( ); + } + } + else + { + Print_Short_Use( ); + } + + /* TODO free option_tests */ + + return status; +} + +/*****/ diff --git a/Source/optioncheck.h b/Source/optioncheck.h new file mode 100644 index 0000000..286822c --- /dev/null +++ b/Source/optioncheck.h @@ -0,0 +1,31 @@ +#ifndef ROBODOC_OPTION_CHECK_H +#define ROBODOC_OPTION_CHECK_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +int Check_Options( + void ); + +void Print_Short_Use( void ); + +#endif /* ROBODOC_OPTION_CHECK_H */ diff --git a/Source/part.c b/Source/part.c new file mode 100644 index 0000000..1ec4fea --- /dev/null +++ b/Source/part.c @@ -0,0 +1,187 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* ROBODoc/Part + * FUNCTION + * Structures and functions that deal with documentation parts. A + * part links a sourcefile to the documentation file and contains + * all the headers found in a sourcefile. Parts (in the form of + * struct RB_Part) are stored in a RB_Document structure. + ***** + */ + +#include +#include +#include "headers.h" +#include "file.h" +#include "part.h" +#include "util.h" + + +#ifdef DMALLOC +#include +#endif + + +/****f* Part/RB_Get_RB_Part + * FUNCTION + * Create a new RB_Part and initialize it. + * SYNOPSIS + */ +struct RB_Part* RB_Get_RB_Part( void ) +/* + * RESULT + * A freshly allocated and initializedand RB_Part. + * SOURCE + */ +{ + struct RB_Part *part = NULL; + part = ( struct RB_Part * ) malloc( sizeof( struct RB_Part ) ); + if ( part ) + { + part->next = NULL; + part->filename = NULL; + part->headers = NULL; + part->last_header = NULL; + } + else + { + RB_Panic( "Out of memory! RB_Get_RB_Part()" ); + } + return part; +} + +/******/ + + + +/****f* Part/RB_Free_RB_Part + * FUNCTION + * Free the memory used by an RB_Part. Most of this is handled in + * other functions. + * SYNOPSIS + */ +void RB_Free_RB_Part( struct RB_Part *part ) +/* + * INPUTS + * o part -- the part to be freed. + * SOURCE + */ +{ + /* part->filename is freed by RB_Directory */ + /* part->headers. Headers are freed by the document */ + free( part ); +} + +/*******/ + +/****f* Part/RB_Open_Source + * FUNCTION + * Open the sourcefile of this part. + * SYNOPSIS + */ +FILE* RB_Open_Source( struct RB_Part *part ) +/* + * INPUTS + * o part -- the part for which the file is opened. + * SOURCE + */ +{ + char *sourcefilename = NULL; + FILE *result; + + assert( part ); + assert( part->filename ); + sourcefilename = Get_Fullname( part->filename ); + result = fopen( sourcefilename, "r" ); + if ( result ) + { + /* OK */ + } + else + { + RB_Panic( "can't open %s!", sourcefilename ); + } + return result; +} + +/******/ + + +/* TODO Documentation */ +FILE* RB_Open_Documentation( struct RB_Part * part ) +{ + char *docfilename = NULL; + FILE *result; + + assert( part ); + assert( part->filename ); + docfilename = RB_Get_FullDocname( part->filename ); + RB_Say( "Creating file %s\n", SAY_DEBUG, docfilename ); + result = fopen( docfilename, "w" ); + if ( result ) + { + /* OK */ + } + else + { + RB_Panic( "can't open %s!", docfilename ); + } + return result; +} + + +/* TODO Documentation */ +void +RB_Part_Add_Source( struct RB_Part *part, struct RB_Filename *sourcefilename ) +{ + /* One sourcefile per part. */ + part->filename = sourcefilename; +} + +struct RB_Filename *RB_Part_Get_Source( struct RB_Part *part ) +{ + return part->filename; +} + +/* TODO Documentation */ +void +RB_Part_Add_Header( struct RB_Part *part, struct RB_header *header ) +{ + assert( header ); + assert( header->module_name ); + assert( header->function_name ); + + header->owner = part; + if ( part->last_header ) + { + header->next = NULL; + part->last_header->next = header; + part->last_header = header; + } + else + { + header->next = NULL; + part->headers = header; + part->last_header = header; + } +} diff --git a/Source/part.h b/Source/part.h new file mode 100644 index 0000000..4f7b753 --- /dev/null +++ b/Source/part.h @@ -0,0 +1,85 @@ +#ifndef ROBODOC_PART_H +#define ROBODOC_PART_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include + +/****s* Part/RB_Part + * NAME + * RB_Part -- a part of the total documentation + * FUNCTION + * RB_Parts are stored in RB_Document. For each source file there + * is an RB_Part. It points to the source file, the documentation + * file, and contains all the headers that were found in the source + * file. + * ATTRIBUTES + * o next -- pointer to the next part + * (to form a linked list). + * o filename -- Information over the path to the + * sourcefile and the correcsponding + * documentation file. + * o headers -- All the headers that were + * found in the sourcefile. + * o last_header -- pointer to the last element in the + * list of headers. + * This is used to make it possible + * to add the the heades in the + * same order as they were found in + * the source file. + ***** + */ + +struct RB_Part +{ + struct RB_Part *next; + struct RB_Filename *filename; + struct RB_header *headers; + struct RB_header *last_header; +}; + + +struct RB_Part *RB_Get_RB_Part( + void ); +void RB_Free_RB_Part( + struct RB_Part *part ); +FILE *RB_Open_Documentation( + struct RB_Part *part ); +FILE *RB_Open_Source( + struct RB_Part *part ); + +void RB_Part_Add_Header( + struct RB_Part *part, + struct RB_header *header ); +void RB_Part_Add_Source( + struct RB_Part *part, + struct RB_Filename *sourcefilename ); +void RB_Part_Add_Doc( + struct RB_Part *part, + struct RB_Filename *docfilename ); +void RB_Part_Dump( + struct RB_Part *part ); +struct RB_Filename *RB_Part_Get_Source( + struct RB_Part *part ); + +#endif /* ROBODOC_PART_H */ diff --git a/Source/path.c b/Source/path.c new file mode 100644 index 0000000..38e81d0 --- /dev/null +++ b/Source/path.c @@ -0,0 +1,137 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +#include +#include +#include +#include "path.h" +#include "robodoc.h" +#include "headers.h" +#include "util.h" + +#ifdef DMALLOC +#include +#endif + +/* TODO Documentation */ + +struct RB_Path * +RB_Get_RB_Path( char *arg_pathname ) +{ + struct RB_Path *rb_path; + int needs_slash = FALSE; + + if ( strlen( arg_pathname ) == 0 ) + { + RB_Panic( "Trying to use a path with as name \"\"\n" ); + return 0; /* Keep the compiler happy. */ + } + else + { + /* Check if the path ends with a / if not we will need to add one. */ + needs_slash = ( arg_pathname[strlen( arg_pathname ) - 1] != '/' ); + rb_path = ( struct RB_Path * ) malloc( sizeof( struct RB_Path ) ); + + if ( ! rb_path ) + { + RB_Panic( "Out of memory! %s()\n", "RB_Get_RB_Path" ); + } + + /* 2 extra for the '/' and '\0' */ + rb_path->name = + ( char * ) calloc( strlen( arg_pathname ) + 2, sizeof( char ) ); + + if ( ! rb_path->name ) + { + RB_Panic( "Out of memory! %s()\n", "RB_Get_RB_Path" ); + } + + *( rb_path->name ) = '\0'; + rb_path->parent = NULL; + rb_path->next = NULL; + strcat( rb_path->name, arg_pathname ); + if ( needs_slash ) + { + strcat( rb_path->name, "/" ); + } + rb_path->docname = NULL; + } + return rb_path; +} + +/*x**f* ROBODoc/RB_Get_RB_Path2 + * NAME + * RB_Get_RB_Path2 -- create a new RB_Path structure. + * FUNCTION + * NOTE + * Has a wrong name... + ***** + */ + +/* TODO Documentation */ +struct RB_Path * +RB_Get_RB_Path2( char *arg_current_path, char *arg_subdirectory ) +{ + struct RB_Path *rb_path; + rb_path = ( struct RB_Path * ) malloc( sizeof( struct RB_Path ) ); + /* allocate memory for the path name, + it will consist of the current_pathname plus the + subdirectory plus a '\0' */ + rb_path->name = + ( char * ) malloc( strlen( arg_current_path ) + + strlen( arg_subdirectory ) + 2 ); + + if ( ! rb_path->name ) + { + RB_Panic( "Out of memory! %s()\n", "RB_Get_RB_Path2" ); + } + + strcpy( rb_path->name, arg_current_path ); + strcat( rb_path->name, arg_subdirectory ); + if ( arg_subdirectory[strlen( arg_subdirectory ) - 1] != '/' ) + { + strcat( rb_path->name, "/" ); + } + rb_path->docname = NULL; + rb_path->parent = NULL; + rb_path->next = 0; + return rb_path; +} + +/*x**f* ROBODoc/RB_Free_RB_Path + * NAME + * RB_Free_RB_Path -- free a RB_Path structure. + ***** + * TODO Documentation + */ + +void +RB_Free_RB_Path( struct RB_Path *arg_rb_path ) +{ + free( arg_rb_path->name ); + if ( arg_rb_path->docname ) + { + free( arg_rb_path->docname ); + } + free( arg_rb_path ); +} + diff --git a/Source/path.h b/Source/path.h new file mode 100644 index 0000000..a5eef87 --- /dev/null +++ b/Source/path.h @@ -0,0 +1,56 @@ +#ifndef ROBODOC_PATH_H +#define ROBODOC_PATH_H +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****s* ROBODoc/RB_Path + * NAME + * RB_Path -- Path to a file + * ATTRIBUTES + * * next -- pointer to the next RB_Path structure. + * * parent -- the parent path (one directory up). + * * name -- null terminated string with the name of the path. + * (Path names can be relative) + * * docname -- the corresponding docpath. + * SOURCE + */ + +struct RB_Path +{ + struct RB_Path *next; + struct RB_Path *parent; + char *name; + char *docname; +}; + +/*****/ + +struct RB_Path *RB_Get_RB_Path( + char *arg_pathname ); +struct RB_Path *RB_Get_RB_Path2( + char *arg_current_path, + char *arg_subdirectory ); +void RB_Free_RB_Path( + struct RB_Path *arg_rb_path ); + +#endif /* ROBODOC_PATH_H */ diff --git a/Source/roboconfig.c b/Source/roboconfig.c new file mode 100644 index 0000000..e8b8532 --- /dev/null +++ b/Source/roboconfig.c @@ -0,0 +1,1401 @@ +// vi: spell ff=unix +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****h* ROBODoc/Configuration + * FUNCTION + * Functions to access the ROBODoc configuration and configuration + * file (robodoc.rc) or the file specified with the --rc option. + * + * The robodoc.rc file consists of a number of blocks. Each + * block starts with a line of the form + * + * : + * + * This is followed by a number of lines of data. Each line starts + * with at least one space followed by the actual data. + * + * This module parses this data and stores it in the global + * configuration. + * + * NOTES + * Is missing a lot of documentation. + * + * You can not use RB_Say() in this module since the --tell flag + * won't be parsed until after this module has finished. + * + ****** + * $Id: roboconfig.c,v 1.55 2007/07/10 19:13:52 gumpu Exp $ + */ + +#include +#include +#include +#include +#include +#include "headertypes.h" +#include "util.h" +#include "roboconfig.h" +#include "globals.h" +#include "optioncheck.h" + +#ifdef DMALLOC +#include +#endif + + +/****v* Configuration/default_item_names + * FUNCTION + * Defines the names of items that ROBODoc recognized as + * items by default if none are specified in the + * robodoc.rc file. + * SOURCE + */ + +static char *default_item_names[] = { + "SOURCE", /* source code inclusion */ + "NAME", /* Item name + short description */ + "COPYRIGHT", /* who own the copyright : "(c) - by " */ + "SYNOPSIS", "USAGE", /* how to use it */ + "FUNCTION", "DESCRIPTION", "PURPOSE", /* what does it */ + "AUTHOR", /* who wrote it */ + "CREATION DATE", /* when did the work start */ + "MODIFICATION HISTORY", "HISTORY", /* who done what changes when */ + "INPUTS", "ARGUMENTS", "OPTIONS", "PARAMETERS", "SWITCHES", /* what can we feed into it */ + "OUTPUT", "SIDE EFFECTS", /* what output will be made */ + "RESULT", "RETURN VALUE", /* what do we get returned */ + "EXAMPLE", /* a clear example of the items use */ + "NOTES", /* any annotations */ + "DIAGNOSTICS", /* diagnostical output */ + "WARNINGS", "ERRORS", /* warning & error-messages */ + "BUGS", /* known bugs */ + "TODO", "IDEAS", /* what to implement next & ideas */ + "PORTABILITY", /* where does it come from, where will it work */ + "SEE ALSO", /* references */ + "METHODS", "NEW METHODS", /* oop methods */ + "ATTRIBUTES", "NEW ATTRIBUTES", /* oop attributes */ + "TAGS", /* tagitem description */ + "COMMANDS", /* command description */ + "DERIVED FROM", /* oop super class */ + "DERIVED BY", /* oop sub class */ + "USES", "CHILDREN", /* what modules are used by this one */ + "USED BY", "PARENTS", /* which modules do use this */ + NULL, /* don't delete, so we can count how many there are... */ +}; + +/***********/ + +static char *default_remark_begin_markers[] = { + "/*", + "(*", + "", + "*}", + NULL +}; + +/****v* Configuration/c_keywords + * FUNCTION + * The default C keywords. + * SOURCE + */ + +static char *c_keywords[] = { + + // ANSI C Keywords + "auto", + "break", + "case", + "char", + "const", + "continue", + "default", + "do", + "double", + "else", + "enum", + "extern", + "float", + "for", + "goto", + "if", + "int", + "long", + "register", + "return", + "short", + "signed", + "sizeof", + "static", + "struct", + "switch", + "typedef", + "union", + "unsigned", + "void", + "volatile", + "while", + + // Some preprocessor directives + "#include", + "#define", + "#undef", + "#if", + "#else", + "#elif", + "#endif", + "#ifdef", + "#ifndef", + "#pragma", + + NULL, /* don't delete, so we can count how many there are... */ +}; + +// C comments +#define C_LINE_COMMENT "//" +#define C_BLOCK_COMMENT_START "/*" +#define C_BLOCK_COMMENT_END "*/" + +/***********/ + + +// Default header separation character +static char *default_header_separate_chars[] = { + ",", + NULL +}; + + +// Default header ignore character (to include remarks, version data, etc...) +static char *default_header_ignore_chars[] = { + "[", + NULL +}; + + +/* Maximum length of a line in the configuration file */ +#define BUFFER_LENGTH 2048 + + +/****v* Configuration/configuration + * FUNCTION + * This global stores all the configuration parameters specified on + * the command line and in the robodoc.rc file. + * SOURCE + */ + +struct RB_Configuration configuration; + +/*****/ + + +static T_Block_Kind BlockKind( + char *line ); +static T_Line_Kind ConfigLineKind( + char *line ); +static void SecondScan( + FILE *f ); +static void Alloc_Parameters( + struct Parameters *parameters, + unsigned int size ); +static void AddParameter( + char *name, + struct Parameters *parameters ); +static void GetParameters( + char *line, + struct Parameters *parameters ); +static void Install_Custom_HeaderTypes( + void ); +static void Complement_Remark_Markers( + void ); +static void ComplementItemNames( + void ); +static void ComplementHeaderMarkers( + void ); +static char *Get_rc( + char *rcname ); + + +/****v* Configuration/keywords_hash_mask + * FUNCTION + * Mask for keyword hash function. + * This mask reduces the hash value for the actual hash table size. + * Also the size of the hash table can be derived from this mask: + * hash table size = keywords_hash_mask + 1 + * SOURCE + */ +static unsigned int keywords_hash_mask; + +/*****/ + +/****v* Configuration/keywords_hash + * FUNCTION + * This is the hash table for the keywords. + * See keywords_hash_s. + * SOURCE + */ +static struct keywords_hash_s **keywords_hash; + +/*****/ + +/****f* Configuration/allocate_keywords_hash_table + * FUNCTION + * Allocates space for the keyword hash table. + * + * The size of the table depends on the number of keywords rounded up to the + * next power of two. + * SYNOPSIS + */ +void allocate_keywords_hash_table( + void ) +/* + * SOURCE + */ +{ + unsigned int i; + + // Calculate hash table size (powers of two) + for ( keywords_hash_mask = 2; + keywords_hash_mask < configuration.keywords.number; + keywords_hash_mask <<= 1 ); + keywords_hash_mask -= 1; + + // Allocate space for hash table + keywords_hash = RB_malloc( ( keywords_hash_mask + 1 ) * + sizeof( struct keywords_hash_s * ) ); + + // Zero out all rows + for ( i = 0; i <= keywords_hash_mask; i++ ) + { + keywords_hash[i] = NULL; + } +} + +/*****/ + +/****f* Configuration/Hash_Keyword + * FUNCTION + * Calculate the hash value for a string + * + * The hash value is based on the CRC32 hash function. It is then reduced by + * an AND operation to the actual size of the hash table. + * SYNOPSIS + */ +unsigned long Hash_Keyword( + char *keyword, + unsigned int len ) +/* + * INPUTS + * - keyword -- The keyword string + * - len -- The length of the keyword string + * RETURN VALUE + * The hash value for the keyword. + * SOURCE + */ +{ + // Generate hash value + return RB_crc32( ( unsigned char * ) keyword, len, + len ) & keywords_hash_mask; +} + +/*****/ + + +/****f* Configuration/add_to_keywords_hash_table + * FUNCTION + * Add a keyword to the hash table + * SYNOPSIS + */ +void add_to_keywords_hash_table( + char *keyword ) +/* + * INPUTS + * keyword -- The keyword string + * SOURCE + */ +{ + struct keywords_hash_s *tmp, **curr; + unsigned long hash; + + // Allocate space for new entry in hash table + tmp = RB_malloc( sizeof( struct keywords_hash_s ) ); + // and initialise it + tmp->keyword = keyword; + tmp->next = NULL; + + // Calculate hash value + hash = Hash_Keyword( keyword, strlen( keyword ) ); + + // Seek to last element in hash table row + for ( curr = &( keywords_hash[hash] ); *curr; + curr = &( ( *curr )->next ) ); + + // Insert entry into hash table + *curr = tmp; +} + +/*****/ + + +/****f* Configuration/Find_Keyword + * FUNCTION + * Find a keyword in the hash table + * SYNOPSIS + */ +char *Find_Keyword( + char *keyword, + int len ) +/* + * INPUTS + * - keyword -- The keyword string + * - len -- The length of the keyword string + * RETURN VALUE + * - pointer to the found keyword string in hash table or + * - NULL if the keyword is not found + * SOURCE + */ +{ + unsigned long hash; + struct keywords_hash_s *curr; + + // Calculate hash value + hash = Hash_Keyword( keyword, len ); + + // Seek through hash table row + for ( curr = keywords_hash[hash]; curr; curr = curr->next ) + { + // Check for keyword in row element + if ( !strncmp( keyword, curr->keyword, len ) ) + { + // Found it! + return curr->keyword; + } + } + + // Keyword not found + return NULL; +} + +/*****/ + + +/****f* Configuration/add_keywords_to_hash_table + * FUNCTION + * Initalize hash table and add all keywords from configuration.keywords + * to the hash table + * SOURCE + */ +void add_keywords_to_hash_table( + void ) +{ + unsigned int i; + + // If nothing to add, exit + if ( !configuration.keywords.number ) + return; + + // Make some allocations + Make_crc32_table( ); + allocate_keywords_hash_table( ); + + // Add keywords to hash table + for ( i = 0; i < configuration.keywords.number; i++ ) + { + add_to_keywords_hash_table( configuration.keywords.names[i] ); + } +} + +/*****/ + + +/* TODO Documentation */ +static void AllocOptions( + unsigned int argc, + char **argv ) +{ + unsigned int i; + + Alloc_Parameters( &( configuration.options ), argc ); + for ( i = 0; i < argc; ++i ) + { + AddParameter( argv[i], &( configuration.options ) ); + } +} + + +/* TODO Documentation */ + +char *Get_rc( + char *rcname ) +{ + char *s = NULL; + char *s2 = NULL; + char *path = NULL; + + if ( Stat_Path( 'e', rcname ) && Stat_Path( 'f', rcname ) ) + { + return RB_StrDup( rcname ); + } + else + { + if ( strchr( rcname, ':' ) || strchr( rcname, '/' ) ) + { + /* The rc names is a proper path, and not just a filename, + * we stop searching */ + } + else + { + s = getenv( "HOME" ); + if ( !s ) + { + if ( ( s = getenv( "HOMEDRIVE" ) ) + && ( s2 = getenv( "HOMEPATH" ) ) ) + { + /* HOMEDRIVE includes backslash */ + path = + ( char * ) malloc( sizeof( char ) * + ( strlen( s ) + strlen( s2 ) + 1 + + 1 + strlen( rcname ) ) ); + sprintf( path, "%s%s%c%s", s, s2, '\\', rcname ); + } + else + { + return NULL; + } + } + else + { + path = + ( char * ) malloc( sizeof( char ) * + ( strlen( s ) + 1 + 1 + + strlen( rcname ) ) ); + sprintf( path, "%s%c%s", s, '/', rcname ); + } + + if ( path && Stat_Path( 'e', path ) && Stat_Path( 'f', path ) ) + { + return path; + } + else + { + char* sitespecific = +#ifdef ROBO_PREFIX + ROBO_PREFIX + "/share/doc/robodoc/"; +#else + "/usr/local/robodoc/"; +#endif + + if ( path ) + { + free( path ); + } + + path = + ( char * ) malloc( sizeof( char ) * + ( strlen( sitespecific ) + 1 + + strlen( rcname ) ) ); + sprintf( path, "%s%s", sitespecific, rcname ); + + /* default failed -- try site-specific config file */ + if ( Stat_Path( 'e', path ) && Stat_Path( 'f', path ) ) + { + /* site-specific file can be stat'ed */ + return path; + } + else + { + free( path ); + return NULL; + } + } + } + } + return NULL; +} + + +/****f* Configuration/ReadConfiguration + * FUNCTION + * Read the robodoc configuration file, and create + * a RB_Configuration structure. + * SYNOPSIS + */ + +char *ReadConfiguration( + unsigned int argc, + char **argv, + char *filename ) +/* + * INPUTS + * o argc -- the arg count as received by main() + * o argv -- the arg valules as received by main() + * o filename -- an optional filename. If none is given, + * "robodoc.rc" is used. + * RESULT + * An initialized configuration (a global). + * SOURCE + */ +{ + FILE *f = NULL; + char *path = NULL; + + if ( filename ) + { + path = Get_rc( filename ); + if ( path ) + { + f = fopen( path, "r" ); + } + if ( !f ) + { + /* It should open as the user claimed it exists somewhere */ + RB_Panic( "Can't open %s\n", filename ); + } + } + else + { + /* Try the default rc file */ + path = Get_rc( "robodoc.rc" ); + if ( path ) + { + f = fopen( path, "r" ); + } + } + + AllocOptions( argc, argv ); + Alloc_Parameters( &( configuration.items ), 10 ); + Alloc_Parameters( &( configuration.ignore_items ), 10 ); + Alloc_Parameters( &( configuration.source_items ), 10 ); + Alloc_Parameters( &( configuration.preformatted_items ), 10 ); + Alloc_Parameters( &( configuration.format_items ), 10 ); + Alloc_Parameters( &( configuration.item_order ), 10 ); + + Alloc_Parameters( &( configuration.custom_headertypes ), 10 ); + Alloc_Parameters( &( configuration.ignore_files ), 10 ); + Alloc_Parameters( &( configuration.accept_files ), 10 ); + Alloc_Parameters( &( configuration.header_markers ), 10 ); + Alloc_Parameters( &( configuration.remark_markers ), 10 ); + Alloc_Parameters( &( configuration.end_markers ), 10 ); + Alloc_Parameters( &( configuration.remark_begin_markers ), 10 ); + Alloc_Parameters( &( configuration.remark_end_markers ), 10 ); + Alloc_Parameters( &( configuration.keywords ), 10 ); + Alloc_Parameters( &( configuration.source_line_comments ), 10 ); + Alloc_Parameters( &( configuration.header_ignore_chars ), 10 ); + Alloc_Parameters( &( configuration.header_separate_chars ), 10 ); + + if ( f ) + { + SecondScan( f ); + fclose( f ); + } + else + { + /* No .rc file found. That's OK */ + } + ComplementItemNames( ); + ComplementHeaderMarkers( ); + Complement_Remark_Markers( ); + Install_Custom_HeaderTypes( ); + + // Make keywords hash table (if necessarry) + add_keywords_to_hash_table( ); + + assert( configuration.items.number ); + + return path; +} + +/******/ + + +/* TODO Documentation */ +static void Complement_Remark_Markers( + void ) +{ + unsigned int i; + + if ( configuration.remark_begin_markers.number ) + { + /* The user specified his own remark_begin_markers */ + } + else + { + for ( i = 0; default_remark_begin_markers[i]; ++i ) + { + AddParameter( default_remark_begin_markers[i], + &( configuration.remark_begin_markers ) ); + } + } + + if ( configuration.remark_end_markers.number ) + { + /* The user specified his own remark_end_markers */ + } + else + { + for ( i = 0; default_remark_end_markers[i]; ++i ) + { + AddParameter( default_remark_end_markers[i], + &( configuration.remark_end_markers ) ); + } + } +} + + +/****f* Configuration/Find_Parameter_Exact + * FUNCTION + * Checks for the existence of a given configuration parameter + * (exact string match) + * SOURCE + */ +char *Find_Parameter_Exact( + struct Parameters *params, + char *paramname ) +{ + unsigned int i; + + // we are looking for an exact match + for ( i = 0; i < params->number; i++ ) + { + if ( !strcmp( params->names[i], paramname ) ) + { + // found it + return params->names[i]; + } + } + + // parameter not found + return NULL; +} + +/******/ + +/****f* Configuration/Find_Parameter_Partial + * FUNCTION + * Checks for the existence of a given configuration parameter + * (partial string match) + * SOURCE + */ +char *Find_Parameter_Partial( + struct Parameters *params, + char *paramname ) +{ + unsigned int i; + + // we are looking for a not exact match + for ( i = 0; i < params->number; i++ ) + { + if ( !strncmp + ( params->names[i], paramname, strlen( params->names[i] ) ) ) + { + // found it + return params->names[i]; + } + } + + // parameter not found + return NULL; +} + +/******/ + + +/****f* Configuration/Find_Parameter_Char + * FUNCTION + * Checks for the existence of a given configuration parameter + * (Character match) + * SOURCE + */ +char *Find_Parameter_Char( + struct Parameters *params, + char param ) +{ + unsigned int i; + + for ( i = 0; i < params->number; i++ ) + { + if ( params->names[i][0] == param ) + { + // found it + return params->names[i]; + } + } + + // parameter not found + return NULL; +} + +/******/ + + +/****f* Configuration/Install_C_Syntax + * FUNCTION + * Install default C keywords and comments + * SOURCE + */ +void Install_C_Syntax( + void ) +{ + unsigned int i; + + // Check if we can install our default C keywords + if ( !configuration.keywords.number ) + { + for ( i = 0; c_keywords[i]; i++ ) + { + AddParameter( c_keywords[i], &( configuration.keywords ) ); + } + + // Make keywords hash table (if necessarry) + add_keywords_to_hash_table( ); + } + + // Make sure that C line comment is present + if ( Find_Parameter_Exact + ( &( configuration.source_line_comments ), C_LINE_COMMENT ) == NULL ) + { + AddParameter( C_LINE_COMMENT, + &( configuration.source_line_comments ) ); + } + + + // Make sure that C block comment start is present + if ( Find_Parameter_Exact + ( &( configuration.remark_begin_markers ), + C_BLOCK_COMMENT_START ) == NULL ) + { + AddParameter( C_BLOCK_COMMENT_START, + &( configuration.remark_begin_markers ) ); + } + + // Make sure that C block comment end is present + if ( Find_Parameter_Exact + ( &( configuration.remark_end_markers ), + C_BLOCK_COMMENT_END ) == NULL ) + { + AddParameter( C_BLOCK_COMMENT_END, + &( configuration.remark_end_markers ) ); + } +} + +/******/ + + + + +/* TODO Documentation */ +static void ComplementHeaderMarkers( + void ) +{ + unsigned int i; + + if ( configuration.header_markers.number ) + { + /* The user specified his own header_markers */ + } + else + { + for ( i = 0; header_markers[i]; ++i ) + { + AddParameter( header_markers[i], + &( configuration.header_markers ) ); + } + } + + if ( configuration.remark_markers.number ) + { + /* The user specified his own remark_markers */ + } + else + { + for ( i = 0; remark_markers[i]; ++i ) + { + AddParameter( remark_markers[i], + &( configuration.remark_markers ) ); + } + } + + if ( configuration.end_markers.number ) + { + /* The user specified his own end_markers */ + } + else + { + for ( i = 0; end_markers[i]; ++i ) + { + AddParameter( end_markers[i], &( configuration.end_markers ) ); + } + } + + if ( configuration.header_separate_chars.number ) + { + /* The user specified his own header_separate_chars */ + } + else + { + for ( i = 0; default_header_separate_chars[i]; ++i ) + { + AddParameter( default_header_separate_chars[i], + &( configuration.header_separate_chars ) ); + } + } + + if ( configuration.header_ignore_chars.number ) + { + /* The user specified his own header_ignore_chars */ + } + else + { + for ( i = 0; default_header_ignore_chars[i]; ++i ) + { + AddParameter( default_header_ignore_chars[i], + &( configuration.header_ignore_chars ) ); + } + } +} + + + +/****if* Config/ConfigLineKind + * FUNCTION + * Deterimine the kind of line we a currently processing. + * SYNOPSIS + */ + +static T_Line_Kind ConfigLineKind( + char *line ) +/* + * INPUTS + * line -- the current line. + * RETURN + * The kind of line. + * SOURCE + */ +{ + T_Line_Kind kind = CFL_UNKNOWN; + + if ( *line == '\0' ) + { + kind = CFL_EMPTYLINE; + } + else if ( *line == '#' ) + { + kind = CFL_REMARK; + } + else if ( utf8_isspace( *line ) ) + { + char *cur_char = line; + + for ( ; *cur_char && utf8_isspace( *cur_char ); ++cur_char ) + { + /* Empty */ + } + if ( *cur_char == '\0' ) + { + kind = CFL_EMPTYLINE; + } + else + { + /* There is atleast one non-space character */ + kind = CFL_PARAMETER; + } + } + else + { + kind = CFL_SECTION; + } + return kind; +} + +/********/ + + +static T_Block_Kind BlockKind( + char *line ) +{ + T_Block_Kind section_kind = SK_UNKNOWN; + + if ( strcmp( line, "items:" ) == 0 ) + { + section_kind = SK_ITEMS; + } + else if ( strcmp( line, "options:" ) == 0 ) + { + section_kind = SK_OPTIONS; + } + else if ( strcmp( line, "extensions:" ) == 0 ) + { + printf + ( "Warning: the 'extensions:' block is obsolete, use 'ignore files:' instead\n" ); + } + else if ( strcmp( line, "ignore items:" ) == 0 ) + { + section_kind = SK_IGNOREITEMS; + } + else if ( strcmp( line, "source items:" ) == 0 ) + { + section_kind = SK_SOURCE_ITEMS; + } + else if ( strcmp( line, "headertypes:" ) == 0 ) + { + section_kind = SK_HEADERTYPES; + } + else if ( strcmp( line, "ignore files:" ) == 0 ) + { + section_kind = SK_IGNORE_FILES; + } + else if ( strcmp( line, "accept files:" ) == 0 ) + { + section_kind = SK_ACCEPT_FILES; + } + else if ( strcmp( line, "header markers:" ) == 0 ) + { + section_kind = SK_HEADER_MARKERS; + } + else if ( strcmp( line, "remark markers:" ) == 0 ) + { + section_kind = SK_REMARK_MARKERS; + } + else if ( strcmp( line, "end markers:" ) == 0 ) + { + section_kind = SK_END_MARKERS; + } + else if ( strcmp( line, "remark begin markers:" ) == 0 ) + { + section_kind = SK_REMARK_BEGIN_MARKERS; + } + else if ( strcmp( line, "remark end markers:" ) == 0 ) + { + section_kind = SK_REMARK_END_MARKERS; + } + else if ( strcmp( line, "keywords:" ) == 0 ) + { + section_kind = SK_KEYWORDS; + } + else if ( strcmp( line, "source line comments:" ) == 0 ) + { + section_kind = SK_SOURCE_LINE_COMMENTS; + } + else if ( strcmp( line, "header ignore characters:" ) == 0 ) + { + section_kind = SK_HEADER_IGNORE_CHARS; + } + else if ( strcmp( line, "header separate characters:" ) == 0 ) + { + section_kind = SK_HEADER_SEPARATE_CHARS; + } + else if ( strcmp( line, "preformatted items:" ) == 0 ) + { + section_kind = SK_PREFORMATTED_ITEMS; + } + else if ( strcmp( line, "format items:" ) == 0 ) + { + section_kind = SK_FORMAT_ITEMS; + } + else if ( strcmp( line, "item order:" ) == 0 ) + { + section_kind = SK_ITEM_ORDER; + } + else + { + RB_Panic( "unknown block kind \"%s\"\n", line ); + } + return section_kind; +} + + +static void Install_Custom_HeaderTypes( + void ) +{ + unsigned int i; + struct Parameters headertype; + unsigned int priority = 0; + + // Install custom header types + for ( i = 0; i < configuration.custom_headertypes.number; i++ ) + { + // Allocate some default space for parameters + Alloc_Parameters( &headertype, 10 ); + // Break current line into parameters + GetParameters( configuration.custom_headertypes.names[i], + &headertype ); + + // Check how many parameters do we have + switch ( headertype.number ) + { + // 3 parameters -> no priority specified, assign default + case 3: + priority = 0; + break; + + // 4 parameters -> priority specified, convert it + case 4: + priority = atoi( headertype.names[3] ); + break; + + // Any more or less parameters are illegal + default: + RB_Panic( "Error near header type: '%s'\n" + "You must have either 3 or 4 parameters there !\n", + headertype.names[0] ); + } + + // Check if type character is legal + if ( strlen( headertype.names[0] ) > 1 ) + { + RB_Panic( "Error near header type: '%s'\n" + "Type character can only be one character long !\n", + headertype.names[0] ); + } + + // Add custom header type + RB_AddHeaderType( headertype.names[0][0], headertype.names[1], + headertype.names[2], priority ); + + // Free temporary space + free( headertype.names ); + } +} + + + +static void Alloc_Parameters( + struct Parameters *parameters, + unsigned int size ) +{ + parameters->size = size; + parameters->number = 0; + parameters->names = calloc( size, sizeof( char * ) ); +} + + +/* TODO Documentation */ +static void AddParameter( + char *name, + struct Parameters *parameters ) +{ + parameters->names[parameters->number] = RB_StrDup( name ); + parameters->number++; + if ( parameters->number >= parameters->size ) + { + parameters->size *= 2; + parameters->names = + realloc( parameters->names, parameters->size * sizeof( char * ) ); + } +} + + +/****f* Configuration/GetParameters + * FUNCTION + * Parse a line of text and store the individual words in + * a Parameters structure. Words are seperated by spaces, + * the exception are words surrounded by quotes. So: + * aap noot mies "back to the future" + * contains four words. + * INPUTS + * o line -- the line of text. + * o parameters -- the set of parameters + * SOURCE + */ + +static void GetParameters( + char *line, + struct Parameters *parameters ) +{ + int i; + int n = strlen( line ); + + /* Remove any spaces at the end of the line */ + for ( i = n - 1; i >= 0 && utf8_isspace( line[i] ); --i ) + { + line[i] = '\0'; + } + + assert( i > 0 ); /* If i <= 0 then the line was empty + and that cannot be, because this + is supposed to be a parameter */ + + /* Skip any white space at the begin of the line. */ + n = strlen( line ); + for ( i = 0; i < n && utf8_isspace( line[i] ); ++i ) + { + /* Empty */ + } + line += i; + + n = strlen( line ); + for ( i = 0; i < n; /* empty */ ) + { + char *name = line; + + if ( line[i] == '"' ) + { + /* It is quoted string, fetch everything until + * the next quote */ + ++name; /* skip the double quote */ + for ( ++i; ( i < n ) && ( line[i] != '"' ); ++i ) + { + /* empty */ + } + if ( i == n ) + { + RB_Panic( "Missing quote in your .rc file in line:\n %s\n", + line ); + } + else + { +#if defined(__APPLE__) + /* hacked because of error when compiling on Mac OS X */ + assert( line[i] == 34 ); +#else + assert( line[i] == '"' ); +#endif + line[i] = '\0'; + AddParameter( name, parameters ); + } + } + else + { + /* a single word, find the next space */ + for ( ; ( i < n ) && !utf8_isspace( line[i] ); ++i ) + { + /* empty */ + } + if ( i < n ) + { + line[i] = '\0'; + } + AddParameter( name, parameters ); + } + /* Is there anything left? */ + if ( i < n ) + { + /* skip any spaces until the next parameter */ + ++i; /* first skip the nul character */ + line += i; + n = strlen( line ); + for ( i = 0; ( i < n ) && utf8_isspace( line[i] ); ++i ) + { + /* empty */ + } + line += i; + n = strlen( line ); + i = 0; + } + } +} + +/*******/ + +void GetParameter( + char *line, + struct Parameters *parameters ) +{ + int i; + int n = strlen( line ); + + /* Remove any spaces at the end of the line */ + for ( i = n - 1; i >= 0 && utf8_isspace( line[i] ); --i ) + { + line[i] = '\0'; + } + assert( i > 0 ); /* If i <= 0 then the line was empty + and that cannot be, because this + is supposed to be a parameter */ + /* Skip any white space at the begin of the line. */ + n = strlen( line ); + for ( i = 0; i < n && utf8_isspace( line[i] ); ++i ) + { + /* Empty */ + } + line += i; + + AddParameter( line, parameters ); +} + + + + +void Free_Configuration( + void ) +{ + /* TODO Deallocate custom_headertypes */ +} + + + + +static void ComplementItemNames( + void ) +{ + if ( configuration.items.number ) + { + char *first_item = configuration.items.names[0]; + + /* The SOURCE item is always included, and should be the + * first one! */ + configuration.items.names[0] = RB_StrDup( "SOURCE" ); + AddParameter( first_item, &( configuration.items ) ); + free( first_item ); + } + else + { + /* No item names were defined, so we use the default ones */ + unsigned int i = 0; + + for ( ; default_item_names[i]; ++i ) + { + AddParameter( default_item_names[i], &( configuration.items ) ); + } + } +} + + +/* TODO Documentation */ + + +static void SecondScan( + FILE *f ) +{ + char *myConfLine = NULL; + int readConfChars = 0; + T_Block_Kind section_kind = SK_UNKNOWN; + T_Line_Kind line_kind = CFL_UNKNOWN; + + while ( !feof( f ) ) + { + free( myConfLine ); + readConfChars = 0; + myConfLine = RB_ReadWholeLine( f, line_buffer, &readConfChars ); + RB_StripCR( myConfLine ); + line_kind = ConfigLineKind( myConfLine ); + switch ( line_kind ) + { + case CFL_REMARK: + case CFL_EMPTYLINE: /* fall through */ + /* Do nothing */ + break; + case CFL_SECTION: + section_kind = BlockKind( myConfLine ); + break; + case CFL_PARAMETER: + { + switch ( section_kind ) + { + case SK_ITEMS: + GetParameter( myConfLine, &( configuration.items ) ); + break; + case SK_OPTIONS: + GetParameters( myConfLine, &( configuration.options ) ); + break; + case SK_IGNOREITEMS: + GetParameter( myConfLine, + &( configuration.ignore_items ) ); + break; + case SK_SOURCE_ITEMS: + GetParameter( myConfLine, + &( configuration.source_items ) ); + break; + case SK_HEADERTYPES: + // Store all complete lines, they will be broken down later + // in Install_Custom_HeaderTypes() + GetParameter( myConfLine, + &( configuration.custom_headertypes ) ); + break; + case SK_IGNORE_FILES: + GetParameters( myConfLine, + &( configuration.ignore_files ) ); + break; + case SK_ACCEPT_FILES: + GetParameters( myConfLine, + &( configuration.accept_files ) ); + break; + case SK_HEADER_MARKERS: + GetParameter( myConfLine, + &( configuration.header_markers ) ); + break; + case SK_REMARK_MARKERS: + GetParameter( myConfLine, + &( configuration.remark_markers ) ); + break; + case SK_END_MARKERS: + GetParameter( myConfLine, + &( configuration.end_markers ) ); + break; + case SK_REMARK_END_MARKERS: + GetParameter( myConfLine, + &( configuration.remark_end_markers ) ); + break; + case SK_REMARK_BEGIN_MARKERS: + GetParameter( myConfLine, + &( configuration.remark_begin_markers ) ); + break; + case SK_KEYWORDS: + GetParameter( myConfLine, &( configuration.keywords ) ); + break; + case SK_SOURCE_LINE_COMMENTS: + GetParameter( myConfLine, + &( configuration.source_line_comments ) ); + break; + case SK_HEADER_IGNORE_CHARS: + GetParameter( myConfLine, + &( configuration.header_ignore_chars ) ); + break; + case SK_HEADER_SEPARATE_CHARS: + GetParameter( myConfLine, + &( configuration.header_separate_chars ) ); + break; + case SK_PREFORMATTED_ITEMS: + GetParameter( myConfLine, + &( configuration.preformatted_items ) ); + break; + case SK_FORMAT_ITEMS: + GetParameter( myConfLine, + &( configuration.format_items ) ); + break; + case SK_ITEM_ORDER: + GetParameter( myConfLine, + &( configuration.item_order ) ); + break; + case SK_UNKNOWN: + break; + default: + assert( 0 ); + } + } + break; + case CFL_UNKNOWN: + default: + assert( 0 ); + } + } + free( myConfLine ); +} diff --git a/Source/roboconfig.h b/Source/roboconfig.h new file mode 100644 index 0000000..0d7183a --- /dev/null +++ b/Source/roboconfig.h @@ -0,0 +1,195 @@ +#ifndef ROBODOC_CONFIG_H +#define ROBODOC_CONFIG_H +// vi: spell ff=unix +// + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +typedef enum +{ + CFL_REMARK = 0, + CFL_PARAMETER, + CFL_SECTION, + CFL_EMPTYLINE, + CFL_UNKNOWN +} T_Line_Kind; + +typedef enum +{ + SK_ITEMS = 0, + SK_IGNOREITEMS, + SK_OPTIONS, + SK_HEADERTYPES, + SK_IGNORE_FILES, + SK_ACCEPT_FILES, + SK_HEADER_MARKERS, + SK_REMARK_MARKERS, + SK_END_MARKERS, + SK_REMARK_BEGIN_MARKERS, + SK_REMARK_END_MARKERS, + SK_SOURCE_ITEMS, + SK_KEYWORDS, + SK_SOURCE_LINE_COMMENTS, + SK_HEADER_IGNORE_CHARS, + SK_HEADER_SEPARATE_CHARS, + SK_PREFORMATTED_ITEMS, + SK_FORMAT_ITEMS, + SK_ITEM_ORDER, + SK_UNKNOWN +} T_Block_Kind; + + +/****s* Configuration/keywords_hash_s + * FUNCTION + * Structure for a keyword hash table row. + * ATTRIBUTES + * o keyword -- pointer to the keyword + * o next -- pointer to next entry in the row + * SOURCE + */ +struct keywords_hash_s +{ + struct keywords_hash_s *next; + char *keyword; +}; + +/*****/ + + +/****s* Configuration/Parameters + * FUNCTION + * Structure to store all the paramters found in a block in the + * robodoc configuation file. + * ATTRIBUTES + * o number -- the number of parameters found. + * o size -- the maximum size of the names array. + * o names -- an array with the values of the parameters. + * NOTES + * Find a better name for the attribute 'names' + * SOURCE + */ + +struct Parameters +{ + unsigned int number; + unsigned int size; + char **names; +}; + +/*****/ + + +/****s* Configuration/RB_Configuration + * FUNCTION + * All the data from the robodoc.rc file is stored in this + * structure. + * ATTRIBUTES + * o items -- an array with names that robodoc recognizes as + * items. Alsways includes the name "SOURCE" as + * the first element. + * o ignore_items -- an array with the names of items that ROBODoc + * should ignore. + * o source_items -- an array with the names of items that work + * similar to the built-in SOURCE item. + * o preformatted_items -- item names that will be automatically + * preformatted + * o format_items -- item names that should be formatted by the + * browser + * o item_order -- an array with item names that + * indicates which items should be displayed first. + * o options -- Array with all options specified both on the + * commandline as well as in the robodoc.rc file. + * o custom_headertypes -- list with custom header types. + * o ignore_files -- list with wildcard expressions that specifies + * files and directories that robodoc should skip + * while scanning the source tree. + * o header_markers -- list with markers that mark the begin of a + * header. + * o remark_markers -- list with markers that mark a remark. + * o end_markers -- list with markers that markt the end of a + * header. + * o remark_begin_markers -- list of markers that mark the begin of + * a remark. For instance (* + * o remakr_end_markers -- list of markers that mark the end of a + * remark. For instance *) + * o keywords -- source keywords to recognise (and colorise) + * o source_line_comments -- comment markers that span until the end of line + * o header_ignore_chars -- characters for beginning of header remarks + * o header_separate_chars -- characters that separates header artifacts + * + * SOURCE + */ + +struct RB_Configuration +{ + struct Parameters items; + struct Parameters ignore_items; + struct Parameters source_items; + struct Parameters preformatted_items; + struct Parameters format_items; + struct Parameters item_order; + + struct Parameters options; + + struct Parameters ignore_files; + struct Parameters accept_files; + + struct Parameters custom_headertypes; + struct Parameters header_markers; + struct Parameters remark_markers; + struct Parameters end_markers; + struct Parameters remark_begin_markers; + struct Parameters remark_end_markers; + + struct Parameters keywords; + struct Parameters source_line_comments; + struct Parameters header_ignore_chars; + struct Parameters header_separate_chars; +}; + +/*******/ + +char *ReadConfiguration( + unsigned int argc, + char **argv, + char *filename ); +void Free_Configuration( + void ); +void Install_C_Syntax( + void ); +char *Find_Keyword( + char *keyword, + int len ); +char *Find_Parameter_Exact( + struct Parameters *params, + char *paramname ); +char *Find_Parameter_Partial( + struct Parameters *params, + char *paramname ); +char *Find_Parameter_Char( + struct Parameters *params, + char param ); + +extern struct RB_Configuration configuration; + +#endif diff --git a/Source/robodoc.c b/Source/robodoc.c new file mode 100644 index 0000000..2cf5332 --- /dev/null +++ b/Source/robodoc.c @@ -0,0 +1,1473 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/****h* Docuwala/ROBODoc + * FUNCTION + * ROBODoc is intended to be a replacement for the original AutoDocs + * program. ROBODoc will extract the comment headers from a source + * file, and put them into a separate documentation file. + * General Flow + * + * Sourcecode ---> [ROBODoc] ---> Document. + * + * The whole ROBODoc process consists of three steps: scanning, + * analysing, generating. + * + * Scanning + * + * ROBODoc scans the source directory tree. This collects the names of + * all the source files. + * + * Analysing + * + * ROBODOc analyses all the sourcefiles. This reads the content of all + * source files and collects all the headers. + * + * Generating + * + * In this step the headers are written to one or more documentation files. + * In addition + * + * + * The data collected during scanning and analysing is stored in a + * number of structures. + * + * RB_Directory, it stores the names of the sourcefiles and directories in + * the source direcory tree. File names are stored in a RB_Filename + * structure, directory names in a RB_Path structure. Each RB_Filename + * contains a pointer (path) to a RB_Path structure that tells in which + * directory a file is located. Each RB_Path has a pointer (parent) to + * another RB_Path structure that tells in which directory is a directory + * located (of which directory it is a subdirectory). The only exception + * is the root directory. + * + * Besides the name of the sourcefile, the RB_Filename also stores the + * name of the documentation file. + * + * For each sourcefile there is an RB_Part structure. It contains a + * pointer (filename) to the RB_Filename and a list (headers) of + * RB_Header structure containing the headers found in the sourcefile. + * + * Every RB_Header structure contains a pointer (owner) to the RB_Part + * structure to which it belongs. Headers can form a hierarchy that is + * used to create sections and subsections in the documentation. To + * store this hierarchy every RB_header structure contains a pointer + * (parent) to its parent header. For instance, given the following two + * headers, SubModule is the parent of SubSubModule. + * ****h* TopModule/SubModule + * * + * **** + * + * ****h* SubModule/SubSubModule + * * + * **** + * + * In the documentation this creates the sections + * 1.TopModule + * 1.1 SubModule + * 1.1.1 SubSubModule + * + * The RB_Directory and the linked list of RB_Part structures are + * stored in a RB_Document structure. + * + * During the generation of the documentation ROBODoc tries to create + * cross links between the mention of a header's name (an object) and the + * documentation generated from that header (the documentation for the + * object). + * + * To aid this proces there is an array of RB_link structures. This + * array is sorted for quick searching. RB_link structures the name + * of a header and the name of the label under which the documentation + * can be found in the documentation file. + * + * AUTHOR + * See AUTHORS in the archive. + * CREATION DATE + * 20-Dec-94 Jacco van Weert. + * MODIFICATION HISTORY + * See ChangeLog in the archive. Latest version can be found on: + * o http://www.xs4all.nl/~rfsber/Robo/ + * BUGS + * Other bugs? Catch them in a jar and send them to rfsber -(at)- xs4all.nl + * + **** + * $Id: robodoc.c,v 1.106 2007/07/10 19:13:52 gumpu Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#ifdef __APPLE__ +#include +#endif + +#include "robodoc.h" +#include "globals.h" +#include "headers.h" +#include "util.h" +#include "links.h" +#include "part.h" +#include "analyser.h" +#include "generator.h" +#include "document.h" +#include "directory.h" +#include "roboconfig.h" +#include "optioncheck.h" + +#ifdef DMALLOC +#include +#endif + +/* Functions local to this file. */ + +T_RB_DocType Find_DocType( + void ); + +actions_t Find_Actions( + void ); + +long Find_DebugMode( + void ); + +int Find_Option( + char *option ); + +static int PathBegin_Check( + char *path ); + +static void Path_Check( + char *sourcepath, + char *docpath ); + +char *Find_Parameterized_Option( + char *actionname ); + +char *RB_Find_In_Argv_Parameterized_Option( + int argc, + char **argv, + char *optionname ); + +static char *General_Find_Parameterized_Option( + int n, + char **options, + char *optionname ); + +static char *Fix_Path( + char *path ); + +static char *Path_Convert_Win32_to_Unix( + char *path ); + +static char *Find_And_Fix_Path( + char *option_name ); + +static void RB_Summary( + struct RB_Document *document ); + +static void Find_Tabstops( + void ); + +static void Find_And_Install_Document_Name( + char *option, + unsigned char type ); + +char RB_VER[] = + "$VER: robodoc " VERSION " (" __DATE__ + ") (c) by Maverick Software Development 1994-2006"; + + +/****h* ROBODoc/UserInterface + * FUNCTION + * This module contains functions to parse the + * command line and inform the user about any errors. + ***** + */ + + +/****v* UserInterface/use + * NAME + * use -- usage string + * FUNCTION + * Inform the user how to use ROBODoc. + * AUTHOR + * Koessi + * SOURCE + */ + +char use[] = +// 1 2 3 4 5 6 7 8 +// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + "ROBODoc Version " VERSION " autodocs formatter ($Revision: 1.106 $)\n" + "(c) 1994-2007 Frans Slothouber, Petteri Kettunen, \n" + " Gergely Budai and Jacco van Weert\n" + "ROBODoc comes with ABSOLUTELY NO WARRANTY.\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions; type `robodoc -c' for details.\n" "\n"; +char use_usage[] = + "Usage:\n" + " robodoc --src --doc --multidoc [type] [options]\n" + " robodoc --src --doc --singledoc [type] [options]\n" + " robodoc --src --doc --singlefile [type] [options]\n" + "\n" + "Type:\n" " --html, --rtf, --latex, --ascii, --dbxml, --troff\n" "\n"; +char use_options1[] = + "Options:\n" + " --charset NAME Add character encoding information (html only).\n" + " --cmode Use ANSI C grammar in source items (html only).\n" + " --css Specify the stylesheet to use.\n" + " --ext EXTENSION Set extension for generated files.\n" + " --footless Do not create the foot of a document.\n" + " --headless Do not create the head of a document.\n" + " --index Add an index.\n"; +char use_options2[] = + " --internal Also include internal headers.\n" + " --internalonly Only include internal headers.\n" + " --lock Recognize only one header marker per file.\n" + " --nodesc Do not descent into subdirectories.\n" + " --no_subdirectories\n" + " Do no create documentation subdirectories.\n" + " --nopre Do not use
         
        in the HTML output.\n" + " --nosort Do not sort the headers.\n" + " --nosource Do not include SOURCE items.\n" + " --nogeneratedwith\n" + " Do not add the 'generated by robodoc' message\n" + " at the top of each documentation file.\n" + " --ignore_case_when_linking\n" + " Ignore the case of the symbols when trying\n" + " to create crosslinks.\n"; +char use_options3[] = + " --rc Specify an alternate configuration file.\n" + " --sections Add sections and subsections.\n" + " --first_section_level NUMBER\n" + " Start the first section not at 1 but at \n" + " level NUMBER.\n" + " --tabsize NUMBER Set the tab size.\n" + " --tabstops a,b,..,n\n" + " Set TAB stops \n" + " --tell ROBODoc will tell you what it is doing.\n" + " --debug same as --tell, but with lots more details.\n" + " --toc Add a table of contents.\n" + " --version Print version info and exit.\n" + " --sectionnameonly\n" + " Generate section header with name only.\n" + " --compress Only supported by TROFF output format. Defines by which\n" + " program manpages will be compressed. Either bzip2 or gzip.\n" + " --mansection Manual section where pages will be inserted (default: 3).\n" + " --documenttitle TITLE\n" + " Set the document title\n" + " --altlatex Alternate LaTeX file format (bigger / clearer than normal)\n" + " --latexparts Make the first module level as PART in LaTeX output\n" + " --syntaxcolors Turn on all syntax highlighting features in SOURCE items\n" + " (html only)\n" + " --syntaxcolors_enable quotes,squotes,line_comments,block_comments,\n" + " keywords,non_alpha\n" + " Enable only specific syntax highlighting features in\n" + " SOURCE items (html only)\n" + " --dotname NAME Specify the name (and path / options) of DOT tool\n" + " --masterindex title,filename\n" + " Specify the tile and filename for master index page\n" + " --sourceindex title,filename\n" + " Specify the tile and filename for source files index page\n" + " --one_file_per_header\n" + " Create a separate documentation file for each header\n" + " --header_breaks NUMBER\n" + " Insert a linebreak after every NUMBER header names\n" + " (default value: 2, set to zero to disable)\n" "\n"; +char use_authors[] = + "Authors/Contributors:\n" + " Frans Slothouber, Jacco van Weert, Petteri Kettunen, Bernd Koesling,\n" + " Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, Sasha Vasko,\n" + " Kai Hofmann, Thierry Pierron, Friedrich Haase, Gergely Budai.\n"; +/********/ + + +/****v* UserInterface/copying + * FUNCTION + * Information about the ROBODoc licence. + * AUTHOR + * Frans + * HISTORY + * 2003-02-25/petterik: corrected link to GNU copyleft. + ******* + */ + +char copying[] = + "\n" + " Distributed under the GNU GENERAL PUBLIC LICENSE\n" + " TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n" + " See the source archive for a copy of the complete licence\n" + " If you do not have it you can get it from URL\n" + " http://www.gnu.org/copyleft/gpl.html\n"; + + +static void dump_version( + void ) +{ + printf( "%s\n", VERSION ); + /* TODO create an option to show robodoc configuration, + * including compiler setting etc.. + printf( "Configuration:\n" ); + printf( " locale: %s", setlocale( LC_ALL, "" ) ); + */ +} + +/* TODO This function is too long. */ + +/****f* UserInterface/main + * FUNCTION + * Get and parse the arguments. Analyse document and generate the + * documentation. Everything starts from here. + * SYNOPSIS + */ +int main( + int argc, + char **argv ) +/* + * SOURCE + */ +{ + struct RB_Document *document = NULL; + struct RB_Directory *srctree = NULL; + char *optstr = NULL; + char *used_rc_file = NULL; + long debug = 0; + +/* + TODO, make setlocale work. + char * loc; + + if ( (loc = getenv("LC_CTYPE") ) != NULL ) + { + printf( ".... %s\n", loc ); + setlocale( LC_ALL, loc); + } + else + { + setlocale(LC_ALL, ""); + } +*/ + + whoami = argv[0]; /* global me,myself&i */ + + // Init Actions global + course_of_action = No_Actions( ); + + /* Read the configuration file. This might contain + addition options. */ + RB_SetCurrentFile( NULL ); + used_rc_file = ReadConfiguration( argc, argv, + RB_Find_In_Argv_Parameterized_Option + ( argc, argv, "--rc" ) ); + + /* Force debug mode early if the user wants the debug mode */ + debugmode = Find_DebugMode( ); + course_of_action.do_tell = TRUE; + + if ( Check_Options( ) == EXIT_FAILURE ) + { + + return EXIT_FAILURE; + } + + if ( Find_Option( "-c" ) ) + { + printf( "%s", copying ); + return EXIT_SUCCESS; + } + + if ( Find_Option( "--version" ) ) + { + dump_version( ); + return EXIT_SUCCESS; + } + + if ( Find_Option( "--help" ) ) + { + printf( "%s%s%s%s%s%s", use, use_usage, use_options1, use_options2, + use_options3, use_authors ); + return EXIT_SUCCESS; + } + + output_mode = Find_DocType( ); /* one of the globals that are still left */ + if ( output_mode == UNKNOWN ) + { + Print_Short_Use( ); + return EXIT_SUCCESS; + } + + /* First the basics. */ + document = RB_Get_RB_Document( ); + document->doctype = output_mode; + document->actions = Find_Actions( ); + debug = document->debugmode = Find_DebugMode( ); + document->charset = Find_Parameterized_Option( "--charset" ); + document->extension = Find_Parameterized_Option( "--ext" ); + document->css = Find_Parameterized_Option( "--css" ); + document->compress = Find_Parameterized_Option( "--compress" ); + document->section = Find_Parameterized_Option( "--mansection" ); + document_title = Find_Parameterized_Option( "--documenttitle" ); + optstr = Find_Parameterized_Option( "--first_section_level" ); + if ( optstr ) + { + document->first_section_level = atoi( optstr ); + } + + course_of_action = document->actions; /* a global */ + debugmode = document->debugmode; /* a global */ + + RB_Say( "Using %s for defaults\n", SAY_INFO, used_rc_file ); + free( used_rc_file ); /* No longer necessary */ + used_rc_file = NULL; + + if ( document->css ) + { + document->css = Path_Convert_Win32_to_Unix( document->css ); + } + + if ( ( document->actions.do_index ) && output_mode == TROFF ) + { + RB_Warning( "Index generation not supported for TROFF format.\n" ); + document->actions.do_index = FALSE; + } + + if ( Find_Parameterized_Option( "--doctype_name" ) && + Find_Parameterized_Option( "--doctype_location" ) ) + { + document->doctype_name = + Find_Parameterized_Option( "--doctype_name" ); + document->doctype_location = + Find_Parameterized_Option( "--doctype_location" ); + } + + // Find tab sizes and tab stops + Find_Tabstops( ); + + // Find master index file name + Find_And_Install_Document_Name( "--masterindex", HT_MASTERINDEXTYPE ); + + // Find source index file name + Find_And_Install_Document_Name( "--sourceindex", HT_SOURCEHEADERTYPE ); + + // Find DOT tool name + optstr = Find_Parameterized_Option( "--dotname" ); + if ( optstr ) + { + dot_name = optstr; + } + + // Find number of headers before linebreak + optstr = Find_Parameterized_Option( "--header_breaks" ); + if ( optstr ) + { + int breaks = atoi( optstr ); + + if ( breaks == 0 ) + { + breaks = MAX_HEADER_BREAKS; + } + header_breaks = breaks; + } + + // Get extension + if ( !document->extension ) + { + document->extension = RB_Get_Default_Extension( document->doctype ); + } + + + /* Test if there is a --src and --doc */ + if ( !Find_Parameterized_Option( "--src" ) ) + { + printf( "Error: you need to specify a source" + " file or directory with --src.\n" ); + Print_Short_Use( ); + return EXIT_FAILURE; + } + if ( !Find_Parameterized_Option( "--doc" ) ) + { + printf( "Error: you need to specify a documentation file" + " or directory with --doc.\n" ); + Print_Short_Use( ); + return EXIT_FAILURE; + } + + /* What mode are we using? */ + if ( Find_Option( "--multidoc" ) ) + { + char *srcrootname; /* directory */ + char *docrootname; + + srcrootname = Find_And_Fix_Path( "--src" ); + if ( !Stat_Path( 'e', srcrootname ) ) + { + printf( "Error: %s does not exists\n", srcrootname ); + Print_Short_Use( ); + return EXIT_FAILURE; + } + + if ( !Stat_Path( 'd', srcrootname ) ) + { + printf( "Error: %s is not a directory\n", srcrootname ); + Print_Short_Use( ); + return EXIT_FAILURE; + } + document->srcroot = RB_Get_RB_Path( srcrootname ); + + docrootname = Find_And_Fix_Path( "--doc" ); + Path_Check( srcrootname, docrootname ); + + document->docroot = RB_Get_RB_Path( docrootname ); + + srctree = RB_Get_RB_Directory( srcrootname, docrootname ); + document->srctree = srctree; + + RB_Document_Create_Parts( document ); + RB_Analyse_Document( document ); + RB_Generate_Documentation( document ); + + RB_Free_RB_Path( document->srcroot ); + document->srcroot = 0; + RB_Free_RB_Path( document->docroot ); + document->docroot = 0; + RB_Free_RB_Directory( srctree ); + document->srctree = 0; + } + else if ( output_mode == TROFF ) + { + RB_Panic( "Only --multidoc is supported for TROFF output.\n" ); + } + else if ( Find_Option( "--singledoc" ) ) + { + char *srcrootname; /* directory */ + + srcrootname = Find_And_Fix_Path( "--src" ); + if ( !Stat_Path( 'e', srcrootname ) ) + { + printf( "Error: %s does not exists\n", srcrootname ); + Print_Short_Use( ); + return EXIT_FAILURE; + } + + if ( !Stat_Path( 'd', srcrootname ) ) + { + printf( "Error: %s is not a directory\n", srcrootname ); + Print_Short_Use( ); + return EXIT_FAILURE; + }; + document->srcroot = RB_Get_RB_Path( srcrootname ); + + document->docroot = 0; + document->singledoc_name = Find_And_Fix_Path( "--doc" ); + + srctree = RB_Get_RB_Directory( srcrootname, NULL ); + document->srctree = srctree; + + RB_Document_Create_Parts( document ); + RB_Analyse_Document( document ); + RB_Generate_Documentation( document ); + + RB_Free_RB_Directory( srctree ); + } + else if ( Find_Option( "--singlefile" ) ) + { + char *srcfile; /* file */ + char *docfile; /* file */ + + document->docroot = 0; + docfile = Find_And_Fix_Path( "--doc" ); + document->singledoc_name = docfile; + srcfile = Find_And_Fix_Path( "--src" ); + if ( !Stat_Path( 'e', srcfile ) ) + { + printf( "Error: %s does not exists\n", srcfile ); + Print_Short_Use( ); + return EXIT_FAILURE; + }; + + if ( !Stat_Path( 'f', srcfile ) ) + { + printf( "Error: %s is not a file\n", srcfile ); + Print_Short_Use( ); + return EXIT_FAILURE; + }; + + document->srctree = RB_Get_RB_SingleFileDirectory( srcfile ); + document->srcroot = + RB_Get_RB_Path( document->srctree->first_path->name ); + + RB_Document_Create_Parts( document ); + RB_Analyse_Document( document ); + RB_Generate_Documentation( document ); + + RB_Free_RB_Directory( document->srctree ); + } + else + { + Print_Short_Use( ); + printf + ( "\n\nError: Use either --multidoc, --singledoc, or --singlefile\n" ); + return EXIT_FAILURE; + } + + RB_Summary( document ); + RB_Free_RB_Document( document ); + Free_Configuration( ); + +#ifdef __APPLE__ + /* Mac OS X specific: print memory leaks */ + if ( debug & SAY_DEBUG ) + { + char cmd[32]; + + sprintf( cmd, "/usr/bin/leaks %d", getpid( ) ); + system( cmd ); + } +#endif /* __APPLE__ */ + + return EXIT_SUCCESS; +} + +/*******/ + + +/****if* UserInterface/Find_Tabstops + * FUNCTION + * This function looks for the tab stop configuration and fills out the + * tab_stops table. + * SYNOPSIS + */ +static void Find_Tabstops( + void ) +/* + * SOURCE + */ +{ + int i; + int tabsize = DEFAULT_TABSIZE; + char *optstr, *str; + + // Find tab sizes + optstr = Find_Parameterized_Option( "--tabsize" ); + if ( optstr ) + { + tabsize = atoi( optstr ); + } + + // Fill tabstop table with default values + for ( i = 0; i < MAX_TABS; i++ ) + { + tab_stops[i] = tabsize * ( i + 1 ); + } + + // Find tab stops + optstr = Find_Parameterized_Option( "--tabstops" ); + if ( optstr ) + { + // Get TAB sizes and fill table + for ( str = strtok( optstr, TABSIZE_SEPARATOR ), i = 0; + str != NULL && i < MAX_TABS; + str = strtok( NULL, TABSIZE_SEPARATOR ), i++ ) + { + tab_stops[i] = atoi( str ) - 1; + } + } +} + +/*******/ + + +/****if* UserInterface/Find_And_Install_Document_Name + * FUNCTION + * Looks for specific option strings and installs special document titles + * and filenames. + * + * Should be used to overwrite the HT_MASTERINDEXTYPE or HT_SOURCEHEADERTYPE + * entries in the header_type_lookup_table. + * SYNOPSIS + */ +static void Find_And_Install_Document_Name( + char *option, + unsigned char type ) +/* + * INPUTS + * o option -- the option string to look for + * o type -- the type entry in header_type_lookup_table to overwrite + * (Should be either HT_MASTERINDEXTYPE or HT_SOURCEHEADERTYPE) + * + * SOURCE + */ +{ + char *title = NULL, *filename = NULL, *optstr = NULL; + + // First find the option + optstr = Find_Parameterized_Option( option ); + if ( optstr ) + { + + // Break the option into substrings + title = strtok( optstr, "," ); + filename = strtok( NULL, "," ); + + // If something missing + if ( title == NULL || filename == NULL ) + { + RB_Panic( "Invalid %s option\n", option ); + } + + // Install document title and filename + RB_AddHeaderType( type, title, filename, 0 ); + } +} + +/*******/ + + + +/****f* UserInterface/Find_And_Fix_Path + * FUNCTION + * Searches through the options to find a path. + * This path is converted to a propper path + * if it contains errors such as the use of + * '\' or when it does not start with ./ or a + * drive name. + * The option must exist. + * SYNOPSIS + */ +static char *Find_And_Fix_Path( + char *option_name ) +/* + * INPUTS + * o option_name -- the option name for the path + * RESULT + * o path -- the path. + * + * SOURCE + */ +{ + char *temp; + char *temp2; + + temp = Find_Parameterized_Option( option_name ); + assert( temp ); + temp = Path_Convert_Win32_to_Unix( temp ); + temp2 = Fix_Path( temp ); + free( temp ); + return temp2; +} + +/*******/ + + +/****f* UserInterface/Path_Convert_Win32_to_Unix + * FUNCTION + * Although people are supposed to specify all paths + * with a '/' as seperator, sometimes people on Win32 + * use '\', this causes problems later on in some + * other function of robodoc that expect a '/'. + * So to prevent this we replace all the '\' in a path + * with '/' + * + * In addition people sometimes add a '/' at the + * end of the path. We remove it. + * + * SYNOPSIS + */ +static char *Path_Convert_Win32_to_Unix( + char *path ) +/* + * INPUTS + * o path -- the path. + * RESULT + * o path -- the converted path (in a newly allocated + * block of memory). + * SOURCE + */ +{ + size_t i; + + /* First make a copy */ + path = RB_StrDup( path ); + for ( i = 0; i < strlen( path ); ++i ) + { + if ( path[i] == '\\' ) + { + path[i] = '/'; + } + } + + /* Remove trailing '/' if there is one. */ + if ( path[strlen( path ) - 1] == '/' ) + { + path[strlen( path ) - 1] = '\0'; + } + + return path; +} + +/*****/ + +/****f* UserInterface/Path_Check + * FUNCTION + * Test the validity of the doc and source path. The doc path should + * not be a sub directory of the source path otherwise the generated + * documentation will be part of the generated documentation if + * robodoc is run more than once. + * SYNOPSIS + */ + +static void Path_Check( + char *sourcepath, + char *docpath ) +/* + * INPUTS + * o sourcepath -- the path to the source files. + * o docpath -- the path to the documentation files. + * OUTPUT + * o error messages + * SOURCE + */ +{ + if ( docpath ) + { + int dl; + int sl; + + dl = strlen( docpath ); + sl = strlen( sourcepath ); + if ( dl >= sl ) + { + int i; + int equal = TRUE; + + for ( i = 0; i < sl; ++i ) + { + if ( docpath[i] != sourcepath[i] ) + { + equal = FALSE; + break; + } + } + if ( equal && ( dl == sl ) ) + { + RB_Panic + ( "The source path and document path can not be equal\n" ); + } + else + { + /* OK */ + } + } + } +} + +/*****/ + + +/****f* UserInterface/PathBegin_Check + * FUNCTION + * Checks the validity of a path. + * A path should start with + * ./ + * or + * / + * or + * have a ':' some where + * SYNOPSIS + */ +static int PathBegin_Check( + char *path ) +/* + * INPUTS + * o path -- the path to be cheked. + * RESULT + * o FALSE -- path is not OK. + * o TRUE -- path is OK. + * SOURCE + */ +{ + int result = FALSE; + int l = strlen( path ); + + if ( l == 1 ) + { + result = ( path[0] == '.' ); + } + else if ( l >= 2 ) + { + result = ( ( path[0] == '.' ) && ( path[1] == '/' ) ) || + ( path[0] == '/' ) || ( strchr( path, ':' ) != NULL ); + } + else + { + /* Empty */ + } + return result; +} + +/******/ + + + +/****f* UserInterface/Find_Option + * FUNCTION + * Search configuration.options for a specific option. + * SYNOPSIS + */ +int Find_Option( + char *option ) +/* INPUTS + * o option -- the option to be found. + * RESULT + * o TRUE -- option does exist + * o FALSE -- option does not exist + * SOURCE + */ +{ + unsigned int parameter_nr; + int found = FALSE; + + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + if ( !RB_Str_Case_Cmp + ( configuration.options.names[parameter_nr], option ) ) + { + found = TRUE; + break; + } + } + return found; +} + +/******/ + +/****f* UserInterface/Fix_Path + * FUNCTION + * Add a "./" to a path if it does not start with a "./" or does not + * contain a ":". If the path was "." just add a "/". Adding a + * "./" simplifies the creating of relative links during the + * generation process. + * SYNOPSIS + */ + +static char *Fix_Path( + char *path ) +/* + * INPUTS + * o path -- the path to be fixed. + * RESULT + * A pointer to a newly allocated string containing the path. + * SOURCE + */ +{ + char *result = 0; + + if ( !PathBegin_Check( path ) ) + { + char *prefix = "./"; + + if ( strcmp( path, "." ) == 0 ) + { + result = RB_StrDup( prefix ); + } + else + { + int l = strlen( path ); + + l += strlen( prefix ) + 1; + result = malloc( l ); + assert( result ); + result[0] = '\0'; + strcat( result, prefix ); + strcat( result, path ); + } + } + else + { + result = RB_StrDup( path ); + } + return result; +} + +/*****/ + + +/* TODO: FS Documentation */ + +T_RB_DocType Find_DocType( + void ) +{ + T_RB_DocType doctype = UNKNOWN; + unsigned int parameter_nr; + + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + + if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--html" ) ) + { + doctype = HTML; + break; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--latex" ) ) + { + doctype = LATEX; + break; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--ascii" ) ) + { + doctype = ASCII; + break; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--rtf" ) ) + { + doctype = RTF; + break; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--test" ) ) + { + doctype = TEST; + break; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--troff" ) ) + { + doctype = TROFF; + break; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--dbxml" ) ) + { + doctype = XMLDOCBOOK; + break; + } + else + { + /* Ignore */ + } + } + return doctype; +} + + +actions_t No_Actions( + void ) +{ + actions_t actions; + unsigned int i; + unsigned char *actptr; + + for ( i = 0, actptr = ( unsigned char * ) &actions; + i < sizeof( actions ); i++, actptr++ ) + { + *actptr = 0; + } + + return actions; +} + +/* TODO: FS Documentation */ +actions_t Find_Actions( + void ) +{ + actions_t actions; + unsigned int parameter_nr; + char *optstr; + + actions = No_Actions( ); + + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--singledoc" ) ) + { + actions.do_singledoc = TRUE; + } + if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--singlefile" ) ) + { + actions.do_singlefile = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--multidoc" ) ) + { + actions.do_multidoc = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--no_subdirectories" ) ) + { + actions.do_no_subdirectories = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--one_file_per_header" ) ) + { + actions.do_one_file_per_header = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--sections" ) ) + { + actions.do_sections = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--internal" ) ) + { + actions.do_include_internal = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--ignore_case_when_linking" ) ) + { + actions.do_ignore_case_when_linking = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--internalonly" ) ) + { + actions.do_internal_only = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--toc" ) ) + { + actions.do_toc = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--index" ) ) + { + actions.do_index = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--nosource" ) ) + { + actions.do_nosource = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--tell" ) ) + { + actions.do_tell = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--debug" ) ) + { + actions.do_tell = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--nodesc" ) ) + { + actions.do_nodesc = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--nogeneratedwith" ) ) + { + actions.do_nogenwith = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--cmode" ) ) + { + actions.do_quotes = TRUE; + actions.do_squotes = TRUE; + actions.do_line_comments = TRUE; + actions.do_block_comments = TRUE; + actions.do_keywords = TRUE; + actions.do_non_alpha = TRUE; + + Install_C_Syntax( ); + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--lock" ) ) + { + actions.do_lockheader = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--footless" ) ) + { + actions.do_footless = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--verbal" ) ) + { + actions.do_verbal = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--ms_errors" ) ) + { + actions.do_ms_errors = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--headless" ) ) + { + actions.do_headless = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--nosort" ) ) + { + actions.do_nosort = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--nopre" ) ) + { + actions.do_nopre = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--sectionnameonly" ) ) + { + actions.do_sectionnameonly = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--altlatex" ) ) + { + actions.do_altlatex = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--latexparts" ) ) + { + actions.do_latexparts = TRUE; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--syntaxcolors" ) ) + { + actions.do_quotes = TRUE; + actions.do_squotes = TRUE; + actions.do_line_comments = TRUE; + actions.do_block_comments = TRUE; + actions.do_keywords = TRUE; + actions.do_non_alpha = TRUE; + } + else + { + /* Not an action */ + } + } + + // Find specific syntax colors enable options + optstr = Find_Parameterized_Option( "--syntaxcolors_enable" ); + if ( optstr ) + { + char *str; + + // Parse options + for ( str = strtok( optstr, "," ); str; str = strtok( NULL, "," ) ) + { + if ( !RB_Str_Case_Cmp( str, "quotes" ) ) + { + actions.do_quotes = TRUE; + } + else if ( !RB_Str_Case_Cmp( str, "squotes" ) ) + { + actions.do_squotes = TRUE; + } + else if ( !RB_Str_Case_Cmp( str, "line_comments" ) ) + { + actions.do_line_comments = TRUE; + } + else if ( !RB_Str_Case_Cmp( str, "block_comments" ) ) + { + actions.do_block_comments = TRUE; + } + else if ( !RB_Str_Case_Cmp( str, "keywords" ) ) + { + actions.do_keywords = TRUE; + } + else if ( !RB_Str_Case_Cmp( str, "non_alpha" ) ) + { + actions.do_non_alpha = TRUE; + } + else + { + // Bad option specified + RB_Panic( "Invalid --syntaxcolors_enable option: %s\n", str ); + } + } + } + + return actions; +} + +/* TODO: FS Documentation */ +long Find_DebugMode( + void ) +{ + long modes = 0; + unsigned int parameter_nr; + + for ( parameter_nr = 0; + parameter_nr < configuration.options.number; parameter_nr++ ) + { + if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--debug" ) ) + { + modes |= SAY_INFO; + modes |= SAY_DEBUG; + } + else if ( !RB_Str_Case_Cmp( configuration.options.names[parameter_nr], + "--tell" ) ) + { + modes |= SAY_INFO; + } + } + return modes; +} + +/****f* UserInterface/Find_Parameterized_Option + * FUNCTION + * Search for an option of the form + * --a_option_name a_value + * in configuration.options. + * SYNOPSIS + */ +char *Find_Parameterized_Option( + char *optionname ) +/* + * INPUTS + * optionname -- the name of the option to search for. + * RESULT + * NULL if the option is not found, a pointer to the value + * otherwise. + * NOTES + * Results in a Panic if the option is found but + * no value is specified. + * SOURCE + */ +{ + return General_Find_Parameterized_Option( configuration.options.number, + &( configuration.options. + names[0] ), optionname ); +} + +/******/ + + +/****f* UserInterface/RB_Find_In_Argv_Parameterized_Option + * FUNCTION + * Search for an option of the form + * --a_option_name a_value + * in argv. The function is used to look for the + * --rc + * option that can be used to specify an + * alternate robodoc configuration file. + * SYNOPSIS + */ +char *RB_Find_In_Argv_Parameterized_Option( + int argc, + char **argv, + char *optionname ) +/* + * INPUTS + * * argc -- the argument count as received by main(). + * * argv -- the array of argument values as received by main() + * * optionname -- the name of the option to search for. + * RESULT + * NULL if the option is not found, a pointer to the value + * otherwise. + * NOTES + * Results in a Panic if the option is found but + * no value is specified. + * SOURCE + */ +{ + return General_Find_Parameterized_Option( argc, argv, optionname ); +} + +/*****/ + + +/****f* UserInterface/General_Find_Parameterized_Option + * FUNCTION + * Search for an option of the form + * --a_option_name a_value + * SYNOPSIS + */ +static char *General_Find_Parameterized_Option( + int n, + char **options, + char *optionname ) +/* + * INPUTS + * o n -- the number of options in the options array. + * o options -- the options array + * o optionname -- the name of the option to search for. + * RESULT + * NULL if the option is not found, a pointer to the value + * otherwise. + * NOTES + * Results in a Panic if the option is found but + * no value is specified. + * SOURCE + */ +{ + int parameter_nr; + char *value = NULL; + + for ( parameter_nr = 0; parameter_nr < n; parameter_nr++ ) + { + if ( !RB_Str_Case_Cmp( options[parameter_nr], optionname ) ) + { + if ( parameter_nr < n - 1 ) + { + value = options[parameter_nr + 1]; + if ( ( value[0] == '-' ) && ( value[1] == '-' ) ) + { + value = NULL; + } + } + else + { + /* to few parameters. */ + } + if ( !value ) + { + RB_Panic( "you must be more specific" + " with the %s option\n", optionname ); + } + } + } + return value; +} + +/******/ + + +/* TODO Documentation */ + +static void RB_Summary( + struct RB_Document *document ) +{ + USE( document ); +#if 0 + printf( "Ready\n" ); + if ( document ) + { + printf( "Found %d headers\n", document->no_headers ); + } + if ( number_of_warnings ) + { + printf( "Found %d warnings\n", number_of_warnings ); + } +#endif +} diff --git a/Source/robodoc.h b/Source/robodoc.h new file mode 100644 index 0000000..086c904 --- /dev/null +++ b/Source/robodoc.h @@ -0,0 +1,141 @@ +#ifndef ROBODOC_ROBODOC_H +#define ROBODOC_ROBODOC_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef VERSION +#define VERSION "4.99.36" +#endif + +#define COMMENT_ROBODOC \ + "Generated with ROBODoc Version " VERSION " (" __DATE__ ")\n" +#define COMMENT_COPYRIGHT\ + "ROBODoc (c) 1994-2007 by Frans Slothouber and many others.\n" + +// Semaphore bits for actions +typedef struct actions_s +{ + // General options + int do_nosort:1; + int do_nodesc:1; + int do_toc:1; + int do_include_internal:1; + int do_internal_only:1; + int do_tell:1; + int do_index:1; + int do_nosource:1; + int do_robo_head:1; + int do_sections:1; + int do_lockheader:1; + int do_footless:1; + int do_headless:1; + int do_nopre:1; + int do_ignore_case_when_linking:1; + int do_nogenwith:1; + int do_sectionnameonly:1; + int do_verbal:1; + int do_ms_errors:1; + + // Document modes + int do_singledoc:1; + int do_multidoc:1; + int do_singlefile:1; + int do_one_file_per_header:1; + int do_no_subdirectories:1; + + // Latex options + int do_altlatex:1; + int do_latexparts:1; + + // Syntax coloring + int do_quotes:1; + int do_squotes:1; + int do_line_comments:1; + int do_block_comments:1; + int do_keywords:1; + int do_non_alpha:1; + +} actions_t; + +/* RB_Say modes */ +#define SAY_DEBUG (1<<0) +#define SAY_INFO (1<<1) + + +/* Output Modes */ + +/****t* Generator/T_RB_DocType + * FUNCTION + * Enumeration for the various output formats that are + * supported by ROBODoc. + * NOTES + * These should be prefixed with RB_ + * SOURCE + */ + +typedef enum +{ + TEST = 1, /* Special output mode for testing */ + ASCII, + HTML, + LATEX, + RTF, + TROFF, + XMLDOCBOOK, + /* SIZE_MODES, */ + /* Reserved for Future Use */ + /* ANSI, */ + /* GNUINFO, */ + /* XML, */ + UNKNOWN +} T_RB_DocType; + +/*****/ + + +#define USE( x ) ( x = x ); + +/* Evil macros !! */ +#define skip_while(cond) { for (;*cur_char && (cond);cur_char++) ; } +#define find_eol { for (;*cur_char && *cur_char!='\n';cur_char++) ; } +#define find_quote { for (;*cur_char && *cur_char!='\"';cur_char++) ; } + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +/* Prototypes */ + +actions_t No_Actions( + void ); + +#endif /* ROBODOC_ROBODOC_H */ + diff --git a/Source/robodoc_basic_style.css b/Source/robodoc_basic_style.css new file mode 100644 index 0000000..55d8b30 --- /dev/null +++ b/Source/robodoc_basic_style.css @@ -0,0 +1,298 @@ +/****h* ROBODoc/ROBODoc Cascading Style Sheet + * FUNCTION + * This is the default cascading style sheet for documentation + * generated with ROBODoc. + * You can edit this file to your own liking and then use + * it with the option + * --css + * + * This style-sheet defines the following layout + * +----------------------------------------+ + * | logo | + * +----------------------------------------+ + * | extra | + * +----------------------------------------+ + * | | navi- | + * | | gation | + * | content | | + * | | | + * +----------------------------------------+ + * | footer | + * +----------------------------------------+ + * + * This style-sheet is based on a style-sheet that was automatically + * generated with the Strange Banana stylesheet generator. + * See http://www.strangebanana.com/generator.aspx + * + ****** + * $Id: robodoc_basic_style.css,v 1.8 2007/05/10 14:20:58 thuffir Exp $ + */ + +body +{ + background-color: rgb(255,255,255); + color: rgb(98,84,55); + font-family: Arial, serif; + border-color: rgb(226,199,143); +} + +pre +{ + font-family: monospace; + margin: 15px; + padding: 5px; + white-space: pre; + color: #000; +} + +pre.source +{ + background-color: #ffe; + border: dashed #aa9 1px; +} + +p +{ + margin:15px; +} + +p.item_name +{ + font-weight: bolder; + margin:5px; + font-size: 120%; +} + +#content +{ + font-size: 100%; + color: rgb(0,0,0); + background-color: rgb(255,255,255); + border-left-width: 0px; + border-right-width: 0px; + border-top-width: 0px; + border-bottom-width: 0px; + border-left-style: none; + border-right-style: none; + border-top-style: none; + border-bottom-style: none; + padding: 40px 31px 14px 17px; + border-color: rgb(0,0,0); + text-align: justify; +} + +#navigation +{ + background-color: rgb(98,84,55); + color: rgb(230,221,202); + font-family: "Times New Roman", serif; + font-style: normal; + border-color: rgb(0,0,0); +} + +a.menuitem +{ + font-size: 120%; + background-color: rgb(0,0,0); + color: rgb(195,165,100); + font-variant: normal; + text-transform: none; + font-weight: normal; + padding: 1px 8px 3px 1px; + margin-left: 5px; + margin-right: 5px; + margin-top: 5px; + margin-bottom: 5px; + border-color: rgb(159,126,57); + text-align: right; +} + +#logo, #logo a +{ + font-size: 130%; + background-color: rgb(198,178,135); + color: rgb(98,84,55); + font-family: Georgia, serif; + font-style: normal; + font-variant: normal; + text-transform: none; + font-weight: bold; + padding: 20px 18px 20px 18px; + border-color: rgb(255,255,255); + text-align: right; +} + +#extra, #extra a +{ + font-size: 128%; + background-color: rgb(0,0,0); + color: rgb(230,221,202); + font-style: normal; + font-variant: normal; + text-transform: none; + font-weight: normal; + border-left-width: 0px; + border-right-width: 0px; + border-top-width: 0px; + border-bottom-width: 0px; + border-left-style: none; + border-right-style: none; + border-top-style: none; + border-bottom-style: none; + padding: 12px 12px 12px 12px; + border-color: rgb(195,165,100); + text-align: center; +} + +#content a +{ + color: rgb(159,126,57); + text-decoration: none; +} + +#content a:hover, #content a:active +{ + color: rgb(255,255,255); + background-color: rgb(159,126,57); +} + +a.indexitem +{ + display: block; +} + +h1, h2, h3, h4, h5, h6 +{ + background-color: rgb(221,221,221); + font-family: Arial, serif; + font-style: normal; + font-variant: normal; + text-transform: none; + font-weight: normal; +} + +h1 +{ + font-size: 151%; +} + +h2 +{ + font-size: 142%; +} + +h3 +{ + font-size: 133%; +} + +h4 +{ + font-size: 124%; +} + +h5 +{ + font-size: 115%; +} + +h6 +{ + font-size: 106%; +} + +#navigation a +{ + text-decoration: none; +} + +.menuitem:hover +{ + background-color: rgb(195,165,100); + color: rgb(0,0,0); +} + +#extra a +{ + text-decoration: none; +} + +#logo a +{ + text-decoration: none; +} + +#extra a:hover +{ +} + +/* layout */ +#navigation +{ + width: 22%; + position: relative; + top: 0; + right: 0; + float: right; + text-align: center; + margin-left: 10px; +} + +.menuitem {width: auto;} +#content {width: auto;} +.menuitem {display: block;} + + +div#footer +{ + background-color: rgb(198,178,135); + color: rgb(98,84,55); + clear: left; + width: 100%; + font-size: 71%; +} + +div#footer a +{ + background-color: rgb(198,178,135); + color: rgb(98,84,55); +} + +div#footer p +{ + margin:0; + padding:5px 10px +} + +span.keyword +{ + color: #00F; +} + +span.comment +{ + color: #080; +} + +span.quote +{ + color: #F00; +} + +span.squote +{ + color: #F0F; +} + +span.sign +{ + color: #008B8B; +} + + +@media print +{ + #navigation {display: none;} + #content {padding: 0px;} + #content a {text-decoration: underline;} +} diff --git a/Source/robohdrs.c b/Source/robohdrs.c new file mode 100644 index 0000000..a69fbfa --- /dev/null +++ b/Source/robohdrs.c @@ -0,0 +1,922 @@ +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + +/* $Id: robohdrs.c,v 1.14 2007/07/10 19:13:52 gumpu Exp $ */ + +/****h* Docuwala/ROBOhdrs +* NAME +* robohdrs +* DESCRIPTION +* Standalone program to insert ROBODoc headers to source code files. +* This program processes one source file at the time. Existing +* ROBODoc headers, if any, are not checked for. Beware since this +* may result in double headers. Current working directory should +* be the same as where the source file is located. +* USES +* Exuberant Ctags 5.3.1 or newer required +* USAGE +* robohdrs [options] +* EXAMPLE +* robohdrs -p myproj test1.c +* robohdrs -s -p myproj -i "MODIFICATION HISTORY" -i IDEAS test2.c +* +* Type `robohdrs -h' to see all command line options. +* TODO +* - garbage collection +* - support for other languages which ctags program supports +* SEE ALSO +* ROBODoc https://sourceforge.net/projects/robodoc/ +* Exuberant Ctags http://ctags.sourceforge.net/ +* COPYRIGHT +* (c) 2003 Frans Slothouber and Petteri Kettunen +* Copying policy: GPL +* HISTORY +* 2003-08-08/petterik: #define `d' header (bug rep. from Anand Dhanakshirur) +* 2003-08-04/petterik: -t option (suggestion from Anand Dhanakshirur) +* 2003-02-21/petterik: -l option, script option tested +******* +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include +#include +#include + + + +#ifndef HAVE_FORK + +int main( int argc, char** argv ) +{ + printf( "Not supported on this platform\n" ); + printf( "This program requires fork()\n" ); + return EXIT_SUCCESS; +} + +#else + + + +#include +#include +#include +#include "headers.h" + +/****v* ROBOhdrs/PROGNAME +* NAME +* PROGNAME +* SOURCE +*/ +#define PROGNAME "robohdrs" +/********** PROGNAME */ +/****v* ROBOhdrs/PROGVERSION +* NAME +* PROGVERSION +* SOURCE +*/ +#define PROGVERSION "0.01" +/********** PROGVERSION */ +/****v* ROBOhdrs/MAXLINE +* NAME +* MAXLINE +* SOURCE +*/ +#define MAXLINE 10240 +/********** MAXLINE */ +/****v* ROBOhdrs/MAXNAME +* NAME +* MAXNAME +* SOURCE +*/ +#define MAXNAME 1024 + +/********** MAXNAME */ + +/****v* ROBOhdrs/ctagsBin +* NAME +* ctagsBin +* SOURCE +*/ +static char ctagsBin[MAXNAME]; + +/********** ctagsBin */ + +/****v* ROBOhdrs/srcSta +* NAME +* srcSta +* SEE ALSO +* src_constants +* SOURCE +*/ + +static short srcSta = SRC_C; +static short srcRem = SRC_R_C; +static short srcEnd = SRC_E_C; + +/********** srcSta */ + +typedef struct _ctag_t +{ + void *prev; + void *next; + char fname[MAXNAME]; + char name[MAXNAME]; + char decl[MAXLINE]; + char type[MAXNAME]; + int linenum; +} +ctag_t; + +typedef struct _custhdr_t +{ + void *next; + char name[MAXNAME]; +} +custhdr_t; + +typedef struct _ctags_t +{ + ctag_t *ctag; + int cnt; +} +ctags_t; + +/****v* ROBOhdrs/myctags +* NAME +* myctags +* SYNOPSIS +* static ctags_t myctags; +* SOURCE +*/ +static ctags_t myctags; + +/********** myctags */ +/****v* ROBOhdrs/ctags +* NAME +* ctags +* SYNOPSIS +* static ctags_t *ctags; +* SOURCE +*/ +static ctags_t *ctags; + +/********** ctags */ +/****v* ROBOhdrs/custhdrs +* NAME +* custhdrs +* SYNOPSIS +* static custhdr_t *custhdrs = 0; +* SOURCE +*/ +static custhdr_t *custhdrs = 0; + +/********** custhdrs */ +/****v* ROBOhdrs/projName +* NAME +* projName +* SYNOPSIS +* static char projName[MAXNAME]; +* SOURCE +*/ +static char projName[MAXNAME]; + +/********** projName */ +/****v* ROBOhdrs/vcTag +* NAME +* vcTag +* DESCRIPTION +* Version control tag string. This is always specified by the user. +* SYNOPSIS +* static char vcTag[MAXNAME]; +* SOURCE +*/ +static char vcTag[MAXNAME]; + +/********** projName */ +/****v* ROBOhdrs/incSrc +* NAME +* incSrc +* SYNOPSIS +* static char incSrc = 0; +* SOURCE +*/ +static char incSrc = 0; + +/********** incSrc */ +/****f* ROBOhdrs/usage +* NAME +* usage +* SYNOPSIS +* static void usage(void) +* SOURCE +*/ +static void +usage( void ) +{ + printf( "%s version %s, robodoc header insertor\n", PROGNAME, + PROGVERSION ); + printf( "(c) 2003 Frans Slothouber and Petteri Kettunen\n" ); + printf( "%s comes with ABSOLUTELY NO WARRANTY.\n", PROGNAME ); + printf + ( "This is free software, and you are welcome to redistribute it\n" ); + printf( "under the GNU GENERAL PUBLIC LICENSE terms and conditions.\n" ); + printf( "usage: %s [options] \n", PROGNAME ); + printf( "Options are as follows:\n" ); + printf( " -h show this help text\n" ); + printf + ( " -i specify header item (repeat to include multiple items)\n" ); + printf( " -l specify source code language (default C/C++)\n" ); + printf + ( " Supported options are: fortran, fortran90, script, and tex.\n" ); + printf( " -p specify project name\n" ); + printf( " -s include SOURCE item\n" ); + printf( " -t specify CVS/RCS tag to be inserted into a file\n" ); + printf( " -x specify path to ctags binary\n" ); + printf( "NOTE: requires Exuberant Ctags 5.3.1 (or newer)\n" ); + printf( "EXAMPLES:\n" ); + printf + ( "robohdrs -s -p myproj -i \"MODIFICATION HISTORY\" -i IDEAS test.c\n" ); + printf + ( "robohdrs -s -p myproj -l script -t '%cHeader:%c' test.tcl\n", '$', '$' ); + exit( 1 ); +} + +/********** usage */ + +/****f* ROBOhdrs/cmdLine +* NAME +* cmdLine +* SYNOPSIS +* static void cmdLine(int argc, char **argv) +* SOURCE +*/ +static void +cmdLine( int argc, char **argv ) +{ + int ch; + custhdr_t *c, *nc; + + while ( ( ch = getopt( argc, argv, "i:l:p:st:x:" ) ) != -1 ) + switch ( ch ) + { + + case 's': + /* include source item */ + incSrc = 1; + break; + + case 't': + /* specify version control tag */ + strncpy( vcTag, optarg, MAXNAME ); + break; + + case 'p': + /* specify project name */ + strncpy( projName, optarg, MAXNAME ); + break; + + case 'i': + if ( !custhdrs ) + { + assert( ( custhdrs = + ( custhdr_t * ) malloc( sizeof( custhdr_t ) ) ) ); + custhdrs->next = 0; + c = custhdrs; + } + else + { + c = custhdrs; + while ( c->next ) + { + c = c->next; + } + assert( ( nc = + ( custhdr_t * ) malloc( sizeof( custhdr_t ) ) ) ); + nc->next = 0; + c = c->next = nc; + } + strncpy( c->name, optarg, MAXNAME ); + break; + + case 'l': + if ( optarg[0] == 's' && strcmp( optarg, "script" ) == 0 ) + { + srcSta = SRC_SCRIPT; + srcRem = SRC_R_SCRIPT; + srcEnd = SRC_E_SCRIPT; + } + else if ( optarg[0] == 'f' && strcmp( optarg, "fortran" ) == 0 ) + { + srcSta = SRC_FORTRAN; + srcRem = SRC_R_FORTRAN; + srcEnd = SRC_E_FORTRAN; + } + else if ( optarg[0] == 'f' && strcmp( optarg, "fortran90" ) == 0 ) + { + srcSta = SRC_F90; + srcRem = SRC_R_F90; + srcEnd = SRC_E_F90; + } + else if ( optarg[0] == 't' && strcmp( optarg, "tex" ) == 0 ) + { + srcSta = SRC_TEX; + srcRem = SRC_R_TEX; + srcEnd = SRC_E_TEX; + } + else if ( optarg[0] == 'a' && strcmp( optarg, "acm" ) == 0 ) + { + srcSta = SRC_ACM; + srcRem = SRC_R_ACM; + srcEnd = SRC_E_ACM; + } + else + { + usage( ); + } + break; + + case 'x': + strncpy( ctagsBin, optarg, MAXNAME ); + break; + + case '?': + case 'h': + default: + usage( ); + break; + } +} + +/********** cmdLine */ +/****f* ROBOhdrs/linenumCompare +* NAME +* linenumCompare +* SYNOPSIS +* static int linenumCompare(void const * a, void const * b) +* SOURCE +*/ +static int +linenumCompare( void const *a, void const *b ) +{ + ctag_t *ea = ( ctag_t * ) a, *eb = ( ctag_t * ) b; + + return ( ea->linenum - eb->linenum ); +} + +/********** linenumCompare */ +/****f* ROBOhdrs/arrangeCtags +* NAME +* arrangeCtags +* SYNOPSIS +* static void arrangeCtags(ctags_t *e) +* SOURCE +*/ +static void +arrangeCtags( ctags_t * e ) +{ + ctag_t *tmp, *ctag = e->ctag, *ep; + + assert( e && e->cnt && e->ctag ); + tmp = ( ctag_t * ) malloc( e->cnt * sizeof( ctag_t ) ); + assert( tmp ); + + for ( ep = tmp;; ) + { + memcpy( ep++, ctag, sizeof( ctag_t ) ); + if ( ctag->next ) + { + ctag = ctag->next; + } + else + { + break; + } + } + + qsort( tmp, ( size_t ) ( e->cnt ), sizeof( ctag_t ), linenumCompare ); + /* TODO: free ctag */ + e->ctag = tmp; +} + +/********** arrangeCtags */ +/****f* ROBOhdrs/typeOk +* NAME +* typeOk +* SYNOPSIS +* static int typeOk(char *t) +* SOURCE +*/ +static int +typeOk( char *t ) +{ + /* return 1 if supported type for headers */ + if ( t[0] == 'f' && strncmp( t, "function", 8 ) == 0 ) + { + return 1; + } + else if ( t[0] == 'v' && strncmp( t, "variable", 8 ) == 0 ) + { + return 1; /* global variable */ + } +#if 0 + else if ( t[0] == 's' && strncmp( t, "struct", 6 ) == 0 ) + { + return 1; + } +#endif + else if ( t[0] == 'm' && strncmp( t, "macro", 5 ) == 0 ) + { + return 1; + } + return 0; +} + + +/********** typeOk */ +/****f* ROBOhdrs/initMe +* NAME +* initMe +* SYNOPSIS +* static void initMe(void) +* SOURCE +*/ +static void +initMe( void ) +{ + ctags = &myctags; + memset( ctags, 0, sizeof( ctags_t ) ); + projName[0] = '\0'; + ctagsBin[0] = '\0'; + vcTag[0] = '\0'; +} + +/********** initMe */ + +/****f* ROBOhdrs/parseCtagsXLine +* NAME +* parseCtagsXLine +* SYNOPSIS +* static int parseCtagsXLine(char *buf, char *fname, char *name, char *decl, char *type, int *linenum) +* SOURCE +*/ +static int +parseCtagsXLine( char *buf, char *fname, char *name, char *decl, char *type, + int *linenum ) +{ + char *t, *s; + + /* ctags -x output is: */ + /* usage function 56 test.c void usage(void) */ + sscanf( buf, "%s%s%d%s", name, type, linenum, fname ); + s = strstr( buf, fname ); + while ( *s++ != ' ' ) + { + } + while ( *s == ' ' ) + { + ++s; + } + t = decl; + while ( ( *t = *s++ ) != '\n' ) + { + ++t; + } + *t = '\0'; + + return 0; +} + +/********** parseCtagsXLine */ + +/****f* ROBOhdrs/addList +* NAME +* addList +* SYNOPSIS +* static void addList(ctags_t *e, char *fname, char *name, char *decl, char *type, int linenum) +* SOURCE +*/ +static void +addList( ctags_t * e, char *fname, char *name, char *decl, char *type, + int linenum ) +{ + ctag_t *newctag, *ctag = e->ctag; + + if ( !ctag ) + { + /* empty list */ + ctag = ( ctag_t * ) malloc( sizeof( ctag_t ) ); + assert( ctag ); + memset( ctag, 0, sizeof( ctag_t ) ); + e->ctag = ctag; + } + else + { + while ( ctag->next ) + { + ctag = ctag->next; + } + newctag = ( ctag_t * ) malloc( sizeof( ctag_t ) ); + assert( newctag ); + memset( newctag, 0, sizeof( ctag_t ) ); + ctag->next = newctag; + newctag->prev = ctag; + ctag = newctag; + } + + e->cnt++; + + strncpy( ctag->fname, fname, MAXNAME ); + strncpy( ctag->name, name, MAXNAME ); + strncpy( ctag->decl, decl, MAXLINE ); + strncpy( ctag->type, type, MAXNAME ); + ctag->linenum = linenum; +} + +/********** addList */ +/****f* ROBOhdrs/parseCtagsX +* NAME +* parseCtagsX +* SYNOPSIS +* static int parseCtagsX(FILE *fp) +* SOURCE +*/ +static int +parseCtagsX( FILE * fp ) +{ + char buf[MAXLINE + 1]; + int lnum = 0, tagsParsed = 0; + + while ( fgets( buf, MAXLINE, fp ) != NULL ) + { + char decl[MAXNAME + 1], name[MAXNAME + 1]; + char fname[MAXNAME + 1], type[MAXNAME + 1]; + int linenum; + + lnum++; + /* extract info from a line */ + if ( parseCtagsXLine( buf, fname, name, decl, type, &linenum ) ) + { + printf( "error parsing line (%d)", lnum ); + } + else + { + addList( ctags, fname, name, decl, type, linenum ); + tagsParsed++; + } + } /* end while() */ + fclose( fp ); + + return tagsParsed; +} + +/********** parseCtagsX */ + +/****f* ROBOhdrs/roboFileHeader +* NAME +* roboFileHeader +* FUNCTION +* Insert source file header. +* SYNOPSIS +* static void roboFileHeader(FILE *fp, char *proj, char *fname) +* SOURCE +*/ +static void +roboFileHeader( FILE * fp, char *proj, char *fname ) +{ + char *s; + + s = remark_markers[srcRem]; + fprintf( fp, "%sh* %s/%s\n", header_markers[srcSta], + ( proj[0] ? proj : fname ), fname ); + fprintf( fp, "%s NAME\n", s ); + fprintf( fp, "%s %s\n", s, fname ); + if ( *vcTag ) + { + fprintf( fp, "%s %s\n", s, vcTag ); + } + fprintf( fp, "%s DESCRIPTION\n", s ); + fprintf( fp, "%s*******%s\n", s, + ( end_remark_markers[srcEnd] ? end_remark_markers[srcEnd] : + "" ) ); +} + +/********** roboFileHeader */ + +/****f* ROBOhdrs/roboHeader +* NAME +* roboHeader +* SYNOPSIS +* static void roboHeader(FILE *fp, char *fname, char *name, char *type, char *decl) +* SOURCE +*/ +static void +roboHeader( FILE * fp, char *fname, char *name, char *type, char *decl ) +{ + custhdr_t *c; + char *s; + + s = remark_markers[srcRem]; + if ( type[0] == 'v' ) + { + fprintf( fp, "%sv* %s/%s\n", header_markers[srcSta], fname, name ); + } + else if ( type[0] == 'm' ) + { + fprintf( fp, "%sd* %s/%s\n", header_markers[srcSta], fname, name ); + } +#if 0 + else if ( type[0] == 's' ) + { + fprintf( fp, "/****s* %s/%s\n", fname, name ); + } +#endif + else + { + fprintf( fp, "%sf* %s/%s\n", header_markers[srcSta], fname, name ); + } + + fprintf( fp, "%s NAME\n%s %s\n", s, s, name ); + if ( type[0] != 'm' ) + { + fprintf( fp, "%s SYNOPSIS\n%s %s\n", s, s, decl ); + } + if ( custhdrs ) + { + for ( c = custhdrs;; ) + { + fprintf( fp, "%s %s\n", s, c->name ); + if ( c->next ) + { + c = c->next; + } + else + { + break; + } + } + } + + if ( incSrc ) + { + fprintf( fp, "%s SOURCE\n%s\n", s, + ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] : + s ) ); + } + else + { + fprintf( fp, "%s***%s\n", s, + ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] : + "" ) ); + } +} + +/********** roboHeader */ + +/****f* ROBOhdrs/insertSrcEnd +* NAME +* insertSrcEnd +* SYNOPSIS +* static void insertSrcEnd(FILE *fp, char *funcname) +* SOURCE +*/ + +static void +insertSrcEnd( FILE * fp, char *funcname ) +{ + fprintf( fp, "%s********* %s %s\n", end_markers[srcEnd], funcname, + ( end_remark_markers[srcSta] ? end_remark_markers[srcSta] : + "" ) ); +} + +/********** insertSrcEnd */ + +/****f* ROBOhdrs/insertHeaders +* NAME +* insertHeaders +* SYNOPSIS +* static void insertHeaders(ctags_t *e, char *project, char *dstpath, char *srcpath) +* SOURCE +*/ +static void +insertHeaders( ctags_t * e, char *project, char *dstpath, char *srcpath ) +{ + FILE *ifp, *ofp; + ctag_t *ctag = e->ctag; + int lnum = 0, funcline = 0; + char buf[MAXLINE], *funcname = 0; + + if ( !ctag || !dstpath || !srcpath ) + { + return; + } + + assert( ofp = fopen( dstpath, "w" ) ); + assert( ifp = fopen( srcpath, "r" ) ); + + /* include file header only if project name is defined */ + if ( project ) + { + roboFileHeader( ofp, project, dstpath ); + } + + while ( fgets( buf, MAXLINE, ifp ) != NULL ) + { + lnum++; + while ( ctag->prev ) + { + ctag = ctag->prev; + } + for ( ;; ) + { + if ( incSrc && funcline && lnum >= funcline + && ctag->linenum == lnum ) + { + funcline = 0; + insertSrcEnd( ofp, funcname ); + } + if ( ctag->linenum == lnum ) + { + if ( typeOk( ctag->type ) ) + { + roboHeader( ofp, ctag->fname, ctag->name, ctag->type, + ctag->decl ); + funcline = lnum; + funcname = ctag->name; + } + break; + } + else if ( ctag->next ) + { + ctag = ctag->next; + } + else + { + break; + } + } /* end ctag loop */ + fprintf( ofp, "%s", buf ); + } + + if ( incSrc && funcline ) + { + insertSrcEnd( ofp, funcname ); + } + + fclose( ifp ); + fclose( ofp ); +} + +/********** insertHeaders */ +/****f* ROBOhdrs/doCtagsExec +* NAME +* doCtagsExec +* SYNOPSIS +* static FILE * doCtagsExec(char *fname) +* SOURCE +*/ +static FILE * +doCtagsExec( char *fname ) +{ + int fd[2], pid; + FILE *incoming; + char *mybin, *bin = "ctags"; + + mybin = ( ctagsBin[0] ? ctagsBin : bin ); + + if ( pipe( fd ) == -1 ) + { + fprintf( stderr, "pipe failed\n" ); + exit( 1 ); + } + + if ( ( pid = fork( ) ) == 0 ) + { + close( 1 ); + dup( fd[1] ); + close( fd[0] ); + if ( execlp( mybin, mybin, "-x", fname, NULL ) == -1 ) + { + fprintf( stderr, "execlp failed\n" ); + exit( 1 ); + } + } + else if ( pid == -1 ) + { + fprintf( stderr, "fork failed\n" ); + exit( 1 ); + } + else + { + close( 0 ); + dup( fd[0] ); + close( fd[1] ); + + if ( ( incoming = fdopen( 0, "r" ) ) == NULL ) + { + fprintf( stderr, "fdopen failed\n" ); + exit( 1 ); + } + } + + return incoming; +} + +/********** doCtagsExec */ +/****f* ROBOhdrs/doFile +* NAME +* doFile +* SYNOPSIS +* static void doFile(char *proj, char *fname) +* SOURCE +*/ +static void +doFile( char *proj, char *fname ) +{ + char buf[MAXLINE]; + + /* backup */ + sprintf( buf, "/bin/cp -p %s %s~", fname, fname ); + system( buf ); + + if ( parseCtagsX( doCtagsExec( fname ) ) < 1 ) + { + fprintf( stderr, "no tags\n" ); + exit( 1 ); + } + + arrangeCtags( ctags ); + sprintf( buf, "%s~", fname ); + insertHeaders( ctags, proj, fname, buf ); +} + +/********** doFile */ +/****f* ROBOhdrs/cleanUp +* NAME +* cleanUp +* SYNOPSIS +* static void cleanUp(void) +* SOURCE +*/ +static void +cleanUp( void ) +{ + +} + +/********** cleanUp */ + + +/****f* ROBOhdrs/main +* NAME +* main +* SYNOPSIS +* int main(int argc, char **argv) +* SOURCE +*/ +int +main( int argc, char **argv ) +{ + initMe( ); + cmdLine( argc, argv ); + argc -= optind; + argv += optind; + if ( argc == 1 ) + { + doFile( projName, argv[0] ); + } + else + { + usage( ); + } + cleanUp( ); + return 0; +} + +/********** main */ + + +#endif /* HAVE_FORK */ + diff --git a/Source/rtf_generator.c b/Source/rtf_generator.c new file mode 100644 index 0000000..ff4ef12 --- /dev/null +++ b/Source/rtf_generator.c @@ -0,0 +1,327 @@ +// vi: spell ff=unix + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +/****h* ROBODoc/RTF_Generator + * FUNCTION + * A collection of functions to generate output in RTF format. + * Supports sections upto 7 levels deep. + * TODO + * Documentation + * MODIFICATION HISTORY + * ????-??-?? Anthon Pang V1.0 + * 2003-02-03 Frans Slothouber Refactoring + * Anthon Pang + ***** + * $Id: rtf_generator.c,v 1.27 2007/07/10 19:13:52 gumpu Exp $ + */ + + +#include +#include +#include + +#include "rtf_generator.h" +#include "util.h" +#include "robodoc.h" +#include "globals.h" +#include "headers.h" +#include "generator.h" + +#ifdef DMALLOC +#include +#endif + + +void RB_RTF_Generate_False_Link( + FILE *dest_doc, + char *name ) +{ + /* Find out how to emphasize this in rtf */ + fprintf( dest_doc, "%s", name ); +} + +void RB_RTF_Generate_TOC_2( + FILE *dest_doc, + struct RB_header **headers, + int count ) +{ + int i; + + for ( i = 0; i < count; ++i ) + { + struct RB_header *cur_header = headers[i]; + + if ( cur_header->name && cur_header->function_name ) + { + fprintf( dest_doc, "{" ); + RB_RTF_Generate_String( dest_doc, cur_header->name ); + fprintf( dest_doc, "}{\\v " ); + RB_RTF_Generate_String( dest_doc, cur_header->function_name ); + fprintf( dest_doc, "}\\line\n" ); + } + } +} + +void RB_RTF_Generate_Label( + FILE *dest_doc, + char *name ) +{ + USE( dest_doc ); + USE( name ); + /* Empty */ +} + +void RB_RTF_Generate_Item_Name( + FILE *dest_doc, + char *name ) +{ + fprintf( dest_doc, "\\par \\fs18 %s ", name ); +} + +char *RB_RTF_Get_Default_Extension( + void ) +{ + return ".rtf"; +} + + +void RB_RTF_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name ) +{ + fprintf( dest_doc, "\\par {\\s%d %s \\par} \\pard\\plain\n", depth, name ); +} + +void RB_RTF_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ) +{ + USE( dest_doc ); + USE( depth ); + USE( name ); + /* empty */ +} + +/*x**f* RTF_Generator/RB_RTF_Generate_Doc_Start + * NAME + * RB_RTF_Generate_Doc_Start -- + ****** + */ + +void RB_RTF_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char toc ) +{ + USE( toc ); + + /* RTF header */ + fprintf( dest_doc, "{\\rtf1\\ansi \\deff0" + "{\\fonttbl;" + "\\f0\\fswiss MS Sans Serif;" + "\\f1\\fmodern Courier New;" + "\\f2\\ftech Symbol;" + "}" + "{\\colortbl;" + "\\red255\\green255\\blue255;" + "\\red0\\green0\\blue0;" "\\red0\\green0\\blue255;" "}" ); + + /* RTF document info */ + fprintf( dest_doc, "{\\info" + "{\\title %s}" "{\\comment\n" " Source: %s\n", name, src_name ); + if ( course_of_action.do_nogenwith ) + { + fprintf( dest_doc, " " "}" "}" ); + } + else + { + fprintf( dest_doc, " " COMMENT_ROBODOC " " "}" "}" ); + } + + /* RTF stylesheet */ + fprintf( dest_doc, + "{\\stylesheet\n" + "{\\s1 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel0\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 1;}\n" + "{\\s2 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel1\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 2;}\n" + "{\\s3 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel2\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 3;}\n" + "{\\s4 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel3\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 4;}\n" + "{\\s5 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel4\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 5;}\n" + "{\\s6 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel5\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 6;}\n" + "{\\s7 \\fs20 \\keepn\\widctlpar\\jclisttab \\outlinelevel6\\adjustright \\cgrid \\sbasedon0 \\snext0 heading 7;}}\n" ); + /* RTF document format */ + fprintf( dest_doc, "{\\margl1440\\margr1440}\\fs18\n" ); + + /* RTF document section */ + fprintf( dest_doc, "\\f0\\cb1\\cf3\\b1\\qc" + "{\\super #{\\footnote{\\super #}%s_TOC}}" + "{\\super ${\\footnote{\\super $}Contents}}" + "{TABLE OF CONTENTS}\\ql\\b0\\fs20\\cf2\\par\n", src_name ); +} + +/*x**f* RTF_Generator/RB_RTF_Generate_Doc_End + * NAME + * RB_RTF_Generate_Doc_End -- + ****** + */ + +void RB_RTF_Generate_Doc_End( + FILE *dest_doc, + char *name ) +{ + USE( name ); + + fputc( '}', dest_doc ); +} + +/*x**f* RTF_Generator/RB_RTF_Generate_Header_Start + * NAME + * RB_RTF_Generate_Header_Start -- + ****** + */ + +void RB_RTF_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + if ( cur_header->name && cur_header->function_name ) + { + RB_RTF_Generate_String( dest_doc, cur_header->function_name ); + fprintf( dest_doc, "\\page {\\super #{\\footnote{\\super #}" ); + RB_RTF_Generate_String( dest_doc, cur_header->function_name ); + fprintf( dest_doc, "}}{\\super ${\\footnote{\\super $}" ); + RB_RTF_Generate_String( dest_doc, cur_header->name ); + fprintf( dest_doc, "}} " ); + RB_RTF_Generate_String( dest_doc, cur_header->name ); + fprintf( dest_doc, "\\line\n" ); + } +} + +/*x**f* RTF_Generator/RB_RTF_Generate_Header_End + * NAME + * RB_RTF_Generate_Header_End -- + ****** + */ + +void RB_RTF_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ) +{ + USE( cur_header ); + + fprintf( dest_doc, "\\par\n" ); +} + + +void RB_RTF_Generate_Item_Begin( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\\line {\\f1{} \\fs18" ); +} + +void RB_RTF_Generate_Item_End( + FILE *dest_doc ) +{ + fputc( '}', dest_doc ); + fputc( '\n', dest_doc ); +} + +/*x**f* RTF_Generator/RB_RTF_Generate_Empty_Item + * NAME + * RB_RTF_Generate_Empty_Item -- + ****** + */ + +void RB_RTF_Generate_Empty_Item( + FILE *dest_doc ) +{ + fprintf( dest_doc, "\n" ); +} + + +void RB_RTF_Generate_Link( + FILE *dest_doc, + char *dest_name, + char *filename, + char *labelname, + char *linkname + ) +{ + USE( dest_name ); + USE( filename ); + + if ( strcmp( labelname, linkname ) ) + { + fprintf( dest_doc, "{\\b " ); + RB_RTF_Generate_String( dest_doc, linkname ); + fprintf( dest_doc, "}{\\v " ); + RB_RTF_Generate_String( dest_doc, labelname ); + fprintf( dest_doc, "}" ); + } + else + { + RB_RTF_Generate_String( dest_doc, labelname ); + } +} + +void RB_RTF_Generate_String( + FILE *dest_doc, + char *a_string ) +{ + int i; + int l = strlen( a_string ); + unsigned char c; + + for ( i = 0; i < l; ++i ) + { + c = a_string[i]; + RB_RTF_Generate_Char( dest_doc, c ); + } +} + +void RB_RTF_Generate_Char( + FILE *dest_doc, + int c ) +{ + switch ( c ) + { + case '\n': + assert( 0 ); + break; + case '\t': + assert( 0 ); + break; + case '\\': + case '{': + case '}': + fputc( '\\', dest_doc ); + fputc( c, dest_doc ); + break; + default: + fputc( c, dest_doc ); + } +} diff --git a/Source/rtf_generator.h b/Source/rtf_generator.h new file mode 100644 index 0000000..b0a1bce --- /dev/null +++ b/Source/rtf_generator.h @@ -0,0 +1,89 @@ +#ifndef ROBODOC_RTF_GENERATOR_H +#define ROBODOC_RTF_GENERATOR_H + +/* +Copyright (C) 1994-2007 Frans Slothouber, Jacco van Weert, Petteri Kettunen, +Bernd Koesling, Thomas Aglassinger, Anthon Pang, Stefan Kost, David Druffner, +Sasha Vasko, Kai Hofmann, Thierry Pierron, Friedrich Haase, and Gergely Budai. + +This file is part of ROBODoc + +ROBODoc is free software; you can 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 . + +*/ + + +#include "headers.h" + +void RB_RTF_Generate_TOC_2( + FILE *dest_doc, + struct RB_header **headers, + int count ); +void RB_RTF_Generate_Doc_Start( + FILE *dest_doc, + char *src_name, + char *name, + char toc ); +void RB_RTF_Generate_Doc_End( + FILE *dest_doc, + char *name ); +void RB_RTF_Generate_Header_Start( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_RTF_Generate_Header_End( + FILE *dest_doc, + struct RB_header *cur_header ); +void RB_RTF_Generate_Empty_Item( + FILE *dest_doc ); +void RB_RTF_Generate_Link( + FILE *dest_doc, + char *dest_name, + char *filename, + char *labelname, + char *linkname ); +void RB_RTF_Generate_Char( + FILE *dest_doc, + int c ); +void RB_RTF_Generate_EndSection( + FILE *dest_doc, + int depth, + char *name ); +void RB_RTF_Generate_BeginSection( + FILE *dest_doc, + int depth, + char *name ); + +/* size_t RB_RTF_Get_Len_Extension(); */ +/* void RB_RTF_Add_Extension(char* name); */ +char *RB_RTF_Get_Default_Extension( + void ); +void RB_RTF_Generate_Item_Name( + FILE *dest_doc, + char *name ); + +void RB_RTF_Generate_Item_Begin( + FILE *dest_doc ); +void RB_RTF_Generate_Item_End( + FILE *dest_doc ); +void RB_RTF_Generate_Label( + FILE *dest_doc, + char *name ); +void RB_RTF_Generate_False_Link( + FILE *dest_doc, + char *name ); +void RB_RTF_Generate_String( + FILE *dest_doc, + char *a_string ); + +#endif /* ROBODOC_RTF_GENERATOR_H */ diff --git a/Source/t/ROBOTestFrame.pm b/Source/t/ROBOTestFrame.pm new file mode 100644 index 0000000..b06f6a7 --- /dev/null +++ b/Source/t/ROBOTestFrame.pm @@ -0,0 +1,298 @@ +# vi: ff=unix spell +#****h* ROBODoc/ROBOTestFrame +# FUNCTION +# A Perl module with a set of handy functions to create +# test scripts. +# +# These function are: +# * runrobo +# * add_source +# * add_configuration +# * clean +# * mkdocdir +# * is_latex_balanced +# * read_hexdump +# +#***** + +package ROBOTestFrame; +require Exporter; + @ISA = qw(Exporter); + @EXPORT = qw( + runrobo + add_source + add_configuration + clean mkdocdir + is_latex_balanced + read_hexdump + ); # symbols to export on request + +use strict; +use warnings; +# TODO Try to get this to work without IPC::Run +use IPC::Run 'run'; +use File::Path; +use File::Basename; +use IO::File; + +#****f* ROBOTestFrame/robo_win, robo_unix +# FUNCTION +# Location of the ROBODoc executable. +# SOURCE +# +my $robo_win = "../robodoc.exe"; +my $robo_unix = "../robodoc"; +#**** + +#****f* ROBOTestFrame/source_directory +# FUNCTION +# Name of the source directory used to test ROBODoc. +# SOURCE +# +my $source_directory = "Src"; +#***** + +#****f* ROBOTestFrame/documentation_directory +# FUNCTION +# Name of the documentation directory used to test ROBODoc. +# SOURCE +my $documentation_directory = "Doc"; +#***** + +#****f* ROBOTestFrame/configuration_directory +# FUNCTION +# Name of the documentation directory used to test ROBODoc. +# SOURCE +my $configuration_directory = "Config"; +#***** + +#****f* ROBOTestFrame/runrobo +# FUNCTION +# Run robodoc with the given set of +# arguments and capture all output to +# stdout en stderr. +# INPUTS +# A list of options for robodoc.exr +# RETURNS +# stdout and stderr. +# SOURCE +# +sub runrobo +{ + my $robo = ''; + if ( $^O eq 'linux' ) { + $robo = $robo_unix; + } else { + $robo = $robo_win; + } + run( [ $robo, @_ ], \my( $in, $out, $err ) ); + return ($out, $err); +} +#***** + + +#****f* ROBOTestFrame/add_configuration +# FUNCTION +# Add a configuration file somewhere in Config/ +# INPUTS +# - filepath -- path to a file. +# - configuration -- the content for this file +# - binary -- write the raw bytes. [optional] +# SOURCE +# +sub add_configuration +{ + my $filepath = shift; + my $configuration = shift; + my $binary = shift; + add_file( $configuration_directory, $filepath, $configuration, $binary ) +} + +#***** + +#****f* ROBOTestFrame/add_source +# FUNCTION +# Add a single source file somewhere in Src/ +# INPUTS +# - filepath -- path to a file. +# - source_code -- the source code to go into this file +# - binary -- write the raw bytes. [optional] +# SOURCE +# +sub add_source +{ + my $filepath = shift; + my $source_code = shift; + my $binary = shift; + + add_file( $source_directory, $filepath, $source_code, $binary ) +} + +#***** + +#****f* ROBOTestFrame/add_file +# FUNCTION +# Add a single file somewhere in base_path. +# INPUTS +# - base_path -- base path +# - filepath -- relative path to a file. +# - content -- the content to go into this file +# - binary -- write the raw bytes. [optional] +# SOURCE +# + +sub add_file +{ + my $base_path = shift; + my $filepath = shift; + my $content = shift; + my $binary = shift; + + my $path = $base_path . dirname( $filepath ); + + $path =~ s/\.$//; # Fix for Perl 5.8.0 under Linux. + + if ( ! -e "$path" ) { + mkpath $path or die "can't create $path"; + } + + my $full_filepath = "$base_path/$filepath"; + my $file = IO::File->new(">$full_filepath") or + die "Can't open $full_filepath"; + if ( $binary and ( $binary eq 'binary' ) ) { + binmode( $file ); + } + print $file $content; + $file->close(); +} +#***** + + +#****f* ROBOTestFrame/clean +# FUNCTION +# Clean source and documentation directories. +# SOURCE +# +sub clean +{ + if ( -e $source_directory ) { + rmtree( $source_directory ) or die; + } + if ( -e $documentation_directory ) { + rmtree( $documentation_directory ) or die; + } + if ( -e $configuration_directory ) { + rmtree( $configuration_directory ) or die; + } +} + +#***** + +#****f* ROBOTestFrame/mkdocdir +# FUNCTION +# Create a empty documentation directory. +# This is handy for tests that use --singledoc. +# SOURCE +sub mkdocdir +{ + if ( ! -e $documentation_directory ) { + mkpath( $documentation_directory ); + } +} + +#**** + +#****f* ROBOTestFrame/is_latex_balanced +# FUNCTION +# Test the balance of a latex file. +# A latex file is balanced if every +# /begin{xxxx} +# is ended with a +# /end{xxx} +# INPUTS +# * path - path to a latex file. +# RETURNS +# * 0 -- file is not balanced +# * 1 -- file is balanced +# SOURCE + +sub is_latex_balanced { + my $path = shift; + my @stack; + local( $/ ) ; + my $file = IO::File->new("<$path") or die "$path : $!"; + my $string = <$file>; + $file->close(); + + while ( $string =~ m/(begin|end)\{([^}]+)\}/g ) { + my $b_e = $1; # begin or end + my $kind = $2; # document, or equation, or ... + if ( $b_e eq "begin" ) { + push( @stack, $kind ); + } else { + if ( pop( @stack ) eq $kind ) { + # OK. begin and end matches. + } else { + # Not OK! + # begin{ something } + # followed by + # end{ something else } + return 0; # Failure. + } + + } + } + if ( scalar( @stack ) ) { + # there are items left! + return 0; # Not OK. + } + return 1; # OK! +} +#****** + + +#****f* ROBOTestFrame/read_hexdump +# FUNCTION +# Reads a hexdump made with xxd (part of vim http://www.vim.org/) +# This makes it possible to add files with all kinds of +# different formats and characters. +# +# Storing it in hexdump format makes sure that these files are +# not changed when they are checked into cvs or unzipped. +# +# This makes is possible to test cr/lf problems and internationalization +# issues. +# +# INPUTS +# * path - path to a hexdump file. +# RETURNS +# The decoded content of the file as a single string. +# SOURCE + +sub read_hexdump { + my $path = shift; + my $file = IO::File->new("<$path") or die "$path : $!"; + + my $string = ''; + my @all_bytes = (); + while ( my $line = <$file> ) { + $line =~ s/^\S+:\s//; # remove address + $line =~ s/\s\s+.*$//; # remove ascii + $line =~ s/(\S\S)(\S\S)/$1 $2/g; + # Now only the words are left. + my @data = split( /\s/, $line ); + my @bytes = map { chr hex } @data; + push( @all_bytes, @bytes ); + } + # TODO try a join() here. + foreach my $c ( @all_bytes ) { + $string .= $c; + } + + $file->close(); + return $string; +} + +#****** + +1; diff --git a/Source/t/Robodoc.pm b/Source/t/Robodoc.pm new file mode 100644 index 0000000..625027c --- /dev/null +++ b/Source/t/Robodoc.pm @@ -0,0 +1,3 @@ +0; +# OBSOLETE +# diff --git a/Source/t/TestData/iso8859-1_german_header_c.xxd b/Source/t/TestData/iso8859-1_german_header_c.xxd new file mode 100644 index 0000000..1030f9c --- /dev/null +++ b/Source/t/TestData/iso8859-1_german_header_c.xxd @@ -0,0 +1,35 @@ +0000000: 2a2a 2a2a 662a 2074 6573 742f 6973 6f38 ****f* test/iso8 +0000010: 3835 392d 310d 0a2a 2046 554e 4354 494f 859-1..* FUNCTIO +0000020: 4e0d 0a2a 2054 6869 7320 6973 2061 2074 N..* This is a t +0000030: 6573 7420 6f66 2049 534f 2d38 3835 392d est of ISO-8859- +0000040: 3120 696e 7075 743a 20e4 f6fc 20c4 d6dc 1 input: ... ... +0000050: 20df 20b2 b9b3 0d0a 2a0d 0a2a 2041 c420 . .....*..* A. +0000060: 313a 2041 2072 6567 756c 6172 206c 696e 1: A regular lin +0000070: 652c 206e 6f74 2061 2070 7265 666f 726d e, not a preform +0000080: 6174 7465 6420 6974 656d 2c20 636f 6e74 atted item, cont +0000090: 6169 6e69 6e67 2061 206e 6f6e 2d41 5343 aining a non-ASC +00000a0: 4949 2063 6861 720d 0a2a 0d0a 2a20 c441 II char..*..* .A +00000b0: 2032 3a20 4120 7072 6566 6f72 6d61 7474 2: A preformatt +00000c0: 6564 2069 7465 6d20 2862 7567 3f29 2c20 ed item (bug?), +00000d0: 7374 6172 7469 6e67 2077 6974 6820 6120 starting with a +00000e0: 6e6f 6e2d 4153 4349 4920 6368 6172 0d0a non-ASCII char.. +00000f0: 2a0d 0a2a 20dc 5520 333a 2041 2072 6567 *..* .U 3: A reg +0000100: 756c 6172 206c 696e 652c 2073 7461 7274 ular line, start +0000110: 696e 6720 7769 7468 2061 2064 6966 6665 ing with a diffe +0000120: 7265 6e74 206e 6f6e 2d41 5343 4949 2063 rent non-ASCII c +0000130: 6861 720d 0a2a 0d0a 2a20 5472 616e 736c har..*..* Transl +0000140: 6174 6520 7769 7468 3a0d 0a2a 2072 6f62 ate with:..* rob +0000150: 6f64 6f63 202d 2d73 7263 2069 736f 3838 odoc --src iso88 +0000160: 3539 2d31 2e74 7874 202d 2d64 6f63 2069 59-1.txt --doc i +0000170: 736f 3838 3539 2d31 646f 6320 2d2d 7369 so8859-1doc --si +0000180: 6e67 6c65 6669 6c65 202d 2d68 746d 6c20 nglefile --html +0000190: 2d2d 6e6f 7072 650d 0a2a 0d0a 2a20 c448 --nopre..*..* .H +00001a0: 4e4c 4943 4845 204d 4f44 454c 4c45 0d0a NLICHE MODELLE.. +00001b0: 2a20 4669 7273 7420 6368 6172 206f 6620 * First char of +00001c0: 7468 6973 2069 7465 6d20 6e61 6d65 2069 this item name i +00001d0: 7320 6d69 7373 696e 670d 0a2a 0d0a 2a20 s missing..*..* +00001e0: dc42 4552 5452 4147 4241 524b 4549 540d .BERTRAGBARKEIT. +00001f0: 0a2a 2041 6e6f 7468 6572 2069 7465 6d20 .* Another item +0000200: 6e61 6d65 2073 7461 7274 696e 6720 7769 name starting wi +0000210: 7468 206e 6f6e 2d41 5343 4949 0d0a 2a2a th non-ASCII..** +0000220: 2a2a 2a0d 0a0d 0a ***.... diff --git a/Source/t/TestData/iso8859-1_german_robodoc_rc.xxd b/Source/t/TestData/iso8859-1_german_robodoc_rc.xxd new file mode 100644 index 0000000..f790322 --- /dev/null +++ b/Source/t/TestData/iso8859-1_german_robodoc_rc.xxd @@ -0,0 +1,5 @@ +0000000: 6974 656d 733a 0d0a 2020 2020 4655 4e43 items:.. FUNC +0000010: 5449 4f4e 0d0a 2020 2020 c448 4e4c 4943 TION.. .HNLIC +0000020: 4845 204d 4f44 454c 4c45 0d0a 2020 2020 HE MODELLE.. +0000030: dc42 4552 5452 4147 4241 524b 4549 540d .BERTRAGBARKEIT. +0000040: 0a0d 0a ... diff --git a/Source/t/TestData/robodoc_unix_rc.xxd b/Source/t/TestData/robodoc_unix_rc.xxd new file mode 100644 index 0000000..8484991 --- /dev/null +++ b/Source/t/TestData/robodoc_unix_rc.xxd @@ -0,0 +1,4 @@ +0000000: 6974 656d 733a 0a20 2020 2054 4553 540a items:. TEST. +0000010: 2020 2020 464f 4f0a 2020 2020 4241 520a FOO. BAR. +0000020: 6974 656d 206f 7264 6572 3a0a 2020 2020 item order:. +0000030: 4241 520a 2020 2020 464f 4f0a BAR. FOO. diff --git a/Source/t/TestData/robodoc_windows_rc.xxd b/Source/t/TestData/robodoc_windows_rc.xxd new file mode 100644 index 0000000..23a1246 --- /dev/null +++ b/Source/t/TestData/robodoc_windows_rc.xxd @@ -0,0 +1,4 @@ +0000000: 6974 656d 733a 0d0a 2020 2020 4241 520d items:.. BAR. +0000010: 0a20 2020 2046 4f4f 0d0a 2020 2020 534e . FOO.. SN +0000020: 4146 550d 0a69 7465 6d20 6f72 6465 723a AFU..item order: +0000030: 0d0a 2020 2020 4241 520d 0a .. BAR.. diff --git a/Source/t/ascii.t b/Source/t/ascii.t new file mode 100644 index 0000000..a2c74d2 --- /dev/null +++ b/Source/t/ascii.t @@ -0,0 +1,118 @@ +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; +use Test::File; + +#****h* ROBODoc System Tests/ASCII Generator +# FUNCTION +# Test ROBODoc ASCII generator. +# +#**** + + +#****v* ASCII Generator/dummy_header_1 +# FUNCTION +# A dummy header to put into dummy source files. +# SOURCE +# + my $dummy_header_1 = <<'EOF'; +C ****f* Lib/Func +C NAME +C Func -- useless +C Computes the value: +C |latex \begin{equation} +C |latex x = 0 +C |latex \end{equation} +C app +C +C SYNOPSIS +C Func = Func (n) +C Computes the value: +C |latex \begin{equation} +C |latex x = 0 +C |latex \end{equation} +C BUGS +C Generates screwy TeX +C *** + real function Func(n) + Func = 0 + end function Func + +EOF + +#**** + + +#****v* ASCII Generator/dummy_header_2 +# FUNCTION +# A dummy header to put into dummy source files. +# SOURCE +# + my $dummy_header_2 = <<'EOF'; +C ****f* Lib/Func +C NAME +C Func -- useless +C SYNOPSIS +C Example: +C Foo foo foo +C foo +C +C Test paragraph. +C Do da diddi do da dom dom. +C +C BUGS +C A list test: +C * item 1 +C * item 2 +C * item 3 +C +C *** + real function Func(n) + Func = 0 + end function Func + +EOF + +#**** + + +#****x* ASCII Generator/smoke test +# FUNCTION +# Try different combination of options. +# This should not cause any asserts(). +# +# SOURCE +{ + my @sources = ( \$dummy_header_1, \$dummy_header_2 ); + + foreach my $source_ref ( @sources ) { + foreach my $mode_1 qw( --sections --toc --index --nopre ) { + foreach my $mode_2 qw( --singledoc --multidoc ) { + mkdocdir(); + add_source( "test.c", $$source_ref ); + my ( $out, $err ) = runrobo( + qw(--src Src + --doc Doc/test + --ascii + ), $mode_1, $mode_2 ); + # expected results: + is( $out, '', 'No ouput' ); + is( $err, '', '... and no error' ); + my $file_name; + # Docments names differ for the different + # modes. + if ( $mode_2 eq "--multidoc" ) { + $file_name = "Doc/test/test_c.txt"; + } else { + $file_name = "Doc/test.txt"; + } + file_exists_ok( $file_name, + 'there should be documentation' ); + clean(); + } + } + } +} +#**** + diff --git a/Source/t/basics.t b/Source/t/basics.t new file mode 100644 index 0000000..237cfe9 --- /dev/null +++ b/Source/t/basics.t @@ -0,0 +1,193 @@ +#!perl +# vi: spell ff=unix +#------------------------------------------------------------------------------ +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; +use Test::File; +use XML::Simple; + +#****h* ROBODoc System Tests/Basics +# FUNCTION +# Tests basic ROBODoc funcionallity. These are all +# 'happy paths'. +# +#**** + +#****v* Basics/Dummy Headers +# FUNCTION +# A dummy header to put into dummy source files. +# SOURCE +# +my $source = <<'EOF'; +/****f* Test/test + * NAME + * Test + ****** + */ +EOF +#***** + +#****x* Basics/Option version +# FUNCTION +# Test robodoc --version, this should report the current version. +# SOURCE +{ + my ( $out, $err ) = runrobo('--version'); + like( $out, qr/\d+\.\d+.\d+/, '--version should print version number' ); + is( $err, '', '... and no error' ); +} +#**** + +#****x* Basics/Option help +# FUNCTION +# Test the option --help. +# SOURCE +{ + my ( $out, $err ) = runrobo('--help'); + like( $out, qr/ROBODoc Version/, '--help should print version number' ); + is( $err, '', '... and no error' ); +} +#**** + + +#****x* Basics/Option multidoc +# FUNCTION +# Test --multidoc for html output format. +# (Multidoc for other modes does not make much sense). +# We create one source file with a simple header and create multidoc +# SOURCE +{ + add_source( "test.c", $source ); + my ( $out, $err ) = runrobo(qw(--src Src --doc Doc --multidoc --html)); + # expected results: + is( $out, '', 'No ouput' ); + is( $err, '', '... and no error' ); + file_exists_ok( "Doc/test_c.html", 'there should be documentation' ); + file_exists_ok( "Doc/robodoc.css", 'and a stylesheet' ); + + clean(); +} +#**** + + +# TODO FS +# test --multidoc for --troff +# + +# TODO FS +# test --css +# + +#****x* Basics/Singledoc Outputmode with Different Formats +# FUNCTION +# Test singledoc mode for all supported output formats +# and see if it creates output in this format. +# +# SOURCE + +{ + add_source( "test.c", $source ); + + my %output_modes = ( + '--html' => 'html', + '--rtf' => 'rtf', + '--test' => 'xml', + '--latex' => 'tex', + '--dbxml' => 'xml', + ); + + foreach my $mode ( keys %output_modes ) { + my $file_extension = $output_modes{$mode}; + + my @arguments = qw(--src Src --doc testdoc --singledoc); + push( @arguments, $mode ); + + my ( $out, $err ) = runrobo(@arguments); + is( $out, '', 'No ouput' ); + is( $err, '', '... and no error' ); + file_exists_ok( "testdoc.$file_extension", + 'there should be documentation' ); + if ( $mode eq "--html" ) { + file_exists_ok( "testdoc.css", 'and a stylesheet' ); + } + + unlink("testdoc.$file_extension") if -e "testdoc.$file_extension"; + unlink('testdoc.css') if -e 'testdoc.css'; + + } + + clean(); +} + +#**** + +#****v* Basics/test_source_2 +# FUNCTION +# A dummy header to put into dummy source files. +# This one has headers at several levels. +# SOURCE +# +my $test_source_2 = <<'EOF'; +/****f* Level_1/Level_2 + * NAME + * Test + ****** + */ + +/****f* Level_2/_Level_3 + * NAME + * Test + ****** + */ + +/****f* Level_3/_Level_4 + * NAME + * Test + ****** + */ + +EOF +#***** + + +#****x* Basics/Option first section level +# FUNCTION +# Test --first_section_level. +# +# The level of the first section should be +# at level 3 instead of 1. +# +# SOURCE +{ + add_source( "test.c", $test_source_2 ); + mkdocdir(); + my ( $out, $err ) = runrobo( + qw(--src Src + --doc Doc/test + --singledoc + --sections + --test + --toc + --first_section_level 3)); + # expected results: + is( $out, '', 'No ouput' ); + is( $err, '', '... and no error' ); + file_exists_ok( "Doc/test.xml", 'there should be documentation' ); + + # Now test the level of the first header. + my $documentation = XMLin( 'Doc/test.xml' ); + my $section = $documentation->{'section'}; + is ( $section->[0]->{'depth'}, '3', 'First section is at level 3' ); + my $subsection = $section->[0]->{'section'}; + is ( $subsection->{'depth'}, '4', 'First subsection is at level 4' ); + is ( $section->[1]->{'depth'}, '3', 'Second section is at level 3' ); + + clean(); +} +#**** + + +1; + diff --git a/Source/t/encoding.t b/Source/t/encoding.t new file mode 100644 index 0000000..1d803e6 --- /dev/null +++ b/Source/t/encoding.t @@ -0,0 +1,52 @@ +#!/usr/bin/perl -w +# vi: ff=unix spell + +#****h* ROBODoc System Tests/Encoding +# FUNCTION +# Test decoding en encoding of non 7bit ASCII characters. +#***** + +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; +use Test::File; +use XML::Simple; +use Data::Dumper; + +# +# This tests a header with item names that start with +# an letter with an umlaut. +# ROBODoc currently has some problems with this. +# + +{ + my $source = read_hexdump( 'TestData/iso8859-1_german_header_c.xxd' ); + my $config = read_hexdump( 'TestData/iso8859-1_german_robodoc_rc.xxd' ); + + add_source( "test.c", $source, 'binary' ); + add_configuration( "test.rc", $config, 'binary' ); + mkdocdir(); + my ( $out, $err ) = runrobo(qw( + --src Src + --doc Doc/test + --rc Config/test.rc + --singledoc --test --nopre )); + # expected results: + is( $out, '', 'No ouput' ); + is( $err, '', '... and no error' ); + file_exists_ok( "Doc/test.xml", 'there should be documentation' ); + + my $documentation = XMLin( 'Doc/test.xml' ); + my $header = $documentation->{'header'}; +# is ( $header->{'name'}, 'Test Foo Bar/Name With Spaces', 'Header name' ); + my $items = $header->{'item'}; + print Dumper( $items ); + my $body = $items->{'FUNCTION'}->{'item_body'}; + + # TODO currently a bug in robodoc. + is( $body->{'pre'}, undef, 'No preformatted stuff in the body' ); + clean(); +} + + diff --git a/Source/t/errors.t b/Source/t/errors.t new file mode 100644 index 0000000..80caf34 --- /dev/null +++ b/Source/t/errors.t @@ -0,0 +1,224 @@ +#!perl + +#****h* ROBODoc System Tests/Handling Errors +# FUNCTION +# Test wether calling ROBODoc with wrong options or input leads +# to the correct error messages. +#***** + +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; + +# A dummy header to put into dummy source files. +# +my $source = <<'EOF'; +/****f* Test/test + * NAME + * Test + ****** + */ +EOF + +#****x* Handling Errors/Error on Non-existing Option +# FUNCTION +# ROBODoc should complain about non-existing options. +# SOURCE +# +{ + my ($out, $err) = runrobo( '--foobar' ); + like($out, qr/Usage/, 'Unknown option should print usage' ); + like($err, qr/Invalid/, 'and an error message' ); +} +#***** + + +#****x* Handling Errors/Error on Mutual Excluding Options +# FUNCTION +# ROBODoc should complain about options that can not be used +# together. +# SOURCE +# +{ + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --singledoc --html) ); + like($out, qr/Usage/, 'Mutual excluding options should print usage' ); + print $err; + like($err, qr/together/, 'and an error message' ); + clean(); +} +#***** + +#****x* Handling Errors/Error on Mutual Excluding Options II +# FUNCTION +# ROBODoc should complain about options that can not be used +# together. +# SOURCE +# +{ + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --test --dbxml --html) ); + like($out, qr/Usage/, 'Mutual excluding options should print usage' ); + print $err; + like($err, qr/together/, 'and an error message' ); + clean(); +} +#***** + +#****x* Handling Errors/Error on Duplicate Options +# FUNCTION +# ROBODoc should complain about options that are specifed more +# than once. +# SOURCE +# +{ + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw( --src Src --doc Doc --multidoc --test --test --test) ); + print $out; + like($out, qr/Usage/, 'Duplicate options should print usage' ); + print $err; + like($err, qr/than\sonce/, 'and an error message' ); + clean(); +} +#***** + +#****x* Handling Errors/Error on Non-existing rc file +# FUNCTION +# When given a non-existing .rc file, ROBODc should +# at least report the name of the .rc file. +# SOURCE +{ + my ($out, $err) = runrobo( '--rc foobar.rc' ); + like($err, qr/foobar/, 'should give an error message about foorbar.rc' ); +} +#***** + +#****x* Handling Errors/Impossible output file +# FUNCTION +# When given a impossible output filename ROBODoc should +# at least report the filename. +# SOURCE +{ + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Foo/Bar/document --singledoc --html) ); + like($err, qr/document/, 'should give an error message about document' ); +} + +#***** + +#****x* Handling Errors/Non-existing css file +# FUNCTION +# When given a impossible css filename ROBODoc should +# at least report the filename. +# SOURCE +{ + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --html --css Foo/Bar/cascade.css) ); + like($err, qr/cascade/, 'should give an error message about css file' ); +} + +#***** + + + +#****x* Handling Errors/Header without end marker +# FUNCTION +# Test ROBODoc's response on a header without an +# end marker. ROBODoc should detect this. +# SOURCE +# + +{ + my $source = <<'EOF'; +/****f* Test/test + * NAME + * Test + * FUNCTION + * Test2 + * SOURCE + */ + +some source + +and no end of the header .... + +EOF + + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --test) ); + is( $out, '', 'no output' ); + like( $err, qr/end\smarker/, 'error about end marker' ); + clean(); +} + +#**** + +#****x* Handling Errors/Headers with duplicate names +# FUNCTION +# Test ROBODoc's response to a file with two headers that +# have the same name. This should be reported as an error. +# SOURCE + +{ + my $source = <<'EOF'; +/****f* Test/test + * NAME + * Test + * FUNCTION + * Test2 + ***** + */ + +/****f* Test/test + * NAME + * Test + * FUNCTION + * Test2 + ***** + */ + +EOF + + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --test) ); + is( $out, '', 'no output' ); + like( $err, qr/already\sexists/, 'error duplicate header' ); + clean(); +} + +#***** + +{ + my $source = <<'EOF'; +/****f* Test/test + * FOO + * test + ******/ +EOF + + my $rc_file = <<'EOF'; +items: + FOO + BAR + SNAFU +item order: + FOO + BARRRRRR + SNAFU +EOF + + add_configuration( "robodoc.rc", $rc_file ); + add_source( "test.c", $source ); + mkdocdir(); + + my ($out, $err) = runrobo( qw( + --src Src + --doc Doc + --multidoc + --rc Config/robodoc.rc --test) ); + is( $out, '', 'no output' ); + like( $err, qr/item/, 'An unknown item is reported' ); + + clean(); +} diff --git a/Source/t/headers.t b/Source/t/headers.t new file mode 100644 index 0000000..958877f --- /dev/null +++ b/Source/t/headers.t @@ -0,0 +1,278 @@ +#!perl +# vi: spell ff=unix +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; +use XML::Simple; + +#****h* ROBODoc System Tests/Header Test +# FUNCTION +# Tests the parsing of ROBODoc headers. +# +#***** + +#****x* Header Test/Happy Path +# FUNCTION +# Happy Path Simple plain header. This definitely should work +# SOURCE +# +{ + my $source = <<'EOF'; +/****f* Test/test + * NAME + * Test + * FUNCTION + * Test2 + ****** + */ +EOF + + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --test) ); + is( $out, '', 'no output' ); + is( $err, '', 'and no error' ); + clean(); +} +#******* + + +#****x* Header Test/Names with Spaces +# FUNCTION +# Try a header name with spaces and some '*' at +# the end. The '*' should be ignored. +# SOURCE +{ + my $source = <<'EOF'; +/****f* Test Foo Bar/Name With Spaces **** + * NAME + * Test + * FUNCTION + * Test2 + ****** + */ +EOF + + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --test) ); + is( $out, '', 'no output' ); + is( $err, '', 'and no error' ); + my $documentation = XMLin( 'Doc/test_c.xml' ); + my $header = $documentation->{'header'}; + is ( $header->{'name'}, 'Test Foo Bar/Name With Spaces', 'Header name' ); + + clean(); +} + +#***** + +#****x* Header Test/Multiple Names with Spaces +# FUNCTION +# Try several header with names that contain spaces. +# These should be accepted. +# SOURCE +{ + my $source = <<'EOF'; +/****f* Test Foo Bar/Name With Spaces, And Anotherone, + * And One More, More + * NAME + * Test + * FUNCTION + * Test2 + ****** + */ +EOF + + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --multidoc --test) ); + is( $out, '', 'no output' ); + is( $err, '', 'and no error' ); + my $documentation = XMLin( 'Doc/test_c.xml' ); + my $header = $documentation->{'header'}; + is ( $header->{'name'}, 'Test Foo Bar/Name With Spaces', 'Header name' ); + + clean(); +} + +#***** + +#****x* Header Test/Broken header +# FUNCTION +# Try several header with names that contain spaces. +# These should be accepted. +# SOURCE +{ + my $source = <<'EOF'; +{****f* xxxxxx/x_xxx_xxxxxxxxxxxxxxxxxxxxxxxx +* +*OMSCHRIJVING +*xxxx xxxxxxx xxxxxxxxx xxxxxxxxxx xxxxxxx xxxxxxxxxxxx xx xx +xxxxxxxxxxxxxxx +*xxxxxxxxx x_xxx_xxxxxxxxxxxxxxxxxx xxxxxxx +* +*INVOER +*xxxxxxx : xxx xxxxxxx xxxx xxxxxx xxxxxxxxx xxxxxxxxxxxx xxxxx xx xxx +xx +* xxxxxxxxx xxxxxxxxx xxxxx xxxxxxxxxxxx. +*xxxxxxxxxxx : xxx xxxxxxxxx xxxxx xxxxx xxx xx xxxxx xxxxxx xx xxxxxxxxxx +* xxxxxxxxx xxxxxxxx xx +*RETURNWAARDE +*xxxx__xxxxxxx, x_xxx_xxxxxxxxx, xxxx__xxxxxxxx, x_xxx_xxxxxxxx, +*x_xxx_xxxxxxxxx, x_xxx_xxxxxxxxxxxxxx xx x_xxxx_xxxxxx_xxx +xxxxxx xxxxx. +* +*VOORBEELD +*x_xxx_xxxxxxxxxxxxxxxxxxxxxxxx (xxxxxxx := 5000, +* xxxxxxxxxxx := xx_xxxxxxxxxxx); +*DECLARATIE +*} + +{*****} +EOF + + + my $config = <<'EOF'; +items: + OMSCHRIJVING + WIJZIGINGSOVERZICHT + DECLARATIE + INVOER + UITVOER + IN-UITVOER + PARAMETERS + BOUNDARIES + RETURNWAARDE + ATTRIBUTEN + GEBRUIKTE GEGEVENS + VOORBEELD + ZIE VERDER + OPMERKINGEN + PRECONDITIE + POSTCONDITIE + +item order: + OMSCHRIJVING + DECLARATIE + +source items: + DECLARATIE + SOURCE + +preformatted items: + WIJZIGINGSOVERZICHT + INVOER + UITVOER + IN-UITVOER + PARAMETERS + RETURNWAARDE + ATTRIBUTEN + VOORBEELD + +headertypes: + h "Modules" vptlib_modules + f "Functies" vptlib_functies + v "Variabelen" vptlib_variabelen + s "Structuren" vptlib_structuren + e "Enumeraties" vptlib_enumeraties + c "Constanten" vptlib_constanten + u "Unittesten" vptlib_unittesten + t "Typedefinities" vptlib_typedefs + m "Macros" vptlib_macros + d "Definities" vptlib_definities + +options: + --documenttitle "Xxxxxxxxxxxxxxxxxxx" + --tabsize 8 + --index + --sections + --sectionnameonly + --nopre + --multidoc + +header markers: + /**** + #**** + !**** + {**** + +remark markers: + * + # + ! + +end markers: + **** + #**** + !**** + {**** + +remark begin markers: + /* + {* + +remark end markers: + */ + *} + +source line comments: + // + ! + * +EOF + + add_source( "test.c", $source ); + add_configuration( "test.rc", $config ); + my ($out, $err) = runrobo( qw(--src Src --doc Doc --rc Config/test.rc --test) ); + is( $out, '', 'no output' ); + is( $err, '', 'and no error' ); + + clean(); +} + +#***** + + + +#****x* Header Test/Circular header +# FUNCTION +# The 3rd header points to the first header, +# completing a circle. ROBODoc should complain +# about this. +# +# SOURCE +TODO: { + local $TODO = "checking circular headers is not implemented yet."; + my $source = <<'EOF'; + +/****f* Foo/Bar +* NAME +* Bar +****/ + +/****f* Bar/Fii + * NAME + * Foo + *****/ + +/****f* Fii/Bar + * NAME + * Foo + *****/ +EOF + + add_source( "test.c", $source ); + my ($out, $err) = runrobo( qw( + --src Src + --doc Doc + --multidoc + --html + --toc + --sections + ) ); + # ROBODoc should complain about circular + # headers. + isnt( $err, '', 'there should be an error' ); +# clean(); +} + +#***** diff --git a/Source/t/items.t b/Source/t/items.t new file mode 100644 index 0000000..6dd3e8d --- /dev/null +++ b/Source/t/items.t @@ -0,0 +1,107 @@ +#!perl +# vi: spell ff=unix +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; + +#****h* ROBODoc System Tests/Item Test +# FUNCTION +# Tests the parsing generation of ROBODoc items. +# +#***** + +#****x* Item Test/Sorting +# FUNCTION +# Lets see if we can get items sorted according +# to the order specified in a robodoc.rc file. +# +# SOURCE +# +{ + my $source = <<'EOF'; +/****f* Test/test + * FIRST + * Test 1 + * Second + * Test 2 + * THIRD + * Test 3 + * SOURCE + */ + + Test 4 + + /*******/ +EOF + + my $config = <<'EOF'; +items: + FIRST + Second + THIRD + FOURTH +item order: + SOURCE + THIRD +EOF + + my $config_no_sort = <<'EOF'; +items: + FIRST + Second + THIRD + FOURTH +EOF + + add_source( "test.c", $source ); + add_configuration( "robodoc.rc", $config ); + my ($out, $err) = runrobo( qw( + --src Src + --doc Doc --multidoc --ascii + --rc Config/robodoc.rc + ) ); + is( $out, '', 'no output' ); + is( $err, '', 'and no error' ); + my $documentation = IO::File->new( " ) { + if ( $line =~ m/(SOURCE|THIRD|Second|FIRST)/ ) { + push( @items, $1 ); + } + } + is( $items[ 0 ], 'SOURCE', 'First item it the source item' ); + is( $items[ 1 ], 'THIRD', 'Second item it the third item' ); + is( $items[ 2 ], 'FIRST', 'Third item it the first item' ); + $documentation->close(); + + # Now the same but without sorting + add_configuration( "robodoc.rc", $config_no_sort ); + my ($out2, $err2) = runrobo( qw( + --src Src + --doc Doc --multidoc --ascii + --rc Config/robodoc.rc + ) ); + is( $out2, '', 'no output' ); + is( $err2, '', 'and no error' ); + + $documentation = IO::File->new( " ) { + if ( $line =~ m/(SOURCE|THIRD|Second|FIRST)/ ) { + push( @items, $1 ); + } + } + is( $items[ 0 ], 'FIRST', 'First item it the first item' ); + is( $items[ 1 ], 'Second', 'Second item it the second item' ); + is( $items[ 2 ], 'THIRD', 'Third item it the third item' ); + is( $items[ 3 ], 'SOURCE', 'Fourth item it the fourth' ); + $documentation->close(); + + clean(); +} +#******* + + diff --git a/Source/t/latex.t b/Source/t/latex.t new file mode 100644 index 0000000..71c04c3 --- /dev/null +++ b/Source/t/latex.t @@ -0,0 +1,117 @@ +use strict; +use warnings; +use ROBOTestFrame; +use Test::More 'no_plan'; +use Test::File; + +#****h* ROBODoc System Tests/LaTeX Generator +# FUNCTION +# Test ROBODoc LaTeX generator. +# +#**** + + +#****v* LaTeX Generator/dummy_header_1 +# FUNCTION +# A dummy header to put into dummy source files. +# SOURCE +# + my $dummy_header_1 = <<'EOF'; +C ****f* Lib/Func +C NAME +C Func -- useless +C Computes the value: +C |latex \begin{equation} +C |latex x = 0 +C |latex \end{equation} +C app +C +C SYNOPSIS +C Func = Func (n) +C Computes the value: +C |latex \begin{equation} +C |latex x = 0 +C |latex \end{equation} +C BUGS +C Generates screwy TeX +C *** + real function Func(n) + Func = 0 + end function Func + +EOF + +#**** + + +#****v* LaTeX Generator/dummy_header_2 +# FUNCTION +# A dummy header to put into dummy source files. +# SOURCE +# + my $dummy_header_2 = <<'EOF'; +C ****f* Lib/Func +C NAME +C Func -- useless +C SYNOPSIS +C Example: +C Foo foo foo +C foo +C +C Test paragraph. +C Do da diddi do da dom dom. +C +C BUGS +C A list test: +C * item 1 +C * item 2 +C * item 3 +C +C *** + real function Func(n) + Func = 0 + end function Func + +EOF + +#**** + + +#****x* LaTeX Generator/latex is balanced +# FUNCTION +# This function tests whether a generated latex file is balanced +# or not. That is every +# /begin{xxx} +# should end with a +# /end{xxx} +# at the same level. +# +# This is tested with several headers and in different modes. +# +# SOURCE +{ + my @sources = ( \$dummy_header_1, \$dummy_header_2 ); + + foreach my $source_ref ( @sources ) { + foreach my $mode_1 qw( --sections --toc --index ) { + foreach my $mode_2 qw( --nopre --altlatex ) { + mkdocdir(); + add_source( "test.c", $$source_ref ); + my ( $out, $err ) = runrobo( + qw(--src Src + --doc Doc/test + --singledoc + --latex + ), $mode_1, $mode_2 ); + # expected results: + is( $out, '', 'No ouput' ); + is( $err, '', '... and no error' ); + file_exists_ok( "Doc/test.tex", 'there should be documentation' ); + is( is_latex_balanced( "Doc/test.tex" ), 1, 'latex is balanced' ); + clean(); + } + } + } +} +#**** + diff --git a/Source/t/lib/IPC/Run.pm b/Source/t/lib/IPC/Run.pm new file mode 100644 index 0000000..61ca9c2 --- /dev/null +++ b/Source/t/lib/IPC/Run.pm @@ -0,0 +1,4476 @@ +package IPC::Run ; +# +# Copyright (c) 1999 by Barrie Slaymaker, barries@slaysys.com +# +# You may distribute under the terms of either the GNU General Public +# License or the Artistic License, as specified in the README file. +# + +$VERSION = "0.80"; + +=head1 NAME + +IPC::Run - system() and background procs w/ piping, redirs, ptys (Unix, Win32) + +=head1 SYNOPSIS + + ## First,a command to run: + my @cat = qw( cat ) ; + + ## Using run() instead of system(): + use IPC::Run qw( run timeout ) ; + + run \@cmd, \$in, \$out, \$err, timeout( 10 ) or die "cat: $?" + + # Can do I/O to sub refs and filenames, too: + run \@cmd, '<', "in.txt", \&out, \&err or die "cat: $?" + run \@cat, '<', "in.txt", '>>', "out.txt", '2>>', "err.txt" ; + + + # Redirecting using psuedo-terminals instad of pipes. + run \@cat, 'pty>', \$out_and_err ; + + ## Scripting subprocesses (like Expect): + + use IPC::Run qw( start pump finish timeout ) ; + + # Incrementally read from / write to scalars. + # $in is drained as it is fed to cat's stdin, + # $out accumulates cat's stdout + # $err accumulates cat's stderr + # $h is for "harness". + my $h = start \@cat, \$in, \$out, \$err, timeout( 10 ) ; + + $in .= "some input\n" ; + pump $h until $out =~ /input\n/g ; + + $in .= "some more input\n" ; + pump $h until $out =~ /\G.*more input\n/ ; + + $in .= "some final input\n" ; + finish $h or die "cat returned $?" ; + + warn $err if $err ; + print $out ; ## All of cat's output + + # Piping between children + run \@cat, '|', \@gzip ; + + # Multiple children simultaneously (run() blocks until all + # children exit, use start() for background execution): + run \@foo1, '&', \@foo2 ; + + # Calling \&set_up_child in the child before it executes the + # command (only works on systems with true fork() & exec()) + # exceptions thrown in set_up_child() will be propagated back + # to the parent and thrown from run(). + run \@cat, \$in, \$out, + init => \&set_up_child ; + + # Read from / write to file handles you open and close + open IN, 'out.txt' or die $! ; + print OUT "preamble\n" ; + run \@cat, \*IN, \*OUT or die "cat returned $?" ; + print OUT "postamble\n" ; + close IN ; + close OUT ; + + # Create pipes for you to read / write (like IPC::Open2 & 3). + $h = start + \@cat, + 'pipe', \*OUT, + '2>pipe', \*ERR + or die "cat returned $?" ; + print IN "some input\n" ; + close IN ; + print , ; + finish $h ; + + # Mixing input and output modes + run \@cat, 'in.txt', \&catch_some_out, \*ERR_LOG ) ; + + # Other redirection constructs + run \@cat, '>&', \$out_and_err ; + run \@cat, '2>&1' ; + run \@cat, '0<&3' ; + run \@cat, '<&-' ; + run \@cat, '3<', \$in3 ; + run \@cat, '4>', \$out4 ; + # etc. + + # Passing options: + run \@cat, 'in.txt', debug => 1 ; + + # Call this system's shell, returns TRUE on 0 exit code + # THIS IS THE OPPOSITE SENSE OF system()'s RETURN VALUE + run "cat a b c" or die "cat returned $?" ; + + # Launch a sub process directly, no shell. Can't do redirection + # with this form, it's here to behave like system() with an + # inverted result. + $r = run "cat a b c" ; + + # Read from a file in to a scalar + run io( "filename", 'r', \$recv ) ; + run io( \*HANDLE, 'r', \$recv ) ; + +=head1 DESCRIPTION + +IPC::Run allows you run and interact with child processes using files, pipes, +and pseudo-ttys. Both system()-style and scripted usages are supported and +may be mixed. Likewise, functional and OO API styles are both supported and +may be mixed. + +Various redirection operators reminiscent of those seen on common Unix and DOS +command lines are provided. + +Before digging in to the details a few LIMITATIONS are important enough +to be mentioned right up front: + +=over + +=item Win32 Support + +Win32 support is working but B, but does pass all relevant tests +on NT 4.0. See L. + +=item pty Support + +If you need pty support, IPC::Run should work well enough most of the +time, but IO::Pty is being improved, and IPC::Run will be improved to +use IO::Pty's new features when it is release. + +The basic problem is that the pty needs to initialize itself before the +parent writes to the master pty, or the data written gets lost. So +IPC::Run does a sleep(1) in the parent after forking to (hopefully) give +the child a chance to run. This is a kludge that works well on non +heavily loaded systems :(. + +ptys are not supported yet under Win32, but will be emulated... + +=item Debugging Tip + +You may use the environment variable C to see what's going on +under the hood: + + $ IPCRUNDEBUG=basic myscript # prints minimal debugging + $ IPCRUNDEBUG=data myscript # prints all data reads/writes + $ IPCRUNDEBUG=details myscript # prints lots of low-level details + $ IPCRUNDEBUG=gory myscript # (Win32 only) prints data moving through + # the helper processes. + +=back + +We now return you to your regularly scheduled documentation. + +=head2 Harnesses + +Child processes and I/O handles are gathered in to a harness, then +started and run until the processing is finished or aborted. + +=head2 run() vs. start(); pump(); finish(); + +There are two modes you can run harnesses in: run() functions as an +enhanced system(), and start()/pump()/finish() allow for background +processes and scripted interactions with them. + +When using run(), all data to be sent to the harness is set up in +advance (though one can feed subprocesses input from subroutine refs to +get around this limitation). The harness is run and all output is +collected from it, then any child processes are waited for: + + run \@cmd, \< and C<$err> in our examples. + +Regular expressions can be used to wait for appropriate output in +several ways. The C example in the previous section demonstrates +how to pump() until some string appears in the output. Here's an +example that uses C to fetch files from a remote server: + + $h = harness \@smbclient, \$in, \$out ; + + $in = "cd /src\n" ; + $h->pump until $out =~ /^smb.*> \Z/m ; + die "error cding to /src:\n$out" if $out =~ "ERR" ; + $out = '' ; + + $in = "mget *\n" ; + $h->pump until $out =~ /^smb.*> \Z/m ; + die "error retrieving files:\n$out" if $out =~ "ERR" ; + + $in = "quit\n" ; + $h->finish ; + +Notice that we carefully clear $out after the first command/response +cycle? That's because IPC::Run does not delete $out when we continue, +and we don't want to trip over the old output in the second +command/response cycle. + +Say you want to accumulate all the output in $out and analyze it +afterwards. Perl offers incremental regular expression matching using +the C and pattern matching idiom and the C<\G> assertion. +IPC::Run is careful not to disturb the current C value for +scalars it appends data to, so we could modify the above so as not to +destroy $out by adding a couple of C modifiers. The C keeps us +from tripping over the previous prompt and the C keeps us from +resetting the prior match position if the expected prompt doesn't +materialize immediately: + + $h = harness \@smbclient, \$in, \$out ; + + $in = "cd /src\n" ; + $h->pump until $out =~ /^smb.*> \Z/mgc ; + die "error cding to /src:\n$out" if $out =~ "ERR" ; + + $in = "mget *\n" ; + $h->pump until $out =~ /^smb.*> \Z/mgc ; + die "error retrieving files:\n$out" if $out =~ "ERR" ; + + $in = "quit\n" ; + $h->finish ; + + analyze( $out ) ; + +When using this technique, you may want to preallocate $out to have +plenty of memory or you may find that the act of growing $out each time +new input arrives causes an C slowdown as $out grows. +Say we expect no more than 10,000 characters of input at the most. To +preallocate memory to $out, do something like: + + my $out = "x" x 10_000 ; + $out = "" ; + +C will allocate at least 10,000 characters' worth of space, then +mark the $out as having 0 length without freeing all that yummy RAM. + +=head2 Timeouts and Timers + +More than likely, you don't want your subprocesses to run forever, and +sometimes it's nice to know that they're going a little slowly. +Timeouts throw exceptions after a some time has elapsed, timers merely +cause pump() to return after some time has elapsed. Neither is +reset/restarted automatically. + +Timeout objects are created by calling timeout( $interval ) and passing +the result to run(), start() or harness(). The timeout period starts +ticking just after all the child processes have been fork()ed or +spawn()ed, and are polled for expiration in run(), pump() and finish(). +If/when they expire, an exception is thrown. This is typically useful +to keep a subprocess from taking too long. + +If a timeout occurs in run(), all child processes will be terminated and +all file/pipe/ptty descriptors opened by run() will be closed. File +descriptors opened by the parent process and passed in to run() are not +closed in this event. + +If a timeout occurs in pump(), pump_nb(), or finish(), it's up to you to +decide whether to kill_kill() all the children or to implement some more +graceful fallback. No I/O will be closed in pump(), pump_nb() or +finish() by such an exception (though I/O is often closed down in those +routines during the natural course of events). + +Often an exception is too harsh. timer( $interval ) creates timer +objects that merely prevent pump() from blocking forever. This can be +useful for detecting stalled I/O or printing a soothing message or "." +to pacify an anxious user. + +Timeouts and timers can both be restarted at any time using the timer's +start() method (this is not the start() that launches subprocesses). To +restart a timer, you need to keep a reference to the timer: + + ## Start with a nice long timeout to let smbclient connect. If + ## pump or finish take too long, an exception will be thrown. + + my $h ; + eval { + $h = harness \@smbclient, \$in, \$out, \$err, ( my $t = timeout 30 ) ; + sleep 11 ; # No effect: timer not running yet + + start $h ; + $in = "cd /src\n" ; + pump $h until ! length $in ; + + $in = "ls\n" ; + ## Now use a short timeout, since this should be faster + $t->start( 5 ) ; + pump $h until ! length $in ; + + $t->start( 10 ) ; ## Give smbclient a little while to shut down. + $h->finish ; + } ; + if ( $@ ) { + my $x = $@ ; ## Preserve $@ in case another exception occurs + $h->kill_kill ; ## kill it gently, then brutally if need be, or just + ## brutally on Win32. + die $x ; + } + +Timeouts and timers are I checked once the subprocesses are shut +down; they will not expire in the interval between the last valid +process and when IPC::Run scoops up the processes' result codes, for +instance. + +=head2 Spawning synchronization, child exception propagation + +start() pauses the parent until the child executes the command or CODE +reference and propagates any exceptions thrown (including exec() +failure) back to the parent. This has several pleasant effects: any +exceptions thrown in the child, including exec() failure, come flying +out of start() or run() as though they had ocurred in the parent. + +This includes exceptions your code thrown from init subs. In this +example: + + eval { + run \@cmd, init => sub { die "blast it! foiled again!" } ; + } ; + print $@ ; + +the exception "blast it! foiled again" will be thrown from the child +process (preventing the exec()) and printed by the parent. + +In situations like + + run \@cmd1, "|", \@cmd2, "|", \@cmd3 ; + +@cmd1 will be initted and exec()ed before @cmd2, and @cmd2 before @cmd3. +This can save time and prevent oddball errors emitted by later commands +when earlier commands fail to execute. Note that IPC::Run doesn't start +any commands unless it can find the executables referenced by all +commands. These executables must pass both the C<-f> and C<-x> tests +described in L. + +Another nice effect is that init() subs can take their time doing things +and there will be no problems caused by a parent continuing to execute +before a child's init() routine is complete. Say the init() routine +needs to open a socket or a temp file that the parent wants to connect +to; without this synchronization, the parent will need to implement a +retry loop to wait for the child to run, since often, the parent gets a +lot of things done before the child's first timeslice is allocated. + +This is also quite necessary for pseudo-tty initialization, which needs +to take place before the parent writes to the child via pty. Writes +that occur before the pty is set up can get lost. + +A final, minor, nicety is that debugging output from the child will be +emitted before the parent continues on, making for much clearer debugging +output in complex situations. + +The only drawback I can conceive of is that the parent can't continue to +operate while the child is being initted. If this ever becomes a +problem in the field, we can implement an option to avoid this behavior, +but I don't expect it to. + +B: executing CODE references isn't supported on Win32, see +L for details. + +=head2 Syntax + +run(), start(), and harness() can all take a harness specification +as input. A harness specification is either a single string to be passed +to the systems' shell: + + run "echo 'hi there'" ; + +or a list of commands, io operations, and/or timers/timeouts to execute. +Consecutive commands must be separated by a pipe operator '|' or an '&'. +External commands are passed in as array references, and, on systems +supporting fork(), Perl code may be passed in as subs: + + run \@cmd ; + run \@cmd1, '|', \@cmd2 ; + run \@cmd1, '&', \@cmd2 ; + run \&sub1 ; + run \&sub1, '|', \&sub2 ; + run \&sub1, '&', \&sub2 ; + +'|' pipes the stdout of \@cmd1 the stdin of \@cmd2, just like a +shell pipe. '&' does not. Child processes to the right of a '&' +will have their stdin closed unless it's redirected-to. + +L objects may be passed in as well, whether or not +child processes are also specified: + + run io( "infile", ">", \$in ), io( "outfile", "<", \$in ) ; + +as can L objects: + + run \@cmd, io( "outfile", "<", \$in ), timeout( 10 ) ; + +Commands may be followed by scalar, sub, or i/o handle references for +redirecting +child process input & output: + + run \@cmd, \undef, \$out ; + run \@cmd, \$in, \$out ; + run \@cmd1, \&in, '|', \@cmd2, \*OUT ; + run \@cmd1, \*IN, '|', \@cmd2, \&out ; + +This is known as succinct redirection syntax, since run(), start() +and harness(), figure out which file descriptor to redirect and how. +File descriptor 0 is presumed to be an input for +the child process, all others are outputs. The assumed file +descriptor always starts at 0, unless the command is being piped to, +in which case it starts at 1. + +To be explicit about your redirects, or if you need to do more complex +things, there's also a redirection operator syntax: + + run \@cmd, '<', \undef, '>', \$out ; + run \@cmd, '<', \undef, '>&', \$out_and_err ; + run( + \@cmd1, + '<', \$in, + '|', \@cmd2, + \$out + ) ; + +Operator syntax is required if you need to do something other than simple +redirection to/from scalars or subs, like duping or closing file descriptors +or redirecting to/from a named file. The operators are covered in detail +below. + +After each \@cmd (or \&foo), parsing begins in succinct mode and toggles to +operator syntax mode when an operator (ie plain scalar, not a ref) is seen. +Once in +operator syntax mode, parsing only reverts to succinct mode when a '|' or +'&' is seen. + +In succinct mode, each parameter after the \@cmd specifies what to +do with the next highest file descriptor. These File descriptor start +with 0 (stdin) unless stdin is being piped to (C<'|', \@cmd>), in which +case they start with 1 (stdout). Currently, being on the left of +a pipe (C<\@cmd, \$out, \$err, '|'>) does I cause stdout to be +skipped, though this may change since it's not as DWIMerly as it +could be. Only stdin is assumed to be an +input in succinct mode, all others are assumed to be outputs. + +If no piping or redirection is specified for a child, it will inherit +the parent's open file handles as dictated by your system's +close-on-exec behavior and the $^F flag, except that processes after a +'&' will not inherit the parent's stdin. Also note that $^F does not +affect file desciptors obtained via POSIX, since it only applies to +full-fledged Perl file handles. Such processes will have their stdin +closed unless it has been redirected-to. + +If you want to close a child processes stdin, you may do any of: + + run \@cmd, \undef ; + run \@cmd, \"" ; + run \@cmd, '<&-' ; + run \@cmd, '0<&-' ; + +Redirection is done by placing redirection specifications immediately +after a command or child subroutine: + + run \@cmd1, \$in, '|', \@cmd2, \$out ; + run \@cmd1, '<', \$in, '|', \@cmd2, '>', \$out ; + +If you omit the redirection operators, descriptors are counted +starting at 0. Descriptor 0 is assumed to be input, all others +are outputs. A leading '|' consumes descriptor 0, so this +works as expected. + + run \@cmd1, \$in, '|', \@cmd2, \$out ; + +The parameter following a redirection operator can be a scalar ref, +a subroutine ref, a file name, an open filehandle, or a closed +filehandle. + +If it's a scalar ref, the child reads input from or sends output to +that variable: + + $in = "Hello World.\n" ; + run \@cat, \$in, \$out ; + print $out ; + +Scalars used in incremental (start()/pump()/finish()) applications are treated +as queues: input is removed from input scalers, resulting in them dwindling +to '', and output is appended to output scalars. This is not true of +harnesses run() in batch mode. + +It's usually wise to append new input to be sent to the child to the input +queue, and you'll often want to zap output queues to '' before pumping. + + $h = start \@cat, \$in ; + $in = "line 1\n" ; + pump $h ; + $in .= "line 2\n" ; + pump $h ; + $in .= "line 3\n" ; + finish $h ; + +The final call to finish() must be there: it allows the child process(es) +to run to completion and waits for their exit values. + +=head1 OBSTINATE CHILDREN + +Interactive applications are usually optimized for human use. This +can help or hinder trying to interact with them through modules like +IPC::Run. Frequently, programs alter their behavior when they detect +that stdin, stdout, or stderr are not connected to a tty, assuming that +they are being run in batch mode. Whether this helps or hurts depends +on which optimizations change. And there's often no way of telling +what a program does in these areas other than trial and error and, +occasionally, reading the source. This includes different versions +and implementations of the same program. + +All hope is not lost, however. Most programs behave in reasonably +tractable manners, once you figure out what it's trying to do. + +Here are some of the issues you might need to be aware of. + +=over + +=item * + +fflush()ing stdout and stderr + +This lets the user see stdout and stderr immediately. Many programs +undo this optimization if stdout is not a tty, making them harder to +manage by things like IPC::Run. + +Many programs decline to fflush stdout or stderr if they do not +detect a tty there. Some ftp commands do this, for instance. + +If this happens to you, look for a way to force interactive behavior, +like a command line switch or command. If you can't, you will +need to use a pseudo terminal ('pty>'). + +=item * + +false prompts + +Interactive programs generally do not guarantee that output from user +commands won't contain a prompt string. For example, your shell prompt +might be a '$', and a file named '$' might be the only file in a directory +listing. + +This can make it hard to guarantee that your output parser won't be fooled +into early termination of results. + +To help work around this, you can see if the program can alter it's +prompt, and use something you feel is never going to occur in actual +practice. + +You should also look for your prompt to be the only thing on a line: + + pump $h until $out =~ /^\s?\z/m ; + +(use C<(?!\n)\Z> in place of C<\z> on older perls). + +You can also take the approach that IPC::ChildSafe takes and emit a +command with known output after each 'real' command you issue, then +look for this known output. See new_appender() and new_chunker() for +filters that can help with this task. + +If it's not convenient or possibly to alter a prompt or use a known +command/response pair, you might need to autodetect the prompt in case +the local version of the child program is different then the one +you tested with, or if the user has control over the look & feel of +the prompt. + +=item * + +Refusing to accept input unless stdin is a tty. + +Some programs, for security reasons, will only accept certain types +of input from a tty. su, notable, will not prompt for a password unless +it's connected to a tty. + +If this is your situation, use a pseudo terminal ('pty>'). + +=item * + +Not prompting unless connected to a tty. + +Some programs don't prompt unless stdin or stdout is a tty. See if you can +turn prompting back on. If not, see if you can come up with a command that +you can issue after every real command and look for it's output, as +IPC::ChildSafe does. There are two filters included with IPC::Run that +can help with doing this: appender and chunker (see new_appender() and +new_chunker()). + +=item * + +Different output format when not connected to a tty. + +Some commands alter their formats to ease machine parsability when they +aren't connected to a pipe. This is actually good, but can be surprising. + +=back + +=head1 PSEUDO TERMINALS + +On systems providing pseudo terminals under /dev, IPC::Run can use IO::Pty +(available on CPAN) to provide a terminal environment to subprocesses. +This is necessary when the subprocess really wants to think it's connected +to a real terminal. + +=head2 CAVEATS + +Psuedo-terminals are not pipes, though they are similar. Here are some +differences to watch out for. + +=over + +=item Echoing + +Sending to stdin will cause an echo on stdout, which occurs before each +line is passed to the child program. There is currently no way to +disable this, although the child process can and should disable it for +things like passwords. + +=item Shutdown + +IPC::Run cannot close a pty until all output has been collected. This +means that it is not possible to send an EOF to stdin by half-closing +the pty, as we can when using a pipe to stdin. + +This means that you need to send the child process an exit command or +signal, or run() / finish() will time out. Be careful not to expect a +prompt after sending the exit command. + +=item Command line editing + +Some subprocesses, notable shells that depend on the user's prompt +settings, will reissue the prompt plus the command line input so far +once for each character. + +=item '>pty>' means '&>pty>', not '1>pty>' + +The pseudo terminal redirects both stdout and stderr unless you specify +a file descriptor. If you want to grab stderr separately, do this: + + start \@cmd, 'pty>', \$out, '2>', \$err ; + +=item stdin, stdout, and stderr not inherited + +Child processes harnessed to a pseudo terminal have their stdin, stdout, +and stderr completely closed before any redirection operators take +effect. This casts of the bonds of the controlling terminal. This is +not done when using pipes. + +Right now, this affects all children in a harness that has a pty in use, +even if that pty would not affect a particular child. That's a bug and +will be fixed. Until it is, it's best not to mix-and-match children. + +=back + +=head2 Redirection Operators + + Operator SHNP Description + ======== ==== =========== + <, N< SHN Redirects input to a child's fd N (0 assumed) + + >, N> SHN Redirects output from a child's fd N (1 assumed) + >>, N>> SHN Like '>', but appends to scalars or named files + >&, &> SHN Redirects stdout & stderr from a child process + + pty, N>pty S Like '>', but uses a pseudo-tty instead of a pipe + + N<&M Dups input fd N to input fd M + M>&N Dups output fd N to input fd M + N<&- Closes fd N + + pipe, N>pipe P Pipe opens H for caller to read, write, close. + +'N' and 'M' are placeholders for integer file descriptor numbers. The +terms 'input' and 'output' are from the child process's perspective. + +The SHNP field indicates what parameters an operator can take: + + S: \$scalar or \&function references. Filters may be used with + these operators (and only these). + H: \*HANDLE or IO::Handle for caller to open, and close + N: "file name". + P: \*HANDLE opened by IPC::Run as the parent end of a pipe, but read + and written to and closed by the caller (like IPC::Open3). + +=over + +=item Redirecting input: [n]<, [n] +below for more information. + +The : The handle returned is actually a socket handle, so you can +use select() on it. + +=item Redirecting output: [n]>, [n]>>, [n]>&[m], [n]>pipe + +You can redirect any output the child emits +to a scalar variable, subroutine, file handle, or file name. You +can have &run truncate or append to named files or scalars. If +you are redirecting stdin as well, or if the command is on the +receiving end of a pipeline ('|'), you can omit the redirection +operator: + + @ls = ( 'ls' ) ; + run \@ls, \undef, \$out + or die "ls returned $?" ; + + run \@ls, \undef, \&out ; ## Calls &out each time some output + ## is received from the child's + ## when undef is returned. + + run \@ls, \undef, '2>ls.err' ; + run \@ls, '2>', 'ls.err' ; + +The two parameter form guarantees that the filename +will not be interpreted as a redirection operator: + + run \@ls, '>', "&more" ; + run \@ls, '2>', ">foo\n" ; + +You can pass file handles you've opened for writing: + + open( *OUT, ">out.txt" ) ; + open( *ERR, ">err.txt" ) ; + run \@cat, \*OUT, \*ERR ; + +Passing a scalar reference and a code reference requires a little +more work, but allows you to capture all of the output in a scalar +or each piece of output by a callback: + +These two do the same things: + + run( [ 'ls' ], '2>', sub { $err_out .= $_[0] } ) ; + +does the same basic thing as: + + run( [ 'ls' ], '2>', \$err_out ) ; + +The subroutine will be called each time some data is read from the child. + +The >pipe operator is different in concept than the other '>' operators, +although it's syntax is similar: + + $h = start \@cat, $in, '>pipe', \*OUT, '2>pipe', \*ERR ; + $in = "hello world\n" ; + finish $h ; + print ; + print ; + close OUT ; + close ERR ; + +causes two pipe to be created, with one end attached to cat's stdout +and stderr, respectively, and the other left open on OUT and ERR, so +that the script can manually +read(), select(), etc. on them. This is like +the behavior of IPC::Open2 and IPC::Open3. + +B: The handle returned is actually a socket handle, so you can +use select() on it. + +=item Duplicating output descriptors: >&m, n>&m + +This duplicates output descriptor number n (default is 1 if n is omitted) +from descriptor number m. + +=item Duplicating input descriptors: <&m, n<&m + +This duplicates input descriptor number n (default is 0 if n is omitted) +from descriptor number m + +=item Closing descriptors: <&-, 3<&- + +This closes descriptor number n (default is 0 if n is omitted). The +following commands are equivalent: + + run \@cmd, \undef ; + run \@cmd, '<&-' ; + run \@cmd, ', >&, &>pipe, >pipe& + +The following pairs of commands are equivalent: + + run \@cmd, '>&', \$out ; run \@cmd, '>', \$out, '2>&1' ; + run \@cmd, '>&', 'out.txt' ; run \@cmd, '>', 'out.txt', '2>&1' ; + +etc. + +File descriptor numbers are not permitted to the left or the right of +these operators, and the '&' may occur on either end of the operator. + +The '&>pipe' and '>pipe&' variants behave like the '>pipe' operator, except +that both stdout and stderr write to the created pipe. + +=item Redirection Filters + +Both input redirections and output redirections that use scalars or +subs as endpoints may have an arbitrary number of filter subs placed +between them and the child process. This is useful if you want to +receive output in chunks, or if you want to massage each chunk of +data sent to the child. To use this feature, you must use operator +syntax: + + run( + \@cmd + '<', \&in_filter_2, \&in_filter_1, $in, + '>', \&out_filter_1, \&in_filter_2, $out, + ) ; + +This capability is not provided for IO handles or named files. + +Two filters are provided by IPC::Run: appender and chunker. Because +these may take an argument, you need to use the constructor functions +new_appender() and new_chunker() rather than using \& syntax: + + run( + \@cmd + '<', new_appender( "\n" ), $in, + '>', new_chunker, $out, + ) ; + +=back + +=head2 Just doing I/O + +If you just want to do I/O to a handle or file you open yourself, you +may specify a filehandle or filename instead of a command in the harness +specification: + + run io( "filename", '>', \$recv ) ; + + $h = start io( $io, '>', \$recv ) ; + + $h = harness \@cmd, '&', io( "file", '<', \$send ) ; + +=head2 Options + +Options are passed in as name/value pairs: + + run \@cat, \$in, debug => 1 ; + +If you pass the debug option, you may want to pass it in first, so you +can see what parsing is going on: + + run debug => 1, \@cat, \$in ; + +=over + +=item debug + +Enables debugging output in parent and child. Debugging info is emitted +to the STDERR that was present when IPC::Run was first Ced (it's +Ced out of the way so that it can be redirected in children without +having debugging output emitted on it). + +=back + +=head1 RETURN VALUES + +harness() and start() return a reference to an IPC::Run harness. This is +blessed in to the IPC::Run package, so you may make later calls to +functions as members if you like: + + $h = harness( ... ) ; + $h->start ; + $h->pump ; + $h->finish ; + + $h = start( .... ) ; + $h->pump ; + ... + +Of course, using method call syntax lets you deal with any IPC::Run +subclasses that might crop up, but don't hold your breath waiting for +any. + +run() and finish() return TRUE when all subcommands exit with a 0 result +code. B. + +All routines raise exceptions (via die()) when error conditions are +recognized. A non-zero command result is not treated as an error +condition, since some commands are tests whose results are reported +in their exit codes. + +=head1 ROUTINES + +=over + +=cut + +@ISA = qw( Exporter ) ; + +## We use @EXPORT for the end user's convenience: there's only one function +## exported, it's homonymous with the module, it's an unusual name, and +## it can be suppressed by "use IPC::Run () ;". + +my @FILTER_IMP = qw( input_avail get_more_input ) ; +my @FILTERS = qw( + new_appender + new_chunker + new_string_source + new_string_sink +) ; +my @API = qw( + run + harness start pump pumpable finish + signal kill_kill reap_nb + io timer timeout + close_terminal + binary +) ; + +@EXPORT_OK = ( @API, @FILTER_IMP, @FILTERS, qw( filter_tests Win32_MODE ) ) ; +%EXPORT_TAGS = ( + 'filter_imp' => \@FILTER_IMP, + 'all' => \@EXPORT_OK, + 'filters' => \@FILTERS, + 'api' => \@API, +) ; + +use strict ; + +use IPC::Run::Debug; +use Exporter ; +use Fcntl ; +use POSIX () ; +use Symbol ; +use Carp ; +use File::Spec ; +use IO::Handle ; +require IPC::Run::IO ; +require IPC::Run::Timer ; +use UNIVERSAL qw( isa ) ; + +use constant Win32_MODE => $^O =~ /os2|Win32/i ; + +BEGIN { + if ( Win32_MODE ) { + eval "use IPC::Run::Win32Helper; 1;" + or ( $@ && die ) or die "$!" ; + } + else { + eval "use File::Basename; 1;" or die $! ; + } +} + + +sub input_avail() ; +sub get_more_input() ; + +############################################################################### + +## +## State machine states, set in $self->{STATE} +## +## These must be in ascending order numerically +## +sub _newed() {0} +sub _harnessed(){1} +sub _finished() {2} ## _finished behave almost exactly like _harnessed +sub _started() {3} + +## +## Which fds have been opened in the parent. This may have extra fds, since +## we aren't all that rigorous about closing these off, but that's ok. This +## is used on Unixish OSs to close all fds in the child that aren't needed +## by that particular child. +my %fds ; + +## There's a bit of hackery going on here. +## +## We want to have any code anywhere be able to emit +## debugging statements without knowing what harness the code is +## being called in/from, since we'd need to pass a harness around to +## everything. +## +## Thus, $cur_self was born. + +use vars qw( $cur_self ) ; + +sub _debug_fd { + return fileno STDERR unless defined $cur_self ; + + if ( _debugging && ! defined $cur_self->{DEBUG_FD} ) { + my $fd = select STDERR ; $| = 1 ; select $fd ; + $cur_self->{DEBUG_FD} = POSIX::dup fileno STDERR ; + _debug( "debugging fd is $cur_self->{DEBUG_FD}\n" ) + if _debugging_details ; + } + + return fileno STDERR unless defined $cur_self->{DEBUG_FD} ; + + return $cur_self->{DEBUG_FD} +} + +sub DESTROY { + ## We absolutely do not want to do anything else here. We are likely + ## to be in a child process and we don't want to do things like kill_kill + ## ourself or cause other destruction. + my IPC::Run $self = shift ; + POSIX::close $self->{DEBUG_FD} if defined $self->{DEBUG_FD} ; + $self->{DEBUG_FD} = undef ; +} + +## +## Support routines (NOT METHODS) +## +my %cmd_cache ; + +sub _search_path { + my ( $cmd_name ) = @_ ; + if ( File::Spec->file_name_is_absolute( $cmd_name ) && -x $cmd_name) { + _debug "'", $cmd_name, "' is absolute" + if _debugging_details ; + return $cmd_name ; + } + + my $dirsep = + ( Win32_MODE + ? '[/\\\\]' + : $^O =~ /MacOS/ + ? ':' + : $^O =~ /VMS/ + ? '[\[\]]' + : '/' + ) ; + + if ( Win32_MODE + && ( $cmd_name =~ /$dirsep/ ) + && ( $cmd_name !~ /\..+$/ ) ## Only run if cmd_name has no extension? + ) { + for ( split /;/, $ENV{PATHEXT} || ".COM;.BAT;.EXE" ) { + my $name = "$cmd_name$_"; + $cmd_name = $name, last if -f $name && -x _; + } + } + + if ( $cmd_name =~ /($dirsep)/ ) { + _debug "'$cmd_name' contains '$1'" if _debugging; + croak "file not found: $cmd_name" unless -e $cmd_name ; + croak "not a file: $cmd_name" unless -f $cmd_name ; + croak "permission denied: $cmd_name" unless -x $cmd_name ; + return $cmd_name ; + } + + if ( exists $cmd_cache{$cmd_name} ) { + _debug "'$cmd_name' found in cache: '$cmd_cache{$cmd_name}'" + if _debugging; + return $cmd_cache{$cmd_name} if -x $cmd_cache{$cmd_name} ; + _debug "'$cmd_cache{$cmd_name}' no longer executable, searching..." + if _debugging; + delete $cmd_cache{$cmd_name} ; + } + + my @searched_in ; + + ## This next bit is Unix/Win32 specific, unfortunately. + ## There's been some conversation about extending File::Spec to provide + ## a universal interface to PATH, but I haven't seen it yet. + my $re = Win32_MODE ? qr/;/ : qr/:/ ; + +LOOP: + for ( split( $re, $ENV{PATH}, -1 ) ) { + $_ = "." unless length $_ ; + push @searched_in, $_ ; + + my $prospect = File::Spec->catfile( $_, $cmd_name ) ; + my @prospects ; + + @prospects = + ( Win32_MODE && ! ( -f $prospect && -x _ ) ) + ? map "$prospect$_", split /;/, $ENV{PATHEXT} || ".COM;.BAT;.EXE" + : ( $prospect ) ; + + for my $found ( @prospects ) { + if ( -f $found && -x _ ) { + $cmd_cache{$cmd_name} = $found ; + last LOOP ; + } + } + } + + if ( exists $cmd_cache{$cmd_name} ) { + _debug "'", $cmd_name, "' added to cache: '", $cmd_cache{$cmd_name}, "'" + if _debugging_details ; + return $cmd_cache{$cmd_name} ; + } + + croak "Command '$cmd_name' not found in " . join( ", ", @searched_in ) ; +} + + +sub _empty($) { ! ( defined $_[0] && length $_[0] ) } + +## 'safe' versions of otherwise fun things to do. See also IPC::Run::Win32Helper. +sub _close { + confess 'undef' unless defined $_[0] ; + no strict 'refs' ; + my $fd = $_[0] =~ /^\d+$/ ? $_[0] : fileno $_[0] ; + my $r = POSIX::close $fd ; + $r = $r ? '' : " ERROR $!" ; + delete $fds{$fd} ; + _debug "close( $fd ) = " . ( $r || 0 ) if _debugging_details ; +} + +sub _dup { + confess 'undef' unless defined $_[0] ; + my $r = POSIX::dup( $_[0] ) ; + croak "$!: dup( $_[0] )" unless defined $r ; + $r = 0 if $r eq '0 but true' ; + _debug "dup( $_[0] ) = $r" if _debugging_details ; + $fds{$r} = 1 ; + return $r ; +} + + +sub _dup2_rudely { + confess 'undef' unless defined $_[0] && defined $_[1] ; + my $r = POSIX::dup2( $_[0], $_[1] ) ; + croak "$!: dup2( $_[0], $_[1] )" unless defined $r ; + $r = 0 if $r eq '0 but true' ; + _debug "dup2( $_[0], $_[1] ) = $r" if _debugging_details ; + $fds{$r} = 1 ; + return $r ; +} + +sub _exec { + confess 'undef passed' if grep !defined, @_ ; +# exec @_ or croak "$!: exec( " . join( ', ', @_ ) . " )" ; + _debug 'exec()ing ', join " ", map "'$_'", @_ if _debugging_details ; + +# { +## Commented out since we don't call this on Win32. +# # This works around the bug where 5.6.1 complains +# # "Can't exec ...: No error" after an exec on NT, where +# # exec() is simulated and actually returns in Perl's C +# # code, though Perl's &exec does not... +# no warnings "exec" ; +# +# # Just in case the no warnings workaround +# # stops beign a workaround, we don't want +# # old values of $! causing spurious strerr() +# # messages to appear in the "Can't exec" message +# undef $! ; + exec @_ ; +# } +# croak "$!: exec( " . join( ', ', map "'$_'", @_ ) . " )" ; + ## Fall through so $! can be reported to parent. +} + + +sub _sysopen { + confess 'undef' unless defined $_[0] && defined $_[1] ; +_debug sprintf( "O_RDONLY=0x%02x ", O_RDONLY ), +sprintf( "O_WRONLY=0x%02x ", O_WRONLY ), +sprintf( "O_RDWR=0x%02x ", O_RDWR ), +sprintf( "O_TRUNC=0x%02x ", O_TRUNC), +sprintf( "O_CREAT=0x%02x ", O_CREAT), +sprintf( "O_APPEND=0x%02x ", O_APPEND), +if _debugging_details ; + my $r = POSIX::open( $_[0], $_[1], 0644 ) ; + croak "$!: open( $_[0], ", sprintf( "0x%03x", $_[1] ), " )" unless defined $r ; + _debug "open( $_[0], ", sprintf( "0x%03x", $_[1] ), " ) = $r" + if _debugging_data ; + $fds{$r} = 1 ; + return $r ; +} + +sub _pipe { + ## Normal, blocking write for pipes that we read and the child writes, + ## since most children expect writes to stdout to block rather than + ## do a partial write. + my ( $r, $w ) = POSIX::pipe ; + croak "$!: pipe()" unless defined $r ; + _debug "pipe() = ( $r, $w ) " if _debugging_details ; + $fds{$r} = $fds{$w} = 1 ; + return ( $r, $w ) ; +} + +sub _pipe_nb { + ## For pipes that we write, unblock the write side, so we can fill a buffer + ## and continue to select(). + ## Contributed by Borislav Deianov , with minor + ## bugfix on fcntl result by me. + local ( *R, *W ) ; + my $f = pipe( R, W ) ; + croak "$!: pipe()" unless defined $f ; + my ( $r, $w ) = ( fileno R, fileno W ) ; + _debug "pipe_nb pipe() = ( $r, $w )" if _debugging_details ; + unless ( Win32_MODE ) { + ## POSIX::fcntl doesn't take fd numbers, so gotta use Perl's and + ## then _dup the originals (which get closed on leaving this block) + my $fres = fcntl( W, &F_SETFL, O_WRONLY | O_NONBLOCK ); + croak "$!: fcntl( $w, F_SETFL, O_NONBLOCK )" unless $fres ; + _debug "fcntl( $w, F_SETFL, O_NONBLOCK )" if _debugging_details ; + } + ( $r, $w ) = ( _dup( $r ), _dup( $w ) ) ; + _debug "pipe_nb() = ( $r, $w )" if _debugging_details ; + return ( $r, $w ) ; +} + +sub _pty { + require IO::Pty ; + my $pty = IO::Pty->new() ; + croak "$!: pty ()" unless $pty ; + $pty->autoflush() ; + $pty->blocking( 0 ) or croak "$!: pty->blocking ( 0 )" ; + _debug "pty() = ( ", $pty->fileno, ", ", $pty->slave->fileno, " )" + if _debugging_details ; + $fds{$pty->fileno} = $fds{$pty->slave->fileno} = 1 ; + return $pty ; +} + + +sub _read { + confess 'undef' unless defined $_[0] ; + my $s = '' ; + my $r = POSIX::read( $_[0], $s, 10_000 ) ; + croak "$!: read( $_[0] )" if not($r) and $! != POSIX::EINTR; + $r ||= 0; + _debug "read( $_[0] ) = $r chars '$s'" if _debugging_data ; + return $s ; +} + + +## A METHOD, not a function. +sub _spawn { + my IPC::Run $self = shift ; + my ( $kid ) = @_ ; + + _debug "opening sync pipe ", $kid->{PID} if _debugging_details ; + my $sync_reader_fd ; + ( $sync_reader_fd, $self->{SYNC_WRITER_FD} ) = _pipe ; + $kid->{PID} = fork() ; + croak "$! during fork" unless defined $kid->{PID} ; + + unless ( $kid->{PID} ) { + ## _do_kid_and_exit closes sync_reader_fd since it closes all unwanted and + ## unloved fds. + $self->_do_kid_and_exit( $kid ) ; + } + _debug "fork() = ", $kid->{PID} if _debugging_details ; + + ## Wait for kid to get to it's exec() and see if it fails. + _close $self->{SYNC_WRITER_FD} ; + my $sync_pulse = _read $sync_reader_fd ; + _close $sync_reader_fd ; + + if ( ! defined $sync_pulse || length $sync_pulse ) { + if ( waitpid( $kid->{PID}, 0 ) >= 0 ) { + $kid->{RESULT} = $? ; + } + else { + $kid->{RESULT} = -1 ; + } + $sync_pulse = + "error reading synchronization pipe for $kid->{NUM}, pid $kid->{PID}" + unless length $sync_pulse ; + croak $sync_pulse ; + } + return $kid->{PID} ; + +## Wait for pty to get set up. This is a hack until we get synchronous +## selects. +if ( keys %{$self->{PTYS}} && $IO::Pty::VERSION < 0.9 ) { +_debug "sleeping to give pty a chance to init, will fix when newer IO::Pty arrives." ; +sleep 1 ; +} +} + + +sub _write { + confess 'undef' unless defined $_[0] && defined $_[1] ; + my $r = POSIX::write( $_[0], $_[1], length $_[1] ) ; + croak "$!: write( $_[0], '$_[1]' )" unless $r ; + _debug "write( $_[0], '$_[1]' ) = $r" if _debugging_data ; + return $r ; +} + + +=item run + +Run takes a harness or harness specification and runs it, pumping +all input to the child(ren), closing the input pipes when no more +input is available, collecting all output that arrives, until the +pipes delivering output are closed, then waiting for the children to +exit and reaping their result codes. + +You may think of C as being like + + start( ... )->finish() ; + +, though there is one subtle difference: run() does not +set \$input_scalars to '' like finish() does. If an exception is thrown +from run(), all children will be killed off "gently", and then "annihilated" +if they do not go gently (in to that dark night. sorry). + +If any exceptions are thrown, this does a L before propogating +them. + +=cut + +use vars qw( $in_run ); ## No, not Enron ;) + +sub run { + local $in_run = 1; ## Allow run()-only optimizations. + my IPC::Run $self = start( @_ ); + my $r = eval { + $self->{clear_ins} = 0 ; + $self->finish ; + } ; + if ( $@ ) { + my $x = $@ ; + $self->kill_kill ; + die $x ; + } + return $r ; +} + + +=item signal + + ## To send it a specific signal by name ("USR1"): + signal $h, "USR1" ; + $h->signal ( "USR1" ) ; + +If $signal is provided and defined, sends a signal to all child processes. Try +not to send numeric signals, use C<"KILL"> instead of C<9>, for instance. +Numeric signals aren't portable. + +Throws an exception if $signal is undef. + +This will I clean up the harness, C it if you kill it. + +Normally TERM kills a process gracefully (this is what the command line utility +C does by default), INT is sent by one of the keys C<^C>, C or +CDelE>, and C is used to kill a process and make it coredump. + +The C signal is often used to get a process to "restart", rereading +config files, and C and C for really application-specific things. + +Often, running C (that's a lower case "L") on the command line will +list the signals present on your operating system. + +B: The signal subsystem is not at all portable. We *may* offer +to simulate C and C on some operating systems, submit code +to me if you want this. + +B: Up to and including perl v5.6.1, doing almost anything in a +signal handler could be dangerous. The most safe code avoids all +mallocs and system calls, usually by preallocating a flag before +entering the signal handler, altering the flag's value in the +handler, and responding to the changed value in the main system: + + my $got_usr1 = 0 ; + sub usr1_handler { ++$got_signal } + + $SIG{USR1} = \&usr1_handler ; + while () { sleep 1 ; print "GOT IT" while $got_usr1-- ; } + +Even this approach is perilous if ++ and -- aren't atomic on your system +(I've never heard of this on any modern CPU large enough to run perl). + +=cut + +sub signal { + my IPC::Run $self = shift ; + + local $cur_self = $self ; + + $self->_kill_kill_kill_pussycat_kill unless @_ ; + + Carp::cluck "Ignoring extra parameters passed to kill()" if @_ > 1 ; + + my ( $signal ) = @_ ; + croak "Undefined signal passed to signal" unless defined $signal ; + for ( grep $_->{PID} && ! defined $_->{RESULT}, @{$self->{KIDS}} ) { + _debug "sending $signal to $_->{PID}" + if _debugging; + kill $signal, $_->{PID} + or _debugging && _debug "$! sending $signal to $_->{PID}" ; + } + + return ; +} + + +=item kill_kill + + ## To kill off a process: + $h->kill_kill ; + kill_kill $h ; + + ## To specify the grace period other than 30 seconds: + kill_kill $h, grace => 5 ; + + ## To send QUIT instead of KILL if a process refuses to die: + kill_kill $h, coup_d_grace => "QUIT" ; + +Sends a C, waits for all children to exit for up to 30 seconds, then +sends a C to any that survived the C. + +Will wait for up to 30 more seconds for the OS to sucessfully C the +processes. + +The 30 seconds may be overriden by setting the C option, this +overrides both timers. + +The harness is then cleaned up. + +The doubled name indicates that this function may kill again and avoids +colliding with the core Perl C function. + +Returns a 1 if the C was sufficient, or a 0 if C was +required. Throws an exception if C did not permit the children +to be reaped. + +B: The grace period is actually up to 1 second longer than that +given. This is because the granularity of C