From: Graydon, Tracy Date: Wed, 10 Oct 2012 00:20:49 +0000 (-0700) Subject: forking from Tizen:Main for IVI 2.0 X-Git-Tag: 1.0_branch X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Ftags%2F1.0_branch;p=profile%2Fivi%2Fmtools.git forking from Tizen:Main for IVI 2.0 --- 8c437a9a571aa2f59017fbdceef5ae49f53d7915 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/INSTALL b/INSTALL new file mode 100644 index 0000000..db7bbb4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,30 @@ +% Copyright 1996,1997,1999,2001,2002 Alain Knaff. + +% This documentation is for Mtools which is a collection of tools to +% allow Unix systems to manipulate MS-DOS files. + +% Permission is granted to copy, distribute and/or modify this document +% under the terms of the GNU Free Documentation License, Version 1.3 or +% any later version published by the Free Software Foundation; with no +% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +% Texts. A copy of the license is included in the section entitled +% ``GNU Free Documentation License''. + +Installation of mtools is now pretty straightforward: + + 1. Run ./configure + 2. Run make + + Configuration options: + + * Use ./configure --enable-vold to compile mtools to use Solaris' +vold instead of directly accessing the floppy disk + * Use ./configure --disable-xdf to disable support for Xdf disks on Linux + * Use ./configure --enable-new-vold to compile mtools to use the *new* +vold for Solaris. With this, you no longer need precmd=volcheck, and +users don't need to type "eject" before pushing the button. + +Further doc can be found in the manpages, and in the texinfo doc. The +texinfo doc contains the same info as the manpages, but is more up to +date. To generate a printable doc, make dvi. To generate an info file, +make info. diff --git a/Makefile.Be b/Makefile.Be new file mode 100644 index 0000000..8dee7d3 --- /dev/null +++ b/Makefile.Be @@ -0,0 +1,49 @@ +# Copyright 1997 Marco Nelissen +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# +# Makefile for Mtools +# +# check the Configure file for some examples of device-specific setups +# Berkeley flavors of Unix should include -DBSD in the CFLAGS. Pick +# a lock method... either -DLOCKF, -DFLOCK, or -DFCNTL and put that +# string in the CFLAGS line below. + +# +# rudimentary makefile for building mtools 3.1 on the BeOS +# + +CC=mwcc -O7 + +OBJS=buffer.o codepage.o codepages.o config.o copyfile.o devices.o \ +directory.o expand.o fat.o fat_free.o file.o file_name.o file_read.o \ +filter.o force_io.o hash.o init.o match.o mainloop.o mattrib.o mbadblocks.o \ +mcd.o mcopy.o mdel.o mdir.o mformat.o minfo.o misc.o missFuncs.o \ +mk_direntry.o mlabel.o mmd.o mmount.o mmove.o mpartition.o mzip.o mtools.o \ +parse.o plain_io.o precmd.o privileges.o scsi.o signal.o stream.o \ +streamcache.o subdir.o toupper.o tty.o vfat.o xdf_io.o + +all: mtools mkmanifest + +$(OBJS): config.h + +config.h: config.h.Be + cp config.h.Be config.h + +mtools: $(OBJS) + $(CC) -o mtools $(OBJS) + +mkmanifest: mkmanifest.o + $(CC) -o mkmanifest mkmanifest.c diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..85c82ba --- /dev/null +++ b/Makefile.in @@ -0,0 +1,328 @@ +# Copyright 1996-2004,2006-2009 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# +# Makefile for Mtools +# +# check the Configure file for some examples of device-specific setups +# Berkeley flavors of Unix should include -DBSD in the CFLAGS. Pick +# a lock method... either -DLOCKF, -DFLOCK, or -DFCNTL and put that +# string in the CFLAGS line below. + +# User specified flags +USERCFLAGS = +USERLDFLAGS = +USERLDLIBS = + +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi +TEXI2PDF = texi2pdf +TEXI2HTML = texi2html + + +# do not edit below this line +# ============================================================================= + +SHELL = /bin/sh + +top_srcdir=@top_srcdir@ +srcdir=@srcdir@ +VPATH=@srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +infodir = @infodir@ +mandir = @mandir@ +sysconfdir = @sysconfdir@ +datarootdir = @datarootdir@ + +CC = @CC@ +CXX = @CXX@ +MYCFLAGS = @CFLAGS@ +MYCXXFLAGS = @CXXFLAGS@ +CPPFLAGS = @CPPFLAGS@ +HOST_ID = @HOST_ID@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)\" $(HOST_ID) + +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +SHLIB = @SHLIB@ +MACHDEPLIBS = @MACHDEPLIBS@ +LN_S = @LN_S@ +EXE = @EXEEXT@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_INFO = @INSTALL_INFO@ + +.SUFFIXES: +.SUFFIXES: .o .c +.SUFFIXES: .o .c + +MAN1 = floppyd.1 floppyd_installtest.1 mattrib.1 mbadblocks.1 mcat.1 mcd.1 \ +mclasserase.1 mcopy.1 mdel.1 mdeltree.1 mdir.1 mdu.1 mformat.1 minfo.1 \ +mkmanifest.1 mlabel.1 mmd.1 mmount.1 mmove.1 mpartition.1 \ +mrd.1 mren.1 mshowfat.1 mtoolstest.1 mtools.1 mtype.1 mzip.1 +MAN1EXT = 1 +MAN1DIR = $(DESTDIR)$(mandir)/man${MAN1EXT} +MAN5 = mtools.5 +MAN5EXT = 5 +MAN5DIR = $(DESTDIR)$(mandir)/man${MAN5EXT} + +# all files in this directory included in the distribution +DIST = \ +COPYING Changelog INSTALL Makefile Makefile.in README Release.notes \ +buffer.c buffer.h charsetConv.c codepage.h codepages.c config.c \ +config.guess config.h.in config.log config.sub configure configure.in \ +copyfile.c devices.c devices.h dirCache.c dirCache.h directory.c direntry.c \ +expand.c fat.c \ +fat_free.c file.c file.h file_name.h file_name.c files filter.c floppyd.1 \ +floppyd.c floppyd_io.c floppyd_io.h force_io.c fs.h fsP.h \ +getopt.h hash.c htable.h init.c llong.c mainloop.c match.c mattrib.1 \ +mattrib.c mbadblocks.1 mbadblocks.c mcat.1 mcat.c mcd.1 mcd.c mclasserase.c \ +mcopy.1 \ +mcopy.c mdel.1 mdel.c mdeltree.1 mdir.1 mdir.c mdu.c mdu.1 mformat.1 \ +mformat.c minfo.c \ +misc.c tty.c scsi.c missFuncs.c mk_direntry.c mkmanifest.1 mkmanifest.c \ +mlabel.1 mlabel.c mmd.1 mmd.c mmount.1 mmount.c mmove.1 mmove.c \ +mpartition.1 mpartition.c mrd.1 \ +mren.1 msdos.h mshowfat.1 mtoolstest.1 mtools.1 mtools.5 mtools.c \ +mtools.conf mtools.h mtype.1 nameclash.h patchlevel.c \ +plain_io.c plain_io.h precmd.c privileges.c scripts signal.c stream.c stream.h \ +streamcache.c streamcache.h subdir.c sysincludes.h unixdir.c todo \ +vfat.c vfat.h xdf_io.c xdf_io.h + +OBJS1 = buffer.o charsetConv.o codepages.o config.o copyfile.o \ +devices.o dirCache.o directory.o direntry.o expand.o fat.o fat_free.o file.o \ +file_name.o filter.o floppyd_io.o force_io.o hash.o init.o llong.o match.o \ +mainloop.o mattrib.o mbadblocks.o mcat.o mcd.o mclasserase.o mcopy.o mdel.o \ +mdir.o mdoctorfat.o mdu.o \ +mformat.o minfo.o misc.o missFuncs.o mk_direntry.o mlabel.o mmd.o mmount.o \ +mmove.o mpartition.o mshowfat.o mzip.o mtools.o patchlevel.o plain_io.o \ +precmd.o privileges.o scsi.o signal.o stream.o streamcache.o subdir.o \ +unixdir.o tty.o vfat.o xdf_io.o + +OBJS2 = missFuncs.o mkmanifest.o misc.o patchlevel.o + +SRCS3 = floppyd.c + +OBJS4 = floppyd_installtest.o misc.o expand.o privileges.o + +SRCS = buffer.c codepages.c config.c copyfile.c devices.c \ +dirCache.c directory.c direntry.c expand.c fat.c fat_free.c file.c file_name.c \ +file_read.c filter.c floppyd_io.c force_io.c hash.c init.c match.c mainloop.c \ +mattrib.c mbadblocks.c mcat.c mcd.c mclasserase.c mcopy.c mdel.c mdir.c \ +mdu.c mdoctorfat.c mformat.c minfo.c misc.c \ +missFuncs.c mk_direntry.c mlabel.c mmd.c mmount.c mmove.c mpartition.c \ +mshowfat.c mzip.c mtools.c plain_io.c precmd.c privileges.c scsi.o \ +signal.c stream.c streamcache.c subdir.c unixdir.c tty.o vfat.c \ +xdf_io.c mkmanifest.c + + +SCRIPTS = mcheck mxtar uz tgz mcomp amuFormat.sh + +LINKS=mattrib mcat mcd mclasserase mcopy mdel mdeltree mdir mdu mformat minfo \ +mlabel mmd mmount mmove mpartition mrd mren mtype mtoolstest mshowfat \ +mbadblocks mzip + +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +CFLAGS = $(CPPFLAGS) $(DEFS) $(MYCFLAGS) -fno-strict-aliasing -I. @extraincludedir@ -I@srcdir@ $(USERCFLAGS) +CXXFLAGS = $(CPPFLAGS) $(DEFS) $(MYCXXFLAGS) -I. @extraincludedir@ -I@srcdir@ $(USERCFLAGS) +LINK = $(CC) $(LDFLAGS) $(USERLDFLAGS) @extralibdir@ +ALLLIBS = $(USERLDLIBS) $(MACHDEPLIBS) $(SHLIB) $(LIBS) +X_LDFLAGS = $(X_EXTRA_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lXau -lX11 $(LIBS) +X_CCFLAGS = $(X_CFLAGS) $(CFLAGS) + +all: mtools $(LINKS) mkmanifest @FLOPPYD@ + +%.o: %.c + $(CC) $(CFLAGS) -c $< + +#%.o: %.cpp +# $(CXX) $(CXXFLAGS) -c $< + +mtools: $(OBJS1) + $(LINK) $(OBJS1) -o $@ $(ALLLIBS) + +mkmanifest: $(OBJS2) + $(LINK) $(OBJS2) -o $@ $(ALLLIBS) + +floppyd.o: floppyd.c + $(CC) $(X_CCFLAGS) -c $? + +floppyd: floppyd.o + $(LINK) $? -o $@ $(X_LDFLAGS) +floppyd_installtest: $(OBJS4) + $(LINK) $(OBJS4) -o $@ $(ALLLIBS) + + +$(LINKS): mtools + rm -f $@ && $(LN_S) mtools$(EXE) $@ + +mostlyclean: + -rm -f *~ *.orig *.o a.out core 2>/dev/null + +clean: mostlyclean + -rm -f mtools $(LINKS) floppyd floppyd_installtest mkmanifest *.info* *.dvi *.html 2>/dev/null + + +texclean: + -rm -f mtools.aux mtools.toc mtools.log + -rm -f mtools.cps mtools.pgs mtools.vrs + -rm -f mtools.cp mtools.fn mtools.ky + -rm -f mtools.pg mtools.tp mtools.vr + +info: mtools.info +%.info: %.texi + $(MAKEINFO) -I$(srcdir) $< --no-split --output=$@ + +dvi: mtools.dvi +%.dvi: %.texi + $(TEXI2DVI) $< + +ps: mtools.ps +%.ps: %.dvi + dvips -f < $< > $@ + +pdf: mtools.pdf +%.pdf: %.texi + $(TEXI2PDF) $< + + +html: mtools.html mtools_toc.html +%.html %_toc.html: %.texi + $(TEXI2HTML) $< + +# Don't cd, to avoid breaking install-sh references. +install-info: info + $(top_srcdir)/mkinstalldirs $(DESTDIR)$(infodir) + if test -f mtools.info; then \ + for i in mtools.info*; do \ + $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/$$i; \ + done; \ + else \ + for i in $(srcdir)/mtools.info*; do \ + $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/`echo $$i | sed 's|^$(srcdir)/||'`; \ + done; \ + fi; \ + if [ -n "$(INSTALL_INFO)" ] ; then \ + $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/mtools.info; \ + fi + +uninstall-info: + cd $(DESTDIR)$(infodir) && rm -f mtools.info* + +install: $(DESTDIR)$(bindir)/mtools @BINFLOPPYD@ install-man install-links \ + $(DESTDIR)$(bindir)/mkmanifest install-scripts install-info + +uninstall: uninstall-bin uninstall-man uninstall-links \ + uninstall-scripts + +distclean: clean texclean + rm -f config.cache config.h config.status config.log Makefile +maintainer-clean: distclean + + +$(DESTDIR)$(bindir)/floppyd: floppyd + $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) floppyd $(DESTDIR)$(bindir)/floppyd + +$(DESTDIR)$(bindir)/floppyd_installtest: floppyd_installtest + $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) floppyd_installtest $(DESTDIR)$(bindir)/floppyd_installtest + +$(DESTDIR)$(bindir)/mtools: mtools + $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) mtools $(DESTDIR)$(bindir)/mtools + +$(DESTDIR)$(bindir)/mkmanifest: mkmanifest + $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) + $(INSTALL_PROGRAM) mkmanifest $(DESTDIR)$(bindir)/mkmanifest + +#$(ETCDIR)/mtools: mtools.etc +# cp mtools.etc $(ETCDIR)/mtools + +install-links: $(DESTDIR)$(bindir)/mtools + @for j in $(LINKS); do \ + rm -f $(DESTDIR)$(bindir)/$$j ; \ + $(LN_S) mtools$(EXE) $(DESTDIR)$(bindir)/$$j ; \ + echo $(DESTDIR)$(bindir)/$$j ; \ + done + +## "z" is the older version of "gz"; the name is just *too* short +install-scripts: $(DESTDIR)$(bindir)/mtools + @$(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) + @for j in $(SCRIPTS) ; do \ + $(INSTALL_PROGRAM) $(srcdir)/scripts/$$j $(DESTDIR)$(bindir)/$$j ; \ + echo $(DESTDIR)$(bindir)/$$j ; \ + done + rm -f $(DESTDIR)$(bindir)/lz + cd $(DESTDIR)$(bindir) && $(LN_S) uz lz + +install-man: + @$(top_srcdir)/mkinstalldirs $(MAN1DIR) + @for j in $(MAN1); do \ + $(INSTALL_DATA) $(srcdir)/$$j $(MAN1DIR)/$$j ; \ + echo $(MAN1DIR)/$$j ; \ + done + @$(top_srcdir)/mkinstalldirs $(MAN5DIR) + @for j in $(MAN5); do \ + $(INSTALL_DATA) $(srcdir)/$$j $(MAN5DIR)/$$j ; \ + echo $(MAN5DIR)/$$j ; \ + done + +uninstall-bin: + @for j in mtools mkmanifest; do \ + rm -f $(DESTDIR)$(bindir)/$$j ; \ + echo $(DESTDIR)$(bindir)/$$j ; \ + done + +uninstall-scripts: + @for j in $(SCRIPTS); do \ + rm -f $(DESTDIR)$(bindir)/$$j ; \ + echo $(DESTDIR)$(bindir)/$$j ; \ + done + +uninstall-man: + @for j in $(MAN1); do \ + rm -f $(MAN1DIR)/$$j ; \ + echo $(MAN1DIR)/$$j ; \ + done + @for j in $(MAN5); do \ + rm -f $(MAN5DIR)/$$j ; \ + echo $(MAN5DIR)/$$j ; \ + done + +uninstall-links: + @for j in $(LINKS); \ + do rm -f $(DESTDIR)$(bindir)/$$j ; \ + echo $(DESTDIR)$(bindir)/$$j ; \ + done + +depend: $(SRCS) + makedepend -- $(CFLAGS) -- $^ + +check: + echo No self tests included +# check target needed even if empty, in order to make life easyer for +# automatic tools to install GNU soft + + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..278d22d --- /dev/null +++ b/NEWS @@ -0,0 +1,1039 @@ +v4_0_12 + Mingw compatibility fixes +v4_0_11 + Fixed compiler warnings in mlabel.c and elsewhere + Fixed h flag in mattrib.c + Added missing error checking in floppyd and elsewhere + +v4_0_10 + More copyright stuff... + Fixed issues with max filesize (was 2GB instead of 4GB, and + warned only after copying the beginning) +v4_0_9 + More copyright stuff +v4_0_8 + Corrected copyright attributions in the various files +v4_0_7 + Fixed conversion to native on OS/2 + Fix parsing of --help flag +v4_0_6 + Fallback for missing wchar_t iconv codepage on OS/2 + Fixes for LSEEK64 support + Support for --help that returns a 0 exit status +v4_0_5 + Make setpgrp() usage in floppyd conditional + Re-instate PACKED around structure (ARM) + LSEEK64 + +v4_0_4 + BSD support: SCSI, use getuserid/getgroupid in floppyd + Another attempt at putwc fix for OS/2 + Further GNU fixes + Fallback for putwc if there is wchar (OS/2) +v4_0_3 + Fix multipart pathname parsing bug in vfat.c (forgot limited length) + Supplied fallback define for putwc + Copyright notices in all sources +v4_0_2 + Off-by-2 error in unix_name in file_name.c +v4_0_1 + Missing functions on Solaris +v4_0_0 + Offset for -i-specified image files +v4_0_0_pre2 + Use transliteration to represent characters which don't exist in + target set +v4_0_0_pre1 + Mtools-4 with Unicode support + Released 4.0.0_pre1 +v20071226 + Debian build files + Fixed security issue with doctored file names + 64 bit compilation fixes +v20070601 + Fixed misc blunders... +v20070531 + Fixed lots of minor items raised by gcc4 + Merged some of the BSD patches + New version of amuFormat.sh written in sh rather than csh + Support for config parameters after -i file + Released 3.9.11 +v20070411 + Added sizecode printing on minfo + In mformat manpage, use same flag for sector number than printed in + minfo + Limit sizecode to 6, else it will overflow max sector size defined in + msdos.h +v20070308 + Applied mingw patch by Jamey Sharp and Josh Triplett +v20070306 + Fixed doc about /etc/default +v20070305 + Fixed mlabel on read-only disks +v20060626 + Merged Redhat/Fedora patches +v20060531 + #ifdef linux-dependant code in mformat.c +v20060525 + Fix gcc4 warnings + Fix reading of boot sector (block size) +v20060228b + Do no longer open floppy devices with O_EXCL, in order to enable + work-around against broken cache. +v20060228 + If no info dir exists at all, assume dir +v20060227 + Support for DESTDIR +v20051011 + Fix Unix loop +v20050410 + Cygwin compatibility +v20050317 + Solaris 8 compatibility +v20050302 + Released 3.9.10 +v20050228 + Support for multiple drives in floppyd +v20050213b + Updated .spec file +v20050213 + Fixed some long name directory entry freeing bugs +v20040505 + Fixed duplicate FAT writing error. Fixed segfault on short images. + Mformat creates images of correct size. + CYGWIN compatibility (O_BINARY flag). +v20040420 + Cygwin patch for plain_io.c (no locking) +v20040228 + Fix a couple of memory leaks in config file parsing. Fix llong.h + (redefined same symbol twice) + Fix a variable initialization problem in plain_io.c + New mclasserase command to erase memory cards + C99 "compatibility" +v20030718 + Fix rootskip and rate of XDF disks +v20030705 + Fix inverted IS_MFORMAT_ONLY conditon in plain_io.c +v20030609 + Moved putc after variable description (anybody knows about a -W + flag so that gcc warns about these?) +v20030606 + Fixed mattrib -p (missing slash) +v20030605 + Added -m option to mformat to specify a non-standard mediabyte +v20030524 + Added -d options to mformat to specify number of FAT copies. Can + also be set using the MTOOLS_NFATS environmental variable. + Also added similar env variable for root directory length + Signed/unsigned fixes, to satisfy increased pickyness of gcc ;-) + CYGWIN fixes for mcat + floppyd bugfixes +v20030213 + Released 3.9.9 : Identical to pre-3.9.9 except for the version number +v20030213 + Released 3.9.9 Pre-1 + Fixed max numbers of sectors for FAT12 and FAT16 (was off by one...) + Improved fat_len calculation + Fixed plain_io.c bug (Swap byte applied after partition stuff, + instead of before) +v20030118 + Fixed mcat end-of-file bugs (mcat went on writing, and writing, + and writing, even after end of file) +v20030105 + If "standard" CHS specified, but non-standard root dir size do not + use table-lookup based geometry ("old-dos media descriptor") +v20021118 + David's new uz script, that can use commands other than gzip for + compression +v20021116 + Fixed vold support for mpartition +v20021105 + Added PACKED to unicode_char declaration (Arm) + Mpartition can now create the image if -I is specified. +v20021104 + Support for geometry-less Atari disks + Support for byte-swapping disks +v20021102b + Avoid .(l and .)l in generated man pages +v20021102 + -i flag + Fix mformat for 2m + Fix [] wildcard off-by-one error + Avoid overwriting (Unix) file by itself in mcopy + Avoid cloberring any file if implicit target is used (the + one-argument syntax of mcopy) + Added Zip 750 entry to mzip.c + SCO Scsi fix +v20020125 + Fixes for cygwin + Fixes in buffer.c for oddly sized image files + Mformat.c fixes to avoid makeing images which would not be + readable in windows. +v20010908 + Warn for invalid partition numbers +v20010526 + Released pre6-3.9.8 : getting rid of linux-gnu references is + almost as difficult as exorcising the devil... +v20010526 + Released pre5-3.9.8 after fixing a couple of version numbers +v20010526 + Applied Adrian Bunk's patches, minus the Stallmanisms. + De-stallmanized config.gues and config.sub files + pre4-3.9.8 +v20010521 + Fixed DELMARK translation of mcopy's -T option, pre3-3.9.8 +v20010521 + Fixed #ifdef DEBUG statements, pre2-3.9.8 +v20010520 + Released pre-3.9.8 +v20010507 + Updated config.guess/config.sub to support Darwin + Patch for converting contents of files from/to Dos' version of + 8bit Ascii + Fixed bug in to_unix function +v20010330 + Updated freebsd floppy device definitions +v20010325 + Fixes for floppyd to work with current protocol version of floppyd +v20010325 + Fixed parsing of Unix filenames ending with slash +v20010325 + Fixed file closing of floppyd +v20001213 + Fixed a cindex entry in documentation +v20001113 + Rewrote PDF rule to use pdflatex, rather than go through dvi + (pdflatex output looks nicer) +v20001113 + Fixed JAZ Zip file overwrite bug (actually, this bug could occur + on any disk reasonably full...) +v20001018 + Fix mzip manpage to include Linux in the list of supported OS'es +v20001009 + Protect against division by zero when reading BSD disks... +v20000829 + Documentation fixes +v20000820 + Hurd openflags fix in mainloop.c + Added description for t option to mcopy man page + Added -lbsd to list of libraries to be tested for LynxOS + Unset LANG in mkmanpages + Updated config.gues/config.sub + Removed stale documentation for xcopy + Fixed typo in mformat man page +v20000810 + Zip 250 support in mzip +v20000708 + Floppyd robustness +v20000703 + Variable initialization in mdir.c +v20000623 + Do not use offset_t on AIX ==> broken +v20000610 + Large disk fixes, especially for Solaris +v20000601 + Released Mtools-3.9.7 +v20000528 + Mtools-pre2-3.9.7 released: some potential buffer overflows +v20000521 + Mtools-pre-3.9.7 released +v20000520 + Added devices for OpenBSD (the previous NetBSD/OpenBSD where wrong + for OpenBSD) +v20000517 + Fixed a couple of floppyd bugs +v20000514 + Added texclean to make distclean, added new "pdf" target. +v20000510 + Did away with ipaddr_t and replaced it with IPaddr_t which is + guaranteed not to crash anywhere... +v20000509 + Defined geometry for default a: devices on Linux and Solaris with vold +v20000502 + Carefully navigate Solaris' polluted namespace... +v20000501 + Suppressed bogus error message when mcopying to an existing file. +v20000429 + Fixed mformat problem with Fat32 (mformat didn't initialize the + label and fat type fields in the boot sector, and the other mtools + utils didn't check them) +v20000428 + Fixed two more scandisk problems: + - the infosector should end with 0x55aa + - When deleting a file, be sure to DELMARK the VSE's as + well as the main entry +v20000428 + Fixed an evasive Fat32 bug: a parent directory entry pointing to + the root should have an address of 0 instead of the more logical 2 +v20000416 + Corrected mdir error handling + Fixed a bug in mren (problem when renaming short file names) +v20000412 + Corrected a typo in error handling +v20000410 + Fixed size problem with Ctrl-Z. +v20000401 + (No joke): avoid setting volume serial number on "Old Dos" disks +v20000320 + - Re-aligned command line options with Dos + - New -n/-N option for mlabel to change volume serial numbers + - Mattrib -p escapes file names in order to handle file name + containing spaces + - Changed mformat serial number format +v19991121 + Fixed 2 bugs: + - Mtools would never completely use all directory slots, because + it overestimated space consumption by 1 + - Mtools did not initialize the stat struct for pipes, and thus + gave occasionnally bogus "Disk full" error messages +v19991011 + Rearranged tty open call so that it is only opened when actually + needed +v19990807 + Added special case for 0xf7 media descriptor +v19990729 + Make O_NDELAY conditional everywhere +v19990715 + Return correct return value from mt_lseek, even if off_t is a 64 + bit quantity +v19990712 + Treat OpenBSD the same as NetBsd +v19990630 + Released 3.9.6 with the following fixes: + - Typoes in xdf_io.c + - Make Xdf work in nodma mode + - Fix for mformatting MSS disks +v19990628 + 1st attempt to release 3.9.6 with mostly minor fixes: + - platform compatibility + - automatic installation of info files + - mdir's -X flag no longer implies "recursive" +v19990419 + 3.9.5 released with mostly minor fixes: + - Starting cluster numbers of "." directory entry + - Copying of empty Files from Dos to Unix + - Misc platform compatibility issues +v19990315 + Another embarrassing bug found, 3.9.4 released. When will this + nightmare stop? +v19990314 + Mtools 3.9.3 released +v19990314 + Open BSD SCSI fixes & added GLIBC linux/unistd.h for llseek. These + Glibc problems are potentially dangerous, and can lead to data loss. +v19990314 + Mtools 3.9.2 released +v19990310 + Fixed typo in plain_io.c +v19990307 + More rigor about signed vs unsigned issue. FreeBSD Scsi support +v19990223 + Allow for 2GB Jaz drives +v19990218 + Rewrote floppyd in C instead of C++ +v19990208 + More buffer fix +v19990112 + Buffer fix +v19990111 + "Big disk" fixes +v19990104 + OS/2 patch +v19981211 + Make sure that fat_type doesn't overwrite byte 62 with zero => + disk unbootable +v19981204 + Added support for "replay" listing of mattrib. Cleaned up version + number and date handling (date was not always accurate...) +v19981204 + Added geometry autodetection code for Linux harddisks to + mpartition and mformat. Removed misleading references to + "non-removable media" +v19981203 + Added boot sector template option for mpartition. Fixed mtools.1 + man page. Mattrib -s e:/ fix +v19981031 + Man pages bug fixes +v19981029 + Fixed HP SCSI "big write" bug +v19980701 + Fixed debug mode in vfat.c +v19980629 + A few minor floppy related fixes (installation, and replacement + for setenv function, which is absent from some platforms) +v19980523 + Added floppyd (remote access to floppy disks) +v19980522 + Updated mkmanpages script to dynamically get date and mtools + version. Correct "removable media" error message to talk about + /etc/mtools.conf instead of /etc/mtools. Do init_geom to read + geometry if no geometry is set. +v19980514 + Mtools 3.9.1 released +v19980503 + Mformats makes disks which are readable both as partitioned and as + plain +v19980405 + Corrected Tim Hoogasian's e-mail address +v19980404 + OS/2 additions +v19980331 + "Dirty end too big" mformat bug corrected +v19980330 + Corrected typoes for IRIX devices, use macros for attribute types, + fix 0 length file bug. +v19980327 + Loop detection code + Bigger array for SCSI command +v19980323 + GLIBC portability +v19980322 + OS/2 portabilty, GLIBC portability +v19980320 + Fixes related to Solaris new vold support +v19980317 + Fixed a few BSD typoes, and renamed ALLCFLAGS in the Makefile to + CFLAGS for those makes that don't support implicit rules well enough +v19980310 + Mtools 3.9 released +v19980308 + Various Bugfixes (overwrite mode and directory cache) +v19980301 + Added mformat_only flag. +v19980130 + Fixed non-batchmode mcopy bug. Fixed shortname case bug +v19980130 + Minfo and mformat boot program bug fixes +v19980120 + Allow default block sizes per device which are not equal to 512 +v19980108 + Allow and interpret back quotes in file names +v19980101 + Misc bugfixes +v19971231 + Scandir optimizations. Fixed nasty Heisenbug in hash.c. +v19971229 + Fixed integer width problem in fat.c, and minor bugs in hashtable. +v19971222 + More performance optization. Buffer handl + ing redone. New + "asynchronous mode". +v19971216 + Fixed mtype and mcheck. Started cleaning up out-of-memory handling +v19971215 + Jacked up performance, and corrected signal handling bugs. Also + corrected various "Disk full bugs" +v19971212 + Fixed "Bad address" errors which occured when running mdu on empty + files. When copying recursively, do not barf if a directory + already exist at the target. Mcopy operates silently by default. +v19971212 + removed mwrite. Obsoleted long ago by mcopy +v19971211 + fixed mdir -X, added mattrib -X; document both. Fix doc for name + clash handling +v19971210 + fixed polarity of sys_errlist. Renamed some include files which + bore the same name as system include files. Fixed another + memory leak in dir_grow. A/UX termio workaround. +v19971209 + fixed filedescriptor leak. Make mbadblocks stoppable. Doc + fixes. Fixed one memory leak, another one further down the road + remains... Fixed error handling in createDirectory. +v19971208 + bugfixes: mbadblocks, fat, unix quit, null pointers in mcopy... +v19971205 + Renamed it to pre3-3.9 due to mixup when shipping the pre2-3.9 + version. No actual code change apart from patchlevel.h +v19971204 + Pre2-3.9. Added mpartion manpage. Added misc.o dependency to + mkmanifest. Fixed mpartition bug with partitions with more + than 1023 cylinders +v19971129 + Pre-3.9. Redid the mainloop logic, and got rid of lots of cruft + in subdir.c and parse.c. It is now possible to put wildcards in + the directory part of the filename. Design also became simpler, + making it easyer to maintain this part in the future. + Added a -u flag to mzip to temporarily unprotect a disk + Added a test to mzip to prevent manipulation of mounted disks + Added support for partitioned devices in mmount +v19971116 + Added mdu and recursive mdir +v19971112 + Fixed bugs in recursive copy stuff, added recursive mattrib, and + fixed a few buffer overrun bugs +v19971110 + Added recursive copy and attribute conservation flags to mtools +v19971029 + Fix parse.c typo +v19971013 + Include Sys5 directories on SunOs in order to have a correct + timestamp + Detect Lilo disks +v19971006 + Correct vold typo +v19971002 + Use 8 sector clusters for 32-bit FATs: this is what Micro$oft user +v19970823 + Corrected gross bug in fat12_decode +v19970823 + Simplified fat bits handlings +v19970820 + Raw Scsi_io for SGI +v19970813 + Buffer.c and FAT bugfixes +v19970813 + More FAT32 fixes. New mshowfat command. +v19970813 + Fix FAT32 problem (FAT32 does not use the high nibble) +v19970812 + Detect presence of sys_errlist using autoconf instead of + making its usage dependent on BSD. + Fixed make texclean. + Guard against corrupted "next free block" pointer in a FAT32 + InfoBlock +v19970715 + Use root priviliges during scsi_init +v19970714 + Fixed close-on-exec bug. +v19970714 + Fixed #include in HP_UX. Sys/floppy.h is not known on all flavors + of HP_UX +v19970713 + Fixed Makefile so that make -j works without errors. Fixed + upper/lower bug in mmount +v19970708 + Released 3.8 +v19970629 + Add option to mformat to keep boot sector, or to read it from + a file. Added various flags to customize directory listing + appearance and long name behavior +v19970629 + Fix bug in yesterdays fix. Also make sure to resize hash + table if too many deleted entries accumulate. +v19970628 + Fixed yet another hash table bug +v19970619 + Yet another HPUX fix. +v19970619 + Fixed a segfault in mpartition +v19970617 + Removed a few Stallmanisms in config.guess +v19970612 + 3.7 released +v19970611 + Corrected a few errors in new vold code +v19970610 + Removed extra &'s from string addresses. + Added listing of current configuration to mtools -V + Updated version number and date in mkmanpages +v19970604 + New Bebox patch. Removes almost all BEBOX specifities because + they are no longer needed with the new DR9 release. + Small fix for size detection of SCSI disks. +v19970524 + Fixed small typo in new vold code +v19970524 + Added partition consistency checks for accessing device. +v19970523 + New version of Solaris vold code +v19970516 + Solaris floppy geometry. Support for older MO disks (size + returned in non-standard location) + Corrected ftp address for fdutils +v19970504 + Updated README.BEBOX +v19970504 + Brought Makefile.Be and config.h.Be up to date with the recent + changes +v19970504 + Add Ultrix to the list of OS'es which do not define their + prototypes + Small Makefile fix +v19970503 + Various "Next proofintg". + * add VENDOR_, CPU_ and OS_ before machine type tags + detected by autoconf. Next tends to be a frequently + used variable + * use utimes preferably before utime + * try to include _all_ termios functions. + * more precise detection of available termios functions +v19970501 + Added knowledge of Zip Tools Disk password to mzip. +v19970429 + Went back to using ALLCFLAGS in Makefile for those people who + want to override CFLAGS +v19970426 + Added note about Alpha site to doc. +v19970423 + Prefer termios.h on Ultrix +v19970422 + Renamed missing_functions to missFuncs in order to accomodate + operating systems with file name size limits. +v19970420 + Autoextend size for images that are too small. Moved BSD + dependant #ifdef's after the inclusion of sys/param.h, as it + is there where BSD is defined (sigh!) +v19970419 + Insist on the fact that mzip's -f flag only makes sense if + given in addition to -e +v19970419 + Corrected typo in doc. +v19970417 + Removed read and write prototypes, they conflict on an Alpha! +v19970414 + More HP/UX fixes. +v19970414 + 3.6 released +v19970414 + Do not stat any files in /dev/ on BEOS. Remove spurious system + include files from non-sysincludes.h file +v19970413 + Fixed Zip disk eject +v19970412 + Added Sunos4 and SCO support to scsi.c. Use tzset before + gettimeofday, except for BSD. Use Z: for a Zip drive, and J: + for a Jaz drive instead of D: for both. Added machine + specific libraries and CFLAGS for A/UX. +v19970410 + Various A/UX fixes. Changed scanning order for termio and + termios due to problems with the other order on A/UX. +v19970405 + Print error message for wrong password. +v19970405 + Include mzip man page +v19970404 + Document new config flags introduced in 970204. + On systems not supporting euid, do not bail out if both euid + and ruid are 0. +v19970404 + Prevent mmove from moving directories into themselves in order + to keep a tree-like directory structure +v19970403 + Fixes for mtools_no_vfat +v19970402 + Additional config file pointed by MTOOLSRC; possibility to + switch off generation of VFAT long names. +v19970401 + HP/UX setresuid support. "Mcopy a: ." bugfix. +v19970331 + Renamed f_* functions into file_* in order to avoid a clash + with a preprocessor macro named f_data on AIX. +v19970323 + Released 3.5, Solaris compatibility fix w.r.t. memmove +v19970323 + Released 3.4 +v19970319 + Fixed location of configuration file in doc. +v19970318 + Fixed mlabel bug +v19970316 + More BSD & 64 bit changes +v19970308 + Added at_exit implementation for those boxes who have neither + on_exit nor atexit. Added check to make sure the compiler + handels structures in a sane way. +v19970307 + Backed out again of the traditional-cpp change on + larry.jones@sdrc.com's advice +v19970306 + Added traditional-cpp in order to make mtools compilable on a Sun +v19970304 + Fixed nolock flag +v19970227 + BEOS fixes and support for SCSI devices with a sector size + different from 512. +v19970225 + Fixed some preprocessor macros. Added texclean macro to Makefile +v19970224 + Clarified the documentation about the Bebox. +v19970224 + Released 3.3 +v19970220 + Made Makefile "AIX-proof". Added precmd to config.c +v19970219 + Fixed typo in mdel. +v19970217 + Osf4 support. Released 3.2 +v19970216 + Fixed Makefile typo, and fixed various bugs with renaming or + moving dot or dot dot +v19970215 + Fixed streamcache.c bug +v19970214 + Added add-disk script and format.dat file +v19970214 + Fixed mrd e:xxx/, tested Xdf support +v19970210 + Strange mformat fixes... Dos always seems to assume a cluster + size of at least 8 sectors and 512 root directory entries. Sigh! +v19970209 + FAT32 support, BeOS patches +v19970208 + Added more debugging code to mpartition and minfo. Added + "packed" attribute to the partition structure. + Cleaned up argument handling. +v19970207 + Fixed partition removal bug in mpartition.c +v19970206 + Fixed streamcache allocation bug. Clearer error message when + trying to access a non-existant partition. +v19970205 + Added "packed" attribute to some fields of the vfat_subentry + structure, in order to work around a bug in a gcc version for + SunOS. + Use getpass() for password prompting in mzip.c +v19970203 + Various small bug fixes +v19970202 + Fixed typoes in plain_io.c, mpartition.c and mtools.texi. + Relaxed security in mpartition.c, so non-root users may print + a partition, or perform any local changes to it. + Mpartition now prints info to recreate partition. +v19970201 + Add mpartition command to partition Zip, Jaz and other Scsi + devices. + Chose between on_exit or atexit using autoconf. +v19970130 + Added minfo command to print disk geometry and other parameters. +v19970129 + Replaced atexit by onexit. Atexit barfed on SunOs. + Replaced O_RDWR flag in mzip with O_RDONLY. + Added precmd variable to execute commands before opening a + given drive. +v19970127 + Shortened README, segregated config file pathnames into a + separate file. +v19970125 + General cleanup, more enhancements to privilege handling. +v19970123 + Added debugging output to mzip. + Made expand.c safe and still compatible with suid operation. + Fixed mzip typo. + Made device locking optional. +v19970122 + Added const qualifiers +v19970120 + 3.1 Released +v19970116 + Added kludgy xcopy support +v19970111 + Only skip sys_errlist declaration on NetBSD (some older + platforms might need this) +v19970110 + Upgraded to autoconf 2.12, fixed some Stallmanisms. + Added device entry for LynxOs. +v19970107 + Use gettimeofday before tzset (for BSD). +v19970107 + Use correct location of signal.h. Removed declaration + for sys_errlist. +v19970107 + BEOS patches by Marco Nelissen + Removed some clashing prototypes +v19970103 + Prints privilege debugging message to stderr, and reopens SCSI + file with root privileges. +v19961227 + Fixed typoes in mzip. Added pointer to html doc. +v19961226 + Fixed Linux Scsi ioctl. +v19961225 + Added warnings against cookies, fixed doc to reflect new set-uid + policy. +v19961224 + Fixed typoes in privilege routines, and removed Heisenbergian + parts of the debugging code. +v19961223 + Deleted prototypes for random() and srandom(): they *did* + clash (on a DEC Alpha) +v19961222 + Solaris & SunOS privilege management. Fixed date entries in + ChangeLog file. +v19961221 + Solaris ZIP fix. +v19961219 + Cosmetic mzip fixes. Add pointer to info doc to mtools.1 +v19961219 + ISC addition. Doc fix for set_parameters ioctl. +v19961217 + Mformat doc fix. +v19961216 + Replaced zip_* by scsi_*, as these functions are not + specifically relevant to the ZIP (they apply to the JAZ as + well) + Fixed documentation on -n flag for mcopy +v19961217 + Include termio before termios because of SCO + Applied Jaz patch + Do not declare timezone external variable on Ultrix, where it + has a different type. +v19961215 + Changed floppy into rfloppy for HP/UX. +v19961214 + Added -Q option to mcopy, which aborts copying multiple files + as soon as an error for one file is encounteres + Removed useless -i option for mcopy + Small devices.c portability fixes (ultrix and hpux) +v19961211 + Added mzip (eject ZIP disks) (Markus Gyger ) + Renamed mtest to mtoolstest to please pine. +v19961210 + Added warning about running mtools with root privs. +v19961209 + Fixed unitialized variable in fat.c and added example for Sun + mtools.conf +v19961209 + Fixed comment in scripts/tgz +v19961207 + Fixed partition handling code (yes, again!) + Added code to handle ZIP disks on Solaris/SunOS (many thanks + to James P. Dugal (jpd@usl.edu)) +v19961203 + Proper permissions for main directory. +v19961202 + Renamed scripts/gz to scripts/tgz +v19961202 + Added raw devices for Solaris, apparently more performant + Test first for tzset in autoconfigure (Solaris) +v19961202 + Segment fault due to change of buffer size fixed + E-mail adress fixed +v19961117 + Lots of portability fixes. +v19961012 + Yet another typo fix for the partition table code. Oh Gawd, + will this never stop? + Fix for proper .mcwd pathname concatenations +v19961009 + Backed out partition table "fix": the original code was right + after all +v19960920 + Corrected a few uninitialised variables +v19960918 + Corrected doc about devices file. +v19960917 + Added pointer to the doc to the README file +v19960913 + Partition table parsing fixed +v19960807 + Fujitsu DS/90 (UXP) support +v19960727 + ISC device + dispatcher cleanup in mtools.h + fat_bits 12/16 toggle fix. + More space for error message variable in mformat + Typo fix in mren.1 +v19960710 + Fix for CPU names with dots in autoconfigure + Some new device descriptions + FreeBSD fixes +v19960624 + Set XDF mode when formatting an XDF disk (makes sense, after all...) +v19960623 + XDF seems to work. Yeah! +v19960620 + More ED fixes. More parameter size fixed for 64bit. +v19960609 + Beginning of ED and 5 1/4 HD XDF support (doesn't work yet for + ED) +v19960528 + Make vold and "raw" floppy drive accesible simultaneously on + Solaris by calling one A: and the other B: + Add missing mbadblock LINK in Makefile.in +v19960527 + Inserted missing newline character +v19960525 + Treat number of heads or sectors as chars. The BIOS wouldn't + allow bigger numbers anyways, thus big numbers are probably + due to errors. +v19960524 + Pattern match fix. + Geometry setting for HP/UX +v19960522 + Changed auto array in codepage to malloc'ed one in order to + work around buggy compilers + OSF ALPHA devices + Pointers to other doc in the INSTALL file +v19960516 + Do no longer be confused by deleted VSE's + Define MAXPATHLEN for SCO + Missing lockf prototype for SCO +v19960514 + Handle DEBUG flag by autoconf + Added Host vendor to compile flags in order to handle Sinix + Better Sinix handling in devices.c + Only print duplicate VSE messages when running with DEBUG + Fix mlabel exit code + Read-only locking + Doc fixes + Xcopy fixes for Sysv +v19960512 + 3.0 released. +v19960508 + pre4-3.0. Lots of bug fixes. Texinfo file +v19960502 + pre-3.0 +v19960501 + use autoconf to get rid once and for all of those pesky OS + dependencies. +v19960429 + use sys/termio instead of sys/termios to please AIX +v19960427 + more spelling fixes. +v19960426 + Speling fixes +v19960424 + Mmount arg parsing bug fix +v19960422 + New partition configuration variable. +v19960419 + Spelling fixes, removed warning in README, IRIX floppy devices +v19960214 + More Alpha streamlining +v19960213 + Alpha patches (64 bit clean-ness) + AIX patches (built in drive names) + Raw tty patches (no need to type return when confirming an action +v19960131 + Solaris patches + Replaced include strings.h by string.h everywhere where applicable + Changed thousands separator in mdir from a dot to a space to + please both Americans and Europeans. + Fixed memory allocation bug if no "constant device" is present. + #defined strtoul to atol for SunOS +v19960121 + Minor cleanup, released 2.5.4 +v19951205 + Added "magic" header to manpages to have man run them through tbl +v19951209 + MTOOLS_LOWER_CASE is back, various small bug fixes over + Tuesday's changes +v19951205 + Bus strike in Grenoble! Well, let's do something useful and + re-arrange the configuration file syntax :-) + The syntax has become much more flexible now, and also + includes items which used to be only accessible via + environmental variables. + Moreover, it is now possible to include character translation + tables in line. +v19951126 + Fixed another Atari disk bug: Atari disks sport a bogus + "number of hidden sectors" +v19951125 + Fixed missing zero-terminator in autorenamed long names + MTOOLS_SKIP_CHECK now implies MTOOLS_FAT_COMPATIBILITY. +v19951124 + Fixed small quoted-printable-induced typo in the Makefile. + + Folks, please don't use quoted-printable. It sometimes changes + the CONTENT of your messages. Even the MIME RFC's acknowledge this. + Case in point: £400 gets transformed into =A3400, which looks + like 3400 pounds to a person unaware of this MIME "feature". + +v19951123 + Mformat now puts a 12 bit FAT on ED to better match Messy DOS' + behavior. +v19951115 + Added ability to do mcopy e: to copy all files from the root + directory of e: + New Xdf-less Linux target in the Makefile + Relaxed sanity check to let pass wonky Atari disks whose FAT + begins with 3 zero bytes. + Make the check of the initial fat bytes conditional on + mtools_skip_check + Corrected "testna=" bug + Upped minimal sector size to be 256 (instead of 128). This + helps 2m30 +v19951112 + 2m30 compatibility + Manpage update + 2m checksum bug fix + Ability to mformat 2m disks +v19951107 + Xdf bug fix (dev parameters always set to Xdf, even if it + wasn't really an Xdf disk) + Fixed YAHB (yet another hash table bug :) ) . Hope this one's + the last. + Centralizing most env-var handling. + Update of the mtools manpage. + Xdf is now optional, and only active if MTOOLS_USE_XDF is + set. Saves a few milliseconds of startup time on non Xdf + disks. + Some lawyer-proofing, just in case :) +v19951106 + Fast xdf code (finally!) + Minor performance enhancements here and there. + Names which are all lower case now generate a long name entry + (according to Steve Searle, that's how Win'95 behaves). +v19951029 + Character translation table fixes. Other name fixes. +v19951026 + Put restrictions on long names to better match Win'95. + (suggested by Steve Searle) + Reworked autorename code. Catch SIGHUP signal + Added missing file close to main loop + Changed name of the "ask for action" command line flag to 'm', + and used 'a' for 'Autorename'. +v19951024 + Removed infinite loop bug in hash.c, which occurred when the + hash table was filled with deleted entries. +v19951023 + added Atari ST-style serial numbers (they live in the banner) + fixed a troff bug in mtools.1 + Both changes were suggested by D. Hugh Redelmeier (hugh@mimosa.com) +v19950916 + v2.5.3 released (after lots of fixes) +v19950904 + v2.5.2 released +v19950904 + mdir.c: initialized "files" and "blocks" to avoid complaint by GCC + mattrib.c: initialized "code" to avoid complaint by GCC +v19950904 + Based on comments by Paul Slootman : + init.c: fs_init(): initialized disk_size to 0. The section + which previously initialized this is ifdef'd out. Why? + Makefile, device.c: Passed ETCDIR (e.g. /etc or /etc/default) + Gee, the Makefile is pretty ugly! It might be good to start + thinking about autoconfigure, or at least some cleanup. + Makefile, mformat.c: use -DSOLARIS2, use srand48()/rand48() + msdos.h, file.c, mdir.c: prefixed YEAR/MONTH/DAY/HOUR/MINUTE/ + SEC with DOS_ to avoid conflicts with on SVR4 + devices.c: use %i instead of %d to allow different bases + parse.c: Changed comment for get_name()/get_path(); need to + revisit this after deciding on default case behavior + devices.c: load_devices(): fixed bad fprintf, line 748 + parse.c, mformat.c, misc.c: replaced expressions like + "if (islower(foo)) foo=toupper(foo)" with "foo=toupper(foo)" + +v19950829 + v2.5.1 released + +v19950829 + Based on comments by Martin Kraemer : + Bug fixes for compile errors and core dumps under SINIX-D 5.41 + (Siemens SVR4): + plain_io.c + mk_direntry.c + vfat.h + +v19950822 v2.5 released + +v19950820 DCN + Change null-fill for unused remainder of VSE to 0xff fill for + both upper and lower character (just one null for termination) + This seems to better match Win95's behavior; Win95 had been + complaining about bogus characters + file_name.c: unicode_write() + +v19950820 DCN + Commented out enforcement of VSEs being in order. Win95 likes + to put them exactly backwards, so we'd better tolerate getting + them any way they might come! Not sure what is lost by losing + these checks, but it seems to be OK. + + directory.c: dir_read() + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/README b/README new file mode 100644 index 0000000..9befffd --- /dev/null +++ b/README @@ -0,0 +1,76 @@ +Compilation +----------- + + To compile mtools on Unix, first type ./configure, then make. To +compile mtools on a Bebox, refer to README.BEBOX. + +Doc +--- + + The most uptodate doc of this package is the texinfo doc. Type 'make +info' to get online info doc, and 'make dvi ; dvips mtools.dvi' to get +a printed copy. The info doc has a concept index. Make use of it. + You may get an info copy using the following command 'make info'. +This can then be viewed using emacs' info mode, or using a standalone +info viewer. + Man pages are still present, but contain less information. + If you do not have the necessary tools to view the texinfo doc, you +may also find it on the World Wide Web at the following locations: + http://ftp.gnu.org/software/mtools/manual/mtools.html + +Compiler +-------- + + Mtools should be compiled with an Ansi compiler, preferably gcc + +Authors +------- + +Original code (versions through 2.0.7?) by Emmet P. Gray (Texas, USA). +Viktor Dukhovni (at Princeton, USA) had major input into v2.0. + +Since 2.0.7: maintained primarily and until now by Alain Knaff +(Luxembourg) and David Niemi (Reston, Virginia, USA). + +Please report bugs to the mtools mailing list at mtools@www.tux.org. +Before reporting any problems, check whether they have already been +fixed in the Alpha patches at http://mtools.linux.lu and +http://www.tux.org/pub/knaff + +You may subscribe to the mtools mailing list by sending a message +containing 'subscribe mtools' in its body to majordomo@www.tux.org + +Since March 3rd 2009, mtools is now officially a GNU package. Special +thanks to Emmet P. Gray, the original developer of the program, who +supported dubbing mtools a GNU package. + +Current Status +-------------- + +Stable release 4.0.x + +Copying +------- +Mtools is a GNU program published under GPL v3.0 (code) and GNU Free +Documentation License. + +Most files of mtools bears a notice describing the copyright, and +whether it is covered by GPL or GFDL + +GPL: + +debian/control Copyright 2007 Alain Knaff + +debian/changelog Copyright 2007-2009 Alain Knaff + +NEWS Copyright 1995 David C. Niemi + Copyright 1995-2009 Alain Knaff + +mtools.spec Copyright 2003-2005,2007-2009 Alain Knaff + + +GFDL: + +README Copyright 1996-1998,2001,2002,2009 Alain Knaff. +Release.notes Copyright 1995 Alain Knaff + diff --git a/README.BEBOX b/README.BEBOX new file mode 100644 index 0000000..29e6bfa --- /dev/null +++ b/README.BEBOX @@ -0,0 +1,126 @@ +% Copyright 1997 Marco Nelissen. +% Copyright 1996-1998,2001,2002,2009 Alain Knaff. +% This documentation is for Mtools which is a collection of tools to +% allow Unix systems to manipulate MS-DOS files. + +% Permission is granted to copy, distribute and/or modify this document +% under the terms of the GNU Free Documentation License, Version 1.3 or +% any later version published by the Free Software Foundation; with no +% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +% Texts. A copy of the license is included in the section entitled +% ``GNU Free Documentation License''. + + + +NOTE: THIS FILE ONLY REFERS TO THE BEBOX. IF YOU ARE USING UNIX, +REFER TO README. + + +This is mtools 3.6 for BeOS DR9. This release will no longer work on +DR8, which should be no problem since everybody should have upgraded +to DR9 by now. mtools 3.6 can be used as a replacement for the +version 2.0.7 mtools supplied with BeOS. mtools 3.6 supports the VFAT +filesystem (long filenames), which the Be-supplied tools do not. + +To install: + +- build the executables: type "make -f Makefile.Be" in the mtools + directory. Again, this instruction is only for the Bebox, not for any + kind of Unix. They should compile without any warnings or errors. + + WARNING: do NOT rerun the configure script. Although DR9 bash will +no longer lock up when running the configure script, the resulting +files are not entirely correct, and mtools will fail to compile. I +have hand-crafted a config.h that can be used to compile mtools. This +will be used if you just type "make -f Makefile.Be" + +- copy the "mtools" executable (and perhaps also "mkmanifest") to /bin, + or to another directory in your path. + +Since all of the mtools-commands are contained within a single +executable, you must either define aliases for each command, or create +links for them. + +To create aliases, add the following lines to the file /boot/.profile + +alias mattrib="mtools -c mattrib" +alias mbadblocks="mtools -c mbadblocks" +alias mcd="mtools -c mcd" +alias mcopy="mtools -c mcopy" +alias mdel="mtools -c mdel" +alias mdeltree="mtools -c mdeltree" +alias mdir="mtools -c mdir" +alias mformat="mtools -c mformat" +alias minfo="mtools -c minfo" +alias mlabel="mtools -c mlabel" +alias mmd="mtools -c mmd" +alias mmount="mtools -c mmount" +alias mrd="mtools -c mrd" +alias mmove="mtools -c mmove" +alias mpartition="mtools -c mpartition" +alias mren="mtools -c mren" +alias mtoolstest="mtools -c mtoolstest" +alias mtest="mtools -c mtest" +alias mtype="mtools -c mtype" +alias mzip="mtools -c mzip" + + (then close and re-open all terminals and shells, or type +". /boot/.profile" in each open terminal to activate the +aliases. Optional: remove the old mtools from the /bin directory) + + +To create links, open a shell, and type the following commands +(assuming you copied the mtools executable to /bin): + +cd /bin +rm mattrib mcd mcopy mdel mdir mformat mkmanifest mlabel mmd mrd mread mren mtype mwrite +ln -s mtools mattrib +ln -s mtools mbadblocks +ln -s mtools mcd +ln -s mtools mcopy +ln -s mtools mdel +ln -s mtools mdeltree +ln -s mtools mdir +ln -s mtools mformat +ln -s mtools minfo +ln -s mtools mlabel +ln -s mtools mmd +ln -s mtools mmount +ln -s mtools mrd +ln -s mtools mread +ln -s mtools mmove +ln -s mtools mpartition +ln -s mtools mren +ln -s mtools mtoolstest +ln -s mtools mtest +ln -s mtools mtype +ln -s mtools mwrite +ln -s mtools mzip + + +Alternatively, make multiple copies of the "mtools" executable and use +the names mdir, mdel etcetera. + +- if you want more than just floppy support, you need to make a configuration + file. An example mtools.conf.be is included in the distribution. + mtools looks in a number of standard places for its config file, such as: + /boot/.mtoolsrc + /boot/mtools.conf + /boot/system/mtools.conf + By defining the variable MTOOLSRC you can give the config file any name you + like and put it at any location. + + You need to add something like "export MTOOLSRC=/conf/mtools.cfg" to + your .profile file. + + Take care to remove or change the entries that you don't need. The provided + mtools.conf is for unix systems, with some BeOS settings at the end. + The sample entry for a ZIP disk on the BeOS has been provided by + Chris Herborth + (chrish@qnx.com). + + +- enjoy! + +Marco Nelissen +Alain Knaff diff --git a/Release.notes b/Release.notes new file mode 100644 index 0000000..f434b4a --- /dev/null +++ b/Release.notes @@ -0,0 +1,230 @@ +[See Changelog for more recent changes] + +2.5.1 29 Aug 1995 + +Bug fixes to allow compiling and running on SINIX-D 5.41, thanks to +Martin Kraemer . + +----------------------------------------------------------------------------- +2.5 21 Aug 1995 + +First public Alpha Test release of the newly rewritten Mtools. +Summary of the many major changes: + +XDF support, ANSIfication, major restructuring, and debugging (Alain Knaff) +VFAT support, new prompts for overwrites, and debugging (David Niemi) + +----------------------------------------------------------------------------- +Patch #7alk ... 4 Dec 94 + +This patch adds the following features: + + 1) mbadblocks program to mark bad blocks + 2) uses fat_type field of boot block to find out the number + of fat bits. + 3) is able to format hard disk partitions (untested) + 4) sets _all_ standard fields in boot sector, even without 2m mode. + 5) adds boot code to the boot sector (which transfers booting to + the hard drive. In most cases, that's what the user wants.) + +----------------------------------------------------------------------------- +Patch #7alk ... 4 Nov 94 + +This patch adds the following features: + + 1) Use even disk buffer size whenever possible to workaround a + bug in Linux blockdev code [???] + 2) Clearer error message on failed sanity check + 3) Removal of BOGUS Notes file + +----------------------------------------------------------------------------- +Patch #7alk quinter, 2 Nov 94 + +This patch adds the following features: + + 1) O_EXCL flag when opening the device to ensure it is not mounted + 2) Sanity checks to avoid accessing non msdos disks +Both features were suggested by Karl Eichwalder (ke@pertron.central.de) + +----------------------------------------------------------------------------- +Patch #7alk quater, 1 Oct 94 + +This patch adds the following features: + + 1) disk serial number support. + 2) mcheck works for every drive. + +----------------------------------------------------------------------------- +Patch #7alk ter, 10 Sep 94 + +This patch adds the following features: + + 1) mformat works again. + 2) mmount allows the user to pass arbitrary arguments to mount. + Floppy disks are no longer mounted by default on /mount/A /mount/B + etc. + +----------------------------------------------------------------------------- +Patch #7alk bis, 18 jul 94 + +This patch adds the following features: + + 1) Support for variable sector sizes. + 2) Support for "2m" formats. + 3) Support for formatting 16-bit fat disks. + 4) Support for formatting ED disks (Their capacity is too big to + use a 12 bit FAT and 1 sector clusters. Either use bigger + clusters or a 16 bit FAT) + 5) Mcopying from one DOS drive to another works now. (It used to + call mktemp on a non-writable string) + +----------------------------------------------------------------------------- +Patch #7alk, 16 feb 94 + +This patch adds the following features: + + 1) Mtools can now set the disk geometry on Linux. (Useful for + reading 1.72 Mb disks. This was already possible on unixpc and + SPARC ) + 2) New mmount command. Reads the boot sector, sets the geometry + and finally mounts the disk. Only available for Linux. + 3) Mwrite can now write stdout to a DOS file: mwrite - a:test + 4) Mread now also acts as mtype: mread a:test - + 5) Mtools now tries 3 sources to get its drive geometry. + configuration: first ~/.mtoolsrc, then /etc/mtools, and finally + compiled-in. ( The two first are conditional on LOADDEVS being + defined ). LOADDEVS is now compatibles with the various geometry + setting routines (init_linux, init_sparc and init_unixpc). + 6) Bug fixes for -t mode of mwrite and mread. ( For certain file sizes + the trailing DOS end-of-file character wasn't correctly written.) + 7) Bug fixes for "drive probing code." (Now failure to lock onto a disk + causes always trial of the next configuration. Before, mtools used + to abort on certain cases). Similar fixes in mformat. + 8) Optimization/bug fix of cluster/fat repartition in mformat.c + 9) Made fat checking code optional. (1.72mb disks mformatted with old + mtools were almost always rejected) To bypass fat-checking set the + environment variable MTOOLS_FAT_COMPATIBILITY + 10) Mtools now opens /dev/tty to ask for confirmation messages. This + way, it doesn't interfere with mreading/mwriting from/to stdin/stdout. + + +CAUTION: I only tested this with Sparc and Linux. Although I left #ifdefs +for other OS's in devices.c, that doesn't mean that it works on these OS's. + +----------------------------------------------------------------------------- +Patch #7+, 19 sep 93 + +This patch merges in the mods against 2.05 under Linux. Two are the main +changes: that all commands are linked as a single executable, which can +be linked as different name, and that the device specs are no longer +hardcompiled but are read dynamically from /etc/mtools (the latter change +is conditional on LOADDEVS being defined). + +----------------------------------------------------------------------------- +Patch #7, 6 Sep 92 + +This patch will change the method of determining if the FAT encoding +scheme in the devices.c file is correct. The method introduced by patch +#6 was naive and easily fooled. + +A pre-processor variable called CHK_FAT has been added to the fat_read.c +file just in case this new method isn't appropriate for all disks. + +----------------------------------------------------------------------------- +Patch #6, 21 Aug 92 + +This patch will add the following features: + + 1) Mtools commands now use advisory locks to preclude two + processes from writing to the same DOS filesystem. You must + edit the Makefile to choose one of the 3 lock methods: + -DLOCKF, -DFLOCK, or -DFCNTL. + See the Configure file for more details. + + 2) An error detection routine has been added to determine if the + FAT encoding scheme in the devices.c file is correct. + + 3) Mtools commands now return exit codes with the following + meaning: + 0 = success + 1 = utter failure + 2 = partial success/failure. (at least one successful + operation, but at least one failure) + +It also corrects a bug when Mtools is used on machines that have 16 bit +integers. However, machines with 16 bit integers are limited to FAT +tables that are less than 64k in length. +------------------------------------------------------------------------------- +Patch #5, 25 Aug 91 + +This patch will add a few new features: + + 1) Mtools will now work properly on MSDOS partitions that are + greater than 32M. + + 2) If the "current working directory" information (contained in + the $HOME/.mcwd file) is more than 6 hours old, Mtools will + issue a warning and ignore the old information. + + 3) The mcopy command will now copy files between 2 MS-DOS file + systems (such as mcopy "a:*" b:). + +------------------------------------------------------------------------------- +Patch #4, 11 Apr 91 + + This patch will fix a bug in the mmd command where directories + inherited the file name extension of the parent directory. It + also adds a feature that will allow the copying of zero length + files. + +------------------------------------------------------------------------------- +Patch #3, 28 Nov 90 + + This patch will fix a bug where Mtools sometimes bypasses the + disk "cache" and reads/writes to the disk directly. + +------------------------------------------------------------------------------- +Patch #2, 21 Nov 90 + + This patch will fix a bug in the folding of MS-DOS filenames to + lower case, and will fix a bug that could prevent the detection + of a full disk. + +------------------------------------------------------------------------------- +Patch #1, 12 Oct 90 + + This patch will fix a few problems on Berkeley flavors of Unix, + and will fix the floating point exception bug when Mtools is + used with diskettes that have been formatted under very old DOS + (or formatted by some other non-DOS system). + +------------------------------------------------------------------------------- +New in the v2.0 release.... + + 1) Support for multiple devices. Mtools now supports: + multiple floppy disks (A:, B:, etc) + DOS partitions on a hard disk + DOS "images" such as those VP/ix uses. + + 2) Wildcards are supported anywhere in a pathname (not just + in the "filename" part as before) + + 3) Reads and writes to slow devices are now "cylinder buffered" + when appropriate. + + 4) Versions of CD, FORMAT, LABEL, and ATTRIB have been added. + + 5) A Mtools.1 manual page has been added for an overview of Mtools. + + 6) The mkmanifest command has been added. Although not an 'mtool' + command, it makes life easier when fixing up Unix filenames that + get clobbered by MS-DOS file name restrictions. + + 7) The mkdfs program of the "fast-mtools" release for the Sun + SparcStation can be replaced with mformat. + + 8) The Configure file has been included to help those who must add + devices to the devices.c file. + + Many thanks to Viktor Dukhovni (viktor@math.princeton.edu) for + many of the ideas in the new release. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..50b2e21 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,34 @@ +dnl Copyright 1997,2001-2003 Alain Knaff. +dnl This file is part of mtools. +dnl +dnl Mtools is free software: you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl Mtools is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with Mtools. If not, see . +dnl +dnl Check for declaration of sys_errlist in one of stdio.h and errno.h. +dnl Declaration of sys_errlist on BSD4.4 interferes with our declaration. +dnl Reported by Keith Bostic. +AC_DEFUN([CF_SYS_ERRLIST], +[ +AC_MSG_CHECKING([declaration of sys_errlist]) +AC_CACHE_VAL(cf_cv_dcl_sys_errlist,[ + AC_TRY_COMPILE([ +#include +#include +#include ], + [char *c = (char *) *sys_errlist], + [cf_cv_dcl_sys_errlist=yes], + [cf_cv_dcl_sys_errlist=no])]) +AC_MSG_RESULT($cf_cv_dcl_sys_errlist) +test $cf_cv_dcl_sys_errlist = no || AC_DEFINE([DECL_SYS_ERRLIST],1,[Define when sys_errlist is defined in the standard include files]) +])dnl +dnl diff --git a/buffer.c b/buffer.c new file mode 100644 index 0000000..d09030c --- /dev/null +++ b/buffer.c @@ -0,0 +1,392 @@ +/* Copyright 1997,2001-2003 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Buffer read/write module + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "buffer.h" + +typedef struct Buffer_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + size_t size; /* size of read/write buffer */ + int dirty; /* is the buffer dirty? */ + + size_t sectorSize; /* sector size: all operations happen + * in multiples of this */ + size_t cylinderSize; /* cylinder size: preferred alignemnt, + * but for efficiency, less data may be read */ + int ever_dirty; /* was the buffer ever dirty? */ + size_t dirty_pos; + size_t dirty_end; + mt_off_t current; /* first sector in buffer */ + size_t cur_size; /* the current size */ + char *buf; /* disk read/write buffer */ +} Buffer_t; + +/* + * Flush a dirty buffer to disk. Resets Buffer->dirty to zero. + * All errors are fatal. + */ + +static int _buf_flush(Buffer_t *Buffer) +{ + int ret; + + if (!Buffer->Next || !Buffer->dirty) + return 0; + if(Buffer->current < 0L) { + fprintf(stderr,"Should not happen\n"); + return -1; + } +#ifdef DEBUG + fprintf(stderr, "write %08x -- %02x %08x %08x\n", + Buffer, + (unsigned char) Buffer->buf[0], + Buffer->current + Buffer->dirty_pos, + Buffer->dirty_end - Buffer->dirty_pos); +#endif + + ret = force_write(Buffer->Next, + Buffer->buf + Buffer->dirty_pos, + Buffer->current + Buffer->dirty_pos, + Buffer->dirty_end - Buffer->dirty_pos); + if(ret != (signed int) (Buffer->dirty_end - Buffer->dirty_pos)) { + if(ret < 0) + perror("buffer_flush: write"); + else + fprintf(stderr,"buffer_flush: short write\n"); + return -1; + } + Buffer->dirty = 0; + Buffer->dirty_end = 0; + Buffer->dirty_pos = 0; + return 0; +} + +static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start) +{ + /*fprintf(stderr, "invalidate %x\n", Buffer);*/ + if(Buffer->sectorSize == 32) { + fprintf(stderr, "refreshing directory\n"); + } + + if(_buf_flush(Buffer) < 0) + return -1; + + /* start reading at the beginning of start's sector + * don't start reading too early, or we might not even reach + * start */ + Buffer->current = ROUND_DOWN(start, Buffer->sectorSize); + Buffer->cur_size = 0; + return 0; +} + +#undef OFFSET +#define OFFSET (start - This->current) + +typedef enum position_t { + OUTSIDE, + APPEND, + INSIDE, + ERROR +} position_t; + +static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len) +{ + if(start >= This->current && + start < This->current + This->cur_size) { + maximize(*len, This->cur_size - OFFSET); + return INSIDE; + } else if(start == This->current + This->cur_size && + This->cur_size < This->size && + *len >= This->sectorSize) { + /* append to the buffer for this, three conditions have to + * be met: + * 1. The start falls exactly at the end of the currently + * loaded data + * 2. There is still space + * 3. We append at least one sector + */ + maximize(*len, This->size - This->cur_size); + *len = ROUND_DOWN(*len, This->sectorSize); + return APPEND; + } else { + if(invalidate_buffer(This, start) < 0) + return ERROR; + maximize(*len, This->cylinderSize - OFFSET); + maximize(*len, This->cylinderSize - This->current % This->cylinderSize); + return OUTSIDE; + } +} + +static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + size_t length; + int offset; + char *disk_ptr; + int ret; + DeclareThis(Buffer_t); + + if(!len) + return 0; + + /*fprintf(stderr, "buf read %x %x %x\n", Stream, start, len);*/ + switch(isInBuffer(This, start, &len)) { + case OUTSIDE: + case APPEND: + /* always load until the end of the cylinder */ + length = This->cylinderSize - + (This->current + This->cur_size) % This->cylinderSize; + maximize(length, This->size - This->cur_size); + + /* read it! */ + ret=READS(This->Next, + This->buf + This->cur_size, + This->current + This->cur_size, + length); + if ( ret < 0 ) + return ret; + This->cur_size += ret; + if (This->current+This->cur_size < start) { + fprintf(stderr, "Short buffer fill\n"); + exit(1); + } + break; + case INSIDE: + /* nothing to do */ + break; + case ERROR: + return -1; + } + + offset = OFFSET; + disk_ptr = This->buf + offset; + maximize(len, This->cur_size - offset); + memcpy(buf, disk_ptr, len); + return len; +} + +static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + char *disk_ptr; + DeclareThis(Buffer_t); + size_t offset; + + if(!len) + return 0; + + This->ever_dirty = 1; + +#ifdef DEBUG + fprintf(stderr, "buf write %x %02x %08x %08x -- %08x %08x -- %08x\n", + Stream, (unsigned char) This->buf[0], + start, len, This->current, This->cur_size, This->size); + fprintf(stderr, "%d %d %d %x %x\n", + start == This->current + This->cur_size, + This->cur_size < This->size, + len >= This->sectorSize, len, This->sectorSize); +#endif + switch(isInBuffer(This, start, &len)) { + case OUTSIDE: +#ifdef DEBUG + fprintf(stderr, "outside\n"); +#endif + if(start % This->cylinderSize || + len < This->sectorSize) { + size_t readSize; + int ret; + + readSize = This->cylinderSize - + This->current % This->cylinderSize; + + ret=READS(This->Next, This->buf, This->current, readSize); + /* read it! */ + if ( ret < 0 ) + return ret; + if(ret % This->sectorSize) { + fprintf(stderr, "Weird: read size (%d) not a multiple of sector size (%d)\n", ret, (int) This->sectorSize); + ret -= ret % This->sectorSize; + if(ret == 0) { + fprintf(stderr, "Nothing left\n"); + exit(1); + } + } + This->cur_size = ret; + /* for dosemu. Autoextend size */ + if(!This->cur_size) { + memset(This->buf,0,readSize); + This->cur_size = readSize; + } + offset = OFFSET; + break; + } + /* FALL THROUGH */ + case APPEND: +#ifdef DEBUG + fprintf(stderr, "append\n"); +#endif + len = ROUND_DOWN(len, This->sectorSize); + offset = OFFSET; + maximize(len, This->size - offset); + This->cur_size += len; + if(This->Next->Class->pre_allocate) + PRE_ALLOCATE(This->Next, + This->current + This->cur_size); + break; + case INSIDE: + /* nothing to do */ +#ifdef DEBUG + fprintf(stderr, "inside\n"); +#endif + offset = OFFSET; + maximize(len, This->cur_size - offset); + break; + case ERROR: + return -1; + default: +#ifdef DEBUG + fprintf(stderr, "Should not happen\n"); +#endif + exit(1); + } + + disk_ptr = This->buf + offset; + + /* extend if we write beyond end */ + if(offset + len > This->cur_size) { + len -= (offset + len) % This->sectorSize; + This->cur_size = len + offset; + } + + memcpy(disk_ptr, buf, len); + if(!This->dirty || offset < This->dirty_pos) + This->dirty_pos = ROUND_DOWN(offset, This->sectorSize); + if(!This->dirty || offset + len > This->dirty_end) + This->dirty_end = ROUND_UP(offset + len, This->sectorSize); + + if(This->dirty_end > This->cur_size) { + fprintf(stderr, + "Internal error, dirty end too big dirty_end=%x cur_size=%x len=%x offset=%d sectorSize=%x\n", + (unsigned int) This->dirty_end, + (unsigned int) This->cur_size, + (unsigned int) len, + (int) offset, (int) This->sectorSize); + fprintf(stderr, "offset + len + grain - 1 = %x\n", + (int) (offset + len + This->sectorSize - 1)); + fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n", + (int)ROUND_DOWN(offset + len + This->sectorSize - 1, + This->sectorSize)); + fprintf(stderr, "This->dirty = %d\n", This->dirty); + exit(1); + } + + This->dirty = 1; + return len; +} + +static int buf_flush(Stream_t *Stream) +{ + int ret; + DeclareThis(Buffer_t); + + if (!This->ever_dirty) + return 0; + ret = _buf_flush(This); + if(ret == 0) + This->ever_dirty = 0; + return ret; +} + + +static int buf_free(Stream_t *Stream) +{ + DeclareThis(Buffer_t); + + if(This->buf) + free(This->buf); + This->buf = 0; + return 0; +} + +static Class_t BufferClass = { + buf_read, + buf_write, + buf_flush, + buf_free, + 0, /* set_geom */ + get_data_pass_through, /* get_data */ + 0, /* pre-allocate */ + get_dosConvert_pass_through /* dos convert */ +}; + +Stream_t *buf_init(Stream_t *Next, int size, + int cylinderSize, + int sectorSize) +{ + Buffer_t *Buffer; + Stream_t *Stream; + + + if(size % cylinderSize != 0) { + fprintf(stderr, "size not multiple of cylinder size\n"); + exit(1); + } + if(cylinderSize % sectorSize != 0) { + fprintf(stderr, "cylinder size not multiple of sector size\n"); + exit(1); + } + + if(Next->Buffer){ + Next->refs--; + Next->Buffer->refs++; + return Next->Buffer; + } + + Stream = (Stream_t *) malloc (sizeof(Buffer_t)); + if(!Stream) + return 0; + Buffer = (Buffer_t *) Stream; + Buffer->buf = malloc(size); + if ( !Buffer->buf){ + Free(Stream); + return 0; + } + Buffer->size = size; + Buffer->dirty = 0; + Buffer->cylinderSize = cylinderSize; + Buffer->sectorSize = sectorSize; + + Buffer->ever_dirty = 0; + Buffer->dirty_pos = 0; + Buffer->dirty_end = 0; + Buffer->current = 0L; + Buffer->cur_size = 0; /* buffer currently empty */ + + Buffer->Next = Next; + Buffer->Class = &BufferClass; + Buffer->refs = 1; + Buffer->Buffer = 0; + Buffer->Next->Buffer = (Stream_t *) Buffer; + return Stream; +} + diff --git a/buffer.h b/buffer.h new file mode 100644 index 0000000..6c79258 --- /dev/null +++ b/buffer.h @@ -0,0 +1,28 @@ +#ifndef MTOOLS_BUFFER_H +#define MTOOLS_BUFFER_H + +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "stream.h" + +Stream_t *buf_init(Stream_t *Next, + int size, + int cylinderSize, + int sectorSize); + +#endif diff --git a/byte_dword.h b/byte_dword.h new file mode 100644 index 0000000..159faf5 --- /dev/null +++ b/byte_dword.h @@ -0,0 +1,37 @@ +#ifndef BYTE_DWORD +#define BYTE_DWORD + +/* Copyright 2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +static Dword byte2dword(Byte* val) +{ + Dword l; + l = (val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3]; + + return l; +} + +static void dword2byte(Dword parm, Byte* rval) +{ + rval[0] = (parm >> 24) & 0xff; + rval[1] = (parm >> 16) & 0xff; + rval[2] = (parm >> 8) & 0xff; + rval[3] = parm & 0xff; +} + +#endif diff --git a/charsetConv.c b/charsetConv.c new file mode 100644 index 0000000..686a878 --- /dev/null +++ b/charsetConv.c @@ -0,0 +1,418 @@ +/* Copyright 2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Various character set conversions used by mtools + */ +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +#include +#include +#include +#include "file_name.h" + + +#ifdef HAVE_ICONV_H +#include + +struct doscp_t { + iconv_t from; + iconv_t to; +}; + +static char *wcharCp=NULL; + +static char* wcharTries[] = { + "WCHAR_T", + "UTF-32BE", "UTF-32LE", + "UTF-16BE", "UTF-16LE", + "UTF-32", "UTF-16", + "UCS-4BE", "UCS-4LE", + "UCS-2BE", "UCS-2LE", + "UCS-4", "UCS-2" +}; + +static wchar_t *testString = L"ab"; + +static int try(char *testCp) { + size_t res; + char *inbuf = (char *)testString; + size_t inbufLen = 2*sizeof(wchar_t); + char outbuf[3]; + char *outbufP = outbuf; + size_t outbufLen = 2*sizeof(char); + iconv_t test = iconv_open("ASCII", testCp); + + if(test == (iconv_t) -1) + goto fail0; + res = iconv(test, + &inbuf, &inbufLen, + &outbufP, &outbufLen); + if(res != 0 || outbufLen != 0 || inbufLen != 0) + goto fail; + if(memcmp(outbuf, "ab", 2)) + goto fail; + /* fprintf(stderr, "%s ok\n", testCp); */ + return 1; + fail: + iconv_close(test); + fail0: + /*fprintf(stderr, "%s fail\n", testCp);*/ + return 0; +} + +static const char *getWcharCp() { + int i; + if(wcharCp != NULL) + return wcharCp; + for(i=0; i< sizeof(wcharTries) / sizeof(wcharTries[0]); i++) { + if(try(wcharTries[i])) + return (wcharCp=wcharTries[i]); + } + fprintf(stderr, "No codepage found for wchar_t\n"); + return NULL; +} + + +doscp_t *cp_open(int codepage) +{ + char dosCp[17]; + doscp_t *ret; + iconv_t *from; + iconv_t *to; + + if(codepage == 0) + codepage = mtools_default_codepage; + if(codepage < 0 || codepage > 9999) { + fprintf(stderr, "Bad codepage %d\n", codepage); + return NULL; + } + + if(getWcharCp() == NULL) + return NULL; + + sprintf(dosCp, "CP%d", codepage); + from = iconv_open(wcharCp, dosCp); + if(from == (iconv_t)-1) { + fprintf(stderr, "Error converting to codepage %d %s\n", + codepage, strerror(errno)); + return NULL; + } + + sprintf(dosCp, "CP%d//TRANSLIT", codepage); + to = iconv_open(dosCp, wcharCp); + if(to == (iconv_t)-1) { + /* Transliteration not supported? */ + sprintf(dosCp, "CP%d", codepage); + to = iconv_open(dosCp, wcharCp); + } + if(to == (iconv_t)-1) { + iconv_close(from); + fprintf(stderr, "Error converting to codepage %d %s\n", + codepage, strerror(errno)); + return NULL; + } + + ret = New(doscp_t); + if(ret == NULL) + return ret; + ret->from = from; + ret->to = to; + return ret; +} + +void cp_close(doscp_t *cp) +{ + iconv_close(cp->to); + iconv_close(cp->from); + free(cp); +} + +int dos_to_wchar(doscp_t *cp, char *dos, wchar_t *wchar, size_t len) +{ + int r; + size_t in_len=len; + size_t out_len=len*sizeof(wchar_t); + wchar_t *dptr=wchar; + r=iconv(cp->from, &dos, &in_len, (char **)&dptr, &out_len); + if(r < 0) + return r; + *dptr = L'\0'; + return dptr-wchar; +} + +/** + * Converts len wide character to destination. Caller's responsibility to + * ensure that dest is large enough. + * mangled will be set if there has been an untranslatable character. + */ +static int safe_iconv(iconv_t conv, const wchar_t *wchar, char *dest, + size_t len, int *mangled) +{ + int r; + int i; + size_t in_len=len*sizeof(wchar_t); + size_t out_len=len*4; + char *dptr = dest; + + while(in_len > 0) { + r=iconv(conv, (char**)&wchar, &in_len, &dptr, &out_len); + if(r >= 0 || errno != EILSEQ) { + /* everything transformed, or error that is _not_ a bad + * character */ + break; + } + *mangled |= 1; + + if(dptr) + *dptr++ = '_'; + in_len--; + + wchar++; + out_len--; + } + + len = dptr-dest; /* how many dest characters have there been + generated */ + + /* eliminate question marks which might have been formed by + untransliterable characters */ + for(i=0; ito, wchar, dos, len, mangled); +} + +#else + +#include "codepage.h" + +struct doscp_t { + unsigned char *from_dos; + unsigned char to_dos[0x80]; +}; + +doscp_t *cp_open(int codepage) +{ + doscp_t *ret; + int i; + Codepage_t *cp; + + if(codepage == 0) + codepage = 850; + + ret = New(doscp_t); + if(ret == NULL) + return ret; + + for(cp=codepages; cp->nr ; cp++) + if(cp->nr == codepage) { + ret->from_dos = cp->tounix; + break; + } + + if(ret->from_dos == NULL) { + fprintf(stderr, "Bad codepage %d\n", codepage); + free(ret); + return NULL; + } + + for(i=0; i<0x80; i++) { + char native = ret->from_dos[i]; + if(! (native & 0x80)) + continue; + ret->to_dos[native & 0x7f] = 0x80 | i; + } + return ret; +} + +void cp_close(doscp_t *cp) +{ + free(cp); +} + +int dos_to_wchar(doscp_t *cp, char *dos, wchar_t *wchar, size_t len) +{ + int i; + + for(i=0; i= ' ' && c <= '~') + wchar[i] = c; + else { + wchar[i] = cp->from_dos[c & 0x7f]; + } + } + wchar[i] = '\0'; + return i; +} + + +void wchar_to_dos(doscp_t *cp, + wchar_t *wchar, char *dos, size_t len, int *mangled) +{ + int i; + for(i=0; i= ' ' && c <= '~') + dos[i] = c; + else { + dos[i] = cp->to_dos[c & 0x7f]; + if(dos[i] == '\0') { + dos[i]='_'; + *mangled=1; + } + } + } +} + +#endif + + +#ifndef HAVE_WCHAR_H + +typedef int mbstate_t; + +static inline size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps) +{ + *s = wc; + return 1; +} + +static inline size_t mbrtowc(wchar_t *pwc, const char *s, + size_t n, mbstate_t *ps) +{ + *pwc = *s; + return 1; +} + +#endif + +#ifdef HAVE_ICONV_H + +#include + +static iconv_t to_native = NULL; + +static void initialize_to_native(void) +{ + char *li, *cp; + int len; + if(to_native != NULL) + return; + li = nl_langinfo(CODESET); + len = strlen(li) + 11; + if(getWcharCp() == NULL) + exit(1); + cp = safe_malloc(len); + strcpy(cp, li); + strcat(cp, "//TRANSLIT"); + to_native = iconv_open(cp, wcharCp); + if(to_native == (iconv_t) -1) + to_native = iconv_open(li, wcharCp); + if(to_native == (iconv_t) -1) + fprintf(stderr, "Could not allocate iconv for %s\n", cp); + free(cp); + if(to_native == (iconv_t) -1) + exit(1); +} + + + +#endif + + +/** + * Convert wchar string to native, converting at most len wchar characters + * Returns number of generated native characters + */ +int wchar_to_native(const wchar_t *wchar, char *native, size_t len) +{ +#ifdef HAVE_ICONV_H + int mangled; + int r; + initialize_to_native(); + len = wcsnlen(wchar,len); + r=safe_iconv(to_native, wchar, native, len, &mangled); + native[r]='\0'; + return r; +#else + int i; + char *dptr = native; + mbstate_t ps; + memset(&ps, 0, sizeof(ps)); + for(i=0; i= '\xa0' && c < '\xff') + wchar[i] = c & 0xff; + else + wchar[i] = '_'; + memset(&ps, 0, sizeof(ps)); + r=1; + } + if(r == 0) + break; + native += r; + } + if(mangled && end && native < end) + *mangled |= 3; + wchar[i]='\0'; + return i; +} + diff --git a/cleanconfig b/cleanconfig new file mode 100644 index 0000000..1a4d69e --- /dev/null +++ b/cleanconfig @@ -0,0 +1,20 @@ +#!/bin/sh + +# Copyright 2001,2002,2005 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +# Removes all autoconfig related files +rm -f config.sub config.guess configure config.h.in diff --git a/codepage.h b/codepage.h new file mode 100644 index 0000000..8775865 --- /dev/null +++ b/codepage.h @@ -0,0 +1,42 @@ +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +typedef struct Codepage_l { + int nr; + unsigned char tounix[128]; +} Codepage_t; + + +typedef struct country_l { + int country; + int codepage; + int default_codepage; + int to_upper; +} country_t; + + +void init_codepage(void); +unsigned char to_dos(unsigned char c); +void to_unix(char *a, int n); +char contents_to_unix(char a); + +extern Codepage_t *Codepage; +extern char *mstoupper; +extern country_t countries[]; +extern unsigned char toucase[][128]; +extern Codepage_t codepages[]; +extern char *country_string; diff --git a/codepages.c b/codepages.c new file mode 100644 index 0000000..5558724 --- /dev/null +++ b/codepages.c @@ -0,0 +1,117 @@ +/* Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + */ +#include "config.h" + +#ifndef HAVE_ICONV_H +#include "codepage.h" + +Codepage_t codepages[]= { + { 437, + "ÇüéâäàåçêëèïîìÄÅ" + "ÉæÆôöòûùÿÖÜ¢£¥Pf" + "áíóúñѪº¿r¬½¼¡«»" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__" + }, + + { 819, + "________________" + "________________" + " ¡¢£¤¥¦§¨©ª«¬­®¯" + "°±²³´µ¶·¸¹º»¼½¾¿" + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ" + "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß" + "àáâãäåæçèéêëìíîï" + "ðñòóôõö÷øùúûüýþÿ" + }, + + { 850, + "ÇüéâäàåçêëèïîìÄÅ" + "ÉæÆôöòûùÿÖÜø£Ø×_" + "áíóúñѪº¿®¬½¼¡«»" + "_____ÁÂÀ©____¢¥¬" + "______ãÃ_______¤" + "ðÐÉËÈiÍÎÏ____|I_" + "ÓßÔÒõÕµþÞÚÙýÝÞ¯´" + "­±_¾¶§÷¸°¨·¹³²__" + }, + + { 852, + "ÇüéâäucçlëÕõîZÄC" + "ÉLlôöLlSsÖÜTtL×c" + "áíóúAaZzEe zCs«»" + "_____ÁÂES____Zz¬" + "______Aa_______¤" + "ðÐDËdÑÍÎe_r__TU_" + "ÓßÔNnñSsRÚrUýÝt´" + "­~.~~§÷¸°¨·¹uRr_" + }, + + { 860, + "ÇüéâãàåçêëèÍõìÃÂ" + "ÉÀÈôõòÚùÌÕÜ¢£ÙPÓ" + "áíóúñѪº¿Ò¬½¼¡«»" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__" + }, + + { 863, + "ÇüéâÂà¶çêëèïî_À§" + "ÉÈÊôËÏûù¤ÔÜ¢£ÙÛf" + "|´óú¨ ³¯Îr¬½¼¾«»" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__" + }, + + { 865, + "ÇüéâäàåçêëèïîìÄÅ" + "ÉæÆôöòûùÿÖÜø£ØPf" + "áíóúñѪº¿r¬½¼¡«¤" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__", + }, + + /* Taiwanese (Chinese Complex Character) support */ + { 950, + "€‚ƒ„…†‡ˆ‰Š‹ŒŽ" + "‘’“”•–—˜™š›œžŸ" + " ¡¢£¤¥¦§¨©ª«¬­®¯" + "°±²³´µ¶·¸¹º»¼½¾¿" + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ" + "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß" + "àáâãäåæçèéêëìíîï" + "ðñòóôõö÷øùúûüýþÿ", + }, + + + { 0 } +}; + +#endif diff --git a/config.c b/config.c new file mode 100644 index 0000000..33bb6af --- /dev/null +++ b/config.c @@ -0,0 +1,829 @@ +/* Copyright 1996-2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + */ +#include "sysincludes.h" +#include "mtools.h" +#include "codepage.h" +#include "mtoolsPaths.h" + +/* global variables */ +/* they are not really harmful here, because there is only one configuration + * file per invocations */ + +#define MAX_LINE_LEN 256 + +/* scanner */ +static char buffer[MAX_LINE_LEN+1]; /* buffer for the whole line */ +static char *pos; /* position in line */ +static char *token; /* last scanned token */ +static size_t token_length; /* length of the token */ +static FILE *fp; /* file pointer for configuration file */ +static int linenumber; /* current line number. Only used for printing + * error messages */ +static int lastTokenLinenumber; /* line numnber for last token */ +static const char *filename=NULL; /* current file name. Used for printing + * error messages, and for storing in + * the device definition (mtoolstest) */ +static int file_nr=0; + + +static int flag_mask; /* mask of currently set flags */ + +/* devices */ +static int cur_devs; /* current number of defined devices */ +static int cur_dev; /* device being filled in. If negative, none */ +static int trusted=0; /* is the currently parsed device entry trusted? */ +static int nr_dev; /* number of devices that the current table can hold */ +struct device *devices; /* the device table */ +static int token_nr; /* number of tokens in line */ + +static char default_drive='\0'; /* default drive */ + +/* "environment" variables */ +unsigned int mtools_skip_check=0; +unsigned int mtools_fat_compatibility=0; +unsigned int mtools_ignore_short_case=0; +unsigned int mtools_rate_0=0; +unsigned int mtools_rate_any=0; +unsigned int mtools_no_vfat=0; +unsigned int mtools_numeric_tail=1; +unsigned int mtools_dotted_dir=0; +unsigned int mtools_twenty_four_hour_clock=1; +unsigned int mtools_default_codepage=850; +const char *mtools_date_string="yyyy-mm-dd"; +char *country_string=0; + +typedef struct switches_l { + const char *name; + caddr_t address; + enum { + T_INT, + T_STRING, + T_UINT + } type; +} switches_t; + +static switches_t global_switches[] = { + { "MTOOLS_LOWER_CASE", (caddr_t) & mtools_ignore_short_case, T_UINT }, + { "MTOOLS_FAT_COMPATIBILITY", (caddr_t) & mtools_fat_compatibility, T_UINT }, + { "MTOOLS_SKIP_CHECK", (caddr_t) & mtools_skip_check, T_UINT }, + { "MTOOLS_NO_VFAT", (caddr_t) & mtools_no_vfat, T_UINT }, + { "MTOOLS_RATE_0", (caddr_t) &mtools_rate_0, T_UINT }, + { "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT }, + { "MTOOLS_NAME_NUMERIC_TAIL", (caddr_t) &mtools_numeric_tail, T_UINT }, + { "MTOOLS_DOTTED_DIR", (caddr_t) &mtools_dotted_dir, T_UINT }, + { "MTOOLS_TWENTY_FOUR_HOUR_CLOCK", + (caddr_t) &mtools_twenty_four_hour_clock, T_UINT }, + { "MTOOLS_DATE_STRING", + (caddr_t) &mtools_date_string, T_STRING }, + { "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT } +}; + +typedef struct { + const char *name; + int flag; +} flags_t; + +static flags_t openflags[] = { +#ifdef O_SYNC + { "sync", O_SYNC }, +#endif +#ifdef O_NDELAY + { "nodelay", O_NDELAY }, +#endif +#ifdef O_EXCL + { "exclusive", O_EXCL }, +#endif + { "none", 0 } /* hack for those compilers that choke on commas + * after the last element of an array */ +}; + +static flags_t misc_flags[] = { +#ifdef USE_XDF + { "use_xdf", USE_XDF_FLAG }, +#endif + { "scsi", SCSI_FLAG }, + { "nolock", NOLOCK_FLAG }, + { "mformat_only", MFORMAT_ONLY_FLAG }, + { "filter", FILTER_FLAG }, + { "privileged", PRIV_FLAG }, + { "vold", VOLD_FLAG }, + { "remote", FLOPPYD_FLAG }, + { "swap", SWAP_FLAG }, +}; + +static struct { + const char *name; + signed char fat_bits; + int tracks; + unsigned short heads; + unsigned short sectors; +} default_formats[] = { + { "hd514", 12, 80, 2, 15 }, + { "high-density-5-1/4", 12, 80, 2, 15 }, + { "1.2m", 12, 80, 2, 15 }, + + { "hd312", 12, 80, 2, 18 }, + { "high-density-3-1/2", 12, 80, 2, 18 }, + { "1.44m", 12, 80, 2, 18 }, + + { "dd312", 12, 80, 2, 9 }, + { "double-density-3-1/2", 12, 80, 2, 9 }, + { "720k", 12, 80, 2, 9 }, + + { "dd514", 12, 40, 2, 9 }, + { "double-density-5-1/4", 12, 40, 2, 9 }, + { "360k", 12, 40, 2, 9 }, + + { "320k", 12, 40, 2, 8 }, + { "180k", 12, 40, 1, 9 }, + { "160k", 12, 40, 1, 8 } +}; + +#define OFFS(x) ((caddr_t)&((struct device *)0)->x) + +static switches_t dswitches[]= { + { "FILE", OFFS(name), T_STRING }, + { "OFFSET", OFFS(offset), T_UINT }, + { "PARTITION", OFFS(partition), T_UINT }, + { "FAT", OFFS(fat_bits), T_INT }, + { "FAT_BITS", OFFS(fat_bits), T_UINT }, + { "MODE", OFFS(mode), T_UINT }, + { "TRACKS", OFFS(tracks), T_UINT }, + { "CYLINDERS", OFFS(tracks), T_UINT }, + { "HEADS", OFFS(heads), T_UINT }, + { "SECTORS", OFFS(sectors), T_UINT }, + { "HIDDEN", OFFS(hidden), T_UINT }, + { "PRECMD", OFFS(precmd), T_STRING }, + { "BLOCKSIZE", OFFS(blocksize), T_UINT }, + { "CODEPAGE", OFFS(codepage), T_UINT } +}; + +static void maintain_default_drive(char drive) +{ + if(default_drive == ':') + return; /* we have an image */ + if(default_drive == '\0' || + default_drive > drive) + default_drive = drive; +} + +char get_default_drive(void) +{ + if(default_drive != '\0') + return default_drive; + else + return 'A'; +} + +static void syntax(const char *msg, int thisLine) +{ + char drive='\0'; + if(thisLine) + lastTokenLinenumber = linenumber; + if(cur_dev >= 0) + drive = devices[cur_dev].drive; + fprintf(stderr,"Syntax error at line %d ", lastTokenLinenumber); + if(drive) fprintf(stderr, "for drive %c: ", drive); + if(token) fprintf(stderr, "column %ld ", (long)(token - buffer)); + fprintf(stderr, "in file %s: %s\n", filename, msg); + exit(1); +} + +static void get_env_conf(void) +{ + char *s; + unsigned int i; + + for(i=0; i< sizeof(global_switches) / sizeof(*global_switches); i++) { + s = getenv(global_switches[i].name); + if(s) { + if(global_switches[i].type == T_INT) + * ((int *)global_switches[i].address) = (int) strtol(s,0,0); + if(global_switches[i].type == T_UINT) + * ((int *)global_switches[i].address) = (unsigned int) strtoul(s,0,0); + else if (global_switches[i].type == T_STRING) + * ((char **)global_switches[i].address) = s; + } + } +} + +static int mtools_getline(void) +{ + if(!fp || !fgets(buffer, MAX_LINE_LEN, fp)) + return -1; + linenumber++; + pos = buffer; + token_nr = 0; + buffer[MAX_LINE_LEN] = '\0'; + if(strlen(buffer) == MAX_LINE_LEN) + syntax("line too long", 1); + return 0; +} + +static void skip_junk(int expect) +{ + lastTokenLinenumber = linenumber; + while(!pos || !*pos || strchr(" #\n\t", *pos)) { + if(!pos || !*pos || *pos == '#') { + if(mtools_getline()) { + pos = 0; + if(expect) + syntax("end of file unexpected", 1); + return; + } + } else + pos++; + } + token_nr++; +} + +/* get the next token */ +static char *get_next_token(void) +{ + skip_junk(0); + if(!pos) { + token_length = 0; + token = 0; + return 0; + } + token = pos; + token_length = strcspn(token, " \t\n#:="); + pos += token_length; + return token; +} + +static int match_token(const char *template) +{ + return (strlen(template) == token_length && + !strncasecmp(template, token, token_length)); +} + +static void expect_char(char c) +{ + char buf[11]; + + skip_junk(1); + if(*pos != c) { + sprintf(buf, "expected %c", c); + syntax(buf, 1); + } + pos++; +} + +static char *get_string(void) +{ + char *end, *str; + + skip_junk(1); + if(*pos != '"') + syntax(" \" expected", 0); + str = pos+1; + end = strchr(str, '\"'); + if(!end) + syntax("unterminated string constant", 1); + *end = '\0'; + pos = end+1; + return str; +} + +static unsigned int get_unumber(void) +{ + char *last; + unsigned int n; + + skip_junk(1); + last = pos; + n=(unsigned int) strtoul(pos, &pos, 0); + if(last == pos) + syntax("numeral expected", 0); + pos++; + token_nr++; + return n; +} + +static unsigned int get_number(void) +{ + char *last; + int n; + + skip_junk(1); + last = pos; + n=(int) strtol(pos, &pos, 0); + if(last == pos) + syntax("numeral expected", 0); + pos++; + token_nr++; + return n; +} + +/* purge all entries pertaining to a given drive from the table */ +static void purge(char drive, int fn) +{ + int i,j; + + drive = toupper(drive); + for(j=0, i=0; i < cur_devs; i++) { + if(devices[i].drive != drive || + devices[i].file_nr == fn) + devices[j++] = devices[i]; + } + cur_devs = j; +} + +static void grow(void) +{ + if(cur_devs >= nr_dev - 2) { + nr_dev = (cur_devs + 2) << 1; + if(!(devices=Grow(devices, nr_dev, struct device))){ + printOom(); + exit(1); + } + } +} + + +static void init_drive(void) +{ + memset((char *)&devices[cur_dev], 0, sizeof(struct device)); + devices[cur_dev].ssize = 2; +} + +/* prepends a device to the table */ +static void prepend(void) +{ + int i; + + grow(); + for(i=cur_devs; i>0; i--) + devices[i] = devices[i-1]; + cur_dev = 0; + cur_devs++; + init_drive(); +} + + +/* appends a device to the table */ +static void append(void) +{ + grow(); + cur_dev = cur_devs; + cur_devs++; + init_drive(); +} + + +static void finish_drive_clause(void) +{ + char drive; + if(cur_dev == -1) { + trusted = 0; + return; + } + drive = devices[cur_dev].drive; + if(!devices[cur_dev].name) + syntax("missing filename", 0); + if(devices[cur_dev].tracks || + devices[cur_dev].heads || + devices[cur_dev].sectors) { + if(!devices[cur_dev].tracks || + !devices[cur_dev].heads || + !devices[cur_dev].sectors) + syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0); + if(!(devices[cur_dev].misc_flags & + (MFORMAT_ONLY_FLAG | FILTER_FLAG))) + syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0); + } + devices[cur_dev].file_nr = file_nr; + devices[cur_dev].cfg_filename = filename; + if(! (flag_mask & PRIV_FLAG) && IS_SCSI(&devices[cur_dev])) + devices[cur_dev].misc_flags |= PRIV_FLAG; + if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) { + fprintf(stderr, + "Warning: privileged flag ignored for drive %c: defined in file %s\n", + toupper(devices[cur_dev].drive), filename); + devices[cur_dev].misc_flags &= ~PRIV_FLAG; + } + trusted = 0; + cur_dev = -1; +} + +static int set_var(struct switches_l *switches, int nr, + caddr_t base_address) +{ + int i; + for(i=0; i < nr; i++) { + if(match_token(switches[i].name)) { + expect_char('='); + if(switches[i].type == T_UINT) + * ((int *)((long)switches[i].address+base_address)) = + get_unumber(); + if(switches[i].type == T_INT) + * ((int *)((long)switches[i].address+base_address)) = + get_number(); + else if (switches[i].type == T_STRING) + * ((char**)((long)switches[i].address+base_address))= + strdup(get_string()); + return 0; + } + } + return 1; +} + +static int set_openflags(struct device *dev) +{ + unsigned int i; + + for(i=0; i < sizeof(openflags) / sizeof(*openflags); i++) { + if(match_token(openflags[i].name)) { + dev->mode |= openflags[i].flag; + return 0; + } + } + return 1; +} + +static int set_misc_flags(struct device *dev) +{ + unsigned int i; + + for(i=0; i < sizeof(misc_flags) / sizeof(*misc_flags); i++) { + if(match_token(misc_flags[i].name)) { + flag_mask |= misc_flags[i].flag; + skip_junk(0); + if(pos && *pos == '=') { + pos++; + switch(get_number()) { + case 0: + return 0; + case 1: + break; + default: + syntax("expected 0 or 1", 0); + } + } + dev->misc_flags |= misc_flags[i].flag; + return 0; + } + } + return 1; +} + +static int set_def_format(struct device *dev) +{ + unsigned int i; + + for(i=0; i < sizeof(default_formats)/sizeof(*default_formats); i++) { + if(match_token(default_formats[i].name)) { + if(!dev->ssize) + dev->ssize = 2; + if(!dev->tracks) + dev->tracks = default_formats[i].tracks; + if(!dev->heads) + dev->heads = default_formats[i].heads; + if(!dev->sectors) + dev->sectors = default_formats[i].sectors; + if(!dev->fat_bits) + dev->fat_bits = default_formats[i].fat_bits; + return 0; + } + } + return 1; +} + +static int parse_one(int privilege); + +/* check for offset embedded in file name, in the form file@@offset[SKMG] */ +static off_t get_offset(char *name) { + char s, *ofsp, *endp = NULL; + off_t ofs; + + ofsp = strstr(devices[cur_dev].name, "@@"); + if (ofsp == NULL) + return 0; /* no separator */ + ofs = strtol(ofsp+2, &endp, 0); + if (ofs <= 0) + return 0; /* invalid or missing offset */ + s = *endp++; + if (s) { /* trailing char, see if it is a size specifier */ + endp++; + if (s == 's' || s == 'S') /* sector */ + ofs <<= 9; + else if (s == 'k' || s == 'K') /* kb */ + ofs <<= 10; + else if (s == 'm' || s == 'M') /* Mb */ + ofs <<= 20; + else if (s == 'g' || s == 'G') /* Gb */ + ofs <<= 30; + else + return 0; /* invalid character */ + if (*endp) + return 0; /* extra char, invalid */ + } + *ofsp = '\0'; /* truncate file name */ + return ofs; +} + +void set_cmd_line_image(char *img, int flags) { + char *name; + prepend(); + devices[cur_dev].drive = ':'; + default_drive = ':'; + devices[cur_dev].name = name = strdup(img); + devices[cur_dev].fat_bits = 0; + devices[cur_dev].tracks = 0; + devices[cur_dev].heads = 0; + devices[cur_dev].sectors = 0; + devices[cur_dev].offset = get_offset(name); + if (strchr(devices[cur_dev].name, '|')) { + char *pipechar = strchr(devices[cur_dev].name, '|'); + *pipechar = 0; + strncpy(buffer, pipechar+1, MAX_LINE_LEN); + buffer[MAX_LINE_LEN] = '\0'; + fp = NULL; + filename = "{command line}"; + linenumber = 0; + lastTokenLinenumber = 0; + pos = buffer; + token = 0; + while (parse_one(0)); + } +} + +static void parse_old_device_line(char drive) +{ + char name[MAXPATHLEN]; + int items; + long offset; + + /* finish any old drive */ + finish_drive_clause(); + + /* purge out data of old configuration files */ + purge(drive, file_nr); + + /* reserve slot */ + append(); + items = sscanf(token,"%c %s %i %i %i %i %li", + &devices[cur_dev].drive,name,&devices[cur_dev].fat_bits, + &devices[cur_dev].tracks,&devices[cur_dev].heads, + &devices[cur_dev].sectors, &offset); + devices[cur_dev].offset = (off_t) offset; + switch(items){ + case 2: + devices[cur_dev].fat_bits = 0; + /* fall thru */ + case 3: + devices[cur_dev].sectors = 0; + devices[cur_dev].heads = 0; + devices[cur_dev].tracks = 0; + /* fall thru */ + case 6: + devices[cur_dev].offset = 0; + /* fall thru */ + default: + break; + case 0: + case 1: + case 4: + case 5: + syntax("bad number of parameters", 1); + exit(1); + } + if(!devices[cur_dev].tracks){ + devices[cur_dev].sectors = 0; + devices[cur_dev].heads = 0; + } + + devices[cur_dev].drive = toupper(devices[cur_dev].drive); + maintain_default_drive(devices[cur_dev].drive); + if (!(devices[cur_dev].name = strdup(name))) { + printOom(); + exit(1); + } + finish_drive_clause(); + pos=0; +} + +static int parse_one(int privilege) +{ + int action=0; + + get_next_token(); + if(!token) + return 0; + + if((match_token("drive") && ((action = 1)))|| + (match_token("drive+") && ((action = 2))) || + (match_token("+drive") && ((action = 3))) || + (match_token("clear_drive") && ((action = 4))) ) { + /* finish off the previous drive */ + finish_drive_clause(); + + get_next_token(); + if(token_length != 1) + syntax("drive letter expected", 0); + + if(action==1 || action==4) + /* replace existing drive */ + purge(token[0], file_nr); + if(action==4) + return 1; + if(action==3) + prepend(); + else + append(); + memset((char*)(devices+cur_dev), 0, sizeof(*devices)); + trusted = privilege; + flag_mask = 0; + devices[cur_dev].drive = toupper(token[0]); + maintain_default_drive(devices[cur_dev].drive); + expect_char(':'); + return 1; + } + if(token_nr == 1 && token_length == 1) { + parse_old_device_line(token[0]); + return 1; + } + + if((cur_dev < 0 || + (set_var(dswitches, + sizeof(dswitches)/sizeof(*dswitches), + (caddr_t)&devices[cur_dev]) && + set_openflags(&devices[cur_dev]) && + set_misc_flags(&devices[cur_dev]) && + set_def_format(&devices[cur_dev]))) && + set_var(global_switches, + sizeof(global_switches)/sizeof(*global_switches), 0)) + syntax("unrecognized keyword", 1); + return 1; +} + +static int parse(const char *name, int privilege) +{ + if(fp) { + fprintf(stderr, "File descriptor already set (%p)!\n", fp); + exit(1); + } + fp = fopen(name, "r"); + if(!fp) + return 0; + file_nr++; + filename = name; /* no strdup needed: although lifetime of variable + exceeds this function (due to dev->cfg_filename), + we know that the name is always either + 1. a constant + 2. a statically allocate buffer + 3. an environment variable that stays unchanged + */ + linenumber = 0; + lastTokenLinenumber = 0; + pos = 0; + token = 0; + cur_dev = -1; /* no current device */ + + while(parse_one(privilege)); + finish_drive_clause(); + fclose(fp); + filename = NULL; + fp = NULL; + return 1; +} + +void read_config(void) +{ + char *homedir; + char *envConfFile; + static char conf_file[MAXPATHLEN+sizeof(CFG_FILE1)]; + + + /* copy compiled-in devices */ + file_nr = 0; + cur_devs = nr_const_devices; + nr_dev = nr_const_devices + 2; + devices = NewArray(nr_dev, struct device); + if(!devices) { + printOom(); + exit(1); + } + if(nr_const_devices) + memcpy(devices, const_devices, + nr_const_devices*sizeof(struct device)); + + (void) ((parse(CONF_FILE,1) | + parse(LOCAL_CONF_FILE,1) | + parse(SYS_CONF_FILE,1)) || + (parse(OLD_CONF_FILE,1) | + parse(OLD_LOCAL_CONF_FILE,1))); + /* the old-name configuration files only get executed if none of the + * new-name config files were used */ + + homedir = get_homedir(); + if ( homedir ){ + strncpy(conf_file, homedir, MAXPATHLEN ); + conf_file[MAXPATHLEN]='\0'; + strcat( conf_file, CFG_FILE1); + parse(conf_file,0); + } + memset((char *)&devices[cur_devs],0,sizeof(struct device)); + + envConfFile = getenv("MTOOLSRC"); + if(envConfFile) + parse(envConfFile,0); + + /* environmental variables */ + get_env_conf(); + if(mtools_skip_check) + mtools_fat_compatibility=1; +} + +void mtoolstest(int argc, char **argv, int type) +{ + /* testing purposes only */ + struct device *dev; + char drive='\0'; + + if(argc > 1 && argv[1][0] && argv[1][1] == ':') { + drive = toupper(argv[1][0]); + } + + for (dev=devices; dev->name; dev++) { + if(drive && drive != dev->drive) + continue; + printf("drive %c:\n", dev->drive); + printf("\t#fn=%d mode=%d ", + dev->file_nr, dev->mode); + if(dev->cfg_filename) + printf("defined in %s\n", dev->cfg_filename); + else + printf("builtin\n"); + printf("\tfile=\"%s\" fat_bits=%d \n", + dev->name,dev->fat_bits); + printf("\ttracks=%d heads=%d sectors=%d hidden=%d\n", + dev->tracks, dev->heads, dev->sectors, dev->hidden); + printf("\toffset=0x%lx\n", (long) dev->offset); + printf("\tpartition=%d\n", dev->partition); + + if(dev->misc_flags) + printf("\t"); + + if(DO_SWAP(dev)) + printf("swap "); + if(IS_SCSI(dev)) + printf("scsi "); + if(IS_PRIVILEGED(dev)) + printf("privileged"); + if(IS_MFORMAT_ONLY(dev)) + printf("mformat_only "); + if(SHOULD_USE_VOLD(dev)) + printf("vold "); +#ifdef USE_XDF + if(SHOULD_USE_XDF(dev)) + printf("use_xdf "); +#endif + if(dev->misc_flags) + printf("\n"); + + if(dev->mode) + printf("\t"); +#ifdef O_SYNC + if(dev->mode & O_SYNC) + printf("sync "); +#endif +#ifdef O_NDELAY + if((dev->mode & O_NDELAY)) + printf("nodelay "); +#endif +#ifdef O_EXCL + if((dev->mode & O_EXCL)) + printf("exclusive "); +#endif + if(dev->mode) + printf("\n"); + + if(dev->precmd) + printf("\tprecmd=%s\n", dev->precmd); + + printf("\n"); + } + + printf("mtools_fat_compatibility=%d\n",mtools_fat_compatibility); + printf("mtools_skip_check=%d\n",mtools_skip_check); + printf("mtools_lower_case=%d\n",mtools_ignore_short_case); + + exit(0); +} diff --git a/config.guess b/config.guess new file mode 100644 index 0000000..f32079a --- /dev/null +++ b/config.guess @@ -0,0 +1,1526 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2008-01-23' + +# This file 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.Be b/config.h.Be new file mode 100644 index 0000000..fe08c4d --- /dev/null +++ b/config.h.Be @@ -0,0 +1,56 @@ +/* + * Copyright 1997 Marco Nelissen + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#define PREFIX "/boot/system" +#define HAVE_ATEXIT +#define HAVE_FCNTL_H +#define HAVE_GETOPT_H +#define HAVE_LIMITS_H +#define HAVE_SYS_IOCTL_H +#define TIME_WITH_SYS_TIME 1 +#define HAVE_TERMIOS_H +#define HAVE_SYS_PARAM_H +#define HAVE_STRING_H +#define HAVE_MEMORY_H +#define HAVE_MALLOC_H +#define HAVE_UTIME_H +#define HAVE_SYS_WAIT_H +#define HAVE_MEMCPY +#define HAVE_MEMSET +#define HAVE_STRERROR +#define HAVE_STRNCASECMP +#define HAVE_STRCASECMP +#undef HAVE_GETPASS +#define HAVE_STDLIB_H +#define HAVE_STRCHR +#define HAVE_STRRCHR +#define HAVE_UNISTD_H +#define RETSIGTYPE void +#define HAVE_STRDUP +#define HAVE_STRPBRK +#define HAVE_STRSPN +#define HAVE_STRTOUL +#define HAVE_STRCSPN +#define HAVE_RANDOM +#define random rand +#define HAVE_SRANDOM +#define srandom srand +#define INIT_NOOP +#include +#define SYSCONFDIR "/boot/system" +#define USE_RAWTERM diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..7290c88 --- /dev/null +++ b/config.h.in @@ -0,0 +1,394 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define for debugging messages */ +#undef DEBUG + +/* Define when sys_errlist is defined in the standard include files */ +#undef DECL_SYS_ERRLIST + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ASSERT_H + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you have the `basename' function. */ +#undef HAVE_BASENAME + +/* Define to 1 if you have the `fchdir' function. */ +#undef HAVE_FCHDIR + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `flock' function. */ +#undef HAVE_FLOCK + +/* Define to 1 if you have the `getgroupid' function. */ +#undef HAVE_GETGROUPID + +/* Define to 1 if you have the header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the `getpass' function. */ +#undef HAVE_GETPASS + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the `getuserid' function. */ +#undef HAVE_GETUSERID + +/* Define to 1 if you have the `htons' function. */ +#undef HAVE_HTONS + +/* Define to 1 if you have the header file. */ +#undef HAVE_ICONV_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `bsd' library (-lbsd). */ +#undef HAVE_LIBBSD + +/* Define to 1 if you have the `cam' library (-lcam). */ +#undef HAVE_LIBCAM + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBC_H + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `sun' library (-lsun). */ +#undef HAVE_LIBSUN + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_UNISTD_H + +/* Define to 1 if you have the `llseek' function. */ +#undef HAVE_LLSEEK + +/* Define when you have an LLSEEK prototype */ +#undef HAVE_LLSEEK_PROTOTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the `lockf' function. */ +#undef HAVE_LOCKF + +/* Define when the compiler supports LOFF_T type */ +#undef HAVE_LOFF_T + +/* Define when the compiler supports LONG_LONG type */ +#undef HAVE_LONG_LONG + +/* Define to 1 if you have the `lseek64' function. */ +#undef HAVE_LSEEK64 + +/* Define when you have an LSEEK64 prototype */ +#undef HAVE_LSEEK64_PROTOTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `media_oldaliases' function. */ +#undef HAVE_MEDIA_OLDALIASES + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_MNTENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define when the compiler supports OFFSET_T type */ +#undef HAVE_OFFSET_T + +/* Define when the system has a 64 bit off_t type */ +#undef HAVE_OFF_T_64 + +/* Define to 1 if you have the `on_exit' function. */ +#undef HAVE_ON_EXIT + +/* Define to 1 if you have the `putwc' function. */ +#undef HAVE_PUTWC + +/* Define to 1 if you have the `random' function. */ +#undef HAVE_RANDOM + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `seteuid' function. */ +#undef HAVE_SETEUID + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setpgrp' function. */ +#undef HAVE_SETPGRP + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the header file. */ +#undef HAVE_SGTTY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the `srandom' function. */ +#undef HAVE_SRANDOM + +/* Define to 1 if you have the `stat64' function. */ +#undef HAVE_STAT64 + +/* 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 `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strcspn' function. */ +#undef HAVE_STRCSPN + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* 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 `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strnlen' function. */ +#undef HAVE_STRNLEN + +/* Define to 1 if you have the `strpbrk' function. */ +#undef HAVE_STRPBRK + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strspn' function. */ +#undef HAVE_STRSPN + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FLOPPY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SIGNAL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* 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_SYSMACROS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TERMIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the `tcflush' function. */ +#undef HAVE_TCFLUSH + +/* Define to 1 if you have the `tcsetattr' function. */ +#undef HAVE_TCSETATTR + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define to 1 if you have the `tzset' function. */ +#undef HAVE_TZSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `utime' function. */ +#undef HAVE_UTIME + +/* Define to 1 if you have the `utimes' function. */ +#undef HAVE_UTIMES + +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if you have the `wcscasecmp' function. */ +#undef HAVE_WCSCASECMP + +/* Define to 1 if you have the `wcsdup' function. */ +#undef HAVE_WCSDUP + +/* Define to 1 if you have the `wcsnlen' function. */ +#undef HAVE_WCSNLEN + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCTYPE_H + +/* 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 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if the `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if you can safely include both and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Define when you want to include floppyd support */ +#undef USE_FLOPPYD + +/* Define on non Unix OS'es which don't have the concept of tty's */ +#undef USE_RAWTERM + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define this if you want to use Xdf */ +#undef USE_XDF + +/* Define this if you use mtools together with the new Solaris' vold support + */ +#undef USING_NEW_VOLD + +/* Define this if you use mtools together with Solaris' vold */ +#undef USING_VOLD + +/* Define to 1 if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/config.sub b/config.sub new file mode 100644 index 0000000..6759825 --- /dev/null +++ b/config.sub @@ -0,0 +1,1658 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +# Free Software Foundation, Inc. + +timestamp='2008-01-16' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 0000000..e3b2eef --- /dev/null +++ b/configure @@ -0,0 +1,9650 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.63. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell bug-autoconf@gnu.org about your system, + echo including any error possibly output before this message. + echo This can help us improve future autoconf versions. + echo Configuration will now proceed without shell functions. +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="buffer.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +HOST_ID +SHLIB +MACHDEPLIBS +extralibdir +extraincludedir +BINFLOPPYD +FLOPPYD +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +INSTALL_INFO +LN_S +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_xdf +enable_vold +enable_new_vold +enable_debug +enable_raw_term +with_x +enable_floppyd +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +XMKMF' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 + { (exit 1); exit 1; }; } + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { $as_echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { $as_echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 + { (exit 1); exit 1; }; } ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { $as_echo "$as_me: error: working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +X features: + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-xdf support for OS/2 extended density format disks + --enable-vold compatibility with Solaris' vold + --enable-new-vold compatibility with Solaris' vold, new version + --enable-debug debuging messages + --enable-raw-term raw terminal (readkey behaviour, default) + --enable-floppyd floppy daemon support + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-x use the X Window System + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.63 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.63. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers config.h" + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:$LINENO: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } + +# Provide some information about the compiler. +$as_echo "$as_me:$LINENO: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } + fi + fi +fi +{ $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:$LINENO: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:$LINENO: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:$LINENO: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done +done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:$LINENO: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done +done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +if test $ac_cv_c_compiler_gnu = yes; then + { $as_echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5 +$as_echo_n "checking whether $CC needs -traditional... " >&6; } +if test "${ac_cv_prog_gcc_traditional+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_pattern="Autoconf.*'x'" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5 +$as_echo "$ac_cv_prog_gcc_traditional" >&6; } + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + +done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + +# Extract the first word of "install-info", so it can be a program name with args. +set dummy install-info; ac_word=$2 +{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_INSTALL_INFO+set}" = set; then + $as_echo_n "(cached) " >&6 +else + case $INSTALL_INFO in + [\\/]* | ?:[\\/]*) + ac_cv_path_INSTALL_INFO="$INSTALL_INFO" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_INSTALL_INFO="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_path_INSTALL_INFO" && ac_cv_path_INSTALL_INFO="""" + ;; +esac +fi +INSTALL_INFO=$ac_cv_path_INSTALL_INFO +if test -n "$INSTALL_INFO"; then + { $as_echo "$as_me:$LINENO: result: $INSTALL_INFO" >&5 +$as_echo "$INSTALL_INFO" >&6; } +else + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + if test "${ac_cv_header_minix_config_h+set}" = set; then + { $as_echo "$as_me:$LINENO: checking for minix/config.h" >&5 +$as_echo_n "checking for minix/config.h... " >&6; } +if test "${ac_cv_header_minix_config_h+set}" = set; then + $as_echo_n "(cached) " >&6 +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 +$as_echo "$ac_cv_header_minix_config_h" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking minix/config.h usability" >&5 +$as_echo_n "checking minix/config.h usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking minix/config.h presence" >&5 +$as_echo_n "checking minix/config.h presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: minix/config.h: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: minix/config.h: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for minix/config.h" >&5 +$as_echo_n "checking for minix/config.h... " >&6; } +if test "${ac_cv_header_minix_config_h+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_header_minix_config_h=$ac_header_preproc +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5 +$as_echo "$ac_cv_header_minix_config_h" >&6; } + +fi +if test "x$ac_cv_header_minix_config_h" = x""yes; then + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define _POSIX_SOURCE 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define _POSIX_1_SOURCE 2 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define _MINIX 1 +_ACEOF + + fi + + + + { $as_echo "$as_me:$LINENO: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if test "${ac_cv_safe_to_define___extensions__+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_safe_to_define___extensions__=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_safe_to_define___extensions__=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + cat >>confdefs.h <<\_ACEOF +#define __EXTENSIONS__ 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define _ALL_SOURCE 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define _GNU_SOURCE 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define _POSIX_PTHREAD_SEMANTICS 1 +_ACEOF + + cat >>confdefs.h <<\_ACEOF +#define _TANDEM_SOURCE 1 +_ACEOF + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 +$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} + { (exit 1); exit 1; }; } + +{ $as_echo "$as_me:$LINENO: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 +$as_echo "$as_me: error: invalid value of canonical build" >&2;} + { (exit 1); exit 1; }; };; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:$LINENO: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 +$as_echo "$as_me: error: invalid value of canonical host" >&2;} + { (exit 1); exit 1; }; };; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:$LINENO: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5 +$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;} + { (exit 1); exit 1; }; } +fi + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical target" >&5 +$as_echo "$as_me: error: invalid value of canonical target" >&2;} + { (exit 1); exit 1; }; };; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +{ $as_echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if test "${ac_cv_c_const+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_const=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_const=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const /**/ +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_inline=$ac_kw +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + + + +# Check whether --enable-xdf was given. +if test "${enable_xdf+set}" = set; then + enableval=$enable_xdf; if test x$enableval = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define USE_XDF 1 +_ACEOF + +fi +else + +cat >>confdefs.h <<\_ACEOF +#define USE_XDF 1 +_ACEOF + +fi + + + +# Check whether --enable-vold was given. +if test "${enable_vold+set}" = set; then + enableval=$enable_vold; if test x$enableval = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define USING_VOLD 1 +_ACEOF + +fi +fi + + + +# Check whether --enable-new-vold was given. +if test "${enable_new_vold+set}" = set; then + enableval=$enable_new_vold; newVold=x$enableval +if test x$enableval = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define USING_NEW_VOLD 1 +_ACEOF + +fi +fi + + + +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then + enableval=$enable_debug; if test x$enableval = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define DEBUG 1 +_ACEOF + +fi +fi + + + +# Check whether --enable-raw_term was given. +if test "${enable_raw_term+set}" = set; then + enableval=$enable_raw_term; if test x$enableval = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define USE_RAWTERM 1 +_ACEOF + +fi +else + +cat >>confdefs.h <<\_ACEOF +#define USE_RAWTERM 1 +_ACEOF + +fi + + + + + +{ $as_echo "$as_me:$LINENO: checking for getpwnam in -lsun" >&5 +$as_echo_n "checking for getpwnam in -lsun... " >&6; } +if test "${ac_cv_lib_sun_getpwnam+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsun $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char getpwnam (); +int +main () +{ +return getpwnam (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_sun_getpwnam=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_sun_getpwnam=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_sun_getpwnam" >&5 +$as_echo "$ac_cv_lib_sun_getpwnam" >&6; } +if test "x$ac_cv_lib_sun_getpwnam" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSUN 1 +_ACEOF + + LIBS="-lsun $LIBS" + +fi + + +{ $as_echo "$as_me:$LINENO: checking for cam_open_device in -lcam" >&5 +$as_echo_n "checking for cam_open_device in -lcam... " >&6; } +if test "${ac_cv_lib_cam_cam_open_device+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char cam_open_device (); +int +main () +{ +return cam_open_device (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_cam_cam_open_device=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_cam_cam_open_device=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cam_cam_open_device" >&5 +$as_echo "$ac_cv_lib_cam_cam_open_device" >&6; } +if test "x$ac_cv_lib_cam_cam_open_device" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCAM 1 +_ACEOF + + LIBS="-lcam $LIBS" + +fi + + +{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 +$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } +if test "${ac_cv_header_sys_wait_h+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_sys_wait_h=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_sys_wait_h=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 +$as_echo "$ac_cv_header_sys_wait_h" >&6; } +if test $ac_cv_header_sys_wait_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SYS_WAIT_H 1 +_ACEOF + +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_header in getopt.h sys/stat.h stdlib.h unistd.h linux/unistd.h \ +libc.h fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h strings.h string.h \ +sys/param.h memory.h malloc.h signal.h sys/signal.h utime.h sgtty.h \ +sys/floppy.h mntent.h sys/sysmacros.h netinet/in.h assert.h \ +iconv.h wctype.h wchar.h locale.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in termio.h sys/termio.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + break +fi + +done + + + +for ac_header in termios.h sys/termios.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + break +fi + +done + + + +{ $as_echo "$as_me:$LINENO: checking whether llseek declared in unistd.h" >&5 +$as_echo_n "checking whether llseek declared in unistd.h... " >&6; } +if test "${mtools_cv_have_llseek_prototype+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +extern int llseek(int); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + mtools_cv_have_llseek_prototype=no +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + mtools_cv_have_llseek_prototype=yes +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +{ $as_echo "$as_me:$LINENO: result: $mtools_cv_have_llseek_prototype" >&5 +$as_echo "$mtools_cv_have_llseek_prototype" >&6; } +if test "$mtools_cv_have_llseek_prototype" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LLSEEK_PROTOTYPE 1 +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking whether lseek64 declared in unistd.h" >&5 +$as_echo_n "checking whether lseek64 declared in unistd.h... " >&6; } +if test "${mtools_cv_have_lseek64_prototype+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include "sysincludes.h" +#include + +int +main () +{ +extern int lseek64(int); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + mtools_cv_have_lseek64_prototype=no +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + mtools_cv_have_lseek64_prototype=yes +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +{ $as_echo "$as_me:$LINENO: result: $mtools_cv_have_lseek64_prototype" >&5 +$as_echo "$mtools_cv_have_lseek64_prototype" >&6; } +if test "$mtools_cv_have_lseek64_prototype" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LSEEK64_PROTOTYPE 1 +_ACEOF + +fi + + + +for ac_func in htons +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +{ $as_echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if test "${ac_cv_c_const+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_const=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_const=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const /**/ +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if test "${ac_cv_c_inline+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_inline=$ac_kw +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +{ $as_echo "$as_me:$LINENO: checking for size_t" >&5 +$as_echo_n "checking for size_t... " >&6; } +if test "${ac_cv_type_size_t+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_cv_type_size_t=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if (sizeof ((size_t))) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_size_t=yes +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +$as_echo "$ac_cv_type_size_t" >&6; } +if test "x$ac_cv_type_size_t" = x""yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 +$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } +if test "${ac_cv_header_time+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_time=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_time=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 +$as_echo "$ac_cv_header_time" >&6; } +if test $ac_cv_header_time = yes; then + +cat >>confdefs.h <<\_ACEOF +#define TIME_WITH_SYS_TIME 1 +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 +$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } +if test "${ac_cv_struct_tm+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm tm; + int *p = &tm.tm_sec; + return !p; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_struct_tm=time.h +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_struct_tm=sys/time.h +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 +$as_echo "$ac_cv_struct_tm" >&6; } +if test $ac_cv_struct_tm = sys/time.h; then + +cat >>confdefs.h <<\_ACEOF +#define TM_IN_SYS_TIME 1 +_ACEOF + +fi + + + +{ $as_echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +$as_echo_n "checking return type of signal handlers... " >&6; } +if test "${ac_cv_type_signal+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +return *(signal (0, 0)) (0) == 1; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_signal=int +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_signal=void +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +$as_echo "$ac_cv_type_signal" >&6; } + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +for ac_func in strerror random srandom strchr strrchr lockf flock \ +strcasecmp strncasecmp strnlen atexit on_exit getpass memmove \ +strdup strcspn strspn strtoul strtol memcpy strpbrk memset setenv \ +seteuid setresuid setpgrp \ +tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \ +snprintf stat64 setlocale \ +wcsdup wcscasecmp wcsnlen putwc \ +getuserid getgroupid +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +{ $as_echo "$as_me:$LINENO: checking whether setpgrp takes no argument" >&5 +$as_echo_n "checking whether setpgrp takes no argument... " >&6; } +if test "${ac_cv_func_setpgrp_void+set}" = set; then + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then + { { $as_echo "$as_me:$LINENO: error: cannot check setpgrp when cross compiling" >&5 +$as_echo "$as_me: error: cannot check setpgrp when cross compiling" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +/* If this system has a BSD-style setpgrp which takes arguments, + setpgrp(1, 1) will fail with ESRCH and return -1, in that case + exit successfully. */ + return setpgrp (1,1) != -1; + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_setpgrp_void=no +else + $as_echo "$as_me: program exited with status $ac_status" >&5 +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_func_setpgrp_void=yes +fi +rm -rf conftest.dSYM +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_setpgrp_void" >&5 +$as_echo "$ac_cv_func_setpgrp_void" >&6; } +if test $ac_cv_func_setpgrp_void = yes; then + +cat >>confdefs.h <<\_ACEOF +#define SETPGRP_VOID 1 +_ACEOF + +fi + + + + + + + + + + + +{ $as_echo "$as_me:$LINENO: checking for 64-bit off_t" >&5 +$as_echo_n "checking for 64-bit off_t... " >&6; } +if test "${sfs_cv_off_t_64+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + +switch (0) case 0: case (sizeof (off_t) <= 4):; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + sfs_cv_off_t_64=no +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + sfs_cv_off_t_64=yes +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $sfs_cv_off_t_64" >&5 +$as_echo "$sfs_cv_off_t_64" >&6; } +if test $sfs_cv_off_t_64 = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_OFF_T_64 1 +_ACEOF + +fi + +{ $as_echo "$as_me:$LINENO: checking whether ${CC} supports loff_t type" >&5 +$as_echo_n "checking whether ${CC} supports loff_t type... " >&6; } +if test "${ice_cv_have_loff_t+set}" = set; then + $as_echo_n "(cached) " >&6 +else + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +loff_t a; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ice_cv_have_loff_t=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ice_cv_have_loff_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + +{ $as_echo "$as_me:$LINENO: result: $ice_cv_have_loff_t" >&5 +$as_echo "$ice_cv_have_loff_t" >&6; } +if test "$ice_cv_have_loff_t" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LOFF_T 1 +_ACEOF + +fi + + +{ $as_echo "$as_me:$LINENO: checking whether ${CC} supports offset_t type" >&5 +$as_echo_n "checking whether ${CC} supports offset_t type... " >&6; } +if test "${ice_cv_have_offset_t+set}" = set; then + $as_echo_n "(cached) " >&6 +else + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +offset_t a; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ice_cv_have_offset_t=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ice_cv_have_offset_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + +{ $as_echo "$as_me:$LINENO: result: $ice_cv_have_offset_t" >&5 +$as_echo "$ice_cv_have_offset_t" >&6; } +if test "$ice_cv_have_offset_t" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_OFFSET_T 1 +_ACEOF + +fi + + +{ $as_echo "$as_me:$LINENO: checking whether ${CC} supports long long type" >&5 +$as_echo_n "checking whether ${CC} supports long long type... " >&6; } +if test "${ice_cv_have_long_long+set}" = set; then + $as_echo_n "(cached) " >&6 +else + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +long long a; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ice_cv_have_long_long=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ice_cv_have_long_long=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi + +{ $as_echo "$as_me:$LINENO: result: $ice_cv_have_long_long" >&5 +$as_echo "$ice_cv_have_long_long" >&6; } +if test "$ice_cv_have_long_long" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LONG_LONG 1 +_ACEOF + +fi + + + + + +for ac_func in utimes utime +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + break +fi +done + + + +for ac_func in tzset gettimeofday +do +as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 +$as_echo_n "checking for $ac_func... " >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + eval "$as_ac_var=yes" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +as_val=`eval 'as_val=${'$as_ac_var'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +{ $as_echo "$as_me:$LINENO: checking declaration of sys_errlist" >&5 +$as_echo_n "checking declaration of sys_errlist... " >&6; } +if test "${cf_cv_dcl_sys_errlist+set}" = set; then + $as_echo_n "(cached) " >&6 +else + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include +#include +int +main () +{ +char *c = (char *) *sys_errlist + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + cf_cv_dcl_sys_errlist=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cf_cv_dcl_sys_errlist=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +{ $as_echo "$as_me:$LINENO: result: $cf_cv_dcl_sys_errlist" >&5 +$as_echo "$cf_cv_dcl_sys_errlist" >&6; } +test $cf_cv_dcl_sys_errlist = no || +cat >>confdefs.h <<\_ACEOF +#define DECL_SYS_ERRLIST 1 +_ACEOF + + + + +host_os0=`echo $host_os | sed 's/-/_/g'` +host_os1=`echo $host_os0 | sed 's/\./_/g'` +host_os2=`echo $host_os0 | sed 's/^\([^.]*\)\..*$/\1/g'` +host_os3=`echo $host_os2 | sed 's/^\([^0-9]*\)[0-9]*$/\1/g'` +host_cpu1=`echo $host_cpu | sed 's/\./_/g'` +host_vendor1=`echo $host_vendor | sed 's/\./_/g'` +HOST_ID="-DCPU_$host_cpu1 -DVENDOR_$host_vendor1 -DOS_$host_os1" +if [ $host_os1 != $host_os2 ] ; then + HOST_ID="$HOST_ID -DOS_$host_os2" +fi +if [ $host_os1 != $host_os3 ] && [ $host_os2 != $host_os3 ] ; then + HOST_ID="$HOST_ID -DOS_$host_os3" +fi + +my_host_os=`echo $host_os1 $host_os2 $host_os3 | sort -u` +objs=`echo $srcdir/*.c | sed 's/\.c$/.o/' ` +if [ "X$GCC" = "Xyes" ] ; then + if [ "$host_cpu" = i486 ] ; then + CFLAGS="$CFLAGS -m486" + fi + Wall=-Wall + if [ "$host_os3" = sunos ] ; then + Wall="" + fi + if [ "$host_os3" = ultrix ] ; then + Wall="" + fi + if [ "$host_os3" = linux ] ; then + CFLAGS="$CFLAGS -fno-strength-reduce" + fi + if [ "$host_os3" = aux ] ; then + CFLAGS="$CFLAGS -ZP" + MACHDEPLIBS="-lposix -UTIL" + fi + case "${host}" in + arm*-*-linux) CFLAGS="$CFLAGS -mstructure-size-boundary=8";; + esac + CFLAGS="$CFLAGS $Wall" +else + if [ $host_os3 = hpux ] ; then + CPPFLAGS="$CPPFLAGS -Ae" + fi + + if [ $host_os3 = xenix ] ; then + CFLAGS="$CFLAGS -M2e" + fi +fi + +if [ $host_os3 = hpux ] ; then + LDFLAGS="$LDFLAGS -z" +fi + + +if [ $host_vendor = linux ] ; then + LDFLAGS="$LDFLAGS -z" +fi + +if [ $host_os3 = xenix ] ; then + LDFLAGS="$LDFLAGS -M2e -i -f 5000" +fi + +if [ $host_os2 = sysv4 ] ; then + SHLIB="-lc -L/usr/ucblib -lucb" +else + SHLIB="" +fi + +if [ $host_os3 = isc ] ; then + CFLAGS="$CFLAGS -D_SYSV3" + SHLIB="-lc_s" +fi + +if [ $host_os3 = solaris -a x$newVold = xxyes ] ; then + SHLIB="$SHLIB -s -lvolmgt" +fi + +if [ $host_os3 = nextstep ] ; then + CFLAGS="$CFLAGS -DBSD" + SHLIB="" +fi + +if [ -d /usr/5lib ] ; then + extralibdir=-L/usr/5lib +fi + + + +{ $as_echo "$as_me:$LINENO: checking for X" >&5 +$as_echo_n "checking for X... " >&6; } + + +# Check whether --with-x was given. +if test "${with_x+set}" = set; then + withval=$with_x; +fi + +# $have_x is `yes', `no', `disabled', or empty when we do not yet know. +if test "x$with_x" = xno; then + # The user explicitly disabled X. + have_x=disabled +else + case $x_includes,$x_libraries in #( + *\'*) { { $as_echo "$as_me:$LINENO: error: cannot use X directory names containing '" >&5 +$as_echo "$as_me: error: cannot use X directory names containing '" >&2;} + { (exit 1); exit 1; }; };; #( + *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then + $as_echo_n "(cached) " >&6 +else + # One or both of the vars are not set, and there is no cached value. +ac_x_includes=no ac_x_libraries=no +rm -f -r conftest.dir +if mkdir conftest.dir; then + cd conftest.dir + cat >Imakefile <<'_ACEOF' +incroot: + @echo incroot='${INCROOT}' +usrlibdir: + @echo usrlibdir='${USRLIBDIR}' +libdir: + @echo libdir='${LIBDIR}' +_ACEOF + if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then + # GNU make sometimes prints "make[1]: Entering...", which would confuse us. + for ac_var in incroot usrlibdir libdir; do + eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" + done + # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. + for ac_extension in a so sl dylib la dll; do + if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && + test -f "$ac_im_libdir/libX11.$ac_extension"; then + ac_im_usrlibdir=$ac_im_libdir; break + fi + done + # Screen out bogus values from the imake configuration. They are + # bogus both because they are the default anyway, and because + # using them would break gcc on systems where it needs fixed includes. + case $ac_im_incroot in + /usr/include) ac_x_includes= ;; + *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; + esac + case $ac_im_usrlibdir in + /usr/lib | /usr/lib64 | /lib | /lib64) ;; + *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; + esac + fi + cd .. + rm -f -r conftest.dir +fi + +# Standard set of common directories for X headers. +# Check X11 before X11Rn because it is often a symlink to the current release. +ac_x_header_dirs=' +/usr/X11/include +/usr/X11R6/include +/usr/X11R5/include +/usr/X11R4/include + +/usr/include/X11 +/usr/include/X11R6 +/usr/include/X11R5 +/usr/include/X11R4 + +/usr/local/X11/include +/usr/local/X11R6/include +/usr/local/X11R5/include +/usr/local/X11R4/include + +/usr/local/include/X11 +/usr/local/include/X11R6 +/usr/local/include/X11R5 +/usr/local/include/X11R4 + +/usr/X386/include +/usr/x386/include +/usr/XFree86/include/X11 + +/usr/include +/usr/local/include +/usr/unsupported/include +/usr/athena/include +/usr/local/x11r5/include +/usr/lpp/Xamples/include + +/usr/openwin/include +/usr/openwin/share/include' + +if test "$ac_x_includes" = no; then + # Guess where to find include files, by looking for Xlib.h. + # First, try using that file with no special directory specified. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # We can compile using X headers with no special include directory. +ac_x_includes= +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + for ac_dir in $ac_x_header_dirs; do + if test -r "$ac_dir/X11/Xlib.h"; then + ac_x_includes=$ac_dir + break + fi +done +fi + +rm -f conftest.err conftest.$ac_ext +fi # $ac_x_includes = no + +if test "$ac_x_libraries" = no; then + # Check for the libraries. + # See if we find them without any special options. + # Don't add to $LIBS permanently. + ac_save_LIBS=$LIBS + LIBS="-lX11 $LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +XrmInitialize () + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + LIBS=$ac_save_LIBS +# We can link X programs with no special library path. +ac_x_libraries= +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + LIBS=$ac_save_LIBS +for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` +do + # Don't even attempt the hair of trying to link an X program! + for ac_extension in a so sl dylib la dll; do + if test -r "$ac_dir/libX11.$ac_extension"; then + ac_x_libraries=$ac_dir + break 2 + fi + done +done +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi # $ac_x_libraries = no + +case $ac_x_includes,$ac_x_libraries in #( + no,* | *,no | *\'*) + # Didn't find X, or a directory has "'" in its name. + ac_cv_have_x="have_x=no";; #( + *) + # Record where we found X for the cache. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$ac_x_includes'\ + ac_x_libraries='$ac_x_libraries'" +esac +fi +;; #( + *) have_x=yes;; + esac + eval "$ac_cv_have_x" +fi # $with_x != no + +if test "$have_x" != yes; then + { $as_echo "$as_me:$LINENO: result: $have_x" >&5 +$as_echo "$have_x" >&6; } + no_x=yes +else + # If each of the values was on the command line, it overrides each guess. + test "x$x_includes" = xNONE && x_includes=$ac_x_includes + test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries + # Update the cache value to reflect the command line values. + ac_cv_have_x="have_x=yes\ + ac_x_includes='$x_includes'\ + ac_x_libraries='$x_libraries'" + { $as_echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5 +$as_echo "libraries $x_libraries, headers $x_includes" >&6; } +fi + +if test "$no_x" = yes; then + # Not all programs may use this symbol, but it does not hurt to define it. + +cat >>confdefs.h <<\_ACEOF +#define X_DISPLAY_MISSING 1 +_ACEOF + + X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= +else + if test -n "$x_includes"; then + X_CFLAGS="$X_CFLAGS -I$x_includes" + fi + + # It would also be nice to do this for all -L options, not just this one. + if test -n "$x_libraries"; then + X_LIBS="$X_LIBS -L$x_libraries" + # For Solaris; some versions of Sun CC require a space after -R and + # others require no space. Words are not sufficient . . . . + { $as_echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5 +$as_echo_n "checking whether -R must be followed by a space... " >&6; } + ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" + ac_xsave_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + X_LIBS="$X_LIBS -R$x_libraries" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + LIBS="$ac_xsave_LIBS -R $x_libraries" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + X_LIBS="$X_LIBS -R $x_libraries" +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { $as_echo "$as_me:$LINENO: result: neither works" >&5 +$as_echo "neither works" >&6; } +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + ac_c_werror_flag=$ac_xsave_c_werror_flag + LIBS=$ac_xsave_LIBS + fi + + # Check for system-dependent libraries X programs must link with. + # Do this before checking for the system-independent R6 libraries + # (-lICE), since we may need -lsocket or whatever for X linking. + + if test "$ISC" = yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" + else + # Martyn Johnson says this is needed for Ultrix, if the X + # libraries were built with DECnet support. And Karl Berry says + # the Alpha needs dnet_stub (dnet does not exist). + ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char XOpenDisplay (); +int +main () +{ +return XOpenDisplay (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + : +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } +if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dnet_dnet_ntoa=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dnet_dnet_ntoa=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" +fi + + if test $ac_cv_lib_dnet_dnet_ntoa = no; then + { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet_stub" >&5 +$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } +if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldnet_stub $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dnet_ntoa (); +int +main () +{ +return dnet_ntoa (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_dnet_stub_dnet_ntoa=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_dnet_stub_dnet_ntoa=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 +$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } +if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" +fi + + fi +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + LIBS="$ac_xsave_LIBS" + + # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, + # to get the SysV transport functions. + # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) + # needs -lnsl. + # The nsl library prevents programs from opening the X display + # on Irix 5.2, according to T.E. Dickey. + # The functions gethostbyname, getservbyname, and inet_addr are + # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. + { $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5 +$as_echo_n "checking for gethostbyname... " >&6; } +if test "${ac_cv_func_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define gethostbyname to an innocuous variant, in case declares gethostbyname. + For example, HP-UX 11i declares gettimeofday. */ +#define gethostbyname innocuous_gethostbyname + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char gethostbyname (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef gethostbyname + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_gethostbyname || defined __stub___gethostbyname +choke me +#endif + +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 +$as_echo "$ac_cv_func_gethostbyname" >&6; } + + if test $ac_cv_func_gethostbyname = no; then + { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +$as_echo_n "checking for gethostbyname in -lnsl... " >&6; } +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_nsl_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_nsl_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } +if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" +fi + + if test $ac_cv_lib_nsl_gethostbyname = no; then + { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lbsd" >&5 +$as_echo_n "checking for gethostbyname in -lbsd... " >&6; } +if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_bsd_gethostbyname=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_bsd_gethostbyname=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gethostbyname" >&5 +$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } +if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" +fi + + fi + fi + + # lieder@skyler.mavd.honeywell.com says without -lsocket, + # socket/setsockopt and other routines are undefined under SCO ODT + # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary + # on later versions), says Simon Leinen: it contains gethostby* + # variants that don't use the name server (or something). -lsocket + # must be given before -lnsl if both are needed. We assume that + # if connect needs -lnsl, so does gethostbyname. + { $as_echo "$as_me:$LINENO: checking for connect" >&5 +$as_echo_n "checking for connect... " >&6; } +if test "${ac_cv_func_connect+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define connect to an innocuous variant, in case declares connect. + For example, HP-UX 11i declares gettimeofday. */ +#define connect innocuous_connect + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char connect (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef connect + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_connect || defined __stub___connect +choke me +#endif + +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_connect=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_connect=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 +$as_echo "$ac_cv_func_connect" >&6; } + + if test $ac_cv_func_connect = no; then + { $as_echo "$as_me:$LINENO: checking for connect in -lsocket" >&5 +$as_echo_n "checking for connect in -lsocket... " >&6; } +if test "${ac_cv_lib_socket_connect+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $X_EXTRA_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_socket_connect=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_socket_connect=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5 +$as_echo "$ac_cv_lib_socket_connect" >&6; } +if test "x$ac_cv_lib_socket_connect" = x""yes; then + X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" +fi + + fi + + # Guillermo Gomez says -lposix is necessary on A/UX. + { $as_echo "$as_me:$LINENO: checking for remove" >&5 +$as_echo_n "checking for remove... " >&6; } +if test "${ac_cv_func_remove+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define remove to an innocuous variant, in case declares remove. + For example, HP-UX 11i declares gettimeofday. */ +#define remove innocuous_remove + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char remove (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef remove + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_remove || defined __stub___remove +choke me +#endif + +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_remove=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_remove=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_remove" >&5 +$as_echo "$ac_cv_func_remove" >&6; } + + if test $ac_cv_func_remove = no; then + { $as_echo "$as_me:$LINENO: checking for remove in -lposix" >&5 +$as_echo_n "checking for remove in -lposix... " >&6; } +if test "${ac_cv_lib_posix_remove+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lposix $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char remove (); +int +main () +{ +return remove (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_posix_remove=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_posix_remove=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_posix_remove" >&5 +$as_echo "$ac_cv_lib_posix_remove" >&6; } +if test "x$ac_cv_lib_posix_remove" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" +fi + + fi + + # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. + { $as_echo "$as_me:$LINENO: checking for shmat" >&5 +$as_echo_n "checking for shmat... " >&6; } +if test "${ac_cv_func_shmat+set}" = set; then + $as_echo_n "(cached) " >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define shmat to an innocuous variant, in case declares shmat. + For example, HP-UX 11i declares gettimeofday. */ +#define shmat innocuous_shmat + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char shmat (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef shmat + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_shmat || defined __stub___shmat +choke me +#endif + +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_func_shmat=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_shmat=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shmat" >&5 +$as_echo "$ac_cv_func_shmat" >&6; } + + if test $ac_cv_func_shmat = no; then + { $as_echo "$as_me:$LINENO: checking for shmat in -lipc" >&5 +$as_echo_n "checking for shmat in -lipc... " >&6; } +if test "${ac_cv_lib_ipc_shmat+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lipc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shmat (); +int +main () +{ +return shmat (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_ipc_shmat=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_ipc_shmat=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ipc_shmat" >&5 +$as_echo "$ac_cv_lib_ipc_shmat" >&6; } +if test "x$ac_cv_lib_ipc_shmat" = x""yes; then + X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" +fi + + fi + fi + + # Check for libraries that X11R6 Xt/Xaw programs need. + ac_save_LDFLAGS=$LDFLAGS + test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" + # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to + # check for ICE first), but we must link in the order -lSM -lICE or + # we get undefined symbols. So assume we have SM if we have ICE. + # These have to be linked with before -lX11, unlike the other + # libraries we check for below, so use a different variable. + # John Interrante, Karl Berry + { $as_echo "$as_me:$LINENO: checking for IceConnectionNumber in -lICE" >&5 +$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } +if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lICE $X_EXTRA_LIBS $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char IceConnectionNumber (); +int +main () +{ +return IceConnectionNumber (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_ICE_IceConnectionNumber=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_ICE_IceConnectionNumber=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 +$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } +if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then + X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" +fi + + LDFLAGS=$ac_save_LDFLAGS + +fi + + +# Check whether --enable-floppyd was given. +if test "${enable_floppyd+set}" = set; then + enableval=$enable_floppyd; if test x$enableval != x; then + use_floppyd=$enableval +fi +fi + + + +{ $as_echo "$as_me:$LINENO: checking for main in -lsocket" >&5 +$as_echo_n "checking for main in -lsocket... " >&6; } +if test "${ac_cv_lib_socket_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_socket_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_socket_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5 +$as_echo "$ac_cv_lib_socket_main" >&6; } +if test "x$ac_cv_lib_socket_main" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + +{ $as_echo "$as_me:$LINENO: checking for main in -lnsl" >&5 +$as_echo_n "checking for main in -lnsl... " >&6; } +if test "${ac_cv_lib_nsl_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_nsl_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_nsl_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5 +$as_echo "$ac_cv_lib_nsl_main" >&6; } +if test "x$ac_cv_lib_nsl_main" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + +{ $as_echo "$as_me:$LINENO: checking for main in -lbsd" >&5 +$as_echo_n "checking for main in -lbsd... " >&6; } +if test "${ac_cv_lib_bsd_main+set}" = set; then + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then + ac_cv_lib_bsd_main=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_bsd_main=no +fi + +rm -rf conftest.dSYM +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_main" >&5 +$as_echo "$ac_cv_lib_bsd_main" >&6; } +if test "x$ac_cv_lib_bsd_main" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBBSD 1 +_ACEOF + + LIBS="-lbsd $LIBS" + +fi + + + + +for ac_header in sys/socket.h arpa/inet.h netdb.h +do +as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 +$as_echo_n "checking $ac_header usability... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 +$as_echo_n "checking $ac_header presence... " >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +$as_echo "$ac_try_echo") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 +$as_echo_n "checking for $ac_header... " >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + $as_echo_n "(cached) " >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + +fi +as_val=`eval 'as_val=${'$as_ac_Header'} + $as_echo "$as_val"'` + if test "x$as_val" = x""yes; then + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +if test X$use_floppyd = X -a X$no_x = X ; then + use_floppyd="yes" +fi + +if test X$use_floppyd = Xyes; then + if test X$no_x = Xyes ; then + echo "Floppyd needs X support" >&2 + echo "To compile without floppyd, use ./configure --disable-floppyd" >&2 + exit 1 + fi + FLOPPYD="floppyd floppyd_installtest" + BINFLOPPYD="\$(DESTDIR)\$(bindir)/floppyd \$(DESTDIR)\$(bindir)/floppyd_installtest" + +cat >>confdefs.h <<\_ACEOF +#define USE_FLOPPYD 1 +_ACEOF + +else + FLOPPYD= + BINFLOPPYD= +fi + + + + + + + + + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.63. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTION]... [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.63, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2008 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { $as_echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { $as_echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + $as_echo "$as_me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=' ' +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 +$as_echo "$as_me: error: could not setup config files machinery" >&2;} + { (exit 1); exit 1; }; } +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 +$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 +$as_echo "$as_me: error: could not setup config headers machinery" >&2;} + { (exit 1); exit 1; }; } +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 +$as_echo "$as_me: error: invalid tag $ac_tag" >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + ac_file_inputs="$ac_file_inputs '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +$as_echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 +$as_echo "$as_me: error: could not create $ac_file" >&2;} + { (exit 1); exit 1; }; } + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 +$as_echo "$as_me: error: could not create -" >&2;} + { (exit 1); exit 1; }; } + fi + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..52fa860 --- /dev/null +++ b/configure.in @@ -0,0 +1,400 @@ +dnl Copyright 1996-2003,2005,2006,2008,2009 Alain Knaff. +dnl This file is part of mtools. +dnl +dnl Mtools is free software: you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl Mtools is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with Mtools. If not, see . +dnl +dnl Process this file with autoconf to produce a configure script. +AC_INIT(buffer.c) + +AC_CONFIG_HEADER(config.h) + +dnl Checks for compiler +AC_PROG_CC +dnl AC_PROG_CXX +AC_PROG_GCC_TRADITIONAL +AC_PROG_INSTALL +AC_PROG_LN_S + +AC_PATH_PROG(INSTALL_INFO, install-info, "") + +dnl Check for Systems +AC_USE_SYSTEM_EXTENSIONS +AC_CANONICAL_SYSTEM + +AC_C_CONST +AC_C_INLINE + + +dnl Check for configuration options +dnl Enable OS/2 extended density format disks +AC_ARG_ENABLE(xdf, +[ --enable-xdf support for OS/2 extended density format disks], +[if test x$enableval = xyes; then + AC_DEFINE([USE_XDF],1,[Define this if you want to use Xdf]) +fi],AC_DEFINE([USE_XDF],1,[Define this if you want to use Xdf])) + + +dnl Check for configuration options +dnl Enable usage of vold on Solaris +AC_ARG_ENABLE(vold, +[ --enable-vold compatibility with Solaris' vold], +[if test x$enableval = xyes; then + AC_DEFINE([USING_VOLD],1,[Define this if you use mtools together with Solaris' vold]) +fi]) + + +dnl Check for configuration options +dnl Enable usage of vold on Solaris +AC_ARG_ENABLE(new-vold, +[ --enable-new-vold compatibility with Solaris' vold, new version], +[newVold=x$enableval +if test x$enableval = xyes; then + AC_DEFINE([USING_NEW_VOLD],1,[Define this if you use mtools together with the new Solaris' vold support]) +fi]) + + +dnl Check for configuration options +dnl Debugging +AC_ARG_ENABLE(debug, +[ --enable-debug debuging messages], +[if test x$enableval = xyes; then + AC_DEFINE([DEBUG],1,[Define for debugging messages]) +fi]) + + +dnl Check for configuration options +dnl Raw terminal code (enabled by default) +AC_ARG_ENABLE(raw_term, +[ --enable-raw-term raw terminal (readkey behaviour, default)], +[if test x$enableval = xyes; then + AC_DEFINE([USE_RAWTERM],1,[Define on non Unix OS'es which don't have the concept of tty's]) +fi], +AC_DEFINE([USE_RAWTERM],1,[Define on non Unix OS'es which don't have the concept of tty's])) + + +dnl Checks for libraries. + +dnl AC_IRIX_SUN +AC_CHECK_LIB(sun, getpwnam) +AC_CHECK_LIB(cam, cam_open_device) + +dnl Checks for header files. +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(getopt.h sys/stat.h stdlib.h unistd.h linux/unistd.h \ +libc.h fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h strings.h string.h \ +sys/param.h memory.h malloc.h signal.h sys/signal.h utime.h sgtty.h \ +sys/floppy.h mntent.h sys/sysmacros.h netinet/in.h assert.h \ +iconv.h wctype.h wchar.h locale.h) +AC_CHECK_HEADERS(termio.h sys/termio.h, [break]) +AC_CHECK_HEADERS(termios.h sys/termios.h, [break]) + + +dnl +dnl Check to see if llseek() is declared in unistd.h. On some libc's +dnl it is, and on others it isn't..... Thank you glibc developers.... +dnl +dnl Warning! Use of --enable-gcc-wall may throw off this test. +dnl +dnl +AC_MSG_CHECKING(whether llseek declared in unistd.h) +AC_CACHE_VAL(mtools_cv_have_llseek_prototype, + AC_TRY_COMPILE( +[#include ], [extern int llseek(int);], + [mtools_cv_have_llseek_prototype=no], + [mtools_cv_have_llseek_prototype=yes])) +AC_MSG_RESULT($mtools_cv_have_llseek_prototype) +if test "$mtools_cv_have_llseek_prototype" = yes; then + AC_DEFINE([HAVE_LLSEEK_PROTOTYPE],1,[Define when you have an LLSEEK prototype]) +fi + +AC_MSG_CHECKING(whether lseek64 declared in unistd.h) +AC_CACHE_VAL(mtools_cv_have_lseek64_prototype, + AC_TRY_COMPILE( +[ +#include "sysincludes.h" +#include +], [extern int lseek64(int);], + [mtools_cv_have_lseek64_prototype=no], + [mtools_cv_have_lseek64_prototype=yes])) +AC_MSG_RESULT($mtools_cv_have_lseek64_prototype) +if test "$mtools_cv_have_lseek64_prototype" = yes; then + AC_DEFINE([HAVE_LSEEK64_PROTOTYPE],1,[Define when you have an LSEEK64 prototype]) +fi + + +AC_CHECK_FUNCS(htons) + +dnl Apparently termio before termios is preferred by A/UX, AIX and SCO + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM + + +dnl Checks for library functions. +AC_TYPE_SIGNAL +AC_CHECK_FUNCS(strerror random srandom strchr strrchr lockf flock \ +strcasecmp strncasecmp strnlen atexit on_exit getpass memmove \ +strdup strcspn strspn strtoul strtol memcpy strpbrk memset setenv \ +seteuid setresuid setpgrp \ +tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \ +snprintf stat64 setlocale \ +wcsdup wcscasecmp wcsnlen putwc \ +getuserid getgroupid) +AC_FUNC_SETPGRP + +dnl +dnl Check for 64-bit off_t +dnl +AC_DEFUN(SFS_CHECK_OFF_T_64, +[AC_CACHE_CHECK(for 64-bit off_t, sfs_cv_off_t_64, +AC_TRY_COMPILE([ +#include +#include +],[ +switch (0) case 0: case (sizeof (off_t) <= 4):; +], sfs_cv_off_t_64=no, sfs_cv_off_t_64=yes)) +if test $sfs_cv_off_t_64 = yes; then + AC_DEFINE([HAVE_OFF_T_64],1,[Define when the system has a 64 bit off_t type]) +fi]) + + +dnl ICE_CC_LOFF_T +dnl ------------- +dnl +dnl If the CC compiler supports `loff_t' type, define `HAVE_LOFF_T'. +dnl +AC_DEFUN(ICE_CC_LOFF_T, +[ +AC_MSG_CHECKING(whether ${CC} supports loff_t type) +AC_CACHE_VAL(ice_cv_have_loff_t, +[ +AC_TRY_COMPILE([#include ],[loff_t a;], +ice_cv_have_loff_t=yes, +ice_cv_have_loff_t=no) +]) +AC_MSG_RESULT($ice_cv_have_loff_t) +if test "$ice_cv_have_loff_t" = yes; then +AC_DEFINE([HAVE_LOFF_T],1,[Define when the compiler supports LOFF_T type]) +fi +])dnl + + +dnl ICE_CC_OFFSET_T +dnl ------------- +dnl +dnl If the CC compiler supports `offset_t' type, define `HAVE_OFFSET_T'. +dnl +AC_DEFUN(ICE_CC_OFFSET_T, +[ +AC_MSG_CHECKING(whether ${CC} supports offset_t type) +AC_CACHE_VAL(ice_cv_have_offset_t, +[ +AC_TRY_COMPILE([#include ],[offset_t a;], +ice_cv_have_offset_t=yes, +ice_cv_have_offset_t=no) +]) +AC_MSG_RESULT($ice_cv_have_offset_t) +if test "$ice_cv_have_offset_t" = yes; then +AC_DEFINE([HAVE_OFFSET_T],1,[Define when the compiler supports OFFSET_T type]) +fi +])dnl + +dnl ICE_CC_LONG_LONG +dnl ------------- +dnl +dnl If the CC compiler supports `long long' type, define `HAVE_LONG_LONG'. +dnl +AC_DEFUN(ICE_CC_LONG_LONG, +[ +AC_MSG_CHECKING(whether ${CC} supports long long type) +AC_CACHE_VAL(ice_cv_have_long_long, +[ +AC_TRY_COMPILE(,[long long a;], +ice_cv_have_long_long=yes, +ice_cv_have_long_long=no) +]) +AC_MSG_RESULT($ice_cv_have_long_long) +if test "$ice_cv_have_long_long" = yes; then +AC_DEFINE([HAVE_LONG_LONG],1,[Define when the compiler supports LONG_LONG type]) +fi +])dnl + +dnl ICE_CC_OFF64_T +dnl ------------- +dnl +dnl If the CC compiler supports `long long' type, define `HAVE_OFF64_T'. +dnl +AC_DEFUN(ICE_CC_OFF64_T, +[ +AC_MSG_CHECKING(whether ${CC} supports off64_t type) +AC_CACHE_VAL(ice_cv_have_off64_t, +[ +AC_TRY_COMPILE(,[off64_t a;], +ice_cv_have_off64_t=yes, +ice_cv_have_off64_t=no) +]) +AC_MSG_RESULT($ice_cv_have_off64_t) +if test "$ice_cv_have_off64_t" = yes; then +AC_DEFINE([HAVE_OFF64_T],1,[Define when the compiler supports OFF64_T type]) +fi +])dnl + + +SFS_CHECK_OFF_T_64 +ICE_CC_LOFF_T +ICE_CC_OFFSET_T +ICE_CC_LONG_LONG + + +AC_CHECK_FUNCS(utimes utime, [break]) +AC_CHECK_FUNCS(tzset gettimeofday) + +CF_SYS_ERRLIST + +[ +host_os0=`echo $host_os | sed 's/-/_/g'` +host_os1=`echo $host_os0 | sed 's/\./_/g'` +host_os2=`echo $host_os0 | sed 's/^\([^.]*\)\..*$/\1/g'` +host_os3=`echo $host_os2 | sed 's/^\([^0-9]*\)[0-9]*$/\1/g'` +host_cpu1=`echo $host_cpu | sed 's/\./_/g'` +host_vendor1=`echo $host_vendor | sed 's/\./_/g'` +HOST_ID="-DCPU_$host_cpu1 -DVENDOR_$host_vendor1 -DOS_$host_os1" +if [ $host_os1 != $host_os2 ] ; then + HOST_ID="$HOST_ID -DOS_$host_os2" +fi +if [ $host_os1 != $host_os3 ] && [ $host_os2 != $host_os3 ] ; then + HOST_ID="$HOST_ID -DOS_$host_os3" +fi + +my_host_os=`echo $host_os1 $host_os2 $host_os3 | sort -u` +objs=`echo $srcdir/*.c | sed 's/\.c$/.o/' ` +if [ "X$GCC" = "Xyes" ] ; then + if [ "$host_cpu" = i486 ] ; then + CFLAGS="$CFLAGS -m486" + fi + Wall=-Wall + if [ "$host_os3" = sunos ] ; then + Wall="" + fi + if [ "$host_os3" = ultrix ] ; then + Wall="" + fi + if [ "$host_os3" = linux ] ; then + CFLAGS="$CFLAGS -fno-strength-reduce" + fi + if [ "$host_os3" = aux ] ; then + CFLAGS="$CFLAGS -ZP" + MACHDEPLIBS="-lposix -UTIL" + fi + case "${host}" in + arm*-*-linux) CFLAGS="$CFLAGS -mstructure-size-boundary=8";; + esac + CFLAGS="$CFLAGS $Wall" +else + if [ $host_os3 = hpux ] ; then + CPPFLAGS="$CPPFLAGS -Ae" + fi + + if [ $host_os3 = xenix ] ; then + CFLAGS="$CFLAGS -M2e" + fi +fi + +if [ $host_os3 = hpux ] ; then + LDFLAGS="$LDFLAGS -z" +fi + + +if [ $host_vendor = linux ] ; then + LDFLAGS="$LDFLAGS -z" +fi + +if [ $host_os3 = xenix ] ; then + LDFLAGS="$LDFLAGS -M2e -i -f 5000" +fi + +if [ $host_os2 = sysv4 ] ; then + SHLIB="-lc -L/usr/ucblib -lucb" +else + SHLIB="" +fi + +if [ $host_os3 = isc ] ; then + CFLAGS="$CFLAGS -D_SYSV3" + SHLIB="-lc_s" +fi + +if [ $host_os3 = solaris -a x$newVold = xxyes ] ; then + SHLIB="$SHLIB -s -lvolmgt" +fi + +if [ $host_os3 = nextstep ] ; then + CFLAGS="$CFLAGS -DBSD" + SHLIB="" +fi + +if [ -d /usr/5lib ] ; then + extralibdir=-L/usr/5lib +fi + +] + +AC_PATH_X +AC_PATH_XTRA + +dnl Floppyd +AC_ARG_ENABLE(floppyd, +[ --enable-floppyd floppy daemon support], +[if test x$enableval != x; then + use_floppyd=$enableval +fi]) + +AC_CHECK_LIB(socket,main) +AC_CHECK_LIB(nsl,main) +AC_CHECK_LIB(bsd,main) +AC_CHECK_HEADERS(sys/socket.h arpa/inet.h netdb.h) + +if test X$use_floppyd = X -a X$no_x = X ; then + use_floppyd="yes" +fi + +if test X$use_floppyd = Xyes; then + if test X$no_x = Xyes ; then + echo "Floppyd needs X support" >&2 + echo "To compile without floppyd, use ./configure --disable-floppyd" >&2 + exit 1 + fi + FLOPPYD="floppyd floppyd_installtest" + BINFLOPPYD="\$(DESTDIR)\$(bindir)/floppyd \$(DESTDIR)\$(bindir)/floppyd_installtest" + AC_DEFINE([USE_FLOPPYD],1,[Define when you want to include floppyd support]) +else + FLOPPYD= + BINFLOPPYD= +fi + + +AC_SUBST(FLOPPYD) +AC_SUBST(BINFLOPPYD) +AC_SUBST(extraincludedir) +AC_SUBST(extralibdir) +AC_SUBST(MACHDEPLIBS) +AC_SUBST(SHLIB) +AC_SUBST(host_cpu) +AC_SUBST(HOST_ID) +AC_OUTPUT(Makefile) diff --git a/copyfile.c b/copyfile.c new file mode 100644 index 0000000..282c649 --- /dev/null +++ b/copyfile.c @@ -0,0 +1,73 @@ +/* Copyright 1996-1999,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "file.h" +#include "llong.h" + +/* + * Copy the data from source to target + */ + +int copyfile(Stream_t *Source, Stream_t *Target) +{ + char buffer[8*16384]; + mt_off_t pos; + int ret, retw; +/* size_t len;*/ + mt_size_t mt_len; + + if (!Source){ + fprintf(stderr,"Couldn't open source file\n"); + return -1; + } + + if (!Target){ + fprintf(stderr,"Couldn't open target file\n"); + return -1; + } + + pos = 0; + GET_DATA(Source, 0, &mt_len, 0, 0); + while(1){ + ret = READS(Source, buffer, (mt_off_t) pos, 8*16384); + if (ret < 0 ){ + perror("file read"); + return -1; + } + if(!ret) + break; + if(got_signal) + return -1; + if (ret == 0) + break; + if ((retw = force_write(Target, buffer, (mt_off_t) pos, ret)) != ret){ + if(retw < 0 ) + perror("write in copy"); + else + fprintf(stderr, + "Short write %d instead of %d\n", retw, + ret); + if(errno == ENOSPC) + got_signal = 1; + return ret; + } + pos += ret; + } + return 0; +} diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..2f3bc51 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,95 @@ +mtools (4.0.12) stable; urgency=low + + * Mingw compatibility fixes + + -- Alain Knaff Tue, 3 Nov 2009 21:26:58 +0100 +mtools (4.0.11) stable; urgency=low + + * Fixed compiler in mlabel.c and elsewhere + * Fixed h flag in mattrib.c + * Added missing error checking in floppyd and elsewhere + + -- Alain Knaff Sat, 29 Aug 2009 14:38:19 +0200 +mtools (4.0.10) stable; urgency=low + + * More copyright stuff + * Fixed issues with max filesize (was 2GB instead of 4GB, and + warned only after copying the beginning) + + -- Alain Knaff Tue, 3 Mar 2009 22:14:04 +0100 +mtools (4.0.9) stable; urgency=low + + * More copyright stuff + + -- Alain Knaff Mon, 2 Mar 2009 22:15:54 +0100 +mtools (4.0.8) stable; urgency=low + + * Copyright notices + + -- Alain Knaff Sun, 1 Mar 2009 00:36:22 +0100 +mtools (4.0.7) stable; urgency=low + + * Fixed conversion to native on OS/2 + * Fix parsing of --help flag + + -- Alain Knaff Tue, 24 Feb 2009 19:55:46 +0100 +mtools (4.0.6) stable; urgency=low + + * Fallback for missing wchar_t iconv codepage on OS/2 + * Fixes for LSEEK64 support + * Support for --help that returns a 0 exit status + + -- Alain Knaff Sun, 22 Feb 2009 02:04:32 +0100 +mtools (4.0.5) stable; urgency=low + + * Make setpgrp() usage in floppyd conditional + * Re-instate PACKED around structure (ARM) + * LSEEK64 + + -- Alain Knaff Thu, 19 Feb 2009 23:55:04 +0100 +mtools (4.0.4) stable; urgency=low + + * BSD support: SCSI, use getuserid/getgroupid in floppyd + * Another attempt at putwc fix for OS/2 + * Further GNU fixes + * Fallback for putwc if there is wchar (OS/2) + + -- Alain Knaff Sun, 15 Feb 2009 16:18:32 +0100 +mtools (4.0.3) stable; urgency=low + + * Fix multipart pathname parsing bug in vfat.c (forgot limited length) + * Supplied fallback define for putwc + * Copyright notices in all sources + + -- Alain Knaff Mon, 9 Feb 2009 21:46:01 +0100 +mtools (4.0.2) stable; urgency=low + + * Fixed off-by-2 error in unix_name in file_name.c + + -- Alain Knaff Mon, 26 Jan 2009 22:58:06 +0100 +mtools (4.0.1) stable; urgency=low + + * Missing functions on Solaris + + -- Alain Knaff Sun, 7 Dec 2008 21:38:55 +0100 +mtools (4.0.0) stable; urgency=low + + * Offset for -i-specified image files + + -- Alain Knaff Sat, 29 Nov 2008 09:20:30 +0100 +mtools (4.0.0-pre2) stable; urgency=low + + * Use transliteration to represent characters which don't exist in + target set + + -- Alain Knaff Tue, 18 Nov 2008 22:42:23 +0100 +mtools (4.0.0-pre1) stable; urgency=low + + * Unicode support + + -- Alain Knaff Sat, 1 Nov 2008 20:52:58 +0100 +mtools (3.9.11-20071226) stable; urgency=low + + * first release of debian package + + -- Alain Knaff Tue, 28 Aug 2007 23:23:37 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..a8bf5b0 --- /dev/null +++ b/debian/control @@ -0,0 +1,23 @@ +Source: mtools +Build-Depends-Indep: fakeroot, devscripts, debhelper, texinfo +Section: otherosfs +Priority: optional +Maintainer: Alain Knaff + +Package: mtools +Section: otherosfs +Priority: optional +Architecture: any +Depends: libc6 (>= 2.4-1) +Essential: no +Provides: mtools +Description: Tools for manipulating MSDOS files + Mtools is a collection of utilities to access MS-DOS disks + from Unix without mounting them. It supports Win'95 style + long file names, OS/2 Xdf disks, ZIP/JAZ disks and 2m + disks (store up to 1992k on a high density 3 1/2 disk). + . + Also included in this package are commands to eject and manipulate + the write/password protection control of Zip disks. + . + Homepage: http://www.mtools.linux.lu/ diff --git a/debian/mtools.postinst b/debian/mtools.postinst new file mode 100755 index 0000000..5b9fc17 --- /dev/null +++ b/debian/mtools.postinst @@ -0,0 +1,25 @@ +#!/bin/sh + +# Copyright 2007 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +infodir=/usr/share/info +INSTALL_INFO=/usr/sbin/install-info + +if [ -f $INSTALL_INFO ] ; then + $INSTALL_INFO --info-dir=$infodir $infodir/mtools.info +fi + diff --git a/debian/mtools.prerm b/debian/mtools.prerm new file mode 100755 index 0000000..94667cb --- /dev/null +++ b/debian/mtools.prerm @@ -0,0 +1,24 @@ +#!/bin/sh + +# Copyright 2007 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +infodir=/usr/share/info +INSTALL_INFO=/usr/sbin/install-info + +if [ -f $INSTALL_INFO ] ; then + $INSTALL_INFO --info-dir=$infodir --remove $infodir/mtools.info +fi diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..8b3a760 --- /dev/null +++ b/debian/rules @@ -0,0 +1,111 @@ +#!/usr/bin/make -f + +# Copyright 2007 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + + +# Sample debian/rules that uses debhelper. +# This file is public domain software, originally written by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +buildroot=`pwd`/debian/mtools +_prefix=/usr +_infodir=/usr/share/info +_mandir=/usr/share/man + + +build: build-stamp +build-stamp: + dh_testdir + + # Add here commands to compile the package. + #$(MAKE) + ./configure --prefix=$(buildroot)$(_prefix) --sysconfdir=/etc --infodir=$(buildroot)$(_infodir) --mandir=$(buildroot)$(_mandir) + $(MAKE) + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + # Add here commands to clean up after the build process. + #-$(MAKE) clean + #-$(MAKE) distclean + if [ -f Makefile ] ; then $(MAKE) clean ; fi + if [ -f Makefile ] ; then $(MAKE) distclean ; fi + rm -f config.status Makefile config.log config.h build-stamp + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/ + #$(MAKE) prefix=`pwd`/debian/`dh_listpackages`/usr install + $(MAKE) install + rm -f $(buildroot)$(_infodir)/dir.gz + rm -f $(buildroot)$(_infodir)/dir.old.gz + rm -f $(buildroot)$(_infodir)/dir + rm -f $(buildroot)$(_infodir)/dir.old + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples +# dh_install +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installcatalogs +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo +# dh_installwm +# dh_installudev +# dh_undocumented + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_perl +# dh_python +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/devices.c b/devices.c new file mode 100644 index 0000000..9838a95 --- /dev/null +++ b/devices.c @@ -0,0 +1,1109 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2003,2006,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +/* + * Device tables. See the Configure file for a complete description. + */ + +#define NO_TERMIO +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "devices.h" + +#define INIT_NOOP + +#define DEF_ARG1(x) (x), 0x2,0,(char *)0, 0, 0 +#define DEF_ARG0(x) 0,DEF_ARG1(x) + +#define MDEF_ARG 0L,DEF_ARG0(MFORMAT_ONLY_FLAG) +#define FDEF_ARG 0L,DEF_ARG0(0) +#define VOLD_DEF_ARG 0L,DEF_ARG0(VOLD_FLAG|MFORMAT_ONLY_FLAG) + +#define MED312 12,0,80,2,36,0,MDEF_ARG /* 3 1/2 extra density */ +#define MHD312 12,0,80,2,18,0,MDEF_ARG /* 3 1/2 high density */ +#define MDD312 12,0,80,2, 9,0,MDEF_ARG /* 3 1/2 double density */ +#define MHD514 12,0,80,2,15,0,MDEF_ARG /* 5 1/4 high density */ +#define MDD514 12,0,40,2, 9,0,MDEF_ARG /* 5 1/4 double density (360k) */ +#define MSS514 12,0,40,1, 9,0,MDEF_ARG /* 5 1/4 single sided DD, (180k) */ +#define MDDsmall 12,0,40,2, 8,0,MDEF_ARG /* 5 1/4 double density (320k) */ +#define MSSsmall 12,0,40,1, 8,0,MDEF_ARG /* 5 1/4 single sided DD, (160k) */ + +#define FED312 12,0,80,2,36,0,FDEF_ARG /* 3 1/2 extra density */ +#define FHD312 12,0,80,2,18,0,FDEF_ARG /* 3 1/2 high density */ +#define FDD312 12,0,80,2, 9,0,FDEF_ARG /* 3 1/2 double density */ +#define FHD514 12,0,80,2,15,0,FDEF_ARG /* 5 1/4 high density */ +#define FDD514 12,0,40,2, 9,0,FDEF_ARG /* 5 1/4 double density (360k) */ +#define FSS514 12,0,40,1, 9,0,FDEF_ARG /* 5 1/4 single sided DD, (180k) */ +#define FDDsmall 12,0,40,2, 8,0,FDEF_ARG /* 5 1/4 double density (320k) */ +#define FSSsmall 12,0,40,1, 8,0,FDEF_ARG /* 5 1/4 single sided DD, (160k) */ + +#define GENHD 16,0, 0,0, 0,0,MDEF_ARG /* Generic 16 bit FAT fs */ +#define GENFD 12,0,80,2,18,0,MDEF_ARG /* Generic 12 bit FAT fs */ +#define VOLDFD 12,0,80,2,18,0,VOLD_DEF_ARG /* Generic 12 bit FAT fs with vold */ +#define GEN 0,0, 0,0, 0,0,MDEF_ARG /* Generic fs of any FAT bits */ + +#define ZIPJAZ(x,c,h,s,y) 16,(x),(c),(h),(s),(s),0L, 4, \ + DEF_ARG1((y)|MFORMAT_ONLY_FLAG) /* Jaz disks */ + +#define JAZ(x) ZIPJAZ(x,1021, 64, 32, 0) +#define RJAZ(x) ZIPJAZ(x,1021, 64, 32, SCSI_FLAG|PRIV_FLAG) +#define ZIP(x) ZIPJAZ(x,96, 64, 32, 0) +#define RZIP(x) ZIPJAZ(x,96, 64, 32, SCSI_FLAG|PRIV_FLAG) + +#define REMOTE {"$DISPLAY", 'X', 0,0, 0,0, 0,0,0L, DEF_ARG0(FLOPPYD_FLAG)} + + + +#if defined(INIT_GENERIC) || defined(INIT_NOOP) +static int compare_geom(struct device *dev, struct device *orig_dev) +{ + if(IS_MFORMAT_ONLY(orig_dev)) + return 0; /* geometry only for mformatting ==> ok */ + if(!orig_dev || !orig_dev->tracks || !dev || !dev->tracks) + return 0; /* no original device. This is ok */ + return(orig_dev->tracks != dev->tracks || + orig_dev->heads != dev->heads || + orig_dev->sectors != dev->sectors); +} +#endif + +#define devices const_devices + + +#ifdef __CYGWIN__ +#define predefined_devices +struct device devices[] = { + {"\\\\\\\\.\\\\A:", 'A', GENFD }, +}; +#endif /* CYGWIN */ + + +#ifdef OS_aux +#define predefined_devices +struct device devices[] = { + {"/dev/floppy0", 'A', GENFD }, + {"/dev/rdsk/c104d0s31", 'J', JAZ(O_EXCL) }, + {"/dev/rdsk/c105d0s31", 'Z', ZIP(O_EXCL) }, + REMOTE +}; +#endif /* aux */ + + +#ifdef OS_lynxos +#define predefined_devices +struct device devices[] = { + {"/dev/fd1440.0", 'A', MHD312 }, + REMOTE +}; +#endif + + +#ifdef __BEOS__ +#define predefined_devices +struct device devices[] = { + {"/dev/disk/floppy/raw", 'A', MHD312 }, + REMOTE +}; +#endif /* BEBOX */ + + +#ifdef OS_hpux + +#define predefined_devices +struct device devices[] = { +#ifdef OS_hpux10 +/* hpux10 uses different device names according to Frank Maritato + * */ + {"/dev/floppy/c0t0d0", 'A', MHD312 }, + {"/dev/floppy/c0t0d1", 'B', MHD312 }, /* guessed by me */ + {"/dev/rscsi", 'C', GENHD }, /* guessed by me */ +#else +/* Use rfloppy, according to Simao Campos */ + {"/dev/rfloppy/c201d0s0", 'A', FHD312 }, + {"/dev/rfloppy/c20Ad0s0", 'A', FHD312 }, + {"/dev/rfloppy/c201d1s0", 'B', FHD312 }, + {"/dev/rfloppy/c20Ad1s0", 'B', FHD312 }, + {"/dev/rscsi", 'C', GENHD }, +#endif + {"/dev/rdsk/c201d4", 'J', RJAZ(O_EXCL) }, + {"/dev/rdsk/c201d4s0", 'J', RJAZ(O_EXCL) }, + {"/dev/rdsk/c201d5", 'Z', RZIP(O_EXCL) }, + {"/dev/rdsk/c201d5s0", 'Z', RZIP(O_EXCL) }, + REMOTE +}; + +#ifdef HAVE_SYS_FLOPPY +/* geometry setting ioctl's contributed by Paolo Zeppegno + * , may cause "Not a typewriter" messages on other + * versions according to support@vital.com */ + +#include +#undef SSIZE + +struct generic_floppy_struct +{ + struct floppy_geometry fg; +}; + +#define BLOCK_MAJOR 24 +#define CHAR_MAJOR 112 + +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + if (ioctl(fd, FLOPPY_GET_GEOMETRY, &(floppy->fg)) != 0) { + perror("FLOPPY_GET_GEOMETRY"); + return(1); + } + + return 0; +} + +#define TRACKS(floppy) floppy.fg.tracks +#define HEADS(floppy) floppy.fg.heads +#define SECTORS(floppy) floppy.fg.sectors +#define FD_SECTSIZE(floppy) floppy.fg.sector_size +#define FD_SET_SECTSIZE(floppy,v) { floppy.fg.sector_size = v; } + +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + if (ioctl(fd, FLOPPY_SET_GEOMETRY, &(floppy->fg)) != 0) { + perror(""); + return(1); + } + + return 0; +} +#define INIT_GENERIC +#endif + +#endif /* hpux */ + + +#if (defined(OS_sinix) || defined(VENDOR_sni) || defined(SNI)) +#define predefined_devices +struct device devices[] = { +#ifdef CPU_mips /* for Siemens Nixdorf's SINIX-N/O (mips) 5.4x SVR4 */ + { "/dev/at/flp/f0t", 'A', FHD312}, + { "/dev/fd0", 'A', GENFD}, +#else +#ifdef CPU_i386 /* for Siemens Nixdorf's SINIX-D/L (intel) 5.4x SVR4 */ + { "/dev/fd0135ds18", 'A', FHD312}, + { "/dev/fd0135ds9", 'A', FDD312}, + { "/dev/fd0", 'A', GENFD}, + { "/dev/fd1135ds15", 'B', FHD514}, + { "/dev/fd1135ds9", 'B', FDD514}, + { "/dev/fd1", 'B', GENFD}, +#endif /* CPU_i386 */ +#endif /*mips*/ + REMOTE +}; +#endif + +#ifdef OS_ultrix +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0a", 'A', GENFD}, /* guessed */ + {"/dev/rfd0c", 'A', GENFD}, /* guessed */ + REMOTE +}; + +#endif + + +#ifdef OS_isc +#define predefined_devices +#if (defined(OS_isc2) && defined(OLDSTUFF)) +struct device devices[] = { + {"/dev/rdsk/f0d9dt", 'A', FDD514}, + {"/dev/rdsk/f0q15dt", 'A', FHD514}, + {"/dev/rdsk/f0d8dt", 'A', FDDsmall}, + {"/dev/rdsk/f13ht", 'B', FHD312}, + {"/dev/rdsk/f13dt", 'B', FDD312}, + {"/dev/rdsk/0p1", 'C', GENHD}, + {"/usr/vpix/defaults/C:",'D',12, 0, 0, 0, 0,8704L,DEF_ARG0}, + {"$HOME/vpix/C:", 'E', 12, 0, 0, 0, 0,8704L,MDEF_ARG}, + REMOTE +}; +#else +/* contributed by larry.jones@sdrc.com (Larry Jones) */ +struct device devices[] = { + {"/dev/rfd0", 'A', GEN}, + {"/dev/rfd1", 'B', GEN}, + {"/dev/rdsk/0p1", 'C', GEN}, + {"/usr/vpix/defaults/C:",'D', GEN, 1}, + {"$HOME/vpix/C:", 'E', GEN, 1}, + REMOTE +}; + +#include +#include +#undef SSIZE +#define BLOCK_MAJOR 1 +#define CHAR_MAJOR 1 +#define generic_floppy_struct disk_parms +int ioctl(int, int, void *); + +static int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + mt_off_t off; + char buf[512]; + + off = lseek(fd, 0, SEEK_CUR); + if(off < 0) { + perror("device seek 1"); + exit(1); + } + if (off == 0) { + /* need to read at least 1 sector to get correct info */ + read(fd, buf, sizeof buf); + if(lseek(fd, 0, SEEK_SET) < 0) { + perror("device seek 2"); + exit(1); + } + } + return ioctl(fd, V_GETPARMS, floppy); +} + +#define TRACKS(floppy) (floppy).dp_cyls +#define HEADS(floppy) (floppy).dp_heads +#define SECTORS(floppy) (floppy).dp_sectors +#define FD_SECTSIZE(floppy) (floppy).dp_secsiz +#define FD_SET_SECTSIZE(floppy,v) { (floppy).dp_secsiz = (v); } + +static int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + return 1; +} + +#define INIT_GENERIC +#endif +#endif /* isc */ + +#ifdef CPU_i370 +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0", 'A', GENFD}, + REMOTE +}; +#endif /* CPU_i370 */ + +#ifdef OS_aix +/* modified by Federico Bianchi */ +#define predefined_devices +struct device devices[] = { + {"/dev/fd0",'A',GENFD}, + REMOTE +}; +#endif /* aix */ + + +#ifdef OS_osf4 +/* modified by Chris Samuel */ +#define predefined_devices +struct device devices[] = { + {"/dev/fd0c",'A',GENFD}, + REMOTE +}; +#endif /* OS_osf4 */ + + +#ifdef OS_solaris + +#ifdef USING_NEW_VOLD + +char *alias_name = NULL; + +extern char *media_oldaliases(char *); +extern char *media_findname(char *); + +char *getVoldName(struct device *dev, char *name) +{ + char *rname; + + if(!SHOULD_USE_VOLD(dev)) + return name; + + /*** + * Solaris specific routines to use the volume management + * daemon and libraries to get the correct device name... + ***/ + rname = media_findname(name); +#ifdef HAVE_MEDIA_OLDALIASES + if (rname == NULL) { + if ((alias_name = media_oldaliases(name)) != NULL) + rname = media_findname(alias_name); + } +#endif + if (rname == NULL) { + fprintf(stderr, + "No such volume or no media in device: %s.\n", + name); + exit(1); + } + return rname; +} +#endif /* USING_NEW_VOLD */ + +#define predefined_devices +struct device devices[] = { +#ifdef USING_NEW_VOLD + {"floppy", 'A', VOLDFD }, +#elif USING_VOLD + {"/vol/dev/aliases/floppy0", 'A', GENFD}, + {"/dev/rdiskette", 'B', GENFD}, +#else /* ! USING_VOLD */ + {"/dev/rdiskette", 'A', GENFD}, + {"/vol/dev/aliases/floppy0", 'B', GENFD}, +#endif /* USING_VOLD */ + {"/dev/rdsk/c0t4d0s2", 'J', RJAZ(O_NDELAY)}, + {"/dev/rdsk/c0t5d0s2", 'Z', RZIP(O_NDELAY)}, + REMOTE +}; + + + +/* + * Ofer Licht , May 14, 1997. + */ + +#define INIT_GENERIC + +#include +#include /* for major() */ + +struct generic_floppy_struct +{ + struct fd_char fdchar; +}; + +#define BLOCK_MAJOR 36 +#define CHAR_MAJOR 36 + +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + if (ioctl(fd, FDIOGCHAR, &(floppy->fdchar)) != 0) { + perror(""); + ioctl(fd, FDEJECT, NULL); + return(1); + } + return 0; +} + +#define TRACKS(floppy) floppy.fdchar.fdc_ncyl +#define HEADS(floppy) floppy.fdchar.fdc_nhead +#define SECTORS(floppy) floppy.fdchar.fdc_secptrack +/* SECTORS_PER_DISK(floppy) not used */ +#define FD_SECTSIZE(floppy) floppy.fdchar.fdc_sec_size +#define FD_SET_SECTSIZE(floppy,v) { floppy.fdchar.fdc_sec_size = v; } + +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + if (ioctl(fd, FDIOSCHAR, &(floppy->fdchar)) != 0) { + ioctl(fd, FDEJECT, NULL); + perror(""); + return(1); + } + return 0; +} +#define INIT_GENERIC +#endif /* solaris */ + +#ifdef OS_sunos3 +#define predefined_devices +struct device devices[] = { + {"/dev/rfdl0c", 'A', FDD312}, + {"/dev/rfd0c", 'A', FHD312}, + REMOTE +}; +#endif /* OS_sunos3 */ + +#ifdef OS_xenix +#define predefined_devices +struct device devices[] = { + {"/dev/fd096ds15", 'A', FHD514}, + {"/dev/fd048ds9", 'A', FDD514}, + {"/dev/fd1135ds18", 'B', FHD312}, + {"/dev/fd1135ds9", 'B', FDD312}, + {"/dev/hd0d", 'C', GENHD}, + REMOTE +}; +#endif /* OS_xenix */ + +#ifdef OS_sco +#define predefined_devices +struct device devices[] = { + { "/dev/fd0135ds18", 'A', FHD312}, + { "/dev/fd0135ds9", 'A', FDD312}, + { "/dev/fd0", 'A', GENFD}, + { "/dev/fd1135ds15", 'B', FHD514}, + { "/dev/fd1135ds9", 'B', FDD514}, + { "/dev/fd1", 'B', GENFD}, + { "/dev/hd0d", 'C', GENHD}, + REMOTE +}; +#endif /* OS_sco */ + + +#ifdef OS_irix +#define predefined_devices +struct device devices[] = { + { "/dev/rdsk/fds0d2.3.5hi", 'A', FHD312}, + { "/dev/rdsk/fds0d2.3.5", 'A', FDD312}, + { "/dev/rdsk/fds0d2.96", 'A', FHD514}, + {"/dev/rdsk/fds0d2.48", 'A', FDD514}, + REMOTE +}; +#endif /* OS_irix */ + + +#ifdef OS_sunos4 +#include +#include + +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0c", 'A', GENFD}, + {"/dev/rsd4c", 'J', RJAZ(O_NDELAY)}, + {"/dev/rsd5c", 'Z', RZIP(O_NDELAY)}, + REMOTE +}; + +/* + * Stuffing back the floppy parameters into the driver allows for gems + * like 10 sector or single sided floppies from Atari ST systems. + * + * Martin Schulz, Universite de Moncton, N.B., Canada, March 11, 1991. + */ + +#define INIT_GENERIC + +struct generic_floppy_struct +{ + struct fdk_char dkbuf; + struct dk_map dkmap; +}; + +#define BLOCK_MAJOR 16 +#define CHAR_MAJOR 54 + +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + if (ioctl(fd, DKIOCGPART, &(floppy->dkmap)) != 0) { + perror("DKIOCGPART"); + ioctl(fd, FDKEJECT, NULL); + return(1); + } + + if (ioctl(fd, FDKIOGCHAR, &( floppy->dkbuf)) != 0) { + perror(""); + ioctl(fd, FDKEJECT, NULL); + return(1); + } + return 0; +} + +#define TRACKS(floppy) floppy.dkbuf.ncyl +#define HEADS(floppy) floppy.dkbuf.nhead +#define SECTORS(floppy) floppy.dkbuf.secptrack +#define SECTORS_PER_DISK(floppy) floppy.dkmap.dkl_nblk +#define FD_SECTSIZE(floppy) floppy.dkbuf.sec_size +#define FD_SET_SECTSIZE(floppy,v) { floppy.dkbuf.sec_size = v; } + +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + if (ioctl(fd, FDKIOSCHAR, &(floppy->dkbuf)) != 0) { + ioctl(fd, FDKEJECT, NULL); + perror(""); + return(1); + } + + if (ioctl(fd, ( unsigned int) DKIOCSPART, &(floppy->dkmap)) != 0) { + ioctl(fd, FDKEJECT, NULL); + perror(""); + return(1); + } + return 0; +} +#define INIT_GENERIC +#endif /* sparc && sunos */ + + +#ifdef DPX1000 +#define predefined_devices +struct device devices[] = { + /* [block device]: DPX1000 has /dev/flbm60, DPX2 has /dev/easyfb */ + {"/dev/flbm60", 'A', MHD514}; + {"/dev/flbm60", 'B', MDD514}, + {"/dev/flbm60", 'C', MDDsmall}, + {"/dev/flbm60", 'D', MSS}, + {"/dev/flbm60", 'E', MSSsmall}, + REMOTE +}; +#endif /* DPX1000 */ + +#ifdef OS_bosx +#define predefined_devices +struct device devices[] = { + /* [block device]: DPX1000 has /dev/flbm60, DPX2 has /dev/easyfb */ + {"/dev/easyfb", 'A', MHD514}, + {"/dev/easyfb", 'B', MDD514}, + {"/dev/easyfb", 'C', MDDsmall}, + {"/dev/easyfb", 'D', MSS}, + {"/dev/easyfb", 'E', MSSsmall}, + REMOTE +}; +#endif /* OS_bosx */ + +#ifdef OS_linux + +const char *error_msg[22]={ +"Missing Data Address Mark", +"Bad cylinder", +"Scan not satisfied", +"Scan equal hit", +"Wrong cylinder", +"CRC error in data field", +"Control Mark = deleted", +0, + +"Missing Address Mark", +"Write Protect", +"No Data - unreadable", +0, +"OverRun", +"CRC error in data or address", +0, +"End Of Cylinder", + +0, +0, +0, +"Not ready", +"Equipment check error", +"Seek end" }; + + +static __inline__ void print_message(RawRequest_t *raw_cmd,const char *message) +{ + int i, code; + if(!message) + return; + + fprintf(stderr," "); + for (i=0; i< raw_cmd->cmd_count; i++) + fprintf(stderr,"%2.2x ", + (int)raw_cmd->cmd[i] ); + fprintf(stderr,"\n"); + for (i=0; i< raw_cmd->reply_count; i++) + fprintf(stderr,"%2.2x ", + (int)raw_cmd->reply[i] ); + fprintf(stderr,"\n"); + code = (raw_cmd->reply[0] <<16) + + (raw_cmd->reply[1] << 8) + + raw_cmd->reply[2]; + for(i=0; i<22; i++){ + if ((code & (1 << i)) && error_msg[i]) + fprintf(stderr,"%s\n", + error_msg[i]); + } +} + + +/* return values: + * -1: Fatal error, don't bother retrying. + * 0: OK + * 1: minor error, retry + */ + +int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message) +{ + if (ioctl( fd, FDRAWCMD, raw_cmd) >= 0) { + if (raw_cmd->reply_count < 7) { + fprintf(stderr,"Short reply from FDC\n"); + return -1; + } + return 0; + } + + switch(errno) { + case EBUSY: + fprintf(stderr, "FDC busy, sleeping for a second\n"); + sleep(1); + return 1; + case EIO: + fprintf(stderr,"resetting controller\n"); + if(ioctl(fd, FDRESET, 2) < 0){ + perror("reset"); + return -1; + } + return 1; + default: + perror(message); + return -1; + } +} + + +/* + * return values + * -1: error + * 0: OK, last sector + * 1: more raw commands follow + */ + +int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print) +{ + + if(raw_cmd->reply_count == 7) { + int end; + + if (raw_cmd->reply[3] != raw_cmd->cmd[2]) { + /* end of cylinder */ + end = raw_cmd->cmd[6] + 1; + } else { + end = raw_cmd->reply[5]; + } + + *bytes = end - raw_cmd->cmd[4]; + /* FIXME: over/under run */ + *bytes = *bytes << (7 + raw_cmd->cmd[5]); + } else + *bytes = 0; + + switch(raw_cmd->reply[0] & 0xc0){ + case 0x40: + if ((raw_cmd->reply[0] & 0x38) == 0 && + (raw_cmd->reply[1]) == 0x80 && + (raw_cmd->reply[2]) == 0) { + *bytes += 1 << (7 + raw_cmd->cmd[5]); + break; + } + + if ( raw_cmd->reply[1] & ST1_WP ){ + *bytes = 0; + fprintf(stderr, + "This disk is write protected\n"); + return -1; + } + if(!*bytes && do_print) + print_message(raw_cmd, ""); + return -1; + case 0x80: + *bytes = 0; + fprintf(stderr, + "invalid command given\n"); + return -1; + case 0xc0: + *bytes = 0; + fprintf(stderr, + "abnormal termination caused by polling\n"); + return -1; + default: + break; + } +#ifdef FD_RAW_MORE + if(raw_cmd->flags & FD_RAW_MORE) + return 1; +#endif + return 0; +} + +#define predefined_devices +struct device devices[] = { + {"/dev/fd0", 'A', 0, 0, 80,2, 18,0, MDEF_ARG}, + {"/dev/fd1", 'B', 0, 0, 0,0, 0,0, FDEF_ARG}, + /* we assume that the Zip or Jaz drive is the second on the SCSI bus */ + {"/dev/sdb4",'J', GENHD }, + {"/dev/sdb4",'Z', GENHD }, + /* {"/dev/sda4",'D', GENHD },*/ + REMOTE +}; + +/* + * Stuffing back the floppy parameters into the driver allows for gems + * like 21 sector or single sided floppies from Atari ST systems. + * + * Alain Knaff, Université Joseph Fourier, France, November 12, 1993. + */ + + +#define INIT_GENERIC +#define generic_floppy_struct floppy_struct +#define BLOCK_MAJOR 2 +#define SECTORS(floppy) floppy.sect +#define TRACKS(floppy) floppy.track +#define HEADS(floppy) floppy.head +#define SECTORS_PER_DISK(floppy) floppy.size +#define STRETCH(floppy) floppy.stretch +#define USE_2M(floppy) ((floppy.rate & FD_2M) ? 0xff : 0x80 ) +#define SSIZE(floppy) ((((floppy.rate & 0x38) >> 3 ) + 2) % 8) + +static __inline__ void set_2m(struct floppy_struct *floppy, int value) +{ + if (value & 0x7f) + value = FD_2M; + else + value = 0; + floppy->rate = (floppy->rate & ~FD_2M) | value; +} +#define SET_2M set_2m + +static __inline__ void set_ssize(struct floppy_struct *floppy, int value) +{ + value = (( (value & 7) + 6 ) % 8) << 3; + + floppy->rate = (floppy->rate & ~0x38) | value; +} + +#define SET_SSIZE set_ssize + +static __inline__ int set_parameters(int fd, struct floppy_struct *floppy, + struct MT_STAT *buf) +{ + if ( ( MINOR(buf->st_rdev ) & 0x7f ) > 3 ) + return 1; + + return ioctl(fd, FDSETPRM, floppy); +} + +static __inline__ int get_parameters(int fd, struct floppy_struct *floppy) +{ + return ioctl(fd, FDGETPRM, floppy); +} + +#endif /* linux */ + + +/* OS/2, gcc+emx */ +#ifdef __EMX__ +#define predefined_devices +struct device devices[] = { + {"A:", 'A', GENFD}, + {"B:", 'B', GENFD}, +}; +#define INIT_NOOP +#endif + + + +/*** /jes -- for D.O.S. 486 BL DX2/80 ***/ +/*** Jean-Marc Zucconi 2001/03/30 ***/ +#ifdef OS_freebsd +#define predefined_devices +struct device devices[] = { + {"/dev/fd0.1440", 'A', FHD312}, + {"/dev/fd0.720", 'A', FDD312}, + {"/dev/fd1.1200", 'B', MHD514}, + {"/dev/sd0s1", 'C', GENHD}, + REMOTE +}; +#endif /* __FreeBSD__ */ + +/*** /jes -- for ALR 486 DX4/100 ***/ +#if defined(OS_netbsd) || defined(OS_netbsdelf) +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0a", 'A', FHD312}, + {"/dev/rfd0f", 'A', FDD312}, + {"/dev/rfd0f", 'S', MDD312}, + {"/dev/rfd1a", 'B', FHD514}, + {"/dev/rfd1d", 'B', FDD514}, + {"/dev/rfd1d", 'T', MDD514}, + {"/dev/rwd0d", 'C', 16, 0, 0, 0, 0, 0, 63L*512L, DEF_ARG0(0)}, + REMOTE +}; +#endif /* OS_NetBSD */ + +/* fgsch@openbsd.org 2000/05/19 */ +#if defined(OS_openbsd) +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0Bc", 'A', FHD312}, + {"/dev/rfd0Fc", 'A', FDD312}, + {"/dev/rfd1Cc", 'B', FHD514}, + {"/dev/rfd1Dc", 'B', FDD514}, + {"/dev/rwd0c", 'C', 16, 0, 0, 0, 0, 0, 63L*512L, DEF_ARG0(0)}, + REMOTE +}; +#endif /* OS_openbsd */ + + + +#if (!defined(predefined_devices) && defined (CPU_m68000) && defined (OS_sysv)) +#include + +#define predefined_devices +struct device devices[] = { + {"/dev/rfp020", 'A', 12,O_NDELAY,40,2, 9, 0, MDEF_ARG}, + {"/usr/bin/DOS/dvd000", 'C', GENFD}, + REMOTE +}; + +#undef INIT_NOOP +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf) +{ + struct gdctl gdbuf; + + if (ioctl(fd, GDGETA, &gdbuf) == -1) { + ioctl(fd, GDDISMNT, &gdbuf); + return 1; + } + if((dev->use_2m & 0x7f) || (dev->ssize & 0x7f)) + return 1; + + SET_INT(gdbuf.params.cyls,dev->ntracks); + SET_INT(gdbuf.params.heads,dev->nheads); + SET_INT(gdbuf.params.psectrk,dev->nsect); + dev->ntracks = gdbuf.params.cyls; + dev->nheads = gdbuf.params.heads; + dev->nsect = gdbuf.params.psectrk; + dev->use_2m = 0x80; + dev->ssize = 0x82; + + gdbuf.params.pseccyl = gdbuf.params.psectrk * gdbuf.params.heads; + gdbuf.params.flags = 1; /* disk type flag */ + gdbuf.params.step = 0; /* step rate for controller */ + gdbuf.params.sectorsz = 512; /* sector size */ + + if (ioctl(fd, GDSETA, &gdbuf) < 0) { + ioctl(fd, GDDISMNT, &gdbuf); + return(1); + } + return(0); +} +#endif /* (defined (m68000) && defined (sysv))*/ + +#ifdef CPU_alpha +#ifndef OS_osf4 +#ifdef __osf__ +#include +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0c", 'A', GENFD}, + REMOTE +}; +#endif +#endif +#endif + +#ifdef OS_osf +#ifndef predefined_devices +#define predefined_devices +struct device devices[] = { + {"/dev/fd0a", 'A', MHD312 } }; + REMOTE +#endif +#endif + + +#ifdef OS_nextstep +#define predefined_devices +struct device devices[] = { +#ifdef CPU_m68k + {"/dev/rfd0b", 'A', MED312 }, + REMOTE +#else + {"/dev/rfd0b", 'A', MHD312 }, + REMOTE +#endif +}; +#endif + + +#if (!defined(predefined_devices) && defined(OS_sysv4)) +#ifdef __uxp__ +#define predefined_devices +struct device devices[] = { + {"/dev/fpd0", 'A', FHD312}, + {"/dev/fpd0", 'A', FDD312}, + REMOTE +}; +#else +#define predefined_devices +struct device devices[] = { + {"/dev/rdsk/f1q15dt", 'B', FHD514}, + {"/dev/rdsk/f1d9dt", 'B', FDD514}, + {"/dev/rdsk/f1d8dt", 'B', FDDsmall}, + {"/dev/rdsk/f03ht", 'A', FHD312}, + {"/dev/rdsk/f03dt", 'A', FDD312}, + {"/dev/rdsk/dos", 'C', GENHD}, + REMOTE +}; +#endif +#endif /* sysv4 */ + +#ifdef OS_mingw32msvc +#define predefined_devices +struct device devices[] = { + {"\\\\.\\A:", 'A', GENFD }, +}; +#endif + +#ifdef INIT_GENERIC + +#ifndef USE_2M +#define USE_2M(x) 0x80 +#endif + +#ifndef SSIZE +#define SSIZE(x) 0x82 +#endif + +#ifndef SET_2M +#define SET_2M(x,y) return -1 +#endif + +#ifndef SET_SSIZE +#define SET_SSIZE(x,y) return -1 +#endif + +#undef INIT_NOOP +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf) +{ + struct generic_floppy_struct floppy; + int change; + + /* + * succeed if we don't have a floppy + * this is the case for dosemu floppy image files for instance + */ + if (!((S_ISBLK(statbuf->st_mode) && + major(statbuf->st_rdev) == BLOCK_MAJOR) +#ifdef CHAR_MAJOR + || (S_ISCHR(statbuf->st_mode) && + major(statbuf->st_rdev) == CHAR_MAJOR) +#endif + )) + return compare_geom(dev, orig_dev); + + /* + * We first try to get the current floppy parameters from the kernel. + * This allows us to + * 1. get the rate + * 2. skip the parameter setting if the parameters are already o.k. + */ + + if (get_parameters( fd, & floppy ) ) + /* + * autodetection failure. + * This mostly occurs because of an absent or unformatted disks. + * + * It might also occur because of bizarre formats (for example + * rate 1 on a 3 1/2 disk). + + * If this is the case, the user should do an explicit + * setfdprm before calling mtools + * + * Another cause might be pre-existing wrong parameters. The + * user should do an setfdprm -c to repair this situation. + * + * ...fail immediately... ( Theoretically, we could try to save + * the situation by trying out all rates, but it would be slow + * and awkward) + */ + return 1; + + + /* + * if we have already have the correct parameters, keep them. + * the number of tracks doesn't need to match exactly, it may be bigger. + * the number of heads and sectors must match exactly, to avoid + * miscalculation of the location of a block on the disk + */ + change = 0; + if(compare(dev->sectors, SECTORS(floppy))){ + SECTORS(floppy) = dev->sectors; + change = 1; + } else + dev->sectors = SECTORS(floppy); + + if(compare(dev->heads, HEADS(floppy))){ + HEADS(floppy) = dev->heads; + change = 1; + } else + dev->heads = HEADS(floppy); + + if(compare(dev->tracks, TRACKS(floppy))){ + TRACKS(floppy) = dev->tracks; + change = 1; + } else + dev->tracks = TRACKS(floppy); + + + if(compare(dev->use_2m, USE_2M(floppy))){ + SET_2M(&floppy, dev->use_2m); + change = 1; + } else + dev->use_2m = USE_2M(floppy); + + if( ! (dev->ssize & 0x80) ) + dev->ssize = 0; + if(compare(dev->ssize, SSIZE(floppy) + 128)){ + SET_SSIZE(&floppy, dev->ssize); + change = 1; + } else + dev->ssize = SSIZE(floppy); + + if(!change) + /* no change, succeed */ + return 0; + +#ifdef SECTORS_PER_TRACK + SECTORS_PER_TRACK(floppy) = dev->sectors * dev->heads; +#endif + +#ifdef SECTORS_PER_DISK + SECTORS_PER_DISK(floppy) = dev->sectors * dev->heads * dev->tracks; +#endif + +#ifdef STRETCH + /* ... and the stretch */ + if ( dev->tracks > 41 ) + STRETCH(floppy) = 0; + else + STRETCH(floppy) = 1; +#endif + + return set_parameters( fd, &floppy, statbuf); +} +#endif /* INIT_GENERIC */ + +#ifdef INIT_NOOP +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf) +{ + return compare_geom(dev, orig_dev); +} +#endif + +#ifdef predefined_devices +const int nr_const_devices = sizeof(const_devices) / sizeof(*const_devices); +#else +struct device devices[]={ + {"/dev/fd0", 'A', 0, O_EXCL, 0,0, 0,0, MDEF_ARG}, + /* to shut up Ultrix's native compiler, we can't make this empty :( */ +}; +const int nr_const_devices = 0; +#endif diff --git a/devices.h b/devices.h new file mode 100644 index 0000000..1d0e236 --- /dev/null +++ b/devices.h @@ -0,0 +1,187 @@ +#ifdef OS_linux + +/* Copyright 1996-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include + +#ifdef HAVE_SYS_SYSMACROS_H + +#include +#ifndef MAJOR +#define MAJOR(dev) major(dev) +#endif /* MAJOR not defined */ +#ifndef MINOR +#define MINOR(dev) minor(dev) +#endif /* MINOR not defined */ + +#else + +#include /* get MAJOR/MINOR from Linux kernel */ +#ifndef major +#define major(x) MAJOR(x) +#endif + +#endif /* HAVE_SYS_SYSMACROS_H */ + +#include +#include +#include + + +typedef struct floppy_raw_cmd RawRequest_t; + +UNUSED(static __inline__ void RR_INIT(struct floppy_raw_cmd *request)) +{ + request->data = 0; + request->length = 0; + request->cmd_count = 9; + request->flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK +#ifdef FD_RAW_SOFTFAILUE + | FD_RAW_SOFTFAILURE | FD_RAW_STOP_IF_FAILURE +#endif + ; + request->cmd[1] = 0; + request->cmd[6] = 0; + request->cmd[7] = 0x1b; + request->cmd[8] = 0xff; + request->reply_count = 0; +} + +UNUSED(static __inline__ void RR_SETRATE(struct floppy_raw_cmd *request, int rate)) +{ + request->rate = rate; +} + +UNUSED(static __inline__ void RR_SETDRIVE(struct floppy_raw_cmd *request,int drive)) +{ + request->cmd[1] = (request->cmd[1] & ~3) | (drive & 3); +} + +UNUSED(static __inline__ void RR_SETTRACK(struct floppy_raw_cmd *request,int track)) +{ + request->cmd[2] = track; +} + +UNUSED(static __inline__ void RR_SETPTRACK(struct floppy_raw_cmd *request, + int track)) +{ + request->track = track; +} + +UNUSED(static __inline__ void RR_SETHEAD(struct floppy_raw_cmd *request, int head)) +{ + if(head) + request->cmd[1] |= 4; + else + request->cmd[1] &= ~4; + request->cmd[3] = head; +} + +UNUSED(static __inline__ void RR_SETSECTOR(struct floppy_raw_cmd *request, + int sector)) +{ + request->cmd[4] = sector; + request->cmd[6] = sector-1; +} + +UNUSED(static __inline__ void RR_SETSIZECODE(struct floppy_raw_cmd *request, + int sizecode)) +{ + request->cmd[5] = sizecode; + request->cmd[6]++; + request->length += 128 << sizecode; +} + +#if 0 +static inline void RR_SETEND(struct floppy_raw_cmd *request, int end) +{ + request->cmd[6] = end; +} +#endif + +UNUSED(static __inline__ void RR_SETDIRECTION(struct floppy_raw_cmd *request, + int direction)) +{ + if(direction == MT_READ) { + request->flags |= FD_RAW_READ; + request->cmd[0] = FD_READ & ~0x80; + } else { + request->flags |= FD_RAW_WRITE; + request->cmd[0] = FD_WRITE & ~0x80; + } +} + + +UNUSED(static __inline__ void RR_SETDATA(struct floppy_raw_cmd *request, + caddr_t data)) +{ + request->data = data; +} + + +#if 0 +static inline void RR_SETLENGTH(struct floppy_raw_cmd *request, int length) +{ + request->length += length; +} +#endif + +UNUSED(static __inline__ void RR_SETCONT(struct floppy_raw_cmd *request)) +{ +#ifdef FD_RAW_MORE + request->flags |= FD_RAW_MORE; +#endif +} + + +UNUSED(static __inline__ int RR_SIZECODE(struct floppy_raw_cmd *request)) +{ + return request->cmd[5]; +} + + + +UNUSED(static __inline__ int RR_TRACK(struct floppy_raw_cmd *request)) +{ + return request->cmd[2]; +} + + +UNUSED(static __inline__ int GET_DRIVE(int fd)) +{ + struct MT_STAT statbuf; + + if (MT_FSTAT(fd, &statbuf) < 0 ){ + perror("stat"); + return -1; + } + + if (!S_ISBLK(statbuf.st_mode) || + MAJOR(statbuf.st_rdev) != FLOPPY_MAJOR) + return -1; + + return MINOR( statbuf.st_rdev ); +} + + + +/* void print_message(RawRequest_t *raw_cmd,char *message);*/ +int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message); +int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print); + + +#endif diff --git a/dirCache.c b/dirCache.c new file mode 100644 index 0000000..dea0a02 --- /dev/null +++ b/dirCache.c @@ -0,0 +1,336 @@ +/* Copyright 1998,2001-2003,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "sysincludes.h" +#include "vfat.h" +#include "dirCache.h" + + + + +#define BITS_PER_INT (sizeof(unsigned int) * 8) + + +static __inline__ unsigned int rol(unsigned int arg, int shift) +{ + arg &= 0xffffffff; /* for 64 bit machines */ + return (arg << shift) | (arg >> (32 - shift)); +} + + +static int calcHash(wchar_t *name) +{ + unsigned long hash; + int i; + wchar_t c; + + hash = 0; + i = 0; + while(*name) { + /* rotate it */ + hash = rol(hash,5); /* a shift of 5 makes sure we spread quickly + * over the whole width, moreover, 5 is + * prime with 32, which makes sure that + * successive letters cannot cover each + * other easily */ + c = towupper(*name); + hash ^= (c * (c+2)) ^ (i * (i+2)); + hash &= 0xffffffff; + i++, name++; + } + hash = hash * (hash + 2); + /* the following two xors make sure all info is spread evenly over all + * bytes. Important if we only keep the low order bits later on */ + hash ^= (hash & 0xfff) << 12; + hash ^= (hash & 0xff000) << 24; + return hash; +} + +static int addBit(unsigned int *bitmap, int hash, int checkOnly) +{ + int bit, entry; + + bit = 1 << (hash % BITS_PER_INT); + entry = (hash / BITS_PER_INT) % DC_BITMAP_SIZE; + + if(checkOnly) + return bitmap[entry] & bit; + else { + bitmap[entry] |= bit; + return 1; + } +} + +static int _addHash(dirCache_t *cache, unsigned int hash, int checkOnly) +{ + return + addBit(cache->bm0, hash, checkOnly) && + addBit(cache->bm1, rol(hash,12), checkOnly) && + addBit(cache->bm2, rol(hash,24), checkOnly); +} + + +static void addNameToHash(dirCache_t *cache, wchar_t *name) +{ + _addHash(cache, calcHash(name), 0); +} + +static void hashDce(dirCache_t *cache, dirCacheEntry_t *dce) +{ + if(dce->beginSlot != cache->nrHashed) + return; + cache->nrHashed = dce->endSlot; + if(dce->longName) + addNameToHash(cache, dce->longName); + addNameToHash(cache, dce->shortName); +} + +int isHashed(dirCache_t *cache, wchar_t *name) +{ + int ret; + + ret = _addHash(cache, calcHash(name), 1); + return ret; +} + +int growDirCache(dirCache_t *cache, int slot) +{ + if(slot < 0) { + fprintf(stderr, "Bad slot %d\n", slot); + exit(1); + } + + if( cache->nr_entries <= slot) { + int i; + + cache->entries = realloc(cache->entries, + (slot+1) * 2 * + sizeof(dirCacheEntry_t *)); + if(!cache->entries) + return -1; + for(i= cache->nr_entries; i < (slot+1) * 2; i++) { + cache->entries[i] = 0; + } + cache->nr_entries = (slot+1) * 2; + } + return 0; +} + +dirCache_t *allocDirCache(Stream_t *Stream, int slot) +{ + dirCache_t **dcp; + + if(slot < 0) { + fprintf(stderr, "Bad slot %d\n", slot); + exit(1); + } + + dcp = getDirCacheP(Stream); + if(!*dcp) { + *dcp = New(dirCache_t); + if(!*dcp) + return 0; + (*dcp)->entries = NewArray((slot+1)*2+5, dirCacheEntry_t *); + if(!(*dcp)->entries) { + free(*dcp); + return 0; + } + (*dcp)->nr_entries = (slot+1) * 2; + memset( (*dcp)->bm0, 0, DC_BITMAP_SIZE); + memset( (*dcp)->bm1, 0, DC_BITMAP_SIZE); + memset( (*dcp)->bm2, 0, DC_BITMAP_SIZE); + (*dcp)->nrHashed = 0; + } else + if(growDirCache(*dcp, slot) < 0) + return 0; + return *dcp; +} + +static void freeDirCacheRange(dirCache_t *cache, + unsigned int beginSlot, + unsigned int endSlot) +{ + dirCacheEntry_t *entry; + unsigned int clearBegin; + unsigned int clearEnd; + unsigned int i; + + if(endSlot < beginSlot) { + fprintf(stderr, "Bad slots %d %d in free range\n", + beginSlot, endSlot); + exit(1); + } + + while(beginSlot < endSlot) { + entry = cache->entries[beginSlot]; + if(!entry) { + beginSlot++; + continue; + } + + clearEnd = entry->endSlot; + if(clearEnd > endSlot) + clearEnd = endSlot; + clearBegin = beginSlot; + + for(i = clearBegin; i entries[i] = 0; + + if(entry->endSlot == endSlot) + entry->endSlot = beginSlot; + else if(entry->beginSlot == beginSlot) + entry->beginSlot = endSlot; + else { + fprintf(stderr, + "Internal error, non contiguous de-allocation\n"); + fprintf(stderr, "%d %d\n", beginSlot, endSlot); + fprintf(stderr, "%d %d\n", entry->beginSlot, + entry->endSlot); + exit(1); + } + + if(entry->beginSlot == entry->endSlot) { + if(entry->longName) + free(entry->longName); + if(entry->shortName) + free(entry->shortName); + free(entry); + } + + beginSlot = clearEnd; + } +} + +static dirCacheEntry_t *allocDirCacheEntry(dirCache_t *cache, int beginSlot, + int endSlot, + dirCacheEntryType_t type) +{ + dirCacheEntry_t *entry; + int i; + + if(growDirCache(cache, endSlot) < 0) + return 0; + + entry = New(dirCacheEntry_t); + if(!entry) + return 0; + entry->type = type; + entry->longName = 0; + entry->shortName = 0; + entry->beginSlot = beginSlot; + entry->endSlot = endSlot; + + freeDirCacheRange(cache, beginSlot, endSlot); + for(i=beginSlot; ientries[i] = entry; + } + return entry; +} + +dirCacheEntry_t *addUsedEntry(dirCache_t *cache, int beginSlot, int endSlot, + wchar_t *longName, wchar_t *shortName, + struct directory *dir) +{ + dirCacheEntry_t *entry; + + if(endSlot < beginSlot) { + fprintf(stderr, + "Bad slots %d %d in add used entry\n", + beginSlot, endSlot); + exit(1); + } + + + entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_USED); + if(!entry) + return 0; + + entry->beginSlot = beginSlot; + entry->endSlot = endSlot; + if(longName) + entry->longName = wcsdup(longName); + entry->shortName = wcsdup(shortName); + entry->dir = *dir; + hashDce(cache, entry); + return entry; +} + +static void mergeFreeSlots(dirCache_t *cache, int slot) +{ + dirCacheEntry_t *previous, *next; + unsigned int i; + + if(slot == 0) + return; + previous = cache->entries[slot-1]; + next = cache->entries[slot]; + if(next && next->type == DCET_FREE && + previous && previous->type == DCET_FREE) { + for(i=next->beginSlot; i < next->endSlot; i++) + cache->entries[i] = previous; + previous->endSlot = next->endSlot; + free(next); + } +} + +dirCacheEntry_t *addFreeEntry(dirCache_t *cache, + unsigned int beginSlot, + unsigned int endSlot) +{ + dirCacheEntry_t *entry; + + if(beginSlot < cache->nrHashed) + cache->nrHashed = beginSlot; + + if(endSlot < beginSlot) { + fprintf(stderr, "Bad slots %d %d in add free entry\n", + beginSlot, endSlot); + exit(1); + } + + if(endSlot == beginSlot) + return 0; + entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_FREE); + mergeFreeSlots(cache, beginSlot); + mergeFreeSlots(cache, endSlot); + return cache->entries[beginSlot]; +} + + +dirCacheEntry_t *addEndEntry(dirCache_t *cache, int pos) +{ + return allocDirCacheEntry(cache, pos, pos+1, DCET_END); +} + +dirCacheEntry_t *lookupInDircache(dirCache_t *cache, int pos) +{ + if(growDirCache(cache, pos+1) < 0) + return 0; + return cache->entries[pos]; +} + +void freeDirCache(Stream_t *Stream) +{ + dirCache_t *cache, **dcp; + + dcp = getDirCacheP(Stream); + cache = *dcp; + if(cache) { + freeDirCacheRange(cache, 0, cache->nr_entries); + free(cache); + *dcp = 0; + } +} diff --git a/dirCache.h b/dirCache.h new file mode 100644 index 0000000..808f428 --- /dev/null +++ b/dirCache.h @@ -0,0 +1,57 @@ +#ifndef MTOOLS_DIRCACHE_H +#define MTOOLS_DIRCACHE_H + +/* Copyright 1997,1999,2001-2003,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +typedef enum { + DCET_FREE, + DCET_USED, + DCET_END +} dirCacheEntryType_t; + +#define DC_BITMAP_SIZE 128 + +typedef struct dirCacheEntry_t { + dirCacheEntryType_t type; + unsigned int beginSlot; + unsigned int endSlot; + wchar_t *shortName; + wchar_t *longName; + struct directory dir; +} dirCacheEntry_t; + +typedef struct dirCache_t { + struct dirCacheEntry_t **entries; + int nr_entries; + unsigned int nrHashed; + unsigned int bm0[DC_BITMAP_SIZE]; + unsigned int bm1[DC_BITMAP_SIZE]; + unsigned int bm2[DC_BITMAP_SIZE]; +} dirCache_t; + +int isHashed(dirCache_t *cache, wchar_t *name); +int growDirCache(dirCache_t *cache, int slot); +dirCache_t *allocDirCache(Stream_t *Stream, int slot); +dirCacheEntry_t *addUsedEntry(dirCache_t *Stream, int begin, int end, + wchar_t *longName, wchar_t *shortName, + struct directory *dir); +void freeDirCache(Stream_t *Stream); +dirCacheEntry_t *addFreeEntry(dirCache_t *Stream, + unsigned int begin, unsigned int end); +dirCacheEntry_t *addEndEntry(dirCache_t *Stream, int pos); +dirCacheEntry_t *lookupInDircache(dirCache_t *Stream, int pos); +#endif diff --git a/directory.c b/directory.c new file mode 100644 index 0000000..9c8cb9c --- /dev/null +++ b/directory.c @@ -0,0 +1,138 @@ +/* Copyright 1995 David C. Niemi + * Copyright 1996-2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "file.h" +#include "fs.h" +#include "file_name.h" + +/* #define DEBUG */ + +/* + * Read a directory entry into caller supplied buffer + */ +struct directory *dir_read(direntry_t *entry, int *error) +{ + int n; + *error = 0; + if((n=force_read(entry->Dir, (char *) (&entry->dir), + (mt_off_t) entry->entry * MDIR_SIZE, + MDIR_SIZE)) != MDIR_SIZE) { + if (n < 0) { + *error = -1; + } + return NULL; + } + return &entry->dir; +} + +/* + * Make a subdirectory grow in length. Only subdirectories (not root) + * may grow. Returns a 0 on success, 1 on failure (disk full), or -1 + * on error. + */ + +int dir_grow(Stream_t *Dir, int size) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(FsPublic_t); + int ret; + int buflen; + char *buffer; + + if (!getfreeMinClusters(Dir, 1)) + return -1; + + buflen = This->cluster_size * This->sector_size; + + if(! (buffer=malloc(buflen)) ){ + perror("dir_grow: malloc"); + return -1; + } + + memset((char *) buffer, '\0', buflen); + ret = force_write(Dir, buffer, (mt_off_t) size * MDIR_SIZE, buflen); + free(buffer); + if(ret < buflen) + return -1; + return 0; +} + + +void low_level_dir_write(direntry_t *entry) +{ + force_write(entry->Dir, + (char *) (&entry->dir), + (mt_off_t) entry->entry * MDIR_SIZE, MDIR_SIZE); +} + + +/* + * Make a directory entry. Builds a directory entry based on the + * name, attribute, starting cluster number, and size. Returns a pointer + * to a static directory structure. + */ + +struct directory *mk_entry(const dos_name_t *dn, char attr, + unsigned int fat, size_t size, time_t date, + struct directory *ndir) +{ + struct tm *now; + time_t date2 = date; + unsigned char hour, min_hi, min_low, sec; + unsigned char year, month_hi, month_low, day; + + now = localtime(&date2); + dosnameToDirentry(dn, ndir); + ndir->attr = attr; + ndir->ctime_ms = 0; + hour = now->tm_hour << 3; + min_hi = now->tm_min >> 3; + min_low = now->tm_min << 5; + sec = now->tm_sec / 2; + ndir->ctime[1] = ndir->time[1] = hour + min_hi; + ndir->ctime[0] = ndir->time[0] = min_low + sec; + year = (now->tm_year - 80) << 1; + month_hi = (now->tm_mon + 1) >> 3; + month_low = (now->tm_mon + 1) << 5; + day = now->tm_mday; + ndir -> adate[1] = ndir->cdate[1] = ndir->date[1] = year + month_hi; + ndir -> adate[0] = ndir->cdate[0] = ndir->date[0] = month_low + day; + + set_word(ndir->start, fat & 0xffff); + set_word(ndir->startHi, fat >> 16); + set_dword(ndir->size, size); + return ndir; +} + +/* + * Make a directory entry from base name. This is supposed to be used + * from places such as mmd for making special entries (".", "..", "/", ...) + * Thus it doesn't bother with character set conversions + */ +struct directory *mk_entry_from_base(const char *base, char attr, + unsigned int fat, size_t size, time_t date, + struct directory *ndir) +{ + struct dos_name_t dn; + strncpy(dn.base, base, 8); + strncpy(dn.ext, " ", 3); + return mk_entry(&dn, attr, fat, size, date, ndir); +} diff --git a/direntry.c b/direntry.c new file mode 100644 index 0000000..07a1f0b --- /dev/null +++ b/direntry.c @@ -0,0 +1,139 @@ +/* Copyright 1997,2000-2003,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "file.h" +#include "mtoolsDirentry.h" +#include "file_name.h" + +void initializeDirentry(direntry_t *entry, Stream_t *Dir) +{ + entry->entry = -1; +/* entry->parent = getDirentry(Dir);*/ + entry->Dir = Dir; + entry->beginSlot = 0; + entry->endSlot = 0; +} + +int isNotFound(direntry_t *entry) +{ + return entry->entry == -2; +} + +direntry_t *getParent(direntry_t *entry) +{ + return getDirentry(entry->Dir); +} + + +static int getPathLen(direntry_t *entry) +{ + int length=0; + + while(1) { + if(entry->entry == -3) /* rootDir */ + return length + 3; + + length += 1 + wcslen(entry->name); + entry = getDirentry(entry->Dir); + } +} + +static char *sprintPwd(direntry_t *entry, char *ptr) +{ + if(entry->entry == -3) { + *ptr++ = getDrive(entry->Dir); + *ptr++ = ':'; + *ptr++ = '/'; + } else { + ptr = sprintPwd(getDirentry(entry->Dir), ptr); + if(ptr[-1] != '/') + *ptr++ = '/'; + ptr += wchar_to_native(entry->name, ptr, MAX_VNAMELEN); + } + return ptr; +} + + +#ifdef HAVE_WCHAR_H +#define NEED_ESCAPE L"\"$\\" +#else +#define NEED_ESCAPE "\"$\\" +#endif + +static void _fprintPwd(FILE *f, direntry_t *entry, int recurs, int escape) +{ + if(entry->entry == -3) { + putc(getDrive(entry->Dir), f); + putc(':', f); + if(!recurs) + putc('/', f); + } else { + _fprintPwd(f, getDirentry(entry->Dir), 1, escape); + if (escape && wcspbrk(entry->name, NEED_ESCAPE)) { + wchar_t *ptr; + putc('/', f); + for(ptr = entry->name; *ptr; ptr++) { + if (wcschr(NEED_ESCAPE, *ptr)) + putc('\\', f); + putwc(*ptr, f); + } + } else { + char tmp[4*MAX_VNAMELEN+1]; + wchar_to_native(entry->name,tmp,MAX_VNAMELEN); + fprintf(f, "/%s", tmp); + } + } +} + +void fprintPwd(FILE *f, direntry_t *entry, int escape) +{ + if (escape) + putc('"', f); + _fprintPwd(f, entry, 0, escape); + if(escape) + putc('"', f); +} + +char *getPwd(direntry_t *entry) +{ + int size; + char *ret; + char *end; + + size = getPathLen(entry); + ret = malloc(size+1); + if(!ret) + return 0; + end = sprintPwd(entry, ret); + *end = '\0'; + return ret; +} + +int isSubdirOf(Stream_t *inside, Stream_t *outside) +{ + while(1) { + if(inside == outside) /* both are the same */ + return 1; + if(getDirentry(inside)->entry == -3) /* root directory */ + return 0; + /* look further up */ + inside = getDirentry(inside)->Dir; + } +} diff --git a/expand.c b/expand.c new file mode 100644 index 0000000..6b11f09 --- /dev/null +++ b/expand.c @@ -0,0 +1,108 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Do filename expansion with the shell. + */ + +#define EXPAND_BUF 2048 + +#include "sysincludes.h" +#include "mtools.h" + +#ifndef OS_mingw32msvc +int safePopenOut(const char **command, char *output, int len) +{ + int pipefd[2]; + pid_t pid; + int status; + int last; + + if(pipe(pipefd)) { + return -2; + } + switch((pid=fork())){ + case -1: + return -2; + case 0: /* the son */ + close(pipefd[0]); + destroy_privs(); + close(1); + close(2); /* avoid nasty error messages on stderr */ + if(dup(pipefd[1]) < 0) { + perror("Dup error"); + exit(1); + } + close(pipefd[1]); + execvp(command[0], (char**)(command+1)); + exit(1); + default: + close(pipefd[1]); + break; + } + last=read(pipefd[0], output, len); + kill(pid,9); + wait(&status); + if(last<0) { + return -1; + } + return last; +} +#endif + + +const char *expand(const char *input, char *ans) +{ +#ifndef OS_mingw32msvc + int last; + char buf[256]; + const char *command[] = { "/bin/sh", "sh", "-c", 0, 0 }; + + ans[EXPAND_BUF-1]='\0'; + + if (input == NULL) + return(NULL); + if (*input == '\0') + return(""); + /* any thing to expand? */ + if (!strpbrk(input, "$*(){}[]\\?`~")) { + strncpy(ans, input, EXPAND_BUF-1); + return(ans); + } + /* popen an echo */ +#ifdef HAVE_SNPRINTF + snprintf(buf, 255, "echo %s", input); +#else + sprintf(buf, "echo %s", input); +#endif + + command[3]=buf; + last=safePopenOut(command, ans, EXPAND_BUF-1); + if(last<0) { + perror("Pipe read error"); + exit(1); + } + if(last) + ans[last-1] = '\0'; + else + strncpy(ans, input, EXPAND_BUF-1); + return ans; +#else + strncpy(ans, input, EXPAND_BUF-1); + ans[EXPAND_BUF-1]='\0'; + return ans; +#endif +} diff --git a/fat.c b/fat.c new file mode 100644 index 0000000..c9463f2 --- /dev/null +++ b/fat.c @@ -0,0 +1,1000 @@ +/* Copyright 1996-2006,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "file_name.h" + +#ifdef HAVE_LONG_LONG +typedef long long fatBitMask; +#else +typedef long fatBitMask; +#endif + +typedef struct FatMap_t { + unsigned char *data; + fatBitMask dirty; + fatBitMask valid; +} FatMap_t; + +#define SECT_PER_ENTRY (sizeof(fatBitMask)*8) +#define ONE ((fatBitMask) 1) + +static __inline__ int readSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return READS(This->Next, buf, sectorsToBytes((Stream_t *)This, off), + size << This->sectorShift); +} + + +static __inline__ int forceReadSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return force_read(This->Next, buf, sectorsToBytes((Stream_t *)This, off), + size << This->sectorShift); +} + + +static __inline__ int writeSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return WRITES(This->Next, buf, sectorsToBytes((Stream_t*)This, off), + size << This->sectorShift); +} + +static __inline__ int forceWriteSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return force_write(This->Next, buf, sectorsToBytes((Stream_t*)This, off), + size << This->sectorShift); +} + + +static FatMap_t *GetFatMap(Fs_t *Stream) +{ + int nr_entries,i; + FatMap_t *map; + + Stream->fat_error = 0; + nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY; + map = NewArray(nr_entries, FatMap_t); + if(!map) + return 0; + + for(i=0; i< nr_entries; i++) { + map[i].data = 0; + map[i].valid = 0; + map[i].dirty = 0; + } + + return map; +} + +static __inline__ int locate(Fs_t *Stream, size_t offset, int *slot, int *bit) +{ + if(offset >= Stream->fat_len) + return -1; + *slot = offset / SECT_PER_ENTRY; + *bit = offset % SECT_PER_ENTRY; + return 0; +} + +static __inline__ int fatReadSector(Fs_t *This, int sector, int slot, + int bit, int dupe, fatBitMask bitmap) +{ + int fat_start, ret; + int nr_sectors; + + dupe = (dupe + This->primaryFat) % This->num_fat; + fat_start = This->fat_start + This->fat_len * dupe; + + if(bitmap == 0) { + nr_sectors = SECT_PER_ENTRY - bit%SECT_PER_ENTRY; + } else { + nr_sectors = 1; + } + + /* first, read as much as the buffer can give us */ + ret = readSector(This, + (char *)(This->FatMap[slot].data+(bit<sectorShift)), + fat_start+sector, + nr_sectors); + if(ret < 0) + return 0; + + if((unsigned int) ret < This->sector_size) { + /* if we got less than one sector's worth, insist to get at + * least one sector */ + ret = forceReadSector(This, + (char *) (This->FatMap[slot].data + + (bit << This->sectorShift)), + fat_start+sector, 1); + if(ret < (int) This->sector_size) + return 0; + return 1; + } + + return ret >> This->sectorShift; +} + + +static int fatWriteSector(Fs_t *This, int sector, int slot, int bit, int dupe) +{ + int fat_start; + + dupe = (dupe + This->primaryFat) % This->num_fat; + if(dupe && !This->writeAllFats) + return This->sector_size; + + fat_start = This->fat_start + This->fat_len * dupe; + + return forceWriteSector(This, + (char *) + (This->FatMap[slot].data + bit * This->sector_size), + fat_start+sector, 1); +} + +static unsigned char *loadSector(Fs_t *This, + unsigned int sector, fatAccessMode_t mode, + int recurs) +{ + int slot, bit, ret; + + if(locate(This,sector, &slot, &bit) < 0) + return 0; +#if 0 + if (((This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY) <= slot) { + fprintf(stderr,"This should not happen\n"); + fprintf(stderr, "fat_len = %d\n", This->fat_len); + fprintf(stderr, "SECT_PER_ENTRY=%d\n", (int)SECT_PER_ENTRY); + fprintf(stderr, "sector = %d slot = %d bit=%d\n", + sector, slot, bit); + fprintf(stderr, "left = %d",(int) + ((This->fat_len+SECT_PER_ENTRY-1) / SECT_PER_ENTRY)); + return 0; + } +#endif + if(!This->FatMap[slot].data) { + /* allocate the storage space */ + This->FatMap[slot].data = + malloc(This->sector_size * SECT_PER_ENTRY); + if(!This->FatMap[slot].data) + return 0; + memset(This->FatMap[slot].data, 0xee, + This->sector_size * SECT_PER_ENTRY); + } + + if(! (This->FatMap[slot].valid & (ONE << bit))) { + unsigned int i; + ret = -1; + for(i=0; i< This->num_fat; i++) { + /* read the sector */ + ret = fatReadSector(This, sector, slot, bit, i, + This->FatMap[slot].valid); + + if(ret == 0) { + fprintf(stderr, + "Error reading fat number %d\n", i); + continue; + } + if(This->FatMap[slot].valid) + /* Set recurs if there have already been + * sectors loaded in this bitmap long + */ + recurs = 1; + break; + } + + /* all copies bad. Return error */ + if(ret == 0) + return 0; + + for(i=0; (int) i < ret; i++) + This->FatMap[slot].valid |= ONE << (bit + i); + + if(!recurs && ret == 1) + /* do some prefetching, if we happened to only + * get one sector */ + loadSector(This, sector+1, mode, 1); + if(!recurs && batchmode) + for(i=0; i < 1024; i++) + loadSector(This, sector+i, mode, 1); + } + + if(mode == FAT_ACCESS_WRITE) { + This->FatMap[slot].dirty |= ONE << bit; + This->fat_dirty = 1; + } + return This->FatMap[slot].data + (bit << This->sectorShift); +} + + +static unsigned char *getAddress(Fs_t *Stream, + unsigned int num, fatAccessMode_t mode) +{ + unsigned char *ret; + int sector; + int offset; + + sector = num >> Stream->sectorShift; + ret = 0; + if(sector == Stream->lastFatSectorNr && + Stream->lastFatAccessMode >= mode) + ret = Stream->lastFatSectorData; + if(!ret) { + ret = loadSector(Stream, sector, mode, 0); + if(!ret) + return 0; + Stream->lastFatSectorNr = sector; + Stream->lastFatSectorData = ret; + Stream->lastFatAccessMode = mode; + } + offset = num & Stream->sectorMask; + return ret+offset; +} + + +static int readByte(Fs_t *Stream, int start) +{ + unsigned char *address; + + address = getAddress(Stream, start, FAT_ACCESS_READ); + if(!address) + return -1; + return *address; +} + + +/* + * Fat 12 encoding: + * | byte n | byte n+1 | byte n+2 | + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | | | | | | | | | + * | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 | + * \_____ \____ \______/________/_____ / + * ____\______\________/ _____/ ____\_/ + * / \ \ / / \ + * | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 | + * | FAT entry k | FAT entry k+1 | + */ + + /* + * Get and decode a FAT (file allocation table) entry. Returns the cluster + * number on success or 1 on failure. + */ + +static unsigned int fat12_decode(Fs_t *Stream, unsigned int num) +{ + unsigned int start = num * 3 / 2; + int byte0 = readByte(Stream, start); + int byte1 = readByte(Stream, start+1); + + if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1) { + fprintf(stderr,"[1] Bad address %d\n", num); + return 1; + } + + if (num & 1) + return (byte1 << 4) | ((byte0 & 0xf0)>>4); + else + return ((byte1 & 0xf) << 8) | byte0; +} + + +/* + * Puts a code into the FAT table. Is the opposite of fat_decode(). No + * sanity checking is done on the code. Returns a 1 on error. + */ +static void fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + int start = num * 3 / 2; + unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE); + unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE); + + if (num & 1) { + /* (odd) not on byte boundary */ + *address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0); + *address1 = (code >> 4) & 0xff; + } else { + /* (even) on byte boundary */ + *address0 = code & 0xff; + *address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f); + } +} + + +/* + * Fat 16 encoding: + * | byte n | byte n+1 | + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | + * | FAT entry k | + */ + +static unsigned int fat16_decode(Fs_t *Stream, unsigned int num) +{ + unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ); + if(!address) + return 1; + return _WORD(address); +} + +static void fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE); + set_word(address, code); +} + + +static unsigned int fast_fat16_decode(Fs_t *Stream, unsigned int num) +{ + unsigned short *address = + (unsigned short *) getAddress(Stream, num << 1, + FAT_ACCESS_READ); + if(!address) + return 1; + return *address; +} + +static void fast_fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned short *address = + (unsigned short *) getAddress(Stream, num << 1, + FAT_ACCESS_WRITE); + *address = code; +} + + + + +/* + * Fat 32 encoding + */ +#define FAT32_HIGH 0xf0000000 +#define FAT32_ADDR 0x0fffffff + +static unsigned int fat32_decode(Fs_t *Stream, unsigned int num) +{ + unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ); + if(!address) + return 1; + return _DWORD(address) & FAT32_ADDR; +} + +static void fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE); + set_dword(address,(code&FAT32_ADDR) | (_DWORD(address)&FAT32_HIGH)); +} + + +static unsigned int fast_fat32_decode(Fs_t *Stream, unsigned int num) +{ + unsigned int *address = + (unsigned int *) getAddress(Stream, num << 2, + FAT_ACCESS_READ); + if(!address) + return 1; + return (*address) & FAT32_ADDR; +} + +static void fast_fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned int *address = + (unsigned int *) getAddress(Stream, num << 2, + FAT_ACCESS_WRITE); + *address = (*address & FAT32_HIGH) | (code & FAT32_ADDR); +} + + +/* + * Write the FAT table to the disk. Up to now the FAT manipulation has + * been done in memory. All errors are fatal. (Might not be too smart + * to wait till the end of the program to write the table. Oh well...) + */ + +void fat_write(Fs_t *This) +{ + unsigned int i, j, dups, bit, slot; + int ret; + int fat_start; + + /*fprintf(stderr, "Fat write\n");*/ + + if (!This->fat_dirty) + return; + + dups = This->num_fat; + if (This->fat_error) + dups = 1; + + + for(i=0; ifat_start + i*This->fat_len; + for(slot=0;jfat_len;slot++) { + if(!This->FatMap[slot].dirty) { + j += SECT_PER_ENTRY; + continue; + } + for(bit=0; + bit < SECT_PER_ENTRY && jfat_len; + bit++,j++) { + if(!(This->FatMap[slot].dirty & (ONE << bit))) + continue; + ret = fatWriteSector(This,j,slot, bit, i); + if (ret < (int) This->sector_size){ + if (ret < 0 ){ + perror("error in fat_write"); + exit(1); + } else { + fprintf(stderr, + "end of file in fat_write\n"); + exit(1); + } + } + /* if last dupe, zero it out */ + if(i==dups-1) + This->FatMap[slot].dirty &= ~(ONE<infoSectorLoc && This->infoSectorLoc != MAX32) { + /* initialize info sector */ + InfoSector_t *infoSector; + infoSector = (InfoSector_t *) safe_malloc(This->sector_size); + set_dword(infoSector->signature1, INFOSECT_SIGNATURE1); + memset(infoSector->filler1, 0, sizeof(infoSector->filler1)); + memset(infoSector->filler2, 0, sizeof(infoSector->filler2)); + set_dword(infoSector->signature2, INFOSECT_SIGNATURE2); + set_dword(infoSector->pos, This->last); + set_dword(infoSector->count, This->freeSpace); + set_dword(infoSector->signature3, 0xaa55); + if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) != + (signed int) This->sector_size) + fprintf(stderr,"Trouble writing the info sector\n"); + free(infoSector); + } + This->fat_dirty = 0; + This->lastFatAccessMode = FAT_ACCESS_READ; +} + + + +/* + * Zero-Fat + * Used by mformat. + */ +int zero_fat(Fs_t *Stream, int media_descriptor) +{ + unsigned int i, j; + unsigned int fat_start; + unsigned char *buf; + + buf = malloc(Stream->sector_size); + if(!buf) { + perror("alloc fat sector buffer"); + return -1; + } + for(i=0; i< Stream->num_fat; i++) { + fat_start = Stream->fat_start + i*Stream->fat_len; + for(j = 0; j < Stream->fat_len; j++) { + if(j <= 1) + memset(buf, 0, Stream->sector_size); + if(!j) { + buf[0] = media_descriptor; + buf[2] = buf[1] = 0xff; + if(Stream->fat_bits > 12) + buf[3] = 0xff; + if(Stream->fat_bits > 16) { + buf[4] = 0xff; + buf[5] = 0xff; + buf[6] = 0xff; + buf[7] = 0x0f; + } + } + + if(forceWriteSector(Stream, (char *)buf, + fat_start + j, 1) != + (signed int) Stream->sector_size) { + fprintf(stderr, + "Trouble initializing a FAT sector\n"); + free(buf); + return -1; + } + } + } + + free(buf); + Stream->FatMap = GetFatMap(Stream); + if (Stream->FatMap == NULL) { + perror("alloc fat map"); + return -1; + } + return 0; +} + + +void set_fat12(Fs_t *This) +{ + This->fat_bits = 12; + This->end_fat = 0xfff; + This->last_fat = 0xff6; + This->fat_decode = fat12_decode; + This->fat_encode = fat12_encode; +} + +static char word_endian_test[] = { 0x34, 0x12 }; + +void set_fat16(Fs_t *This) +{ + This->fat_bits = 16; + This->end_fat = 0xffff; + This->last_fat = 0xfff6; + + if(sizeof(unsigned short) == 2 && + * (unsigned short *) word_endian_test == 0x1234) { + This->fat_decode = fast_fat16_decode; + This->fat_encode = fast_fat16_encode; + } else { + This->fat_decode = fat16_decode; + This->fat_encode = fat16_encode; + } +} + +static char dword_endian_test[] = { 0x78, 0x56, 0x34, 0x12 }; + +void set_fat32(Fs_t *This) +{ + This->fat_bits = 32; + This->end_fat = 0xfffffff; + This->last_fat = 0xffffff6; + + if(sizeof(unsigned int) == 4 && + * (unsigned int *) dword_endian_test == 0x12345678) { + This->fat_decode = fast_fat32_decode; + This->fat_encode = fast_fat32_encode; + } else { + This->fat_decode = fat32_decode; + This->fat_encode = fat32_encode; + } +} + + +static int check_fat(Fs_t *This) +{ + /* + * This is only a sanity check. For disks with really big FATs, + * there is no point in checking the whole FAT. + */ + + unsigned int i, f; + unsigned int tocheck; + if(mtools_skip_check) + return 0; + + /* too few sectors in the FAT */ + if(This->fat_len < NEEDED_FAT_SIZE(This)) + return -1; + /* we do not warn about too much sectors in FAT, which may + * happen when a partition has been shrunk using FIPS, or on + * other occurrences */ + + tocheck = This->num_clus; + if (tocheck + 1 >= This->last_fat) { + fprintf(stderr, "Too many clusters in FAT\n"); + return -1; + } + + if(tocheck > 4096) + tocheck = 4096; + + for ( i= 3 ; i < tocheck; i++){ + f = This->fat_decode(This,i); + if (f == 1 || (f < This->last_fat && f > This->num_clus)){ + fprintf(stderr, + "Cluster # at %d too big(%#x)\n", i,f); + fprintf(stderr,"Probably non MS-DOS disk\n"); + return -1; + } + } + return 0; +} + + +/* + * Read the first sector of FAT table into memory. Crude error detection on + * wrong FAT encoding scheme. + */ +static int check_media_type(Fs_t *This, union bootsector *boot, + unsigned int tot_sectors) +{ + unsigned char *address; + + This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size; + + This->FatMap = GetFatMap(This); + if (This->FatMap == NULL) { + perror("alloc fat map"); + return -1; + } + + address = getAddress(This, 0, FAT_ACCESS_READ); + if(!address) { + fprintf(stderr, + "Could not read first FAT sector\n"); + return -1; + } + + if(mtools_skip_check) + return 0; + + if(!address[0] && !address[1] && !address[2]) + /* Some Atari disks have zeroes where Dos has media descriptor + * and 0xff. Do not consider this as an error */ + return 0; + + if((address[0] != boot->boot.descr && boot->boot.descr >= 0xf0 && + ((address[0] != 0xf9 && address[0] != 0xf7) + || boot->boot.descr != 0xf0)) || address[0] < 0xf0) { + fprintf(stderr, + "Bad media types %02x/%02x, probably non-MSDOS disk\n", + address[0], + boot->boot.descr); + return -1; + } + + if(address[1] != 0xff || address[2] != 0xff){ + fprintf(stderr,"Initial byte of fat is not 0xff\n"); + return -1; + } + + return 0; +} + +static int fat_32_read(Fs_t *This, union bootsector *boot, + unsigned int tot_sectors) +{ + int size; + + This->fat_len = DWORD(ext.fat32.bigFat); + This->writeAllFats = !(boot->boot.ext.fat32.extFlags[0] & 0x80); + This->primaryFat = boot->boot.ext.fat32.extFlags[0] & 0xf; + This->rootCluster = DWORD(ext.fat32.rootCluster); + This->clus_start = This->fat_start + This->num_fat * This->fat_len; + + /* read the info sector */ + size = This->sector_size; + This->infoSectorLoc = WORD(ext.fat32.infoSector); + if(This->sector_size >= 512 && + This->infoSectorLoc && This->infoSectorLoc != MAX32) { + InfoSector_t *infoSector; + infoSector = (InfoSector_t *) safe_malloc(size); + if(forceReadSector(This, (char *)infoSector, + This->infoSectorLoc, 1) == + (signed int) This->sector_size && + _DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1 && + _DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2) { + This->freeSpace = _DWORD(infoSector->count); + This->last = _DWORD(infoSector->pos); + } + free(infoSector); + } + + set_fat32(This); + return(check_media_type(This, boot, tot_sectors) || + check_fat(This)); +} + + +static int old_fat_read(Fs_t *This, union bootsector *boot, + int config_fat_bits, + size_t tot_sectors, int nodups) +{ + This->writeAllFats = 1; + This->primaryFat = 0; + This->dir_start = This->fat_start + This->num_fat * This->fat_len; + This->clus_start = This->dir_start + This->dir_len; + This->infoSectorLoc = MAX32; + + if(nodups) + This->num_fat = 1; + + if(check_media_type(This,boot, tot_sectors)) + return -1; + + if(This->num_clus >= FAT12) { + set_fat16(This); + /* third FAT byte must be 0xff */ + if(!mtools_skip_check && readByte(This, 3) != 0xff) + return -1; + } else + set_fat12(This); + + return check_fat(This); +} + +/* + * Read the first sector of the FAT table into memory and initialize + * structures. + */ +int fat_read(Fs_t *This, union bootsector *boot, int fat_bits, + size_t tot_sectors, int nodups) +{ + This->fat_error = 0; + This->fat_dirty = 0; + This->last = MAX32; + This->freeSpace = MAX32; + This->lastFatSectorNr = 0; + This->lastFatSectorData = 0; + + if(This->fat_len) + return old_fat_read(This, boot, fat_bits, tot_sectors, nodups); + else + return fat_32_read(This, boot, tot_sectors); +} + + +unsigned int fatDecode(Fs_t *This, unsigned int pos) +{ + unsigned int ret; + + ret = This->fat_decode(This, pos); + if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) { + fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos); + This->fat_error++; + } + return ret; +} + +/* append a new cluster */ +void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos) +{ + This->fat_encode(This, pos, newpos); + This->fat_encode(This, newpos, This->end_fat); + if(This->freeSpace != MAX32) + This->freeSpace--; +} + +/* de-allocates the given cluster */ +void fatDeallocate(Fs_t *This, unsigned int pos) +{ + This->fat_encode(This, pos, 0); + if(This->freeSpace != MAX32) + This->freeSpace++; +} + +/* allocate a new cluster */ +void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value) +{ + This->fat_encode(This, pos, value); + if(This->freeSpace != MAX32) + This->freeSpace--; +} + +void fatEncode(Fs_t *This, unsigned int pos, unsigned int value) +{ + unsigned int oldvalue = This->fat_decode(This, pos); + This->fat_encode(This, pos, value); + if(This->freeSpace != MAX32) { + if(oldvalue) + This->freeSpace++; + if(value) + This->freeSpace--; + } +} + +unsigned int get_next_free_cluster(Fs_t *This, unsigned int last) +{ + unsigned int i; + + if(This->last != MAX32) + last = This->last; + + if (last < 2 || + last >= This->num_clus+1) + last = 1; + + for (i=last+1; i< This->num_clus+2; i++) { + unsigned int r = fatDecode(This, i); + if(r == 1) + goto exit_0; + if (!r) { + This->last = i; + return i; + } + } + + for(i=2; i < last+1; i++) { + unsigned int r = fatDecode(This, i); + if(r == 1) + goto exit_0; + if (!r) { + This->last = i; + return i; + } + } + + + fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters, + This->last); + return 1; + exit_0: + fprintf(stderr, "FAT error\n"); + return 1; +} + +int fat_error(Stream_t *Dir) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + if(This->fat_error) + fprintf(stderr,"Fat error detected\n"); + + return This->fat_error; +} + +int fat32RootCluster(Stream_t *Dir) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + if(This->fat_bits == 32) + return This->rootCluster; + else + return 0; +} + + +/* + * Get the amount of free space on the diskette + */ + +mt_size_t getfree(Stream_t *Dir) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + if(This->freeSpace == MAX32 || This->freeSpace == 0) { + register unsigned int i; + size_t total; + + total = 0L; + for (i = 2; i < This->num_clus + 2; i++) { + unsigned int r = fatDecode(This,i); + if(r == 1) { + return -1; + } + if (!r) + total++; + } + This->freeSpace = total; + } + return sectorsToBytes((Stream_t*)This, + This->freeSpace * This->cluster_size); +} + + +/* + * Ensure that there is a minimum of total sectors free + */ +int getfreeMinClusters(Stream_t *Dir, size_t size) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + register unsigned int i, last; + size_t total; + + if(batchmode && This->freeSpace == MAX32) + getfree(Stream); + + if(This->freeSpace != MAX32) { + if(This->freeSpace >= size) + return 1; + else { + fprintf(stderr, "Disk full\n"); + got_signal = 1; + return 0; + } + } + + total = 0L; + + /* we start at the same place where we'll start later to actually + * allocate the sectors. That way, the same sectors of the FAT, which + * are already loaded during getfreeMin will be able to be reused + * during get_next_free_cluster */ + last = This->last; + + if ( last < 2 || last >= This->num_clus + 2) + last = 1; + for (i=last+1; i< This->num_clus+2; i++){ + unsigned int r = fatDecode(This, i); + if(r == 1) { + goto exit_0; + } + if (!r) + total++; + if(total >= size) + return 1; + } + for(i=2; i < last+1; i++){ + unsigned int r = fatDecode(This, i); + if(r == 1) { + goto exit_0; + } + if (!r) + total++; + if(total >= size) + return 1; + } + fprintf(stderr, "Disk full\n"); + got_signal = 1; + return 0; + exit_0: + fprintf(stderr, "FAT error\n"); + return 0; +} + + +int getfreeMinBytes(Stream_t *Dir, mt_size_t size) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + size_t size2; + + size2 = size / (This->sector_size * This->cluster_size); + if(size % (This->sector_size * This->cluster_size)) + size2++; + return getfreeMinClusters(Dir, size2); +} + + +unsigned int getStart(Stream_t *Dir, struct directory *dir) +{ + Stream_t *Stream = GetFs(Dir); + unsigned int first; + + first = START(dir); + if(fat32RootCluster(Stream)) + first |= STARTHI(dir) << 16; + return first; +} + +int fs_free(Stream_t *Stream) +{ + DeclareThis(Fs_t); + + if(This->FatMap) { + int i, nr_entries; + nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) / + SECT_PER_ENTRY; + for(i=0; i< nr_entries; i++) + if(This->FatMap[i].data) + free(This->FatMap[i].data); + free(This->FatMap); + } + if(This->cp) + cp_close(This->cp); + return 0; +} diff --git a/fat_free.c b/fat_free.c new file mode 100644 index 0000000..6d49018 --- /dev/null +++ b/fat_free.c @@ -0,0 +1,72 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-1998,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "fsP.h" +#include "mtoolsDirentry.h" + +/* + * Remove a string of FAT entries (delete the file). The argument is + * the beginning of the string. Does not consider the file length, so + * if FAT is corrupted, watch out! + */ + +int fat_free(Stream_t *Dir, unsigned int fat) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + unsigned int next_no_step; + /* a zero length file? */ + if (fat == 0) + return(0); + /* CONSTCOND */ + while (!This->fat_error) { + /* get next cluster number */ + next_no_step = fatDecode(This,fat); + /* mark current cluster as empty */ + fatDeallocate(This,fat); + if (next_no_step >= This->last_fat) + break; + fat = next_no_step; + } + return(0); +} + +int fatFreeWithDir(Stream_t *Dir, struct directory *dir) +{ + unsigned int first; + + if((!strncmp(dir->name,". ",8) || + !strncmp(dir->name,".. ",8)) && + !strncmp(dir->ext," ",3)) { + fprintf(stderr,"Trying to remove . or .. entry\n"); + return -1; + } + + first = START(dir); + if(fat32RootCluster(Dir)) + first |= STARTHI(dir) << 16; + return fat_free(Dir, first); +} + +int fatFreeWithDirentry(direntry_t *entry) +{ + return fatFreeWithDir(entry->Dir, &entry->dir); +} + diff --git a/fat_size_calculation.tex b/fat_size_calculation.tex new file mode 100644 index 0000000..55b6884 --- /dev/null +++ b/fat_size_calculation.tex @@ -0,0 +1,227 @@ +% Copyright 2003,2005,2007 Alain Knaff. + +% This documentation is for Mtools which is a collection of tools to +% allow Unix systems to manipulate MS-DOS files. + +% Permission is granted to copy, distribute and/or modify this document +% under the terms of the GNU Free Documentation License, Version 1.3 or +% any later version published by the Free Software Foundation; with no +% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +%Texts. A copy of the license is included in the section entitled +% ``GNU Free Documentation License''. + +\documentclass[a4paper,12pt]{article} + +\usepackage[T1]{fontenc} +\usepackage[latin1]{inputenc} +\usepackage{pslatex} +\usepackage[pdfpagemode=None,colorlinks]{hyperref} + +\author{Alain Knaff} +\title{How mformat-3.9.10 and above calculates needed FAT size} + +\begin{document} + +\maketitle + +This small document explains the formula used by {\tt mformat.c} to +figure out fat size and number of clusters. Due to the way that +filesystem parameters are stored in the boot sector, we can afford to +have a FAT that is larger than need to be to accomodate the clusters +present on disk, but under no circumstances can we have one that is +too small. + +In this discussion, we use the following variable names: + +\begin{tabular}{|r|p{12cm}|} + +\hline + +$fatNybls$& +Number of nubbles (4 bit unit per FAT). This is 3 for FAT12, 4 for +FAT16, and 8 for FAT16\\ + +\hline + +$numClus$& +Number of clusters on the disk\\ + +\hline + +$clusSiz$& +Size of a cluster, expressed in sectors\\ + +\hline + +$secSiz$& +Size of a sector, in bytes. Size of a sector in nybbles is $secSiz$ * 2\\ + +\hline + +$nfats$& +Number of FAT copies, usually two\\ + +\hline + +$remSects$& +``Remaining sectors'', after number of boot sectors and root directory +have been accounted for\\ + +\hline + +$fatLen$& +Length of the FAT, in sectors\\ + +\hline + + +\end{tabular} + + +Taking into account both data and fat, each cluster takes up the +following number of nybbles (units of 4 bytes): + + +$$clusSiz * (2*secSiz) + nfats * fatNybls$$ + +This accounts for the data of the cluster ($clusSiz * secSiz$), +as well as for the space taken up by its descriptor. + +The space taken up by all clusters together, plus the space taken by +descriptors for clusters 0 and 1 ($2*nfats*fatNybls$) should be less +than what is available. + +Additional sectors may be lost due to slack (you have to use a full +FAT sector, you also have to use a full cluster in the data +area). Thus, an {\em upper bound} for the number of clusters is as +follows: + +$$ +numClus \le {2*remSect*secSiz - 2*nfats*fatNybls \over +2*clusSiz*secSiz + nfats*fatNybls} +$$ + + +$$ +numClus \le {(remSect+2*clusSiz)*2*secSiz \over +2*clusSiz*secSiz + nfats*fatNybls} - 2 +$$ + + +These will take up at most the following space in one copy of the FAT +(we have to round up, because even a half-full fat sector must be +taken in its entirety) + +$$ +fatLen \le \left\lceil { (numClus+2)*fatNybls \over secSiz * 2 } \right\rceil +$$ + + +$$ +fatLen \le \left\lceil { +\left( { 2*(remSect+2*clusSiz)*secSiz \over +2*clusSiz*secSiz + nfats*fatNybls} \right) * fatNybls \over +2*secSiz +} \right\rceil +$$ + + +$$ +fatLen \le \left\lceil { +(remSect+2*clusSiz)* fatNybls \over +2*clusSiz*secSiz + nfats*fatNybls +} \right\rceil +$$ + +The space left after FAT sector has been deduced is now {\em less than +or equal} to what would be needed for the data area of the clusters +(including fractional clusters), which is good, as we may have under +no circumstances {\em more} clusters in the data area than in the FAT. +An important point in this calculation is that we based the needed FAT +size on a {\em fractional} number of clusters, rather than a rounded +down amount of clusters. Indeed, using a rounded down number could +have exposed us to a situation where we had an {\em almost enough} +space for one more cluster (i.e. not enough space for data + FAT, but +enough for data alone). This situation, combined with a situation +where the last FAT sector was flush full could have lead to a +situation where $numClus$ would become too large for the FAT to +accomodate. I think this is clearer with an example: +\begin{itemize} +\item $remSect=4127$, $clusSiz=1$, $nfats=1$ +\item (Non rounded down) $numClus={(4127+2)*(1024) \over 1032} - +2 =4094.992$ +\item Rounded down: 4094 clusters +\item These fit into 16 FAT sectors, exactly +\item ... leaving us 4095 clusters, which is one to many (because +these 4095 clusters would now need 17 FAT clusters) +\end{itemize} + +Keeping the fractional part (0.992) allows us to round {\em up} the +needed number of FAT sectors to 17, nicely solving this problem. + +The downside of counting the fractional part however is that we quite +often waste a sector in the really common situation where both $nfats$ +and $clusSiz$ are even, while $remSect$ is odd. An easy way to address +this is to substract one from $remSect$ before application of the +formula, if this case is detected. Such operation carries no risk, as +the odd final sector cannot be used to make a full cluster. + +There is still a case however, where fatLen must be grown manually +after application of the formula: If numClus exceeds the maximum +number of clusters allowable for FAT12 or FAT16), we need to shrink +$numClus$ after application of the formula, and manually make the FAT +larger in order to take up any excess space. + +Also note that as we used upper bounds, we may waste a certain number +of sectors, which an exact calculation may not have wasted. However, +normally, we should not lose more than one sector per FAT copy. + +N.B. In its document at \url{http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf}, +Microsoft proposes a much simpler formula. However, this formula is +both wrong (i.e. occasionally it produces a smaller FAT than is +needed for the clusters on disk), less generic (only works for sector +sizes equal to 512), and less efficient (in case of FAT32, it may +waste up to 8 sectors!) + +The formula is the following (for FAT16): +$$ +fatLen \le \left\lceil { remSect \over 256 * clusSiz + nfats} \right\rceil +$$ + +Note that it doesn't account for the dummy clusters 0 and 1. Thus, if +we have 258 sectors remaining, with a cluster size of 1, and two FAT +copies, the Microsoft formula mistakenly assumes fatLen = 1. This +leaves 258 - 2 = 256 sectors for clusters, which yields 256 clusters. +However, those clusters do not fit into the FAT, as two clusters are +lost (0 and 1). However, to Micro\$ofts' credit, this is not actually +the formula they're using (tested with $remsect=160056$ and +$clusSize=4$), so this seems to be a documentation issue rather than a +genuine bug. + +In case of FAT32, Microsoft just halves the denominator. This is +wasteful, as only the $256*clusSiz$ part would need to be halved. + +If we assume 16777000, and a cluster size of 8, our formula would give +us: +$$fatLen = \left\lceil (16777000 + 16) * 8 \over 2 * 8 * 512 + 16 +\right\rceil = 16352$$ +This would leave $16777000-2*16352=16744296$ sectors for the clusters, +i.e. 2093037 clusters. The FAT descriptors for those 2093037 clusters +do indeed fit into our 16352 fat sectors. + +Microsoft, on the other hand, would get: $$fatLen = \left\lceil{ +16777000 \over (256 * 8 + 2)/2} \right\rceil = 16368$$ This would only +leave $16777000-2*16368=16744264$, i.e. 2093033 clusters, thus wasting +4 clusters. The FAT would be 28 sectors too big, i.e. more than the +mere 8 sectors announced by Microsoft! Unfortunately, I currently +don't have access to any sufficiently recent Windows to check out +whether this really happens in the code, or whether it is only a +documentation issue as well. + +Oh, and before somebody points it out: the formula in this document +occassionnally wastes sectors too, although not as much (Example: With +$remsect=685$, $clusSiz=1$ and $nfats=2$ our formula gives $fatLen=3$, +which leaves 679 clusters. However, we could use $fatLen=2$, leaving +681 clusters, + +\end{document} diff --git a/file.c b/file.c new file mode 100644 index 0000000..cba4c89 --- /dev/null +++ b/file.c @@ -0,0 +1,694 @@ +/* Copyright 1996-1999,2001-2003,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "file.h" +#include "htable.h" +#include "dirCache.h" + +typedef struct File_t { + Class_t *Class; + int refs; + struct Fs_t *Fs; /* Filesystem that this fat file belongs to */ + Stream_t *Buffer; + + int (*map)(struct File_t *this, off_t where, size_t *len, int mode, + mt_off_t *res); + size_t FileSize; + + size_t preallocatedSize; + int preallocatedClusters; + + /* Absolute position of first cluster of file */ + unsigned int FirstAbsCluNr; + + /* Absolute position of previous cluster */ + unsigned int PreviousAbsCluNr; + + /* Relative position of previous cluster */ + unsigned int PreviousRelCluNr; + direntry_t direntry; + int hint; + struct dirCache_t *dcp; + + unsigned int loopDetectRel; + unsigned int loopDetectAbs; +} File_t; + +static Class_t FileClass; +T_HashTable *filehash; + +static File_t *getUnbufferedFile(Stream_t *Stream) +{ + while(Stream->Class != &FileClass) + Stream = Stream->Next; + return (File_t *) Stream; +} + +Fs_t *getFs(Stream_t *Stream) +{ + return getUnbufferedFile(Stream)->Fs; +} + +struct dirCache_t **getDirCacheP(Stream_t *Stream) +{ + return &getUnbufferedFile(Stream)->dcp; +} + +direntry_t *getDirentry(Stream_t *Stream) +{ + return &getUnbufferedFile(Stream)->direntry; +} + + +static int recalcPreallocSize(File_t *This) +{ + size_t currentClusters, neededClusters; + int clus_size; + int neededPrealloc; + Fs_t *Fs = This->Fs; + int r; + +#if 0 + if(This->FileSize & 0xc0000000) { + fprintf(stderr, "Bad filesize\n"); + } + if(This->preallocatedSize & 0xc0000000) { + fprintf(stderr, "Bad preallocated size %x\n", + (int) This->preallocatedSize); + } +#endif + clus_size = Fs->cluster_size * Fs->sector_size; + + currentClusters = (This->FileSize + clus_size - 1) / clus_size; + neededClusters = (This->preallocatedSize + clus_size - 1) / clus_size; + neededPrealloc = neededClusters - currentClusters; + if(neededPrealloc < 0) + neededPrealloc = 0; + r = fsPreallocateClusters(Fs, neededPrealloc - This->preallocatedClusters); + if(r) + return r; + This->preallocatedClusters = neededPrealloc; + return 0; +} + +static int _loopDetect(unsigned int *oldrel, unsigned int rel, + unsigned int *oldabs, unsigned int absol) +{ + if(*oldrel && rel > *oldrel && absol == *oldabs) { + fprintf(stderr, "loop detected! oldrel=%d newrel=%d abs=%d\n", + *oldrel, rel, absol); + return -1; + } + + if(rel >= 2 * *oldrel + 1) { + *oldrel = rel; + *oldabs = absol; + } + return 0; +} + + +static int loopDetect(File_t *This, unsigned int rel, unsigned int absol) +{ + return _loopDetect(&This->loopDetectRel, rel, &This->loopDetectAbs, absol); +} + +static unsigned int _countBlocks(Fs_t *This, unsigned int block) +{ + unsigned int blocks; + unsigned int rel, oldabs, oldrel; + + blocks = 0; + + oldabs = oldrel = rel = 0; + + while (block <= This->last_fat && block != 1 && block) { + blocks++; + block = fatDecode(This, block); + rel++; + if(_loopDetect(&oldrel, rel, &oldabs, block) < 0) + block = -1; + } + return blocks; +} + +unsigned int countBlocks(Stream_t *Dir, unsigned int block) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + return _countBlocks(This, block); +} + +/* returns number of bytes in a directory. Represents a file size, and + * can hence be not bigger than 2^32 + */ +static size_t countBytes(Stream_t *Dir, unsigned int block) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + + return _countBlocks(This, block) * + This->sector_size * This->cluster_size; +} + +void printFat(Stream_t *Stream) +{ + File_t *This = getUnbufferedFile(Stream); + unsigned long n; + int rel; + unsigned long begin, end; + int first; + + n = This->FirstAbsCluNr; + if(!n) { + printf("Root directory or empty file\n"); + return; + } + + rel = 0; + first = 1; + begin = end = 0; + do { + if (first || n != end+1) { + if (!first) { + if (begin != end) + printf("-%lu", end); + printf("> "); + } + begin = end = n; + printf("<%lu", begin); + } else { + end++; + } + first = 0; + n = fatDecode(This->Fs, n); + rel++; + if(loopDetect(This, rel, n) < 0) + n = 1; + } while (n <= This->Fs->last_fat && n != 1); + if(!first) { + if (begin != end) + printf("-%lu", end); + printf(">"); + } +} + +static int normal_map(File_t *This, off_t where, size_t *len, int mode, + mt_off_t *res) +{ + int offset; + size_t end; + int NrClu; /* number of clusters to read */ + unsigned int RelCluNr; + unsigned int CurCluNr; + unsigned int NewCluNr; + unsigned int AbsCluNr; + int clus_size; + Fs_t *Fs = This->Fs; + + *res = 0; + clus_size = Fs->cluster_size * Fs->sector_size; + offset = where % clus_size; + + if (mode == MT_READ) + maximize(*len, This->FileSize - where); + if (*len == 0 ) + return 0; + + if (This->FirstAbsCluNr < 2){ + if( mode == MT_READ || *len == 0){ + *len = 0; + return 0; + } + NewCluNr = get_next_free_cluster(This->Fs, 1); + if (NewCluNr == 1 ){ + errno = ENOSPC; + return -2; + } + hash_remove(filehash, (void *) This, This->hint); + This->FirstAbsCluNr = NewCluNr; + hash_add(filehash, (void *) This, &This->hint); + fatAllocate(This->Fs, NewCluNr, Fs->end_fat); + } + + RelCluNr = where / clus_size; + + if (RelCluNr >= This->PreviousRelCluNr){ + CurCluNr = This->PreviousRelCluNr; + AbsCluNr = This->PreviousAbsCluNr; + } else { + CurCluNr = 0; + AbsCluNr = This->FirstAbsCluNr; + } + + + NrClu = (offset + *len - 1) / clus_size; + while (CurCluNr <= RelCluNr + NrClu){ + if (CurCluNr == RelCluNr){ + /* we have reached the beginning of our zone. Save + * coordinates */ + This->PreviousRelCluNr = RelCluNr; + This->PreviousAbsCluNr = AbsCluNr; + } + NewCluNr = fatDecode(This->Fs, AbsCluNr); + if (NewCluNr == 1 || NewCluNr == 0){ + fprintf(stderr,"Fat problem while decoding %d %x\n", + AbsCluNr, NewCluNr); + exit(1); + } + if(CurCluNr == RelCluNr + NrClu) + break; + if (NewCluNr > Fs->last_fat && mode == MT_WRITE){ + /* if at end, and writing, extend it */ + NewCluNr = get_next_free_cluster(This->Fs, AbsCluNr); + if (NewCluNr == 1 ){ /* no more space */ + errno = ENOSPC; + return -2; + } + fatAppend(This->Fs, AbsCluNr, NewCluNr); + } + + if (CurCluNr < RelCluNr && NewCluNr > Fs->last_fat){ + *len = 0; + return 0; + } + + if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1) + break; + CurCluNr++; + AbsCluNr = NewCluNr; + if(loopDetect(This, CurCluNr, AbsCluNr)) { + errno = EIO; + return -2; + } + } + + maximize(*len, (1 + CurCluNr - RelCluNr) * clus_size - offset); + + end = where + *len; + if(batchmode && + mode == MT_WRITE && + end >= This->FileSize) { + *len += ROUND_UP(end, clus_size) - end; + } + + if((*len + offset) / clus_size + This->PreviousAbsCluNr-2 > + Fs->num_clus) { + fprintf(stderr, "cluster too big\n"); + exit(1); + } + + *res = sectorsToBytes((Stream_t*)Fs, + (This->PreviousAbsCluNr-2) * Fs->cluster_size + + Fs->clus_start) + offset; + return 1; +} + + +static int root_map(File_t *This, off_t where, size_t *len, int mode, + mt_off_t *res) +{ + Fs_t *Fs = This->Fs; + + if(Fs->dir_len * Fs->sector_size < (size_t) where) { + *len = 0; + errno = ENOSPC; + return -2; + } + + maximize(*len, Fs->dir_len * Fs->sector_size - where); + if (*len == 0) + return 0; + + *res = sectorsToBytes((Stream_t*)Fs, Fs->dir_start) + where; + return 1; +} + + +static int read_file(Stream_t *Stream, char *buf, mt_off_t iwhere, + size_t len) +{ + DeclareThis(File_t); + mt_off_t pos; + int err; + off_t where = truncBytes32(iwhere); + + Stream_t *Disk = This->Fs->Next; + + err = This->map(This, where, &len, MT_READ, &pos); + if(err <= 0) + return err; + return READS(Disk, buf, pos, len); +} + +static int write_file(Stream_t *Stream, char *buf, mt_off_t iwhere, size_t len) +{ + DeclareThis(File_t); + mt_off_t pos; + int ret; + size_t requestedLen; + Stream_t *Disk = This->Fs->Next; + off_t where = truncBytes32(iwhere); + int err; + + requestedLen = len; + err = This->map(This, where, &len, MT_WRITE, &pos); + if( err <= 0) + return err; + if(batchmode) + ret = force_write(Disk, buf, pos, len); + else + ret = WRITES(Disk, buf, pos, len); + if(ret > (signed int) requestedLen) + ret = requestedLen; + if (ret > 0 && + where + ret > (off_t) This->FileSize ) + This->FileSize = where + ret; + recalcPreallocSize(This); + return ret; +} + + +/* + * Convert an MSDOS time & date stamp to the Unix time() format + */ + +static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, + 0, 0, 0 }; +static __inline__ time_t conv_stamp(struct directory *dir) +{ + struct tm *tmbuf; + long tzone, dst; + time_t accum, tmp; + + accum = DOS_YEAR(dir) - 1970; /* years past */ + + /* days passed */ + accum = accum * 365L + month[DOS_MONTH(dir)-1] + DOS_DAY(dir); + + /* leap years */ + accum += (DOS_YEAR(dir) - 1972) / 4L; + + /* back off 1 day if before 29 Feb */ + if (!(DOS_YEAR(dir) % 4) && DOS_MONTH(dir) < 3) + accum--; + accum = accum * 24L + DOS_HOUR(dir); /* hours passed */ + accum = accum * 60L + DOS_MINUTE(dir); /* minutes passed */ + accum = accum * 60L + DOS_SEC(dir); /* seconds passed */ + + /* correct for Time Zone */ +#ifdef HAVE_GETTIMEOFDAY + { + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + tzone = tz.tz_minuteswest * 60L; + } +#else +#if defined HAVE_TZSET && !defined OS_mingw32msvc + { +#if !defined OS_ultrix && !defined OS_cygwin + /* Ultrix defines this to be a different type */ + extern long timezone; +#endif + tzset(); + tzone = (long) timezone; + } +#else + tzone = 0; +#endif /* HAVE_TZSET */ +#endif /* HAVE_GETTIMEOFDAY */ + + accum += tzone; + + /* correct for Daylight Saving Time */ + tmp = accum; + tmbuf = localtime(&tmp); + dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L; + accum += dst; + + return accum; +} + + +static int get_file_data(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + DeclareThis(File_t); + + if(date) + *date = conv_stamp(& This->direntry.dir); + if(size) + *size = (mt_size_t) This->FileSize; + if(type) + *type = This->direntry.dir.attr & ATTR_DIR; + if(address) + *address = This->FirstAbsCluNr; + return 0; +} + + +static int free_file(Stream_t *Stream) +{ + DeclareThis(File_t); + Fs_t *Fs = This->Fs; + fsPreallocateClusters(Fs, -This->preallocatedClusters); + FREE(&This->direntry.Dir); + freeDirCache(Stream); + return hash_remove(filehash, (void *) Stream, This->hint); +} + + +static int flush_file(Stream_t *Stream) +{ + DeclareThis(File_t); + direntry_t *entry = &This->direntry; + + if(isRootDir(Stream)) { + return 0; + } + + if(This->FirstAbsCluNr != getStart(entry->Dir, &entry->dir)) { + set_word(entry->dir.start, This->FirstAbsCluNr & 0xffff); + set_word(entry->dir.startHi, This->FirstAbsCluNr >> 16); + dir_write(entry); + } + return 0; +} + + +static int pre_allocate_file(Stream_t *Stream, mt_size_t isize) +{ + DeclareThis(File_t); + + size_t size = truncBytes32(isize); + + if(size > This->FileSize && + size > This->preallocatedSize) { + This->preallocatedSize = size; + return recalcPreallocSize(This); + } else + return 0; +} + +static Class_t FileClass = { + read_file, + write_file, + flush_file, /* flush */ + free_file, /* free */ + 0, /* get_geom */ + get_file_data, + pre_allocate_file, + get_dosConvert_pass_through +}; + +static unsigned int getAbsCluNr(File_t *This) +{ + if(This->FirstAbsCluNr) + return This->FirstAbsCluNr; + if(isRootDir((Stream_t *) This)) + return 0; + return 1; +} + +static unsigned int func1(void *Stream) +{ + DeclareThis(File_t); + + return getAbsCluNr(This) ^ (long) This->Fs; +} + +static unsigned int func2(void *Stream) +{ + DeclareThis(File_t); + + return getAbsCluNr(This); +} + +static int comp(void *Stream, void *Stream2) +{ + DeclareThis(File_t); + + File_t *This2 = (File_t *) Stream2; + + return This->Fs != This2->Fs || + getAbsCluNr(This) != getAbsCluNr(This2); +} + +static void init_hash(void) +{ + static int is_initialised=0; + + if(!is_initialised){ + make_ht(func1, func2, comp, 20, &filehash); + is_initialised = 1; + } +} + + +static Stream_t *_internalFileOpen(Stream_t *Dir, unsigned int first, + size_t size, direntry_t *entry) +{ + Stream_t *Stream = GetFs(Dir); + DeclareThis(Fs_t); + File_t Pattern; + File_t *File; + + init_hash(); + This->refs++; + + if(first != 1){ + /* we use the illegal cluster 1 to mark newly created files. + * do not manage those by hashtable */ + Pattern.Fs = This; + Pattern.Class = &FileClass; + if(first || (entry && !IS_DIR(entry))) + Pattern.map = normal_map; + else + Pattern.map = root_map; + Pattern.FirstAbsCluNr = first; + Pattern.loopDetectRel = 0; + Pattern.loopDetectAbs = first; + if(!hash_lookup(filehash, (T_HashTableEl) &Pattern, + (T_HashTableEl **)&File, 0)){ + File->refs++; + This->refs--; + return (Stream_t *) File; + } + } + + File = New(File_t); + if (!File) + return NULL; + File->dcp = 0; + File->preallocatedClusters = 0; + File->preallocatedSize = 0; + /* memorize dir for date and attrib */ + File->direntry = *entry; + if(entry->entry == -3) + File->direntry.Dir = (Stream_t *) File; /* root directory */ + else + COPY(File->direntry.Dir); + + File->Class = &FileClass; + File->Fs = This; + if(first || (entry && !IS_DIR(entry))) + File->map = normal_map; + else + File->map = root_map; /* FAT 12/16 root directory */ + if(first == 1) + File->FirstAbsCluNr = 0; + else + File->FirstAbsCluNr = first; + + File->loopDetectRel = 0; + File->loopDetectAbs = 0; + + File->PreviousRelCluNr = 0xffff; + File->FileSize = size; + File->refs = 1; + File->Buffer = 0; + hash_add(filehash, (void *) File, &File->hint); + return (Stream_t *) File; +} + +Stream_t *OpenRoot(Stream_t *Dir) +{ + unsigned int num; + direntry_t entry; + size_t size; + Stream_t *file; + + memset(&entry, 0, sizeof(direntry_t)); + + num = fat32RootCluster(Dir); + + /* make the directory entry */ + entry.entry = -3; + entry.name[0] = '\0'; + mk_entry_from_base("/", ATTR_DIR, num, 0, 0, &entry.dir); + + if(num) + size = countBytes(Dir, num); + else { + Fs_t *Fs = (Fs_t *) GetFs(Dir); + size = Fs->dir_len * Fs->sector_size; + } + file = _internalFileOpen(Dir, num, size, &entry); + bufferize(&file); + return file; +} + + +Stream_t *OpenFileByDirentry(direntry_t *entry) +{ + Stream_t *file; + unsigned int first; + size_t size; + + first = getStart(entry->Dir, &entry->dir); + + if(!first && IS_DIR(entry)) + return OpenRoot(entry->Dir); + if (IS_DIR(entry)) + size = countBytes(entry->Dir, first); + else + size = FILE_SIZE(&entry->dir); + file = _internalFileOpen(entry->Dir, first, size, entry); + if(IS_DIR(entry)) { + bufferize(&file); + if(first == 1) + dir_grow(file, 0); + } + + return file; +} + + +int isRootDir(Stream_t *Stream) +{ + File_t *This = getUnbufferedFile(Stream); + + return This->map == root_map; +} diff --git a/file.h b/file.h new file mode 100644 index 0000000..a2e0244 --- /dev/null +++ b/file.h @@ -0,0 +1,27 @@ +#ifndef MTOOLS_FILE_H +#define MTOOLS_FILE_H +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "stream.h" +#include "mtoolsDirentry.h" + +Stream_t *OpenFileByDirentry(direntry_t *entry); +Stream_t *OpenRoot(Stream_t *Dir); +void printFat(Stream_t *Stream); +direntry_t *getDirentry(Stream_t *Stream); +#endif diff --git a/file_name.c b/file_name.c new file mode 100644 index 0000000..e38bbe3 --- /dev/null +++ b/file_name.c @@ -0,0 +1,229 @@ +/* Copyright 1995 David C. Niemi + * Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "codepage.h" +#include "file_name.h" + +/* Write a DOS name + extension into a legal unix-style name. */ +char *unix_normalize (doscp_t *cp, char *ans, dos_name_t *dn) +{ + char buffer[13]; + wchar_t wbuffer[13]; + char *a; + int j; + + for (a=buffer,j=0; (j<8) && (dn->base[j] > ' '); ++j,++a) + *a = dn->base[j]; + if(dn->ext[0] > ' ') { + *a++ = '.'; + for (j=0; j<3 && dn->ext[j] > ' '; ++j,++a) + *a = dn->ext[j]; + } + *a++ = '\0'; + dos_to_wchar(cp, buffer, wbuffer, 13); + wchar_to_native(wbuffer, ans, 13); + return ans; +} + +typedef enum Case_l { + NONE, + UPPER, + LOWER +} Case_t; + +static void TranslateToDos(doscp_t *toDos, const char *in, char *out, int count, + char *end, Case_t *Case, int *mangled) +{ + wchar_t buffer[12]; + wchar_t *s=buffer; + wchar_t *t=buffer; + + /* first convert to wchar, so we get to use towupper etc. */ + native_to_wchar(in, buffer, count, end, mangled); + buffer[count]='\0'; + + *Case = NONE; + for( ; *s ; s++) { + if(!count) { + *mangled |= 3; + break; + } + /* skip spaces & dots */ + if(*s == ' ' || *s == '.') { + *mangled |= 3; + continue; + } + + if (iswcntrl(*s)) { + /* "control" characters */ + *mangled |= 3; + *t = '_'; + } else if (iswlower(*s)) { + *t = towupper(*s); + if(*Case == UPPER && !mtools_no_vfat) + *mangled |= 1; + else + *Case = LOWER; + } else if (iswupper(*s)) { + *t = *s; + if(*Case == LOWER && !mtools_no_vfat) + *mangled |= 1; + else + *Case = UPPER; + } else + *t = *s; + count--; + t++; + } + wchar_to_dos(toDos, buffer, out, t - buffer, mangled); +} + +/* dos_name + * + * Convert a Unix-style filename to a legal MSDOS name and extension. + * Will truncate file and extension names, will substitute + * the character '~' for any illegal character(s) in the name. + */ +void dos_name(doscp_t *toDos, const char *name, int verbose, int *mangled, + dos_name_t *dn) +{ + char *s, *ext; + register int i; + Case_t BaseCase, ExtCase; + + *mangled = 0; + + /* skip drive letter */ + if (name[0] && name[1] == ':') + name = &name[2]; + + /* zap the leading path */ + name = (char *) _basename(name); + if ((s = strrchr(name, '\\'))) + name = s + 1; + + memset(dn, ' ', 11); + + /* skip leading dots and spaces */ + i = strspn(name, ". "); + if(i) { + name += i; + *mangled = 3; + } + + ext = strrchr(name, '.'); + + /* main name */ + TranslateToDos(toDos, name, dn->base, 8, ext, &BaseCase, mangled); + if(ext) + TranslateToDos(toDos, ext+1, dn->ext, 3, 0, &ExtCase, mangled); + + if(*mangled & 2) + autorename_short(dn, 0); + + if(!*mangled) { + if(BaseCase == LOWER) + *mangled |= BASECASE; + if(ExtCase == LOWER) + *mangled |= EXTCASE; + if((BaseCase == LOWER || ExtCase == LOWER) && + !mtools_no_vfat) { + *mangled |= 1; + } + } +} + + +/* + * Get rid of spaces in an MSDOS 'raw' name (one that has come from the + * directory structure) so that it can be used for regular expression + * matching with a Unix filename. Also used to 'unfix' a name that has + * been altered by dos_name(). + */ + +wchar_t *unix_name(doscp_t *dosCp, + const char *base, const char *ext, char Case, wchar_t *ret) +{ + char *s, tname[9], text[4], ans[13]; + int i; + + strncpy(tname, base, 8); + tname[8] = '\0'; + if ((s = strchr(tname, ' '))) + *s = '\0'; + + if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case) + Case |= BASECASE | EXTCASE; + + if(Case & BASECASE) + for(i=0;i<8 && tname[i];i++) + tname[i] = tolower(tname[i]); + + strncpy(text, ext, 3); + text[3] = '\0'; + if ((s = strchr(text, ' '))) + *s = '\0'; + + if(Case & EXTCASE) + for(i=0;i<3 && text[i];i++) + text[i] = tolower(text[i]); + + if (*text) { + strcpy(ans, tname); + strcat(ans, "."); + strcat(ans, text); + } else + strcpy(ans, tname); + + /* fix special characters (above 0x80) */ + dos_to_wchar(dosCp, ans, ret, 12); + return ret; +} + +/* If null encountered, set *end to 0x40 and write nulls rest of way + * 950820: Win95 does not like this! It complains about bad characters. + * So, instead: If null encountered, set *end to 0x40, write the null, and + * write 0xff the rest of the way (that is what Win95 seems to do; hopefully + * that will make it happy) + */ +/* Always return num */ +int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p) +{ + int j; + + for (j=0; juchar = out->lchar = (char) 0xff; + else { + out->uchar = *in >> 8; + out->lchar = *in; + if (! *in) { + *end_p = VSE_LAST; + } + } + + ++out; + ++in; + } + return num; +} diff --git a/file_name.h b/file_name.h new file mode 100644 index 0000000..0d9ac90 --- /dev/null +++ b/file_name.h @@ -0,0 +1,44 @@ +#ifndef FILE_NAME_H +#define FILE_NAME_H + +/* Copyright 2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include +#include "mtools.h" + +/** + * raw dos-name coming straight from the directory entry + * MYFILE TXT + */ +struct dos_name_t { + char base[8]; + char ext[3]; + char sentinel; +}; + +int dos_to_wchar(doscp_t *fromDos, char *dos, wchar_t *wchar, size_t len); +void wchar_to_dos(doscp_t *toDos, wchar_t *wchar, char *dos, size_t len, int *mangled); + +doscp_t *cp_open(int codepage); +void cp_close(doscp_t *cp); + +int wchar_to_native(const wchar_t *wchar, char *native, size_t len); +int native_to_wchar(const char *native, wchar_t *wchar, size_t len, + const char *end, int *mangled); + +#endif diff --git a/file_read.c b/file_read.c new file mode 100644 index 0000000..60e336f --- /dev/null +++ b/file_read.c @@ -0,0 +1,55 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996,1997,1999,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "file.h" + +/* + * Read the clusters given the beginning FAT entry. Returns 0 on success. + */ + +int file_read(FILE *fp, Stream_t *Source, int textmode, int stripmode) +{ + char buffer[16384]; + int pos; + int ret; + + if (!Source){ + fprintf(stderr,"Couldn't open source file\n"); + return -1; + } + + pos = 0; + while(1){ + ret = Source->Class->read(Source, buffer, pos, 16384); + if (ret < 0 ){ + perror("file read"); + return -1; + } + if ( ret == 0) + break; + if(!fwrite(buffer, 1, ret, fp)){ + perror("write"); + return -1; + } + pos += ret; + } + return 0; +} diff --git a/filter.c b/filter.c new file mode 100644 index 0000000..6a78217 --- /dev/null +++ b/filter.c @@ -0,0 +1,173 @@ +/* Copyright 1996,1997,1999,2001-2003,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "codepage.h" + +typedef struct Filter_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + int dospos; + int unixpos; + int mode; + int rw; + int lastchar; + /* int convertCharset; */ +} Filter_t; + +#define F_READ 1 +#define F_WRITE 2 + +/* read filter filters out messy dos' bizarre end of lines and final 0x1a's */ + +static int read_filter(Stream_t *Stream, char *buf, mt_off_t iwhere, size_t len) +{ + DeclareThis(Filter_t); + int i,j,ret; + unsigned char newchar; + + off_t where = truncBytes32(iwhere); + + if ( where != This->unixpos ){ + fprintf(stderr,"Bad offset\n"); + exit(1); + } + if (This->rw == F_WRITE){ + fprintf(stderr,"Change of transfer direction!\n"); + exit(1); + } + This->rw = F_READ; + + ret = READS(This->Next, buf, (mt_off_t) This->dospos, len); + if ( ret < 0 ) + return ret; + + j = 0; + for (i=0; i< ret; i++){ + if ( buf[i] == '\r' ) + continue; + if (buf[i] == 0x1a) + break; + newchar = buf[i]; + /* + if (This->convertCharset) newchar = contents_to_unix(newchar); + */ + This->lastchar = buf[j++] = newchar; + } + + This->dospos += i; + This->unixpos += j; + return j; +} + +static int write_filter(Stream_t *Stream, char *buf, mt_off_t iwhere, + size_t len) +{ + DeclareThis(Filter_t); + unsigned int i,j; + int ret; + char buffer[1025]; + unsigned char newchar; + + off_t where = truncBytes32(iwhere); + + if(This->unixpos == -1) + return -1; + + if (where != This->unixpos ){ + fprintf(stderr,"Bad offset\n"); + exit(1); + } + + if (This->rw == F_READ){ + fprintf(stderr,"Change of transfer direction!\n"); + exit(1); + } + This->rw = F_WRITE; + + j=i=0; + while(i < 1024 && j < len){ + if (buf[j] == '\n' ){ + buffer[i++] = '\r'; + buffer[i++] = '\n'; + j++; + continue; + } + newchar = buf[j++]; + /* + if (This->convertCharset) newchar = to_dos(newchar); + */ + buffer[i++] = newchar; + } + This->unixpos += j; + + ret = force_write(This->Next, buffer, (mt_off_t) This->dospos, i); + if(ret >0 ) + This->dospos += ret; + if ( ret != (signed int) i ){ + /* no space on target file ? */ + This->unixpos = -1; + return -1; + } + return j; +} + +static int free_filter(Stream_t *Stream) +{ + DeclareThis(Filter_t); + char buffer=0x1a; + + /* write end of file */ + if (This->rw == F_WRITE) + return force_write(This->Next, &buffer, (mt_off_t) This->dospos, 1); + else + return 0; +} + +static Class_t FilterClass = { + read_filter, + write_filter, + 0, /* flush */ + free_filter, + 0, /* set geometry */ + get_data_pass_through, + 0 +}; + +Stream_t *open_filter(Stream_t *Next, int convertCharset) +{ + Filter_t *This; + + This = New(Filter_t); + if (!This) + return NULL; + This->Class = &FilterClass; + This->dospos = This->unixpos = This->rw = 0; + This->Next = Next; + This->refs = 1; + This->Buffer = 0; + /* + This->convertCharset = convertCharset; + */ + + return (Stream_t *) This; +} diff --git a/floppyd.1 b/floppyd.1 new file mode 100644 index 0000000..7f03d14 --- /dev/null +++ b/floppyd.1 @@ -0,0 +1,258 @@ +.TH floppyd 1 "03Nov09" mtools-4.0.12 +.SH Name +floppyd - floppy daemon for remote access to floppy drive +floppyd_installtest - tests whether floppyd is installed and running +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p floppyd" +.iX "c X terminal" +.iX "c remote floppy access" +.PP +\&\fR\&\f(CWFloppyd\fR is used as a server to grant access to the floppy drive +to clients running on a remote machine, just as an X server grants +access to the display to remote clients. It has the following syntax: +.PP +\&\fR\&\f(CWfloppyd\fR [\fR\&\f(CW-d\fR] [\fR\&\f(CW-l\fR] [\fR\&\f(CW-s\fR \fIport\fR] [\fR\&\f(CW-r\fR +\&\fIuser\fR] [\fR\&\f(CW-b\fR \fIipaddr\fR] [\fR\&\f(CW-x\fR \fIdisplay\fR] \fIdevicenames\fR +.PP +\&\fR\&\f(CWfloppyd\fR is always associated with an X server. It runs on the +same machine as its X server, and listens on port 5703 and above. +.PP +.SH Authentication +.PP +\&\fR\&\f(CWfloppyd\fR authenticates remote clients using the \fR\&\f(CWXauthority\fR +protocol. Xhost authentication is not supported. Each floppyd is +associated with an X server. When a remote client attempts to connect +to floppyd, it sends floppyd the X authority record corresponding to +floppyd's X server. Floppyd in turn then tries to open up a connection +to the X server in order to verify the authenticity of the xauth record. +If the connection to the X server succeeds, the client is granted +access. +\&\fR\&\f(CWDISPLAY\fR. +.PP +\&\fBCaution\fR: In order to make authentication work correctly, the +local host should \fBnot\fR be listed in the \fR\&\f(CWxhost\fR list of +allowed hosts. + Indeed, hosts listed in \fR\&\f(CWxhost\fR do not need a correct +\&\fR\&\f(CWXauthority\fR cookie to connect to the X server. As \fR\&\f(CWfloppyd\fR +runs on the same host as the X server, all its probe connection would +succeed even for clients who supplied a bad cookie. This means that +your floppy drive would be open to the world, i.e. a huge security hole. + If your X server does not allow you to remove \fR\&\f(CWlocalhost:0\fR and +\&\fR\&\f(CW:0\fR from the \fR\&\f(CWxhost\fR list, you can prevent floppyd from +probing those display names with the \fR\&\f(CW-l\fR option. +.PP +.SH Command\ line\ options +.TP +\&\fR\&\f(CWd\fR\ +Daemon mode. Floppyd runs its own server loop. Do not supply this if +you start floppyd from \fR\&\f(CWinetd.conf\fR +.TP +\&\fR\&\f(CWs\ \ \fIport\fR\&\f(CW\fR\ +Port number for deamon mode. Default is 5703 + \fIdisplaynumber\fR. +This flag implies daemon mode. For example, for display +\&\fR\&\f(CWhitchhiker:5\fR, the port would be 5708. +.TP +\&\fR\&\f(CWb\ \ \fIipaddr\fR\&\f(CW\fR\ +Bind address (for multihomed hosts). This flag implies daemon mode +.TP +\&\fR\&\f(CWr\ \fIuser\fR\&\f(CW\fR\ +Run the server under as the given user +.TP +\&\fR\&\f(CWx\ \fIdisplay\fR\&\f(CW\fR\ +X display to use for authentication. By default, this is taken from the +\&\fR\&\f(CWDISPLAY\fR variable. If neither the \fR\&\f(CWx\fR attribute is present +nor \fR\&\f(CWDISPLAY\fR is set, floppyd uses \fR\&\f(CW:0.0\fR. +.PP +\&\fIdevicenames\fR is a list of device nodes to be opened. Default +is \fR\&\f(CW/dev/fd0\fR. Multiple devices are only supported on mtools +versions newer than 3.9.11. +.PP +.SH Connecting\ to\ floppyd +.PP + In order to use floppyd, add the flag \fR\&\f(CWremote\fR to the device +description in your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR file. If the flag \fR\&\f(CWremote\fR +is given, the \fR\&\f(CWfile\fR parameter of the device description is taken +to be a remote address. It's format is the following: +\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR[\fIbaseport\fR][\fR\&\f(CW/\fR\fIdrive\fR]]. When +using this entry, mtools connects to port +\&\fIbaseport\fR+\fIdisplaynumber\fR at \fIhostname\fR. By default +\&\fIbaseport\fR is 5703. The drive parameter is to distinguish among +multiple drives associated with a single display (only mtools versions +more recent than 3.9.11) +.PP +.SH Examples: +.PP + The following starts a floppy daemon giving access to \fR\&\f(CW\(if/dev/fd0\(is\fR, +listening on the default port 5703, tied to the default X servers: +.PP + +.nf +.ft 3 +.in +0.3i +floppyd -d /dev/fd0 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP + Each of the following starts a floppy daemon giving access to +\&\fR\&\f(CW\(if/dev/fd1\(is\fR, tied to the :1 local X servers, and listening on port +5704. We assume that the local host is named \fR\&\f(CWhitchhiker\fR. +.PP + +.nf +.ft 3 +.in +0.3i +floppyd -d /dev/fd0 +floppyd -d -x :1 -p 5704 /dev/fd0 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP + If you want to start floppyd by \fR\&\f(CWinetd\fR instead of running it as a +daemon, insert the following lines into \fR\&\f(CW\(if/etc/services\(is\fR: + +.nf +.ft 3 +.in +0.3i +# floppy daemon +floppyd-0 5703/tcp # floppy daemon for X server :0 +floppyd-1 5704/tcp # floppy daemon for X server :1 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP + And insert the following into \fR\&\f(CW\(if/etc/inetd.conf\(is\fR (assuming that you +have defined a user named floppy in your \fR\&\f(CW\(if/etc/passwd\(is\fR): +.PP + +.nf +.ft 3 +.in +0.3i +# floppy daemon +floppyd-0 stream tcp wait floppy /usr/sbin/floppyd floppyd /dev/fd0 +floppyd-1 stream tcp wait floppy /usr/sbin/floppyd floppyd -x :1 /dev/fd0 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP + Note that you need to supply the X display names for the second +floppyd. This is because the port is opened by inetd.conf, and hence +floppyd cannot know its number to interfere the display number. +.PP +On the client side, insert the following into your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR +to define a drive letter accessing floppy drive in your X terminal: + +.nf +.ft 3 +.in +0.3i +drive x: file="$DISPLAY" remote +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +If your X terminal has more than one drive, you may access the +additional drives as follows: + +.nf +.ft 3 +.in +0.3i +drive y: file="$DISPLAY//1" remote +drive z: file="$DISPLAY//2" remote +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/floppyd.c b/floppyd.c new file mode 100644 index 0000000..69a2cf4 --- /dev/null +++ b/floppyd.c @@ -0,0 +1,1257 @@ +/* Copyright 1999 Peter Schlaile. + * Copyright 1999-2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * the floppyd daemon running on the local X-Server + * + * written by: + * + * Peter Schlaile + * + * udbz@rz.uni-karlsruhe.de + * + * Large parts of the network code shamelessly stolen from + * transproxy by John Saunders + * + * Rewritten in C by Alain Knaff. Apparently C++ is still not as + * portable as C. */ + +#define DEBUG 0 + +#include "sysincludes.h" + +#ifdef USE_FLOPPYD + +#define USE_FLOPPYD_BUFFERED_IO 1 +#define FLOPPYD_DEFAULT_PORT 5703 + +#include "sysincludes.h" +#include "grp.h" +#include +#include + +#include "floppyd_io.h" + +#ifndef SIGCLD +#define SIGCLD SIGCHLD +#endif + +/* For Linux 1.2.13 */ +#ifndef SOMAXCONN +#define SOMAXCONN 5 +#endif + +/* + To compile: + + gcc -Wall floppyd.cpp -o floppyd -lX11 + + floppyd + + Communication to the clients works the following way: + + Client sends his protocol-version. If the version between server and client + differ: bail out. + + After that,we send our .Xauthority-file (a maximum of MAX_XAUTHORITY_LENGTH + Bytes long) to the server. + + The server then checks, if it already has a .Xauthority file. If so + it is interpreted as LOCK-File for the floppy-device and the communication + gets terminated. + + (What if we have 2 floppy devices? Well. Two floppy users with different + home-directories should work nicely...) + + Now, the data is written to the .Xauthority file. Then we try to open + a connection to the local X-Server. If this fails -> bail out. + + *** + + The data packets are built as follows: + + Base-packets: 1 Dword length, then data. + length is in Network-Byte order. (4 Bytes) + + Commands are: 1. Packet Opcode (length 1), 1. Data packet as parameter. + + Return: 1.Packet: 1. Dword: Bytes processed, 2. Dword: Error-Code + + *** + + TODO: + * Implement some IOCTL calls to format floppy disks or so... + * Read is somewhat dirty implemented. Tries multiple times to + read the expected bytes from the socket stream. Don't know + why this is necessary. Maybe the socket stream is nonblocking + or something IT SHOULD NOT BE! + +*/ + +typedef unsigned char Byte; +typedef unsigned long Dword; + + +#define MAX_XAUTHORITY_LENGTH 3000 +#define MAX_DATA_REQUEST 3000000 +#define BUFFERED_IO_SIZE 16348 + + +void serve_client(int sock, char **device_name, int n_dev, int close_stderr); + + +#ifdef USE_FLOPPYD_BUFFERED_IO +typedef struct io_buffer { + Byte out_buffer[BUFFERED_IO_SIZE]; + Byte in_buffer[BUFFERED_IO_SIZE]; + + long in_valid; + long in_start; + long out_valid; + + int handle; +} *io_buffer; + +static io_buffer new_io_buffer (int _handle) { + io_buffer buffer; + + buffer = New(struct io_buffer); + + buffer->handle = _handle; + buffer->in_valid = buffer->in_start = 0; + buffer->out_valid = 0; + return buffer; +} + + +static void flush(io_buffer buffer) { + if (buffer->out_valid) { + if(write(buffer->handle, buffer->out_buffer, buffer->out_valid) < 0) { + perror("floppyd flush"); + } + buffer->out_valid = 0; + } +} + +static void free_io_buffer(io_buffer buffer) { + flush(buffer); + free(buffer); +} + + +static size_t buf_read (io_buffer buf, Byte* buffer, size_t nbytes) { + size_t rval; + + if (nbytes <= buf->in_valid) { + memcpy(buffer, buf->in_buffer+buf->in_start, nbytes); + buf->in_valid -= nbytes; + buf->in_start += nbytes; + rval = nbytes; + } else { + if (buf->in_valid) + memcpy(buffer, buf->in_buffer+buf->in_start, + buf->in_valid); + nbytes -= buf->in_valid; + buffer += buf->in_valid; + if (nbytes > BUFFERED_IO_SIZE) { + rval = read(buf->handle, buffer, nbytes); + if (rval >= 0) { + rval += buf->in_valid; + } + buf->in_valid = buf->in_start = 0; + } else { + rval = read(buf->handle, buf->in_buffer, + BUFFERED_IO_SIZE); + if (rval >= 0) { + if (rval < nbytes) { + memcpy(buffer, buf->in_buffer, rval); + rval += buf->in_valid; + buf->in_valid = buf->in_start = 0; + } else { + size_t a; + memcpy(buffer, buf->in_buffer, nbytes); + buf->in_start = nbytes; + a = buf->in_valid; + buf->in_valid = rval-nbytes; + rval = a + nbytes; + } + } + } + } + return rval; +} + +static size_t buf_write(io_buffer buf, void* buffer, size_t nbytes) { + if (buf->out_valid + nbytes > BUFFERED_IO_SIZE) { + flush(buf); + return write(buf->handle, buffer, nbytes); + } + memcpy(buf->out_buffer+buf->out_valid, buffer, nbytes); + buf->out_valid += nbytes; + return nbytes; +} + + + +#else + +typedef int io_buffer; + +io_buffer new_io_buffer (int handle) { + return handle; +} + + +size_t buf_read (io_buffer handle, Byte* buffer, size_t nbytes) { + return (read(handle, buffer, nbytes)); +} + +size_t buf_write(io_buffer handle, void* buffer, size_t nbytes) { + return (write(handle, buffer, nbytes)); +} + + +void free_io_buffer(io_buffer buffer) { } + + +void flush(io_buffer buffer) { } + +#endif + +typedef struct Packet { + Byte* data; + Dword len; + Dword alloc_size; +} *Packet; + +#include "byte_dword.h" + +static Dword read_dword(io_buffer fp) +{ + Byte val[4]; + if (buf_read(fp, val, 4) < 4) { + return 0xffffffff; + } + + return byte2dword(val); +} + +static void write_dword(io_buffer fp, Dword parm) +{ + Byte val[4]; + + dword2byte(parm, val); + + buf_write(fp, val,4); +} + + +static Packet newPacket(void) +{ + Packet packet; + + packet = New(struct Packet); + packet->data = NULL; + packet->len = packet->alloc_size = 0; + return packet; +} + + +static void destroyPacket(Packet packet) +{ + if(packet->data) + free(packet->data); + free(packet); +} + +static void kill_packet(Packet packet) +{ + if(packet->data) + free(packet->data); + packet->data = NULL; + packet->len = 0; + packet->alloc_size = 0; +} + +static void make_new(Packet packet, unsigned long l) +{ + if (l < packet->alloc_size) { + packet->len = l; + return; + } + kill_packet(packet); + packet->len = packet->alloc_size = l; + packet->data = malloc(l); + memset(packet->data, 0, l); +} + +static char send_packet(Packet packet, io_buffer fp) +{ + if (packet->data) { + write_dword(fp, packet->len); + buf_write(fp, packet->data, packet->len); + flush(fp); +#if DEBUG + fprintf(stderr, "send_packet(): Size: %li\n", packet->len); +#endif + +#if DEBUG + fprintf(stderr, "send_packet(): "); + for (int i = 0; i < packet->len; i++) { + fprintf(stderr, "%d ", packet->data[i]); + } + fprintf(stderr, "\n"); +#endif + + } + return (packet->data != NULL); +} + +static char recv_packet(Packet packet, io_buffer fp, Dword maxlength) +{ + int start; + int l; + Dword length = read_dword(fp); +#if DEBUG + fprintf(stderr, "recv_packet(): Size: %li\n", length); +#endif + if (length > maxlength || length == 0xffffffff ) { + return 0; + } + make_new(packet, length); + l = 0; + for (start = 0; start < length; start += l) { + l = buf_read(fp, packet->data+start, length-start); + if (l == 0) { + return 0; + } + } + if (packet->len == 0) { + return 0; + } +#if DEBUG + fprintf(stderr, "*** read: %li\n", packet->len); +#endif + +#if DEBUG + fprintf(stderr, "recv_packet(): "); + for (i = 0; i < packet->len; i++) { + fprintf(stderr, "%d ", packet->data[i]); + } + fprintf(stderr, "\n"); +#endif + return 1; +} + +static void read_packet(Packet packet, int fd, int length) { + make_new(packet, length); + packet->len = read(fd, packet->data, packet->len); +} + +static int write_packet(Packet packet, int fd) { + return (write(fd, packet->data, packet->len)); +} + +static void put_dword(Packet packet, int my_index, Dword val) { + dword2byte(val, packet->data+my_index); +} + +static Dword get_dword(Packet packet, int my_index) { + return byte2dword(packet->data+my_index); +} + +static Dword get_length(Packet packet) { + return packet->len; +} + +static int eat(char **ptr, int *len, unsigned char c) { + /* remove length + size code + terminating 0 */ + if (*len < c + 3) + return -1; + (*ptr) += c + 2; + (*len) -= c + 2; + return 0; +} + +static const char *dispName; + +static char XAUTHORITY[]="XAUTHORITY"; + +static char do_auth(io_buffer sock, int *version) +{ + int fd; + Display* displ; + Packet proto_version = newPacket(); + Packet mit_cookie; + char *ptr; + int len; + + char authFile[41]="/tmp/floppyd.XXXXXX"; + char template[4096]; + + Packet reply = newPacket(); + + make_new(reply, 4); + + if (!recv_packet(proto_version, sock, 4)) { + put_dword(reply, 0, AUTH_PACKETOVERSIZE); + send_packet(reply, sock); + destroyPacket(reply); + destroyPacket(proto_version); + return 0; + } + + *version = get_dword(proto_version, 0); + if (*version > FLOPPYD_PROTOCOL_VERSION || + *version < FLOPPYD_PROTOCOL_VERSION_OLD) { + /* fail if client requests a newer version than us */ + put_dword(reply, 0, AUTH_WRONGVERSION); + send_packet(reply, sock); + destroyPacket(reply); + destroyPacket(proto_version); + return 0; + } + + if(*version == FLOPPYD_PROTOCOL_VERSION_OLD) { + put_dword(reply, 0, AUTH_SUCCESS); + } else { + make_new(reply, 12); + put_dword(reply, 0, AUTH_SUCCESS); + put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION); + put_dword(reply, 8, FLOPPYD_CAP_EXPLICIT_OPEN); + } + send_packet(reply, sock); + destroyPacket(proto_version); + + make_new(reply, 4); + mit_cookie = newPacket(); + if (!recv_packet(mit_cookie, sock, MAX_XAUTHORITY_LENGTH)) { + put_dword(reply, 0, AUTH_PACKETOVERSIZE); + send_packet(reply, sock); + destroyPacket(reply); + destroyPacket(mit_cookie); + return 0; + } + + umask(077); + fd = mkstemp(authFile); + if(fd == -1) { + /* Different error than file exists */ + put_dword(reply, 0, AUTH_DEVLOCKED); + send_packet(reply, sock); + close(fd); + destroyPacket(reply); + destroyPacket(mit_cookie); + return 0; + } +#ifdef HAVE_SETENV + setenv(XAUTHORITY, authFile, 1); +#else + { + char *buffer=malloc(strlen(XAUTHORITY)+strlen(authFile)+2); + strcpy(buffer, XAUTHORITY); + strcat(buffer, "="); + strcat(buffer, authFile); + putenv(buffer); + } +#endif + + ptr = template; + ptr[4095] = 0; + *ptr++ = 1; + *ptr++ = 0; + *ptr++ = 0; + gethostname(ptr+1, 4088); + len = strlen(ptr+1); + *ptr++ = len; + ptr += len; + *ptr++ = 0; + *ptr++ = 1; + *ptr++ = '0'; /* Display number */ + *ptr++ = '\0'; + + if(write(fd, template, len+8) < len + 8) { + close(fd); + return 0; + } + ptr = (char *)mit_cookie->data; + len = mit_cookie->len; + + if (eat(&ptr,&len,1) || /* the "type" */ + eat(&ptr,&len,*ptr) || /* the hostname */ + eat(&ptr,&len,*ptr)) { /* the display number */ + destroyPacket(mit_cookie); + unlink(XauFileName()); + put_dword(reply, 0, AUTH_BADPACKET); + send_packet(reply, sock); + destroyPacket(reply); + return 0; + } + + if(write(fd, ptr, len) < len) { + close(fd); + return 0; + } + close(fd); + + destroyPacket(mit_cookie); + + displ = XOpenDisplay(dispName); + if (!displ) { + unlink(XauFileName()); + put_dword(reply, 0, AUTH_AUTHFAILED); + send_packet(reply, sock); + destroyPacket(reply); + return 0; + } + XCloseDisplay(displ); + + put_dword(reply, 0, AUTH_SUCCESS); + send_packet(reply, sock); + destroyPacket(reply); + unlink(XauFileName()); + return 1; +} + +/* + * Return the port number, in network order, of the specified service. + */ +static short getportnum(char *portnum) +{ + char *digits = portnum; + struct servent *serv; + short port; + + for (port = 0; isdigit(*digits); ++digits) + { + port = (port * 10) + (*digits - '0'); + } + + if ((*digits != '\0') || (port <= 0)) + { + if ((serv = getservbyname(portnum, "tcp")) != NULL) + { + port = ntohs(serv->s_port); + } + else + { + port = -1; + } + endservent(); + } + +#if DEBUG + fprintf(stderr, "Port lookup %s -> %hd\n", portnum, port); +#endif + + return (port); +} + +/* + * Return the IP address of the specified host. + */ +static IPaddr_t getipaddress(char *ipaddr) +{ + struct hostent *host; + IPaddr_t ip; + + if (((ip = inet_addr(ipaddr)) == INADDR_NONE) + && + (strcmp(ipaddr, "255.255.255.255") != 0)) + { + if ((host = gethostbyname(ipaddr)) != NULL) + { + memcpy(&ip, host->h_addr, sizeof(ip)); + } + endhostent(); + } + +#if DEBUG + fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip); +#endif + + return (ip); +} + +/* + * Find the userid of the specified user. + */ +static uid_t getuserid(char *user) +{ + struct passwd *pw; + uid_t uid; + + if ((pw = getpwnam(user)) != NULL) + { + uid = pw->pw_uid; + } + else if (*user == '#') + { + uid = (uid_t)atoi(&user[1]); + } + else + { +#ifdef HAVE_GETUSERID + id = getuserid("nobody"); +#else + uid = 65535; +#endif + } + +#if DEBUG + fprintf(stderr, "User lookup %s -> %d\n", user, uid); +#endif + + endpwent(); + + return (uid); +} + +/* + * Find the groupid of the specified user. + */ +static uid_t getgroupid(uid_t uid) +{ + struct passwd *pw; + gid_t gid; + + if ((pw = getpwuid(uid)) != NULL) + { + gid = pw->pw_gid; + } + else + { +#ifdef HAVE_GETGROUPID + id = getgroupid(uid); +#else + gid = 65535; +#endif + } + +#if DEBUG + fprintf(stderr, "Group lookup %d -> %d\n", uid, gid); +#endif + + endpwent(); + + return (gid); +} + +/* + * Bind to the specified ip and port. + */ +static int bind_to_port(IPaddr_t bind_ip, short bind_port) +{ + struct sockaddr_in addr; + int sock; + + /* + * Allocate a socket. + */ + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + perror("socket()"); + exit(1); + } + + /* + * Set the SO_REUSEADDR option for debugging. + */ + { + int on = 1; + if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)) < 0) { + perror("setsockopt"); + exit(1); + } + } + + /* + * Set the address to listen to. + */ + addr.sin_family = AF_INET; + addr.sin_port = htons(bind_port); + addr.sin_addr.s_addr = bind_ip; + + /* + * Bind our socket to the above address. + */ + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + perror("bind()"); + exit(1); + } + + /* + * Establish a large listen backlog. + */ + if (listen(sock, SOMAXCONN) < 0) + { + perror("listen()"); + exit(1); + } + + return (sock); +} + +static int sockethandle_now = -1; + +/* + * Catch alarm signals and exit. + */ +static void alarm_signal(int a) +{ + if (sockethandle_now != -1) { + close(sockethandle_now); + sockethandle_now = -1; + unlink(XauFileName()); + } + exit(1); +} + + +/* + * This is the main loop when running as a server. + */ +static void server_main_loop(int sock, char **device_name, int n_dev) +{ + struct sockaddr_in addr; + unsigned int len; + + /* + * Ignore dead servers so no zombies should be left hanging. + */ + signal(SIGCLD, SIG_IGN); + + for (;;) { + int new_sock; + /* + * Accept an incoming connection. + */ + len = sizeof(addr); + while ((new_sock = accept(sock, (struct sockaddr *)&addr, &len)) < 0){} + + /* + * Create a new process to handle the connection. + */ +#if DEBUG == 0 + switch (fork()) { + case -1: + /* + * Under load conditions just ignore new connections. + */ + break; + + case 0: + /* + * Start the proxy work in the new socket. + */ +#endif + serve_client(new_sock,device_name, n_dev, 0); + exit(0); +#if DEBUG == 0 + } +#endif + /* + * Close the socket as the child does the handling. + */ + close(new_sock); + new_sock = -1; + } +} + +/* + * Print some basic help information. + */ +static void usage(char *prog, const char *opt, int ret) +{ + if (opt) + { + fprintf(stderr, "%s: %s\n", prog, opt); + } + fprintf(stderr, "usage: %s [-s port [-r user] [-b ipaddr]] devicename [Names of local host]\n", + prog); + fprintf(stderr, " -d Run as a server (default port 5703 + DISPLAY)\n"); + fprintf(stderr, " -s port Run as a server bound to the specified port.\n"); + fprintf(stderr, " -r user Run as the specified user in server mode.\n"); + fprintf(stderr, " -b ipaddr Bind to the specified ipaddr in server mode.\n"); + fprintf(stderr, " -l Do not attempt to connect to localhost:0 to validate connection\n"); + exit(ret); +} + + +static char *makeDisplayName(int dispNr) +{ + char result[80]; + sprintf(result, ":%d.0", dispNr); + return strdup(result); +} + +int main (int argc, char** argv) +{ + int sockfd = 0; + int arg; + int run_as_server = 0; + IPaddr_t bind_ip = INADDR_ANY; + unsigned short bind_port = 0; + uid_t run_uid = 65535; + gid_t run_gid = 65535; + char* username = strdup("nobody"); + int sock; + int port_is_supplied = 0; + + char *server_hostname=NULL; + char **device_name = NULL; + const char *floppy0 = "/dev/fd0"; + int n_dev; + + + /* + * Parse the command line arguments. + */ + if(argc > 1 && !strcmp(argv[0], "--help")) + usage(argv[0], NULL, 0); + while ((arg = getopt(argc, argv, "ds:r:b:x:h")) != EOF) + { + switch (arg) + { + case 'd': + run_as_server = 1; + break; + case 's': + run_as_server = 1; + port_is_supplied = 1; + bind_port = getportnum(optarg); + break; + + case 'r': + free(username); username = strdup(optarg); + run_uid = getuserid(optarg); + run_gid = getgroupid(run_uid); + break; + + case 'b': + run_as_server = 1; + bind_ip = getipaddress(optarg); + server_hostname=optarg; + break; + case 'x': + dispName = strdup(optarg); + break; + + case 'h': + usage(argv[0], NULL, 0); + break; + case '?': + usage(argv[0], NULL, 1); + break; + } + } + + if(optind < argc) { + device_name = argv + optind; + n_dev = argc - optind; + } else { + device_name = (char **)&floppy0; + n_dev = 1; + } + + if(dispName == NULL) + dispName = getenv("DISPLAY"); + if(dispName==NULL && bind_port != 0) + dispName=makeDisplayName((unsigned short)(bind_port - 5703)); + if(dispName==NULL) + dispName=":0"; + + if(bind_port == 0) { + char *p = strchr(dispName,':'); + bind_port = FLOPPYD_DEFAULT_PORT; + if(p != NULL) + bind_port += atoi(p+1); + } + + if(!run_as_server) { + struct sockaddr_in addr; + unsigned int len = sizeof(addr); + + /* try to find out port that we are connected to */ + if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 && + len == sizeof(addr)) { + port_is_supplied = 1; + bind_port = ntohs(addr.sin_port); + server_hostname = strdup(inet_ntoa(addr.sin_addr)); + } + } + + umask(0077); + + /* + * Test to make sure required args were provided and are valid. + */ + if (run_as_server && (bind_ip == INADDR_NONE)) { + usage(argv[0], "The server ipaddr is invalid.", 1); + } + if (run_as_server && (bind_port == 0)) { + usage(argv[0], "No server port was specified (or it was invalid).", 1); + } + + + /* + * See if we should run as a server. + */ + if (run_as_server) { + /* + * Start by binding to the port, the child inherits this socket. + */ + sock = bind_to_port(bind_ip, bind_port); + + /* + * Start a server process. When DEBUG is defined, just run + * in the foreground. + */ +#if DEBUG + switch (0) +#else + switch (fork()) +#endif + { + case -1: + perror("fork()"); + exit(1); + + case 0: + /* + * Ignore some signals. + */ + signal(SIGHUP, SIG_IGN); +#if DEBUG + signal(SIGINT, SIG_IGN); +#endif + signal(SIGQUIT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGCONT, SIG_IGN); + signal(SIGPIPE, alarm_signal); + /*signal(SIGALRM, alarm_signal);*/ + + /* + * Drop back to an untrusted user. + */ + setgid(run_gid); + initgroups(username, -1); + setuid(run_uid); + + /* + * Start a new session and group. + */ + setsid(); +#ifdef HAVE_SETPGRP +#ifdef SETPGRP_VOID + setpgrp(); +#else + setpgrp(0,0); +#endif +#endif +#if DEBUG + close(2); + open("/dev/null", O_WRONLY); +#endif + /* + * Handle the server main loop. + */ + server_main_loop(sock, device_name, n_dev); + + /* + * Should never exit. + */ + exit(1); + } + + /* + * Parent exits at this stage. + */ + exit(0); + } + + signal(SIGHUP, alarm_signal); +#if DEBUG == 0 + signal(SIGINT, alarm_signal); +#endif + signal(SIGQUIT, alarm_signal); + signal(SIGTERM, alarm_signal); + signal(SIGTSTP, SIG_IGN); + signal(SIGCONT, SIG_IGN); + signal(SIGPIPE, alarm_signal); + /*signal(SIGALRM, alarm_signal);*/ + + /* Starting from inetd */ + + serve_client(sockfd, device_name, n_dev, 1); + return 0; +} + +static void send_reply(int rval, io_buffer sock, int len) { + Packet reply = newPacket(); + + make_new(reply, 8); + put_dword(reply, 0, len); + if (rval == -1) { + put_dword(reply, 4, 0); + } else { + put_dword(reply, 4, errno); + } + send_packet(reply, sock); + destroyPacket(reply); +} + +static void cleanup(int x) { + unlink(XauFileName()); + exit(-1); +} + +#include "lockdev.h" + +void serve_client(int sockhandle, char **device_name, int n_dev, + int close_stderr) { + Packet opcode; + Packet parm; + + int readOnly; + int devFd; + io_buffer sock; + int stopLoop; + int version; + int needSendReply=0; + int rval=0; + + /* + * Set the keepalive socket option to on. + */ + { + int on = 1; + if(setsockopt(sockhandle, SOL_SOCKET, + SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) { + perror("setsockopt"); + exit(1); + } + + } + + +#if DEBUG == 0 + if(close_stderr) { + close(2); + open("/dev/null", O_WRONLY); + } +#endif + + sock = new_io_buffer(sockhandle); + + /* + * Allow 60 seconds for any activity. + */ + alarm(60); + + version = 0; + if (!do_auth(sock, &version)) { + free_io_buffer(sock); + return; + } + alarm(0); + + + signal(SIGTERM, cleanup); + signal(SIGALRM, cleanup); + + + + sockethandle_now = sockhandle; + + + opcode = newPacket(); + parm = newPacket(); + + devFd = -1; + readOnly = 1; + + stopLoop = 0; + if(version == FLOPPYD_PROTOCOL_VERSION_OLD) { + /* old protocol */ + readOnly = 0; + devFd = open(device_name[0], O_RDWR); + + if (devFd < 0) { + readOnly = 1; + devFd = open(device_name[0], + O_RDONLY); + } + if(devFd < 0) { + send_reply(0, sock, devFd); + stopLoop = 1; + } + lock_dev(devFd, !readOnly, NULL); + } + + + while(!stopLoop) { + int dev_nr = 0; + /* + * Allow 60 seconds for any activity. + */ + /*alarm(60);*/ + + if (!recv_packet(opcode, sock, 1)) { + break; + } +/* if(opcode->data[0] != OP_CLOSE)*/ + recv_packet(parm, sock, MAX_DATA_REQUEST); + + + switch(opcode->data[0]) { + case OP_OPRO: + if(get_length(parm) >= 4) + dev_nr = get_dword(parm,0); + else + dev_nr = 0; + if(dev_nr >= n_dev) { + send_reply(0, sock, -1); + break; + } + + devFd = open(device_name[dev_nr], O_RDONLY); +#if DEBUG + fprintf(stderr, "Device opened\n"); +#endif + if(devFd >= 0 && lock_dev(devFd, 0, NULL)) { + send_reply(0, sock, -1); + break; + } + send_reply(0, sock, devFd); + readOnly = 1; + break; + case OP_OPRW: + if(get_length(parm) >= 4) + dev_nr = get_dword(parm,0); + else + dev_nr = 0; + if(dev_nr >= n_dev) { + send_reply(0, sock, -1); + break; + } + devFd = open(device_name[dev_nr], O_RDWR); + if(devFd >= 0 && lock_dev(devFd, 1, NULL)) { + send_reply(0, sock, -1); + break; + } + send_reply(0, sock, devFd); + readOnly = 0; + break; + case OP_READ: +#if DEBUG + fprintf(stderr, "READ:\n"); +#endif + read_packet(parm, devFd, get_dword(parm, 0)); + send_reply(devFd, sock, get_length(parm)); + if(get_length(parm) >= 0) + send_packet(parm, sock); + break; + case OP_WRITE: +#if DEBUG + fprintf(stderr, "WRITE:\n"); +#endif + if(readOnly) { + errno = -EROFS; + rval = -1; + } else { + rval = write_packet(parm, devFd); + } + send_reply(devFd, sock, rval); + break; + case OP_SEEK: +#if DEBUG + fprintf(stderr, "SEEK:\n"); +#endif + + lseek(devFd, + get_dword(parm, 0), get_dword(parm, 4)); + send_reply(devFd, + sock, + lseek(devFd, 0, SEEK_CUR)); + break; + case OP_FLUSH: +#if DEBUG + fprintf(stderr, "FLUSH:\n"); +#endif + fsync(devFd); + send_reply(devFd, sock, 0); + break; + case OP_CLOSE: +#if DEBUG + fprintf(stderr, "CLOSE:\n"); +#endif + + close(devFd); + needSendReply = 1; + rval = devFd; + devFd = -1; + stopLoop = 1; + break; + case OP_IOCTL: + /* Unimplemented for now... */ + break; + default: +#if DEBUG + fprintf(stderr, "Invalid Opcode!\n"); +#endif + errno = EINVAL; + send_reply(devFd, sock, -1); + break; + } + kill_packet(parm); + alarm(0); + } + + + +#if DEBUG + fprintf(stderr, "Closing down...\n"); +#endif + + if (devFd >= 0) { + close(devFd); + devFd = -1; + } + + free_io_buffer(sock); + + /* remove "Lock"-File */ + unlink(XauFileName()); + + if(needSendReply) + send_reply(rval, sock, 0); + destroyPacket(opcode); + destroyPacket(parm); +} + +#else +#include + +int main(int argc, char **argv) +{ + puts("Floppyd support not included!"); + return -1; +} + +#endif diff --git a/floppyd_installtest.1 b/floppyd_installtest.1 new file mode 100644 index 0000000..4dcb001 --- /dev/null +++ b/floppyd_installtest.1 @@ -0,0 +1,96 @@ +.TH floppyd_installtest 1 "03Nov09" mtools-4.0.12 +.SH Name +floppyd_installtest - tests whether floppyd is installed and running +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p floppyd_installtest" +.iX "c X terminal" +.iX "c remote floppy access" +.PP +\&\fR\&\f(CWFloppyd_installtest\fR is used to check for the presence of a running +floppyd daemon. This is usefull, if you have a small frontend script to +mtools, which decides whether to use floppyd or not. +.PP +\&\fR\&\f(CWfloppyd_installtest\fR [\fR\&\f(CW-f\fR] Connect-String +.PP +If the \fR\&\f(CW-f\fR option is specified, \fR\&\f(CWfloppyd_installtest\fR does a +full X-Cookie authentication and complains if this does not work. +.PP +The connect-String has the format described in the floppyd-section: +\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR\fIbaseport\fR] +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/floppyd_installtest.c b/floppyd_installtest.c new file mode 100644 index 0000000..5f44201 --- /dev/null +++ b/floppyd_installtest.c @@ -0,0 +1,323 @@ +/* Copyright 1999 Peter Schlaile. + * Copyright 1999-2002,2006,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Small install-test utility to check if a floppyd-server is running on the + * X-Server-Host. + * + * written by: + * + * Peter Schlaile + * + * udbz@rz.uni-karlsruhe.de + * + */ + +#include "sysincludes.h" +#include "stream.h" +#include "mtools.h" +#include "msdos.h" +#include "scsi.h" +#include "partition.h" +#include "floppyd_io.h" + +#ifdef USE_FLOPPYD +#include +#include +#include + +/* ######################################################################## */ + +typedef unsigned char Byte; +typedef unsigned long Dword; + +const char* AuthErrors[] = { + "Auth success!", + "Auth failed: Packet oversized!", + "Auth failed: X-Cookie doesn't match!", + "Auth failed: Wrong transmission protocol version!", + "Auth failed: Device locked!" +}; + +#include "byte_dword.h" +#include "read_dword.h" + +static int write_dword(int handle, Dword parm) +{ + Byte val[4]; + + dword2byte(parm, val); + + if(write(handle, val, 4) < 4) + return -1; + return 0; +} + + +/* ######################################################################## */ + +static int authenticate_to_floppyd(char fullauth, int sock, char *display, + int protoversion) +{ + off_t filelen=0; + Byte buf[16]; + const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 }; + char *xcookie = NULL; + Dword errcode; + int bytesRead; + + if (fullauth) { + command[4] = display; + + filelen=strlen(display); + filelen += 100; + + xcookie = (char *) safe_malloc(filelen+4); + filelen = safePopenOut(command, xcookie+4, filelen); + if(filelen < 1) + return AUTH_AUTHFAILED; + } + dword2byte(4,buf); + dword2byte(protoversion,buf+4); + if(write(sock, buf, 8) < 8) + return AUTH_IO_ERROR; + + bytesRead = read_dword(sock); + + if (bytesRead != 4 && bytesRead != 12) { + return AUTH_WRONGVERSION; + } + + + errcode = read_dword(sock); + + if (errcode != AUTH_SUCCESS) { + return errcode; + } + + + if(bytesRead == 8) { + protoversion = read_dword(sock); + read_dword(sock); + } + + fprintf(stderr, "Protocol Version=%d\n", protoversion); + + if (fullauth) { + dword2byte(filelen, (Byte *) xcookie); + if(write(sock, xcookie, filelen+4) < filelen+4) + return AUTH_IO_ERROR; + + if (read_dword(sock) != 4) { + return AUTH_PACKETOVERSIZE; + } + + errcode = read_dword(sock); + } + + return errcode; + +} + + +/* ######################################################################## */ + +static int get_host_and_port(const char* name, char** hostname, char **display, + short* port) +{ + char* newname = strdup(name); + char* p; + char* p2; + + p = newname; + while (*p != '/' && *p) p++; + p2 = p; + if (*p) p++; + *p2 = 0; + + *port = atoi(p); + if (*port == 0) { + *port = FLOPPYD_DEFAULT_PORT; + } + + *display = strdup(newname); + + p = newname; + while (*p != ':' && *p) p++; + p2 = p; + if (*p) p++; + *p2 = 0; + + *port += atoi(p); /* add display number to the port */ + + if (!*newname || strcmp(newname, "unix") == 0) { + free(newname); + newname = strdup("localhost"); + } + + *hostname = newname; + return 1; +} + +/* + * * Return the IP address of the specified host. + * */ +static IPaddr_t getipaddress(char *ipaddr) +{ + + struct hostent *host; + IPaddr_t ip; + + if (((ip = inet_addr(ipaddr)) == INADDR_NONE) && + (strcmp(ipaddr, "255.255.255.255") != 0)) { + + if ((host = gethostbyname(ipaddr)) != NULL) { + memcpy(&ip, host->h_addr, sizeof(ip)); + } + + endhostent(); + } + +#ifdef DEBUG + fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip); +#endif + + return (ip); +} + +/* + * * Connect to the floppyd server. + * */ +static int connect_to_server(IPaddr_t ip, short port) +{ + + struct sockaddr_in addr; + int sock; + + /* + * Allocate a socket. + */ + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return (-1); + } + + /* + * Set the address to connect to. + */ + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = ip; + + /* + * Connect our socket to the above address. + */ + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return (-1); + } + + /* + * Set the keepalive socket option to on. + */ + { + int on = 1; + setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, + (char *)&on, sizeof(on)); + + } + + return (sock); +} + +int main (int argc, char** argv) +{ + char* hostname; + char* display; + char* name; + short port; + int sock; + int reply; + int rval; + int protoversion; + char fullauth = 0; + Byte opcode = OP_CLOSE; + + if (argc < 2) { + puts("Usage: floppyd_installtest [-f] Connect-String\n" + "-f\tDo full X-Cookie-Authentication"); + return -1; + } + + name = argv[1]; + if (strcmp(name, "-f") == 0) { + fullauth = 1; + name = argv[2]; + } + + rval = get_host_and_port(name, &hostname, &display, &port); + + if (!rval) return -1; + + sock = connect_to_server(getipaddress(hostname), port); + + if (sock == -1) { + fprintf(stderr, + "Can't connect to floppyd server on %s, port %i!\n", + hostname, port); + return -1; + } + + protoversion = FLOPPYD_PROTOCOL_VERSION; + while(1) { + reply = authenticate_to_floppyd(fullauth, sock, display, + protoversion); + if(protoversion == FLOPPYD_PROTOCOL_VERSION_OLD) + break; + if(reply == AUTH_WRONGVERSION) { + /* fall back on old version */ + protoversion = FLOPPYD_PROTOCOL_VERSION_OLD; + continue; + } + break; + } + + if (reply != 0) { + fprintf(stderr, + "Connection to floppyd failed:\n" + "%s\n", AuthErrors[reply]); + return -1; + } + + free(hostname); + free(display); + + if(write_dword(sock, 1) < 0) { + fprintf(stderr, + "Short write to floppyd:\n" + "%s\n", strerror(errno)); + } + + if(write(sock, &opcode, 1) < 0) { + fprintf(stderr, + "Short write to floppyd:\n" + "%s\n", strerror(errno)); + } + + close(sock); + + return 0; +} +#endif diff --git a/floppyd_io.c b/floppyd_io.c new file mode 100644 index 0000000..9763891 --- /dev/null +++ b/floppyd_io.c @@ -0,0 +1,636 @@ +/* Copyright 1999 Peter Schlaile. + * Copyright 1999-2002,2005-2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * IO to the floppyd daemon running on the local X-Server Host + * + * written by: + * + * Peter Schlaile + * + * udbz@rz.uni-karlsruhe.de + * + */ + +#include "sysincludes.h" +#include "stream.h" +#include "mtools.h" +#include "msdos.h" +#include "scsi.h" +#include "partition.h" +#include "floppyd_io.h" + +#ifdef USE_FLOPPYD + +/* ######################################################################## */ + + +typedef unsigned char Byte; +typedef unsigned long Dword; + +const char* AuthErrors[] = { + "Auth success", + "Auth failed: Packet oversized", + "Auth failed: X-Cookie doesn't match", + "Auth failed: Wrong transmission protocol version", + "Auth failed: Device locked" + "Auth failed: Bad packet", + "Auth failed: I/O Error" +}; + + +typedef struct RemoteFile_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + int fd; + mt_off_t offset; + mt_off_t lastwhere; + mt_off_t size; + int version; + int capabilities; + int drive; +} RemoteFile_t; + + +#include "byte_dword.h" +#include "read_dword.h" + + +/* ######################################################################## */ + +static int authenticate_to_floppyd(RemoteFile_t *floppyd, int sock, char *display) +{ + off_t filelen; + Byte buf[16]; + const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 }; + char *xcookie; + Dword errcode; + int l; + + command[4] = display; + + filelen=strlen(display); + filelen += 100; + + xcookie = (char *) safe_malloc(filelen+4); + filelen = safePopenOut(command, xcookie+4, filelen); + if(filelen < 1) + return AUTH_AUTHFAILED; + + /* Version negotiation */ + dword2byte(4,buf); + dword2byte(floppyd->version,buf+4); + if(write(sock, buf, 8) < 8) + return AUTH_IO_ERROR; + + if ( (l = read_dword(sock)) < 4) { + return AUTH_WRONGVERSION; + } + + errcode = read_dword(sock); + + if (errcode != AUTH_SUCCESS) { + return errcode; + } + + if(l >= 8) + floppyd->version = read_dword(sock); + if(l >= 12) + floppyd->capabilities = read_dword(sock); + + dword2byte(filelen, (Byte *)xcookie); + if(write(sock, xcookie, filelen+4) < filelen + 4) + return AUTH_IO_ERROR; + + if (read_dword(sock) != 4) { + return AUTH_PACKETOVERSIZE; + } + + errcode = read_dword(sock); + + return errcode; +} + + +static int floppyd_reader(int fd, char* buffer, int len) +{ + Dword errcode; + Dword gotlen; + int l; + int start; + Byte buf[16]; + + dword2byte(1, buf); + buf[4] = OP_READ; + dword2byte(4, buf+5); + dword2byte(len, buf+9); + if(write(fd, buf, 13) < 13) + return AUTH_IO_ERROR; + + if (read_dword(fd) != 8) { + errno = EIO; + return -1; + } + + gotlen = read_dword(fd); + errcode = read_dword(fd); + + if (gotlen != -1) { + if (read_dword(fd) != gotlen) { + errno = EIO; + return -1; + } + for (start = 0, l = 0; start < gotlen; start += l) { + l = read(fd, buffer+start, gotlen-start); + if (l == 0) { + errno = EIO; + return -1; + } + } + } else { + errno = errcode; + } + return gotlen; +} + +static int floppyd_writer(int fd, char* buffer, int len) +{ + Dword errcode; + Dword gotlen; + Byte buf[16]; + + dword2byte(1, buf); + buf[4] = OP_WRITE; + dword2byte(len, buf+5); + + if(write(fd, buf, 9) < 9) + return AUTH_IO_ERROR; + if(write(fd, buffer, len) < len) + return AUTH_IO_ERROR; + + if (read_dword(fd) != 8) { + errno = EIO; + return -1; + } + + gotlen = read_dword(fd); + errcode = read_dword(fd); + + errno = errcode; + if(errno != 0 && gotlen == 0) { + if (errno == EBADF) + errno = EROFS; + gotlen = -1; + } + + return gotlen; +} + +static int floppyd_lseek(int fd, mt_off_t offset, int whence) +{ + Dword errcode; + Dword gotlen; + Byte buf[32]; + + dword2byte(1, buf); + buf[4] = OP_SEEK; + + dword2byte(8, buf+5); + dword2byte(truncBytes32(offset), buf+9); + dword2byte(whence, buf+13); + + if(write(fd, buf, 17) < 17) + return AUTH_IO_ERROR; + + if (read_dword(fd) != 8) { + errno = EIO; + return -1; + } + + gotlen = read_dword(fd); + errcode = read_dword(fd); + + errno = errcode; + + return gotlen; +} + +static int floppyd_open(RemoteFile_t *This, int mode) +{ + Dword errcode; + Dword gotlen; + Byte buf[16]; + + if(! (This->capabilities & FLOPPYD_CAP_EXPLICIT_OPEN) ) { + /* floppyd has no "explicit seek" capabilities */ + return 0; + } + + dword2byte(1, buf); + if((mode & O_ACCMODE) == O_RDONLY) + buf[4] = OP_OPRO; + else + buf[4] = OP_OPRW; + dword2byte(4, buf+5); + dword2byte(This->drive, buf+9); + + if(write(This->fd, buf, 13) < 13) + return AUTH_IO_ERROR; + + if (read_dword(This->fd) != 8) { + errno = EIO; + return -1; + } + + gotlen = read_dword(This->fd); + errcode = read_dword(This->fd); + + errno = errcode; + + return gotlen; +} + + +/* ######################################################################## */ + +typedef int (*iofn) (int, char *, int); + +static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, int len, + iofn io) +{ + DeclareThis(RemoteFile_t); + int ret; + + where += This->offset; + + if (where != This->lastwhere ){ + if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){ + perror("floppyd_lseek"); + This->lastwhere = (mt_off_t) -1; + return -1; + } + } + ret = io(This->fd, buf, len); + if ( ret == -1 ){ + perror("floppyd_io"); + This->lastwhere = (mt_off_t) -1; + return -1; + } + This->lastwhere = where + ret; + return ret; +} + +static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + return floppyd_io(Stream, buf, where, len, (iofn) floppyd_reader); +} + +static int floppyd_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + return floppyd_io(Stream, buf, where, len, (iofn) floppyd_writer); +} + +static int floppyd_flush(Stream_t *Stream) +{ + Byte buf[16]; + + DeclareThis(RemoteFile_t); + + dword2byte(1, buf); + buf[4] = OP_FLUSH; + dword2byte(1, buf+5); + buf[9] = '\0'; + + if(write(This->fd, buf, 10) < 10) + return AUTH_IO_ERROR; + + if (read_dword(This->fd) != 8) { + errno = EIO; + return -1; + } + + read_dword(This->fd); + read_dword(This->fd); + return 0; +} + +static int floppyd_free(Stream_t *Stream) +{ + Byte buf[16]; + int gotlen; + int errcode; + DeclareThis(RemoteFile_t); + + if (This->fd > 2) { + dword2byte(1, buf); + buf[4] = OP_CLOSE; + if(write(This->fd, buf, 5) < 5) + return AUTH_IO_ERROR; + shutdown(This->fd, 1); + if (read_dword(This->fd) != 8) { + errno = EIO; + return -1; + } + + gotlen = read_dword(This->fd); + errcode = read_dword(This->fd); + + errno = errcode; + + close(This->fd); + return gotlen; + } else { + return 0; + } +} + +static int floppyd_geom(Stream_t *Stream, struct device *dev, + struct device *orig_dev, + int media, union bootsector *boot) +{ + size_t tot_sectors; + int sect_per_track; + DeclareThis(RemoteFile_t); + + dev->ssize = 2; /* allow for init_geom to change it */ + dev->use_2m = 0x80; /* disable 2m mode to begin */ + + if(media == 0xf0 || media >= 0x100){ + dev->heads = WORD(nheads); + dev->sectors = WORD(nsect); + tot_sectors = DWORD(bigsect); + SET_INT(tot_sectors, WORD(psect)); + sect_per_track = dev->heads * dev->sectors; + tot_sectors += sect_per_track - 1; /* round size up */ + dev->tracks = tot_sectors / sect_per_track; + + } else if (media >= 0xf8){ + media &= 3; + dev->heads = old_dos[media].heads; + dev->tracks = old_dos[media].tracks; + dev->sectors = old_dos[media].sectors; + dev->ssize = 0x80; + dev->use_2m = ~1; + } else { + fprintf(stderr,"Unknown media type\n"); + exit(1); + } + + This->size = (mt_off_t) 512 * dev->sectors * dev->tracks * dev->heads; + + return 0; +} + + +static int floppyd_data(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + DeclareThis(RemoteFile_t); + + if(date) + /* unknown, and irrelevant anyways */ + *date = 0; + if(size) + /* the size derived from the geometry */ + *size = (mt_size_t) This->size; + if(type) + *type = 0; /* not a directory */ + if(address) + *address = 0; + return 0; +} + +/* ######################################################################## */ + +static Class_t FloppydFileClass = { + floppyd_read, + floppyd_write, + floppyd_flush, + floppyd_free, + floppyd_geom, + floppyd_data +}; + +/* ######################################################################## */ + +static int get_host_and_port_and_drive(const char* name, char** hostname, + char **display, short* port, int *drive) +{ + char* newname = strdup(name); + char* p; + char* p2; + + p = newname; + while (*p != '/' && *p) p++; + p2 = p; + if (*p) p++; + *p2 = 0; + + *port = FLOPPYD_DEFAULT_PORT; + if(*p >= '0' && *p <= '9') + *port = strtoul(p, &p, 0); + if(*p == '/') + p++; + *drive = 0; + if(*p >= '0' && *p <= '9') + *drive = strtoul(p, &p, 0); + + *display = strdup(newname); + + p = newname; + while (*p != ':' && *p) p++; + p2 = p; + if (*p) p++; + *p2 = 0; + + *port += atoi(p); /* add display number to the port */ + + if (!*newname || strcmp(newname, "unix") == 0) { + free(newname); + newname = strdup("localhost"); + } + + *hostname = newname; + return 1; +} + +/* + * * Return the IP address of the specified host. + * */ +static IPaddr_t getipaddress(char *ipaddr) +{ + + struct hostent *host; + IPaddr_t ip; + + if (((ip = inet_addr(ipaddr)) == INADDR_NONE) && + (strcmp(ipaddr, "255.255.255.255") != 0)) { + + if ((host = gethostbyname(ipaddr)) != NULL) { + memcpy(&ip, host->h_addr, sizeof(ip)); + } + + endhostent(); + } + +#ifdef DEBUG + fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip); +#endif + + return (ip); +} + +/* + * * Connect to the floppyd server. + * */ +static int connect_to_server(IPaddr_t ip, short port) +{ + + struct sockaddr_in addr; + int sock; + + /* + * Allocate a socket. + */ + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + return (-1); + } + + /* + * Set the address to connect to. + */ + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = ip; + + /* + * Connect our socket to the above address. + */ + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return (-1); + } + + /* + * Set the keepalive socket option to on. + */ + { + int on = 1; + setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (char *)&on, sizeof(on)); + } + + return (sock); +} + +static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name, + char *errmsg); + +Stream_t *FloppydOpen(struct device *dev, struct device *dev2, + char *name, int mode, char *errmsg, + int mode2, int locked) +{ + RemoteFile_t *This; + + if (!dev || !(dev->misc_flags & FLOPPYD_FLAG)) + return NULL; + + This = New(RemoteFile_t); + if (!This){ + printOom(); + return NULL; + } + This->Class = &FloppydFileClass; + This->Next = 0; + This->offset = 0; + This->lastwhere = 0; + This->refs = 1; + This->Buffer = 0; + + This->fd = ConnectToFloppyd(This, name, errmsg); + if (This->fd == -1) { + Free(This); + return NULL; + } + + if(floppyd_open(This, mode) < 0) { + sprintf(errmsg, + "Can't open remote drive: %s", strerror(errno)); + close(This->fd); + Free(This); + return NULL; + } + + return (Stream_t *) This; +} + +static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name, + char *errmsg) +{ + char* hostname; + char* display; + short port; + int rval = get_host_and_port_and_drive(name, &hostname, &display, + &port, &floppyd->drive); + int sock; + int reply; + + if (!rval) return -1; + + floppyd->version = FLOPPYD_PROTOCOL_VERSION; + floppyd->capabilities = 0; + while(1) { + sock = connect_to_server(getipaddress(hostname), port); + + if (sock == -1) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg, 200, + "Can't connect to floppyd server on %s, port %i (%s)!", + hostname, port, strerror(errno)); +#else + sprintf(errmsg, + "Can't connect to floppyd server on %s, port %i!", + hostname, port); +#endif + return -1; + } + + reply = authenticate_to_floppyd(floppyd, sock, display); + if(floppyd->version == FLOPPYD_PROTOCOL_VERSION_OLD) + break; + if(reply == AUTH_WRONGVERSION) { + /* fall back on old version */ + floppyd->version = FLOPPYD_PROTOCOL_VERSION_OLD; + continue; + } + break; + } + + if (reply != 0) { + fprintf(stderr, + "Permission denied, authentication failed!\n" + "%s\n", AuthErrors[reply]); + return -1; + } + + free(hostname); + free(display); + + return sock; +} +#endif diff --git a/floppyd_io.h b/floppyd_io.h new file mode 100644 index 0000000..066d7b9 --- /dev/null +++ b/floppyd_io.h @@ -0,0 +1,64 @@ +#ifndef MTOOLS_FLOPPYDIO_H +#define MTOOLS_FLOPPYDIO_H + +/* Copyright 1999 Peter Schlaile. + * Copyright 1998,2000-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#ifdef USE_FLOPPYD + +#include "stream.h" + +/*extern int ConnectToFloppyd(const char* name, Class_t** ioclass);*/ +Stream_t *FloppydOpen(struct device *dev, struct device *dev2, + char *name, int mode, char *errmsg, + int mode2, int locked); + +#define FLOPPYD_DEFAULT_PORT 5703 + +#define FLOPPYD_PROTOCOL_VERSION_OLD 10 +#define FLOPPYD_PROTOCOL_VERSION 11 + +#define FLOPPYD_CAP_EXPLICIT_OPEN 1 /* explicit open. Useful for + * clean signalling of readonly disks */ +#define FLOPPYD_CAP_LARGE_SEEK 2 /* large seeks */ + +enum FloppydOpcodes { + OP_READ, + OP_WRITE, + OP_SEEK, + OP_FLUSH, + OP_CLOSE, + OP_IOCTL, + OP_OPRO, + OP_OPRW +}; + +enum AuthErrorsEnum { + AUTH_SUCCESS, + AUTH_PACKETOVERSIZE, + AUTH_AUTHFAILED, + AUTH_WRONGVERSION, + AUTH_DEVLOCKED, + AUTH_BADPACKET, + AUTH_IO_ERROR +}; + +typedef unsigned long IPaddr_t; + +#endif +#endif diff --git a/force_io.c b/force_io.c new file mode 100644 index 0000000..006d315 --- /dev/null +++ b/force_io.c @@ -0,0 +1,63 @@ +/* Copyright 1996,1997,1999,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Force I/O to be done to complete transfer length + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" + +static int force_io(Stream_t *Stream, + char *buf, mt_off_t start, size_t len, + int (*io)(Stream_t *, char *, mt_off_t, size_t)) +{ + int ret; + int done=0; + + while(len){ + ret = io(Stream, buf, start, len); + if ( ret <= 0 ){ + if (done) + return done; + else + return ret; + } + start += ret; + done += ret; + len -= ret; + buf += ret; + } + return done; +} + +int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + return force_io(Stream, buf, start, len, + Stream->Class->write); +} + +int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + return force_io(Stream, buf, start, len, + Stream->Class->read); +} diff --git a/fs.h b/fs.h new file mode 100644 index 0000000..65cf466 --- /dev/null +++ b/fs.h @@ -0,0 +1,43 @@ +#ifndef MTOOLS_FS_H +#define MTOOLS_FS_H + +/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "stream.h" + + +typedef struct FsPublic_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + int serialized; + unsigned long serial_number; + int cluster_size; + unsigned int sector_size; +} FsPublic_t; + +Stream_t *fs_init(char drive, int mode, int *isRop); +int fat_free(Stream_t *Dir, unsigned int fat); +int fatFreeWithDir(Stream_t *Dir, struct directory *dir); +int fat_error(Stream_t *Dir); +int fat32RootCluster(Stream_t *Dir); +char getDrive(Stream_t *Stream); + +#endif diff --git a/fsP.h b/fsP.h new file mode 100644 index 0000000..98f73bb --- /dev/null +++ b/fsP.h @@ -0,0 +1,103 @@ +#ifndef MTOOLS_FSP_H +#define MTOOLS_FSP_H + +/* Copyright 1996-1999,2001-2003,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "stream.h" +#include "msdos.h" +#include "fs.h" + +typedef enum fatAccessMode_t { + FAT_ACCESS_READ, + FAT_ACCESS_WRITE +} fatAccessMode_t; + +typedef struct Fs_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + int serialized; + unsigned long serial_number; + unsigned int cluster_size; + unsigned int sector_size; + int fat_error; + + unsigned int (*fat_decode)(struct Fs_t *This, unsigned int num); + void (*fat_encode)(struct Fs_t *This, unsigned int num, + unsigned int code); + + Stream_t *Direct; + int fat_dirty; + unsigned int fat_start; + unsigned int fat_len; + + unsigned int num_fat; + unsigned int end_fat; + unsigned int last_fat; + int fat_bits; /* must be signed, because we use negative values + * for special purposes */ + struct FatMap_t *FatMap; + + unsigned int dir_start; + unsigned int dir_len; + unsigned int clus_start; + + unsigned int num_clus; + char drive; /* for error messages */ + + /* fat 32 */ + unsigned int primaryFat; + unsigned int writeAllFats; + unsigned int rootCluster; + unsigned int infoSectorLoc; + unsigned int last; /* last sector allocated, or MAX32 if unknown */ + unsigned int freeSpace; /* free space, or MAX32 if unknown */ + int preallocatedClusters; + + int lastFatSectorNr; + unsigned char *lastFatSectorData; + fatAccessMode_t lastFatAccessMode; + int sectorMask; + int sectorShift; + + doscp_t *cp; +} Fs_t; + +int fs_free(Stream_t *Stream); + +void set_fat12(Fs_t *Fs); +void set_fat16(Fs_t *Fs); +void set_fat32(Fs_t *Fs); +unsigned int get_next_free_cluster(Fs_t *Fs, unsigned int last); +unsigned int fatDecode(Fs_t *This, unsigned int pos); +void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos); +void fatDeallocate(Fs_t *This, unsigned int pos); +void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value); +void fatEncode(Fs_t *This, unsigned int pos, unsigned int value); + +int fat_read(Fs_t *This, union bootsector *boot, int fat_bits, + size_t tot_sectors, int nodups); +void fat_write(Fs_t *This); +int zero_fat(Fs_t *Fs, int media_descriptor); +extern Class_t FsClass; +int fsPreallocateClusters(Fs_t *Fs, long); +Fs_t *getFs(Stream_t *Stream); + + +#endif diff --git a/hash.c b/hash.c new file mode 100644 index 0000000..ba56287 --- /dev/null +++ b/hash.c @@ -0,0 +1,220 @@ +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * hash.c - hash table. + */ + +#include "sysincludes.h" +#include "htable.h" +#include "mtools.h" + +struct hashtable { + T_HashFunc f1,f2; + T_ComparFunc compar; + int size; /* actual size of the array */ + int fill; /* number of deleted or in use slots */ + int inuse; /* number of slots in use */ + int max; /* maximal number of elements to keep efficient */ + T_HashTableEl *entries; +}; + +static int sizes[]={5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, + 25717, 51437, 102877, 205759, 411527, 823117, 1646237, + 3292489, 6584983, 13169977, 26339969, 52679969, 105359939, + 210719881, 421439783, 842879579, 1685759167, 0 }; +static int deleted=0; +static int unallocated=0; + +static int alloc_ht(T_HashTable *H, int size) +{ + int i; + + for(i=0; sizes[i]; i++) + if (sizes[i] > size*4 ) + break; + if (!sizes[i]) + for(i=0; sizes[i]; i++) + if (sizes[i] > size*2 ) + break; + if (!sizes[i]) + for(i=0; sizes[i]; i++) + if (sizes[i] > size) + break; + if(!sizes[i]) + return -1; + size = sizes[i]; + if(size < H->size) + size = H->size; /* never shrink the table */ + H->max = size * 4 / 5 - 2; + H->size = size; + H->fill = 0; + H->inuse = 0; + H->entries = NewArray(size, T_HashTableEl); + if (H->entries == NULL) + return -1; /* out of memory error */ + + for(i=0; i < size; i++) + H->entries[i] = &unallocated; + return 0; +} + +int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, + T_HashTable **H) +{ + *H = New(T_HashTable); + if (*H == NULL){ + return -1; /* out of memory error */ + } + + (*H)->f1 = f1; + (*H)->f2 = f2; + (*H)->compar = c; + (*H)->size = 0; + if(alloc_ht(*H,size)) + return -1; + return 0; +} + +int free_ht(T_HashTable *H, T_HashFunc entry_free) +{ + int i; + if(entry_free) + for(i=0; i< H->size; i++) + if (H->entries[i] != &unallocated && + H->entries[i] != &deleted) + entry_free(H->entries[i]); + Free(H->entries); + Free(H); + return 0; +} + +/* add into hash table without checking for repeats */ +static int _hash_add(T_HashTable *H,T_HashTableEl *E, int *hint) +{ + int f2, pos, ctr; + + pos = H->f1(E) % H->size; + f2 = -1; + ctr = 0; + while(H->entries[pos] != &unallocated && + H->entries[pos] != &deleted){ + if (f2 == -1) + f2 = H->f2(E) % (H->size - 1); + pos = (pos+f2+1) % H->size; + ctr++; + } + if(H->entries[pos] == &unallocated) + H->fill++; /* only increase fill if the previous element was not yet + * counted, i.e. unallocated */ + H->inuse++; + H->entries[pos] = E; + if(hint) + *hint = pos; + return 0; +} + +static int rehash(T_HashTable *H) +{ + int size,i; + T_HashTableEl *oldentries; + /* resize the table */ + + size = H->size; + oldentries = H->entries; + if(alloc_ht(H,((H->inuse+1)*4+H->fill)/5)) + return -1; + + for(i=0; i < size; i++){ + if(oldentries[i] != &unallocated && oldentries[i] != &deleted) + _hash_add(H, oldentries[i], 0); + } + Free(oldentries); + return 0; +} + +int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint) +{ + if (H->fill >= H->max) + rehash(H); + if (H->fill == H->size) + return -1; /*out of memory error */ + return _hash_add(H,E, hint); +} + + +/* add into hash table without checking for repeats */ +static int _hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2, + int *hint, int isIdentity) +{ + int f2, pos, upos, ttl; + + pos = H->f1(E) % H->size; + ttl = H->size; + f2 = -1; + upos = -1; + while(ttl && + H->entries[pos] != &unallocated && + (H->entries[pos] == &deleted || + ((isIdentity || H->compar(H->entries[pos], E) != 0) && + (!isIdentity || H->entries[pos] != E)))){ + if (f2 == -1) + f2 = H->f2(E) % (H->size - 1); + if (upos == -1 && H->entries[pos] == &deleted) + upos = pos; + pos = (pos+f2+1) % H->size; + ttl--; + } + if(H->entries[pos] == &unallocated || !ttl) + return -1; + if (upos != -1){ + H->entries[upos] = H->entries[pos]; + H->entries[pos] = &deleted; + pos = upos; + } + if(hint) + *hint = pos; + *E2= H->entries[pos]; + return 0; +} + + +int hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2, + int *hint) +{ + return _hash_lookup(H, E, E2, hint, 0); +} + +/* add into hash table without checking for repeats */ +int hash_remove(T_HashTable *H,T_HashTableEl *E, int hint) +{ + T_HashTableEl *E2; + + if (hint >=0 && hint < H->size && + H->entries[hint] == E){ + H->inuse--; + H->entries[hint] = &deleted; + return 0; + } + + if(_hash_lookup(H, E, &E2, &hint, 1)) { + fprintf(stderr, "Removing non-existent entry\n"); + exit(1); + return -1; + } + H->inuse--; + H->entries[hint] = &deleted; + return 0; +} diff --git a/htable.h b/htable.h new file mode 100644 index 0000000..576a2b7 --- /dev/null +++ b/htable.h @@ -0,0 +1,32 @@ +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * hashtable + */ + +typedef struct hashtable T_HashTable; +typedef void *T_HashTableEl; +typedef unsigned int (*T_HashFunc)(void *); +typedef int (*T_ComparFunc)(void *, void *); + + +int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, T_HashTable **H); +int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint); +int hash_remove(T_HashTable *H, T_HashTableEl *E, int hint); +int hash_lookup(T_HashTable *H, T_HashTableEl *E, T_HashTableEl **E2, + int *hint); +int free_ht(T_HashTable *H, T_HashFunc entry_free); + diff --git a/init.c b/init.c new file mode 100644 index 0000000..b495f48 --- /dev/null +++ b/init.c @@ -0,0 +1,424 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2002,2006-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Initialize an MSDOS diskette. Read the boot sector, and switch to the + * proper floppy disk device to match the format on the disk. Sets a bunch + * of global variables. Returns 0 on success, or 1 on failure. + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "plain_io.h" +#include "floppyd_io.h" +#include "xdf_io.h" +#include "buffer.h" +#include "file_name.h" + +#define FULL_CYL + +unsigned int num_clus; /* total number of cluster */ + + +/* + * Read the boot sector. We glean the disk parameters from this sector. + */ +static int read_boot(Stream_t *Stream, union bootsector * boot, int size) +{ + /* read the first sector, or part of it */ + if(!size) + size = BOOTSIZE; + if(size > MAX_BOOT) + size = MAX_BOOT; + + if (force_read(Stream, boot->characters, 0, size) != size) + return -1; + return 0; +} + +static int fs_flush(Stream_t *Stream) +{ + DeclareThis(Fs_t); + + fat_write(This); + return 0; +} + +static doscp_t *get_dosConvert(Stream_t *Stream) +{ + DeclareThis(Fs_t); + return This->cp; +} + +Class_t FsClass = { + read_pass_through, /* read */ + write_pass_through, /* write */ + fs_flush, + fs_free, /* free */ + 0, /* set geometry */ + get_data_pass_through, + 0, /* pre allocate */ + get_dosConvert, /* dosconvert */ +}; + +static int get_media_type(Stream_t *St, union bootsector *boot) +{ + int media; + + media = boot->boot.descr; + if(media < 0xf0){ + char temp[512]; + /* old DOS disk. Media descriptor in the first FAT byte */ + /* old DOS disk always have 512-byte sectors */ + if (force_read(St,temp,(mt_off_t) 512,512) == 512) + media = (unsigned char) temp[0]; + else + media = 0; + } else + media += 0x100; + return media; +} + + +Stream_t *GetFs(Stream_t *Fs) +{ + while(Fs && Fs->Class != &FsClass) + Fs = Fs->Next; + return Fs; +} + +Stream_t *find_device(char drive, int mode, struct device *out_dev, + union bootsector *boot, + char *name, int *media, mt_size_t *maxSize, + int *isRop) +{ + char errmsg[200]; + Stream_t *Stream; + struct device *dev; + int r; + int isRo=0; + + Stream = NULL; + sprintf(errmsg, "Drive '%c:' not supported", drive); + /* open the device */ + for (dev=devices; dev->name; dev++) { + FREE(&Stream); + if (dev->drive != drive) + continue; + *out_dev = *dev; + expand(dev->name,name); +#ifdef USING_NEW_VOLD + strcpy(name, getVoldName(dev, name)); +#endif + + Stream = 0; + if(out_dev->misc_flags & FLOPPYD_FLAG) { + Stream = 0; +#ifdef USE_FLOPPYD + Stream = FloppydOpen(out_dev, dev, name, mode, + errmsg, 0, 1); + if(Stream && maxSize) + *maxSize = max_off_t_31; +#endif + } else { + +#ifdef USE_XDF + Stream = XdfOpen(out_dev, name, mode, errmsg, 0); + if(Stream) { + out_dev->use_2m = 0x7f; + if(maxSize) + *maxSize = max_off_t_31; + } +#endif + + + if (!Stream) + Stream = SimpleFileOpen(out_dev, dev, name, + isRop ? mode | O_RDWR: mode, + errmsg, 0, 1, maxSize); + + if(Stream) { + isRo=0; + } else if(isRop && + (errno == EPERM || errno == EACCES || errno == EROFS)) { + Stream = SimpleFileOpen(out_dev, dev, name, + mode | O_RDONLY, + errmsg, 0, 1, maxSize); + if(Stream) { + isRo=1; + } + } + } + + if( !Stream) + continue; + + /* read the boot sector */ + if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){ + sprintf(errmsg, + "init %c: could not read boot sector", + drive); + continue; + } + + if((*media= get_media_type(Stream, boot)) <= 0xf0 ){ + if (boot->boot.jump[2]=='L') + sprintf(errmsg, + "diskette %c: is Linux LILO, not DOS", + drive); + else + sprintf(errmsg,"init %c: non DOS media", drive); + continue; + } + + /* set new parameters, if needed */ + errno = 0; + if(SET_GEOM(Stream, out_dev, dev, *media, boot)){ + if(errno) +#ifdef HAVE_SNPRINTF + snprintf(errmsg, 199, + "Can't set disk parameters for %c: %s", + drive, strerror(errno)); +#else + sprintf(errmsg, + "Can't set disk parameters for %c: %s", + drive, strerror(errno)); +#endif + else + sprintf(errmsg, + "Can't set disk parameters for %c", + drive); + continue; + } + break; + } + + /* print error msg if needed */ + if ( dev->drive == 0 ){ + FREE(&Stream); + fprintf(stderr,"%s\n",errmsg); + return NULL; + } + if(isRop) + *isRop = isRo; + return Stream; +} + + +Stream_t *fs_init(char drive, int mode, int *isRop) +{ + int blocksize; + int media,i; + int nhs; + int disk_size = 0; /* In case we don't happen to set this below */ + size_t tot_sectors; + char name[EXPAND_BUF]; + int cylinder_size; + struct device dev; + mt_size_t maxSize; + + union bootsector boot; + + Fs_t *This; + + This = New(Fs_t); + if (!This) + return NULL; + + This->Direct = NULL; + This->Next = NULL; + This->refs = 1; + This->Buffer = 0; + This->Class = &FsClass; + This->preallocatedClusters = 0; + This->lastFatSectorNr = 0; + This->lastFatAccessMode = 0; + This->lastFatSectorData = 0; + This->drive = drive; + This->last = 0; + + This->Direct = find_device(drive, mode, &dev, &boot, name, &media, + &maxSize, isRop); + if(!This->Direct) + return NULL; + + This->sector_size = WORD_S(secsiz); + if(This->sector_size > MAX_SECTOR){ + fprintf(stderr,"init %c: sector size too big\n", drive); + return NULL; + } + + i = log_2(This->sector_size); + + if(i == 24) { + fprintf(stderr, + "init %c: sector size (%d) not a small power of two\n", + drive, This->sector_size); + return NULL; + } + This->sectorShift = i; + This->sectorMask = This->sector_size - 1; + + + cylinder_size = dev.heads * dev.sectors; + This->serialized = 0; + if ((media & ~7) == 0xf8){ + i = media & 3; + This->cluster_size = old_dos[i].cluster_size; + tot_sectors = cylinder_size * old_dos[i].tracks; + This->fat_start = 1; + This->fat_len = old_dos[i].fat_len; + This->dir_len = old_dos[i].dir_len; + This->num_fat = 2; + This->sector_size = 512; + This->sectorShift = 9; + This->sectorMask = 511; + This->fat_bits = 12; + nhs = 0; + } else { + struct label_blk_t *labelBlock; + /* + * all numbers are in sectors, except num_clus + * (which is in clusters) + */ + tot_sectors = WORD_S(psect); + if(!tot_sectors) { + tot_sectors = DWORD_S(bigsect); + nhs = DWORD_S(nhs); + } else + nhs = WORD_S(nhs); + + + This->cluster_size = boot.boot.clsiz; + This->fat_start = WORD_S(nrsvsect); + This->fat_len = WORD_S(fatlen); + This->dir_len = WORD_S(dirents) * MDIR_SIZE / This->sector_size; + This->num_fat = boot.boot.nfat; + + if (This->fat_len) { + labelBlock = &boot.boot.ext.old.labelBlock; + } else { + labelBlock = &boot.boot.ext.fat32.labelBlock; + } + + if(labelBlock->dos4 == 0x29) { + This->serialized = 1; + This->serial_number = _DWORD(labelBlock->serial); + } + } + + if (tot_sectors >= (maxSize >> This->sectorShift)) { + fprintf(stderr, "Big disks not supported on this architecture\n"); + exit(1); + } + + if(!mtools_skip_check && (tot_sectors % dev.sectors)){ + fprintf(stderr, + "Total number of sectors (%d) not a multiple of" + " sectors per track (%d)!\n", (int) tot_sectors, + dev.sectors); + fprintf(stderr, + "Add mtools_skip_check=1 to your .mtoolsrc file " + "to skip this test\n"); + exit(1); + } + + /* full cylinder buffering */ +#ifdef FULL_CYL + disk_size = (dev.tracks) ? cylinder_size : 512; +#else /* FULL_CYL */ + disk_size = (dev.tracks) ? dev.sectors : 512; +#endif /* FULL_CYL */ + +#if (defined OS_sysv4 && !defined OS_solaris) + /* + * The driver in Dell's SVR4 v2.01 is unreliable with large writes. + */ + disk_size = 0; +#endif /* (defined sysv4 && !defined(solaris)) */ + +#ifdef OS_linux + disk_size = cylinder_size; +#endif + +#if 1 + if(disk_size > 256) { + disk_size = dev.sectors; + if(dev.sectors % 2) + disk_size <<= 1; + } +#endif + if (disk_size % 2) + disk_size *= 2; + + if(!dev.blocksize || dev.blocksize < This->sector_size) + blocksize = This->sector_size; + else + blocksize = dev.blocksize; + if (disk_size) + This->Next = buf_init(This->Direct, + 8 * disk_size * blocksize, + disk_size * blocksize, + This->sector_size); + else + This->Next = This->Direct; + + if (This->Next == NULL) { + perror("init: allocate buffer"); + This->Next = This->Direct; + } + + /* read the FAT sectors */ + if(fat_read(This, &boot, dev.fat_bits, tot_sectors, dev.use_2m&0x7f)){ + This->num_fat = 1; + FREE(&This->Next); + Free(This->Next); + return NULL; + } + + /* Set the codepage */ + This->cp = cp_open(dev.codepage); + if(This->cp == NULL) { + fs_free((Stream_t *)This); + FREE(&This->Next); + Free(This->Next); + return NULL; + } + + return (Stream_t *) This; +} + +char getDrive(Stream_t *Stream) +{ + DeclareThis(Fs_t); + + if(This->Class != &FsClass) + return getDrive(GetFs(Stream)); + else + return This->drive; +} + +int fsPreallocateClusters(Fs_t *Fs, long size) +{ + if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1) + return -1; + + Fs->preallocatedClusters += size; + return 0; +} diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..89fc9b0 --- /dev/null +++ b/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/llong.c b/llong.c new file mode 100644 index 0000000..a1eaeec --- /dev/null +++ b/llong.c @@ -0,0 +1,96 @@ +/* Copyright 1999-2003,2006,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "stream.h" +#include "fsP.h" +#include "llong.h" +#include "mtools.h" + +#if 1 +const mt_off_t max_off_t_31 = MAX_OFF_T_B(31); /* Floppyd */ +const mt_off_t max_off_t_32 = MAX_OFF_T_B(32); /* Directory */ +const mt_off_t max_off_t_41 = MAX_OFF_T_B(41); /* SCSI */ +const mt_off_t max_off_t_seek = MAX_OFF_T_B(SEEK_BITS); /* SCSI */ +#else +const mt_off_t max_off_t_31 = MAX_OFF_T_B(10); /* Floppyd */ +const mt_off_t max_off_t_41 = MAX_OFF_T_B(10); /* SCSI */ +const mt_off_t max_off_t_seek = MAX_OFF_T_B(10); /* SCSI */ +#endif + +int fileTooBig(mt_off_t off) { + return (off & ~max_off_t_32) != 0; +} + +off_t truncBytes32(mt_off_t off) +{ + if (fileTooBig(off)) { + fprintf(stderr, "Internal error, offset too big\n"); + exit(1); + } + return (off_t) off; +} + +mt_off_t sectorsToBytes(Stream_t *Stream, off_t off) +{ + DeclareThis(Fs_t); + return (mt_off_t) off << This->sectorShift; +} + +#if defined HAVE_LLSEEK +# ifndef HAVE_LLSEEK_PROTOTYPE +extern long long llseek (int fd, long long offset, int origin); +# endif +#endif + +#if defined HAVE_LSEEK64 +# ifndef HAVE_LSEEK64_PROTOTYPE +extern long long lseek64 (int fd, long long offset, int origin); +# endif +#endif + + +int mt_lseek(int fd, mt_off_t where, int whence) +{ +#if defined HAVE_LSEEK64 + if(lseek64(fd, where, whence) >= 0) + return 0; + else + return -1; +#elif defined HAVE_LLSEEK + if(llseek(fd, where, whence) >= 0) + return 0; + else + return -1; +#else + if (lseek(fd, (off_t) where, whence) >= 0) + return 0; + else + return 1; +#endif +} + +unsigned int log_2(int size) +{ + unsigned int i; + + for(i=0; i<24; i++) { + if(1 << i == size) + return i; + } + return 24; +} diff --git a/llong.h b/llong.h new file mode 100644 index 0000000..6be3e9d --- /dev/null +++ b/llong.h @@ -0,0 +1,115 @@ +#ifndef MTOOLS_LLONG_H +#define MTOOLS_LLONG_H + +/* Copyright 1999,2001-2004,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#if 1 + + +#ifdef HAVE_OFF_T_64 +/* if off_t is already 64 bits, be happy, and don't worry about the + * loff_t and llseek stuff */ +#define MT_OFF_T off_t +#define MT_SIZE_T size_t +#endif + +#ifndef MT_OFF_T +# if defined(HAVE_LLSEEK) || defined(HAVE_LSEEK64) +/* we have llseek. Now, what's its type called? loff_t or offset_t ? */ +# ifdef HAVE_LOFF_T +# define MT_OFF_T loff_t +/* use the same type for size. Better to get signedness wrong than width */ +# define MT_SIZE_T loff_t +# else +# ifdef HAVE_OFFSET_T +# define MT_OFF_T offset_t +/* use the same type for size. Better to get signedness wrong than width */ +# define MT_SIZE_T offset_t +# endif +# endif +# endif +#endif + +#ifndef MT_OFF_T +/* we still don't have a suitable mt_off_t type...*/ +# ifdef HAVE_LONG_LONG +/* ... first try long long ... */ +# define MT_OFF_T long long +# define MT_SIZE_T unsigned long long +# else +# ifdef HAVE_OFF64_T +# define MT_OFF_T off64_t +# define MT_SIZE_T off64_t +# else +/* ... and if that fails, fall back on good ole' off_t */ +# define MT_OFF_T off_t +# define MT_SIZE_T size_t +# endif +# endif +#endif + +typedef MT_OFF_T mt_off_t; +typedef MT_SIZE_T mt_size_t; + +#else +/* testing: meant to flag dubious assignments between 32 bit length types + * and 64 bit ones */ +typedef struct { + unsigned int lo; + int high; +} *mt_off_t; + +typedef struct { + unsigned int lo; + unsigned int high; +} *mt_size_t; + +#endif + +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define MAX_OFF_T_B(bits) \ + ((((mt_off_t) 1 << min(bits-1, sizeof(mt_off_t)*8 - 2)) -1) << 1 | 1) + +#if defined(HAVE_LLSEEK) || defined(HAVE_LSEEK64) +# define SEEK_BITS 63 +#else +# define SEEK_BITS (sizeof(off_t) * 8 - 1) +#endif + +extern const mt_off_t max_off_t_31; +extern const mt_off_t max_off_t_41; +extern const mt_off_t max_off_t_seek; + +extern off_t truncBytes32(mt_off_t off); +extern int fileTooBig(mt_off_t off); +mt_off_t sectorsToBytes(Stream_t *This, off_t off); + +mt_size_t getfree(Stream_t *Stream); +int getfreeMinBytes(Stream_t *Stream, mt_size_t ref); + +Stream_t *find_device(char drive, int mode, struct device *out_dev, + union bootsector *boot, + char *name, int *media, mt_size_t *maxSize, + int *isRop); + +int mt_lseek(int fd, mt_off_t where, int whence); + + +unsigned int log_2(int); + +#endif diff --git a/lockdev.h b/lockdev.h new file mode 100644 index 0000000..4467bc2 --- /dev/null +++ b/lockdev.h @@ -0,0 +1,77 @@ +#ifndef LOCK_DEV +#define LOCK_DEV + +/* Copyright 2005,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Create an advisory lock on the device to prevent concurrent writes. + * Uses either lockf, flock, or fcntl locking methods. See the Makefile + * and the Configure files for how to specify the proper method. + */ + +int lock_dev(int fd, int mode, struct device *dev) +{ +#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB)) + /**/ +#else /* FLOCK */ + +#if (defined(HAVE_LOCKF) && defined(F_TLOCK)) + /**/ +#else /* LOCKF */ + +#if (defined(F_SETLK) && defined(F_WRLCK)) + struct flock flk; + +#endif /* FCNTL */ +#endif /* LOCKF */ +#endif /* FLOCK */ + + if(IS_NOLOCK(dev)) + return 0; + +#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB)) + if (flock(fd, (mode ? LOCK_EX : LOCK_SH)|LOCK_NB) < 0) +#else /* FLOCK */ + +#if (defined(HAVE_LOCKF) && defined(F_TLOCK)) + if (mode && lockf(fd, F_TLOCK, 0) < 0) +#else /* LOCKF */ + +#if (defined(F_SETLK) && defined(F_WRLCK)) + flk.l_type = mode ? F_WRLCK : F_RDLCK; + flk.l_whence = 0; + flk.l_start = 0L; + flk.l_len = 0L; + + if (fcntl(fd, F_SETLK, &flk) < 0) +#endif /* FCNTL */ +#endif /* LOCKF */ +#endif /* FLOCK */ + { + if(errno == EINVAL +#ifdef EOPNOTSUPP + || errno == EOPNOTSUPP +#endif + ) + return 0; + else + return 1; + } + return 0; +} + + +#endif diff --git a/mainloop.c b/mainloop.c new file mode 100644 index 0000000..4218edd --- /dev/null +++ b/mainloop.c @@ -0,0 +1,669 @@ +/* Copyright 1997-2002,2005-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mainloop.c + * Iterating over all the command line parameters, and matching patterns + * where needed + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "fs.h" +#include "mainloop.h" +#include "plain_io.h" +#include "file.h" +#include "file_name.h" + + +/* Fix the info in the MCWD file to be a proper directory name. + * Always has a leading separator. Never has a trailing separator + * (unless it is the path itself). */ + +static const char *fix_mcwd(char *ans) +{ + FILE *fp; + char *s; + char buf[MAX_PATH]; + + fp = open_mcwd("r"); + if(!fp || !fgets(buf, MAX_PATH, fp)) { + if(fp) + fclose(fp); + ans[0] = get_default_drive(); + strcpy(ans+1, ":/"); + return ans; + } + + buf[strlen(buf) -1] = '\0'; + fclose(fp); + /* drive letter present? */ + s = buf; + if (buf[0] && buf[1] == ':') { + strncpy(ans, buf, 2); + ans[2] = '\0'; + s = &buf[2]; + } else { + ans[0] = get_default_drive(); + strcpy(ans+1, ":"); + } + /* add a leading separator */ + if (*s != '/' && *s != '\\') { + strcat(ans, "/"); + strcat(ans, s); + } else + strcat(ans, s); + +#if 0 + /* translate to upper case */ + for (s = ans; *s; ++s) { + *s = toupper(*s); + if (*s == '\\') + *s = '/'; + } +#endif + /* if only drive, colon, & separator */ + if (strlen(ans) == 3) + return(ans); + /* zap the trailing separator */ + if (*--s == '/') + *s = '\0'; + return ans; +} + +int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); +int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, + int follow_dir_link); + +static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename) +{ + return unix_dir_loop(Dir, mp); +} + +int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link) +{ + int ret; + int isdir; + int unixNameLength; + + mp->File = NULL; + mp->direntry = NULL; + unixNameLength = strlen(arg); + if(unixNameLength > 1 && arg[unixNameLength-1] == '/') { + /* names ending in slash, and having at least two characters */ + char *name = strdup(arg); + name[unixNameLength-1]='\0'; + mp->unixSourceName = name; + } else { + mp->unixSourceName = arg; + } + /* mp->dir.attr = ATTR_ARCHIVE;*/ + mp->loop = _unix_loop; + if((mp->lookupflags & DO_OPEN)){ + mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0); + if(!mp->File){ + perror(arg); +#if 0 + tmp = _basename(arg); + strncpy(mp->filename, tmp, VBUFSIZE); + mp->filename[VBUFSIZE-1] = '\0'; +#endif + return ERROR_ONE; + } + GET_DATA(mp->File, 0, 0, &isdir, 0); + if(isdir) { +#if !defined(__EMX__) && !defined(OS_mingw32msvc) + struct MT_STAT buf; +#endif + + FREE(&mp->File); +#if !defined(__EMX__) && !defined(OS_mingw32msvc) + if(!follow_dir_link && + MT_LSTAT(arg, &buf) == 0 && + S_ISLNK(buf.st_mode)) { + /* skip links to directories in order to avoid + * infinite loops */ + fprintf(stderr, + "skipping directory symlink %s\n", + arg); + return 0; + } +#endif + if(! (mp->lookupflags & ACCEPT_DIR)) + return 0; + mp->File = OpenDir(Stream, arg); + } + } + + if(isdir) + ret = mp->dirCallback(0, mp); + else + ret = mp->unixcallback(mp); + FREE(&mp->File); + return ret; +} + + +int isSpecial(const char *name) +{ + if(name[0] == '\0') + return 1; + if(!strcmp(name,".")) + return 1; + if(!strcmp(name,"..")) + return 1; + return 0; +} + +#ifdef HAVE_WCHAR_H +int isSpecialW(const wchar_t *name) +{ + if(name[0] == '\0') + return 1; + if(!wcscmp(name,L".")) + return 1; + if(!wcscmp(name,L"..")) + return 1; + return 0; +} +#endif + +static int checkForDot(int lookupflags, const wchar_t *name) +{ + return (lookupflags & NO_DOTS) && isSpecialW(name); +} + + +typedef struct lookupState_t { + Stream_t *container; + int nbContainers; + Stream_t *Dir; + int nbDirs; + const char *filename; +} lookupState_t; + +static int isUniqueTarget(const char *name) +{ + return name && strcmp(name, "-"); +} + +static int handle_leaf(direntry_t *direntry, MainParam_t *mp, + lookupState_t *lookupState) +{ + Stream_t *MyFile=0; + int ret; + + if(got_signal) + return ERROR_ONE; + if(lookupState) { + /* we are looking for a "target" file */ + switch(lookupState->nbDirs) { + case 0: /* no directory yet, open it */ + lookupState->Dir = OpenFileByDirentry(direntry); + lookupState->nbDirs++; + /* dump the container, we have + * better now */ + FREE(&lookupState->container); + return 0; + case 1: /* we have already a directory */ + FREE(&lookupState->Dir); + fprintf(stderr,"Ambigous\n"); + return STOP_NOW | ERROR_ONE; + default: + return STOP_NOW | ERROR_ONE; + } + } + + mp->direntry = direntry; + if(IS_DIR(direntry)) { + if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS)) + MyFile = mp->File = OpenFileByDirentry(direntry); + ret = mp->dirCallback(direntry, mp); + } else { + if(mp->lookupflags & DO_OPEN) + MyFile = mp->File = OpenFileByDirentry(direntry); + ret = mp->callback(direntry, mp); + } + FREE(&MyFile); + if(isUniqueTarget(mp->targetName)) + ret |= STOP_NOW; + return ret; +} + +static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename) +{ + Stream_t *MyFile=0; + direntry_t entry; + int ret; + int r; + + ret = 0; + r=0; + initializeDirentry(&entry, Dir); + while(!got_signal && + (r=vfat_lookup(&entry, filename, -1, + mp->lookupflags, mp->shortname, + mp->longname)) == 0 ){ + mp->File = NULL; + if(!checkForDot(mp->lookupflags,entry.name)) { + MyFile = 0; + if((mp->lookupflags & DO_OPEN) || + (IS_DIR(&entry) && + (mp->lookupflags & DO_OPEN_DIRS))) { + MyFile = mp->File = OpenFileByDirentry(&entry); + } + if(got_signal) + break; + mp->direntry = &entry; + if(IS_DIR(&entry)) + ret |= mp->dirCallback(&entry,mp); + else + ret |= mp->callback(&entry, mp); + FREE(&MyFile); + } + if (fat_error(Dir)) + ret |= ERROR_ONE; + if(mp->fast_quit && (ret & ERROR_ONE)) + break; + } + if (r == -2) + return ERROR_ONE; + if(got_signal) + ret |= ERROR_ONE; + return ret; +} + +static int recurs_dos_loop(MainParam_t *mp, const char *filename0, + const char *filename1, + lookupState_t *lookupState) +{ + /* Dir is de-allocated by the same entity which allocated it */ + const char *ptr; + direntry_t entry; + int length; + int lookupflags; + int ret; + int have_one; + int doing_mcwd; + int r; + + while(1) { + /* strip dots and / */ + if(!strncmp(filename0,"./", 2)) { + filename0 += 2; + continue; + } + if(!strcmp(filename0,".") && filename1) { + filename0 ++; + continue; + } + if(filename0[0] == '/') { + filename0++; + continue; + } + if(!filename0[0]) { + if(!filename1) + break; + filename0 = filename1; + filename1 = 0; + continue; + } + break; + } + + if(!strncmp(filename0,"../", 3) || + (!strcmp(filename0, "..") && filename1)) { + /* up one level */ + mp->File = getDirentry(mp->File)->Dir; + return recurs_dos_loop(mp, filename0+2, filename1, lookupState); + } + + doing_mcwd = !!filename1; + + ptr = strchr(filename0, '/'); + if(!ptr) { + length = strlen(filename0); + ptr = filename1; + filename1 = 0; + } else { + length = ptr - filename0; + ptr++; + } + if(!ptr) { + if(mp->lookupflags & OPEN_PARENT) { + mp->targetName = filename0; + ret = handle_leaf(getDirentry(mp->File), mp, + lookupState); + mp->targetName = 0; + return ret; + } + + if(!strcmp(filename0, ".") || !filename0[0]) { + return handle_leaf(getDirentry(mp->File), + mp, lookupState); + } + + if(!strcmp(filename0, "..")) { + return handle_leaf(getParent(getDirentry(mp->File)), mp, + lookupState); + } + + lookupflags = mp->lookupflags; + + if(lookupState) { + lookupState->filename = filename0; + if(lookupState->nbContainers + lookupState->nbDirs > 0){ + /* we have already one target, don't bother + * with this one. */ + FREE(&lookupState->container); + } else { + /* no match yet. Remember this container for + * later use */ + lookupState->container = COPY(mp->File); + } + lookupState->nbContainers++; + } + } else + lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS; + + ret = 0; + r = 0; + have_one = 0; + initializeDirentry(&entry, mp->File); + while(!(ret & STOP_NOW) && + !got_signal && + (r=vfat_lookup(&entry, filename0, length, + lookupflags | NO_MSG, + mp->shortname, mp->longname)) == 0 ){ + if(checkForDot(lookupflags, entry.name)) + /* while following the path, ignore the + * special entries if they were not + * explicitly given */ + continue; + have_one = 1; + if(ptr) { + Stream_t *SubDir; + SubDir = mp->File = OpenFileByDirentry(&entry); + ret |= recurs_dos_loop(mp, ptr, filename1, lookupState); + FREE(&SubDir); + } else { + ret |= handle_leaf(&entry, mp, lookupState); + if(isUniqueTarget(mp->targetName)) + return ret | STOP_NOW; + } + if(doing_mcwd) + break; + } + if (r == -2) + return ERROR_ONE; + if(got_signal) + return ret | ERROR_ONE; + if(doing_mcwd && !have_one) + return NO_CWD; + return ret; +} + +static int common_dos_loop(MainParam_t *mp, const char *pathname, + lookupState_t *lookupState, int open_mode) + +{ + Stream_t *RootDir; + const char *cwd; + char drive; + + int ret; + mp->loop = _dos_loop; + + drive='\0'; + cwd = ""; + if(*pathname && pathname[1] == ':') { + drive = toupper(*pathname); + pathname += 2; + if(mp->mcwd[0] == drive) + cwd = mp->mcwd+2; + } else if(mp->mcwd[0]) { + drive = mp->mcwd[0]; + cwd = mp->mcwd+2; + } else { + drive = get_default_drive(); + } + + if(*pathname=='/') /* absolute path name */ + cwd = ""; + + RootDir = mp->File = open_root_dir(drive, open_mode, NULL); + if(!mp->File) + return ERROR_ONE; + + ret = recurs_dos_loop(mp, cwd, pathname, lookupState); + if(ret & NO_CWD) { + /* no CWD */ + *mp->mcwd = '\0'; + unlink_mcwd(); + ret = recurs_dos_loop(mp, "", pathname, lookupState); + } + FREE(&RootDir); + return ret; +} + +static int dos_loop(MainParam_t *mp, const char *arg) +{ + return common_dos_loop(mp, arg, 0, mp->openflags); +} + + +static int dos_target_lookup(MainParam_t *mp, const char *arg) +{ + lookupState_t lookupState; + int ret; + int lookupflags; + + lookupState.nbDirs = 0; + lookupState.Dir = 0; + lookupState.nbContainers = 0; + lookupState.container = 0; + + lookupflags = mp->lookupflags; + mp->lookupflags = DO_OPEN | ACCEPT_DIR; + ret = common_dos_loop(mp, arg, &lookupState, O_RDWR); + mp->lookupflags = lookupflags; + if(ret & ERROR_ONE) + return ret; + + if(lookupState.nbDirs) { + mp->targetName = 0; + mp->targetDir = lookupState.Dir; + FREE(&lookupState.container); /* container no longer needed */ + return ret; + } + + switch(lookupState.nbContainers) { + case 0: + /* no match */ + fprintf(stderr,"%s: no match for target\n", arg); + return MISSED_ONE; + case 1: + mp->targetName = strdup(lookupState.filename); + mp->targetDir = lookupState.container; + return ret; + default: + /* too much */ + fprintf(stderr, "Ambigous %s\n", arg); + return ERROR_ONE; + } +} + +static int unix_target_lookup(MainParam_t *mp, const char *arg) +{ + char *ptr; + mp->unixTarget = strdup(arg); + /* try complete filename */ + if(access(mp->unixTarget, F_OK) == 0) + return GOT_ONE; + ptr = strrchr(mp->unixTarget, '/'); + if(!ptr) { + mp->targetName = mp->unixTarget; + mp->unixTarget = strdup("."); + return GOT_ONE; + } else { + *ptr = '\0'; + mp->targetName = ptr+1; + return GOT_ONE; + } +} + +int target_lookup(MainParam_t *mp, const char *arg) +{ + if((mp->lookupflags & NO_UNIX) || (arg[0] && arg[1] == ':' )) + return dos_target_lookup(mp, arg); + else + return unix_target_lookup(mp, arg); +} + +int main_loop(MainParam_t *mp, char **argv, int argc) +{ + int i; + int ret, Bret; + + Bret = 0; + + if(argc != 1 && mp->targetName) { + fprintf(stderr, + "Several file names given, but last argument (%s) not a directory\n", mp->targetName); + } + + for (i = 0; i < argc; i++) { + if ( got_signal ) + break; + mp->originalArg = argv[i]; + mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg), + "*[?") != 0; + if (mp->unixcallback && (!argv[i][0] +#ifdef OS_mingw32msvc +/* On Windows, support only the command-line image drive. */ + || argv[i][0] != ':' +#endif + || argv[i][1] != ':' )) + ret = unix_loop(0, mp, argv[i], 1); + else + ret = dos_loop(mp, argv[i]); + + if (! (ret & (GOT_ONE | ERROR_ONE)) ) { + /* one argument was unmatched */ + fprintf(stderr, "%s: File \"%s\" not found\n", + progname, argv[i]); + ret |= ERROR_ONE; + } + Bret |= ret; + if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE))) + break; + } + FREE(&mp->targetDir); + if(Bret & ERROR_ONE) + return 1; + if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE)) + return 2; + if (Bret & MISSED_ONE) + return 1; + return 0; +} + +static int dispatchToFile(direntry_t *entry, MainParam_t *mp) +{ + if(entry) + return mp->callback(entry, mp); + else + return mp->unixcallback(mp); +} + + +void init_mp(MainParam_t *mp) +{ + fix_mcwd(mp->mcwd); + mp->openflags = O_RDONLY; + mp->targetName = 0; + mp->targetDir = 0; + mp->unixTarget = 0; + mp->dirCallback = dispatchToFile; + mp->unixcallback = NULL; + mp->shortname = mp->longname = 0; + mp->File = 0; + mp->fast_quit = 0; +} + +const char *mpGetBasename(MainParam_t *mp) +{ + if(mp->direntry) { + wchar_to_native(mp->direntry->name, mp->targetBuffer, + MAX_VNAMELEN+1); + return mp->targetBuffer; + } else + return _basename(mp->unixSourceName); +} + +void mpPrintFilename(FILE *fp, MainParam_t *mp) +{ + if(mp->direntry) + fprintPwd(fp, mp->direntry, 0); + else + fprintf(fp,"%s",mp->originalArg); +} + +const char *mpPickTargetName(MainParam_t *mp) +{ + /* picks the target name: either the one explicitly given by the + * user, or the same as the source */ + if(mp->targetName) + return mp->targetName; + else + return mpGetBasename(mp); +} + +char *mpBuildUnixFilename(MainParam_t *mp) +{ + const char *target; + char *ret; + char *tmp; + + target = mpPickTargetName(mp); + ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target)); + if(!ret) + return 0; + strcpy(ret, mp->unixTarget); + if(*target) { +#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */ + if(!mp->targetName && !mp->targetDir) { + struct MT_STAT buf; + if (!MT_STAT(ret, &buf) && !S_ISDIR(buf.st_mode)) + return ret; + } +#endif + strcat(ret, "/"); + if(!strcmp(target, ".")) { + target="DOT"; + } else if(!strcmp(target, "..")) { + target="DOTDOT"; + } + while( (tmp=strchr(target, '/')) ) { + strncat(ret, target, tmp-target); + strcat(ret, "\\"); + target=tmp+1; + } + strcat(ret, target); + } + return ret; +} diff --git a/mainloop.h b/mainloop.h new file mode 100644 index 0000000..940c853 --- /dev/null +++ b/mainloop.h @@ -0,0 +1,101 @@ +#ifndef MTOOLS_MAINLOOP_H +#define MTOOLS_MAINLOOP_H + +/* Copyright 1997,2001,2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include +#include "vfat.h" +#include "mtoolsDirentry.h" + +typedef struct MainParam_t { + /* stuff needing to be initialised by the caller */ + int (*loop)(Stream_t *Dir, struct MainParam_t *mp, + const char *filename); + int (*dirCallback)(direntry_t *, struct MainParam_t *); + int (*callback)(direntry_t *, struct MainParam_t *); + int (*unixcallback)(struct MainParam_t *mp); + + void *arg; /* command-specific parameters + * to be passed to callback */ + + int openflags; /* flags used to open disk */ + int lookupflags; /* flags used to lookup up using vfat_lookup */ + int fast_quit; /* for commands manipulating multiple files, quit + * as soon as even _one_ file has a problem */ + + char *shortname; /* where to put the short name of the matched file */ + char *longname; /* where to put the long name of the matched file */ + + /* out parameters */ + Stream_t *File; + + direntry_t *direntry; /* dir of this entry */ + char *unixSourceName; /* filename of the last opened Unix source + * file (Unix equiv of Dos direntry) */ + + Stream_t *targetDir; /* directory where to place files */ + char *unixTarget; /* directory on Unix where to put files */ + + const char *targetName; /* basename of target file, or NULL if same + * basename as source should be conserved */ + + char *originalArg; /* original argument, complete with wildcards */ + int basenameHasWildcard; /* true if there are wildcards in the + * basename */ + + + /* internal data */ + char mcwd[MAX_PATH+4]; + + char *fileName; /* resolved Unix filename */ + + char targetBuffer[4*MAX_VNAMELEN+1]; /* buffer for target name */ +} MainParam_t; + +void init_mp(MainParam_t *MainParam); +int main_loop(MainParam_t *MainParam, char **argv, int argc); + +int target_lookup(MainParam_t *mp, const char *arg); + +Stream_t *open_root_dir(unsigned char drivename, int flags, int *isRop); + +const char *mpGetBasename(MainParam_t *mp); /* statically allocated + * string */ + +void mpPrintFilename(FILE *file, MainParam_t *mp); +const char *mpPickTargetName(MainParam_t *mp); /* statically allocated string */ + +char *mpBuildUnixFilename(MainParam_t *mp); /* dynamically allocated, must + * be freed */ + +int isSpecial(const char *name); +#ifdef HAVE_WCHAR_H +int isSpecialW(const wchar_t *name); +#else +#define isSpecialW isSpecial +#endif + +#define MISSED_ONE 2 /* set if one cmd line argument didn't match any files */ +#define GOT_ONE 4 /* set if a match was found, used for exit status */ +#define NO_CWD 8 /* file not found while looking for current working + * directory */ +#define ERROR_ONE 16 /* flat out error, such as problems with target file, + interrupt by user, etc. */ +#define STOP_NOW 32 /* stop as soon as possible, not necessarily an error */ + +#endif diff --git a/man-warning-end.texi b/man-warning-end.texi new file mode 100644 index 0000000..12bb530 --- /dev/null +++ b/man-warning-end.texi @@ -0,0 +1,46 @@ +@c Copyright 1998,2001,2002 Alain Knaff. +@c This file is part of mtools +@c Released under the terms of the GNU Free Documentation License, +@c Version 1.3 or any later version published by the Free Software +@c Foundation + +@c for man page version only +@unnumbered See Also +Mtools' texinfo doc +@unnumbered Viewing the texi doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. + +@itemize @bullet +@item +To generate a printable copy from the texinfo doc, run the following +commands: +@example + ./configure; make dvi; dvips mtools.dvi +@end example + +@item +To generate a html copy, run: +@example + ./configure; make html +@end example +A premade html can be found at +@file{http://www.gnu.org/software/mtools/manual/mtools.html} + +@item +To generate an info copy (browsable using emacs' info mode), run: +@example + ./configure; make info +@end example +@end itemize + +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. + diff --git a/man-warning.texi b/man-warning.texi new file mode 100644 index 0000000..4e3ab61 --- /dev/null +++ b/man-warning.texi @@ -0,0 +1,12 @@ +@c Copyright 1997,1998,2001,2002 Alain Knaff. +@c This file is part of mtools +@c Released under the terms of the GNU Free Documentation License, +@c Version 1.3 or any later version published by the Free Software +@c Foundation +@c for man page version only +@unnumbered Note of warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. + +@c skipskipskip diff --git a/match.c b/match.c new file mode 100644 index 0000000..da3a497 --- /dev/null +++ b/match.c @@ -0,0 +1,158 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Do shell-style pattern matching for '?', '\', '[..]', and '*' wildcards. + * Returns 1 if match, 0 if not. + */ + +#include "sysincludes.h" +#include "mtools.h" + + +static int casecmp(wchar_t a, wchar_t b) +{ + return towupper(a) == towupper(b); +} + +static int exactcmp(wchar_t a,wchar_t b) +{ + return a == b; +} + + +static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out, + int (*compfn)(wchar_t a, wchar_t b)) +{ + wchar_t table[256]; + int reverse; + int i; + short first, last; + + if (**p == '^') { + reverse = 1; + (*p)++; + } else + reverse=0; + for(i=0; i<256; i++) + table[i]=0; + while(**p != ']') { + if(!**p) + return 0; + if((*p)[1] == '-') { + first = **p; + (*p)+=2; + if(**p == ']') + last = 256; + else + last = *((*p)++); + for(i=first; i<=last; i++) + table[i] = 1; + } else + table[(int) *((*p)++)] = 1; + } + if(out) + *out = *s; + if(table[(int) *s]) + return 1 ^ reverse; + if(compfn == exactcmp) + return reverse; + if(table[tolower(*s)]) { + if(out) + *out = tolower(*s); + return 1 ^ reverse; + } + if(table[toupper(*s)]) { + if(out) + *out = toupper(*s); + return 1 ^ reverse; + } + return reverse; +} + + +static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, + int length, + int (*compfn) (wchar_t a, wchar_t b)) +{ + for (; *p != '\0' && length; ) { + switch (*p) { + case '?': /* match any one character */ + if (*s == '\0') + return(0); + if(out) + *(out++) = *s; + break; + case '*': /* match everything */ + while (*p == '*' && length) { + p++; + length--; + } + + /* search for next char in pattern */ + while(*s) { + if(_match(s, p, out, Case, length, + compfn)) + return 1; + if(out) + *out++ = *s; + s++; + } + continue; + case '[': /* match range of characters */ + p++; + length--; + if(!parse_range(&p, s, out++, compfn)) + return 0; + break; + case '\\': /* Literal match with next character */ + p++; + length--; + /* fall thru */ + default: + if (!compfn(*s,*p)) + return(0); + if(out) + *(out++) = *p; + break; + } + p++; + length--; + s++; + } + if(out) + *out = '\0'; + + /* string ended prematurely ? */ + if (*s != '\0') + return(0); + else + return(1); +} + + +int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length) +{ + int (*compfn)(wchar_t a, wchar_t b); + + if(Case) + compfn = casecmp; + else + /*compfn = exactcmp;*/ + compfn = casecmp; + return _match(s, p, out, Case, length, compfn); +} + diff --git a/mattrib.1 b/mattrib.1 new file mode 100644 index 0000000..1695521 --- /dev/null +++ b/mattrib.1 @@ -0,0 +1,133 @@ +.TH mattrib 1 "03Nov09" mtools-4.0.12 +.SH Name +mattrib - change MSDOS file attribute flags +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mattrib" +.iX "c Changing file attributes" +.iX "c Hidden files" +.iX "c Read-only files (changing the attribute)" +.iX "c System files" +.iX "c Archive bit" +.PP +\&\fR\&\f(CWMattrib\fR is used to change MS-DOS file attribute flags. It has the +following syntax: +.PP +\&\fR\&\f(CWmattrib\fR [\fR\&\f(CW-a|+a\fR] [\fR\&\f(CW-h|+h\fR] [\fR\&\f(CW-r|+r\fR] +[\fR\&\f(CW-s|+s\fR] [\fR\&\f(CW-/\fR] [\fR\&\f(CW-p\fR] [\fR\&\f(CW-X\fR] \fImsdosfile\fR [ \fImsdosfiles\fR \&... ] +.PP +\&\fR\&\f(CWMattrib\fR adds attribute flags to an MS-DOS file (with the +`\fR\&\f(CW+\fR' operator) or remove attribute flags (with the `\fR\&\f(CW-\fR' +operator). +.PP +\&\fR\&\f(CWMattrib\fR supports the following attribute bits: +.TP +\&\fR\&\f(CWa\fR\ +Archive bit. Used by some backup programs to indicate a new file. +.TP +\&\fR\&\f(CWr\fR\ +Read-only bit. Used to indicate a read-only file. Files with this bit +set cannot be erased by \fR\&\f(CWDEL\fR nor modified. +.TP +\&\fR\&\f(CWs\fR\ +System bit. Used by MS-DOS to indicate a operating system file. +.TP +\&\fR\&\f(CWh\fR\ +Hidden bit. Used to make files hidden from \fR\&\f(CWDIR\fR. +.PP +\&\fR\&\f(CWMattrib\fR supports the following command line flags: +.TP +\&\fR\&\f(CW/\fR\ +Recursive. Recursively list the attributes of the files in the subdirectories. +.TP +\&\fR\&\f(CWX\fR\ +Concise. Prints the attributes whithout any whitespace padding. If +neither the "/" option is given, nor the \fImsdosfile\fR contains a +wildcard, and there is only one Msdos file parameter on the command +line, only the attribute is printed, and not the filename. This option +is convenient for scripts +.TP +\&\fR\&\f(CWp\fR\ +Replay mode. Outputs a series of mformat commands that will reproduce +the current situation, starting from a situation as left by untarring +the Dos filesystem. Commands are only output for attribute settings +that differ from the default (archive bit set for files, unset for +directories). This option is intended to be used in addition to +tar. The \fR\&\f(CWreadonly\fR attribute is not taken into account, as tar can +set that one itself. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mattrib.c b/mattrib.c new file mode 100644 index 0000000..dd6ca20 --- /dev/null +++ b/mattrib.c @@ -0,0 +1,258 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-1998,2000-2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mattrib.c + * Change MSDOS file attribute flags + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "mainloop.h" + +typedef struct Arg_t { + char add; + unsigned char remove; + struct MainParam_t mp; + int recursive; + int doPrintName; +} Arg_t; + +static int attrib_file(direntry_t *entry, MainParam_t *mp) +{ + Arg_t *arg=(Arg_t *) mp->arg; + + if(entry->entry != -3) { + /* if not root directory, change it */ + entry->dir.attr = (entry->dir.attr & arg->remove) | arg->add; + dir_write(entry); + } + return GOT_ONE; +} + +static int replay_attrib(direntry_t *entry, MainParam_t *mp) +{ + if ( (IS_ARCHIVE(entry) && IS_DIR(entry)) || + (!IS_ARCHIVE(entry) && !IS_DIR(entry)) || + IS_SYSTEM(entry) || IS_HIDDEN(entry)) { + + printf("mattrib "); + + if (IS_ARCHIVE(entry) && IS_DIR(entry)) { + printf("+a "); + } + + if (!IS_ARCHIVE(entry) && !IS_DIR(entry)) { + printf("-a "); + } + + if (IS_SYSTEM(entry)) { + printf("+s "); + } + + if (IS_HIDDEN(entry)) { + printf("+h "); + } + + fprintPwd(stdout, entry, 1); + printf("\n"); + } + return GOT_ONE; +} + + + +static int view_attrib(direntry_t *entry, MainParam_t *mp) +{ + printf(" "); + if(IS_ARCHIVE(entry)) + putchar('A'); + else + putchar(' '); + fputs(" ",stdout); + if(IS_SYSTEM(entry)) + putchar('S'); + else + putchar(' '); + if(IS_HIDDEN(entry)) + putchar('H'); + else + putchar(' '); + if(IS_READONLY(entry)) + putchar('R'); + else + putchar(' '); + printf(" "); + fprintPwd(stdout, entry, 0); + printf("\n"); + return GOT_ONE; +} + + +static int concise_view_attrib(direntry_t *entry, MainParam_t *mp) +{ + Arg_t *arg=(Arg_t *) mp->arg; + + if(IS_ARCHIVE(entry)) + putchar('A'); + if(IS_DIR(entry)) + putchar('D'); + if(IS_SYSTEM(entry)) + putchar('S'); + if(IS_HIDDEN(entry)) + putchar('H'); + if(IS_READONLY(entry)) + putchar('R'); + if(arg->doPrintName) { + putchar(' '); + fprintPwd(stdout, entry, 0); + } + putchar('\n'); + return GOT_ONE; +} + +static int recursive_attrib(direntry_t *entry, MainParam_t *mp) +{ + mp->callback(entry, mp); + return mp->loop(mp->File, mp, "*"); +} + + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, + "Usage: %s [-p] [-a|+a] [-h|+h] [-r|+r] [-s|+s] msdosfile [msdosfiles...]\n", + progname); + exit(ret); +} + +static int letterToCode(int letter) +{ + switch (toupper(letter)) { + case 'A': + return ATTR_ARCHIVE; + case 'H': + return ATTR_HIDDEN; + case 'R': + return ATTR_READONLY; + case 'S': + return ATTR_SYSTEM; + default: + usage(1); + } +} + + +void mattrib(int argc, char **argv, int type) +{ + Arg_t arg; + int view; + int c; + int concise; + int replay; + char *ptr; + int wantUsage; + + arg.add = 0; + arg.remove = 0xff; + arg.recursive = 0; + arg.doPrintName = 1; + view = 0; + concise = 0; + replay = 0; + wantUsage = 0; + + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:/ahrsAHRSXp")) != EOF) { + switch (c) { + case 'h': + wantUsage = 1; + /* FALL THROUGH */ + default: + arg.remove &= ~letterToCode(c); + break; + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'p': + replay = 1; + break; + case '/': + arg.recursive = 1; + break; + case 'X': + concise = 1; + break; + case '?': + usage(1); + } + } + + if(optind == argc && wantUsage) { + usage(0); + } + + for(;optind < argc;optind++) { + switch(argv[optind][0]) { + case '+': + for(ptr = argv[optind] + 1; *ptr; ptr++) + arg.add |= letterToCode(*ptr); + continue; + case '-': + for(ptr = argv[optind] + 1; *ptr; ptr++) + arg.remove &= ~letterToCode(*ptr); + continue; + } + break; + } + + if(arg.remove == 0xff && !arg.add) + view = 1; + + if (optind >= argc) + usage(1); + + init_mp(&arg.mp); + if(view){ + if(concise) { + arg.mp.callback = concise_view_attrib; + arg.doPrintName = (argc - optind > 1 || + arg.recursive || + strpbrk(argv[optind], "*[?") != 0); + } else if (replay) { + arg.mp.callback = replay_attrib; + } else + arg.mp.callback = view_attrib; + arg.mp.openflags = O_RDONLY; + } else { + arg.mp.callback = attrib_file; + arg.mp.openflags = O_RDWR; + } + + if(arg.recursive) + arg.mp.dirCallback = recursive_attrib; + + arg.mp.arg = (void *) &arg; + arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR; + if(arg.recursive) + arg.mp.lookupflags |= DO_OPEN_DIRS | NO_DOTS; + exit(main_loop(&arg.mp, argv + optind, argc - optind)); +} diff --git a/mbadblocks.1 b/mbadblocks.1 new file mode 100644 index 0000000..ffae70c --- /dev/null +++ b/mbadblocks.1 @@ -0,0 +1,98 @@ +.TH mbadblocks 1 "03Nov09" mtools-4.0.12 +.SH Name +mbadblocks - tests a floppy disk, and marks the bad blocks in the FAT +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.PP +The \fR\&\f(CWmbadblocks\fR command is used to scan an MS-DOS floppy and mark +its unused bad blocks as bad. It uses the following syntax: +.PP +\&\fR\&\f(CWmbadblocks\fR \fIdrive\fR\fR\&\f(CW:\fR +.iX "p mbadblocks" +.iX "c Marking blocks as bad" +.iX "c Bad blocks" +.iX "c Read errors" +.PP +\&\fR\&\f(CWMbadblocks\fR scans an MS-DOS floppy for bad blocks. All unused bad +blocks are marked as such in the FAT. This is intended to be used right +after \fR\&\f(CWmformat\fR. It is not intended to salvage bad disks. +.SH Bugs +\&\fR\&\f(CWMbadblocks\fR should (but doesn't yet :-( ) also try to salvage bad +blocks which are in use by reading them repeatedly, and then mark them +bad. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mbadblocks.c b/mbadblocks.c new file mode 100644 index 0000000..1ac35a2 --- /dev/null +++ b/mbadblocks.c @@ -0,0 +1,92 @@ +/* Copyright 1995-1999,2001-2003,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mbadblocks.c + * Mark bad blocks on disk + * + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "mainloop.h" +#include "fsP.h" + +void mbadblocks(int argc, char **argv, int type) +{ + unsigned int i; + char *in_buf; + int in_len; + off_t start; + struct MainParam_t mp; + Fs_t *Fs; + Stream_t *Dir; + int ret; + + if (argc != 2 || !argv[1][0] || argv[1][1] != ':' || argv[1][2]) { + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, "Usage: %s [-V] device\n", argv[0]); + exit(1); + } + + init_mp(&mp); + + Dir = open_root_dir(argv[1][0], O_RDWR, NULL); + if (!Dir) { + fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]); + exit(1); + } + + Fs = (Fs_t *)GetFs(Dir); + in_len = Fs->cluster_size * Fs->sector_size; + in_buf = malloc(in_len); + if(!in_buf) { + FREE(&Dir); + printOom(); + exit(1); + } + for(i=0; i < Fs->clus_start; i++ ){ + ret = READS(Fs->Next, in_buf, + sectorsToBytes((Stream_t*)Fs, i), Fs->sector_size); + if( ret < 0 ){ + perror("early error"); + exit(1); + } + if(ret < (signed int) Fs->sector_size){ + fprintf(stderr,"end of file in file_read\n"); + exit(1); + } + } + + in_len = Fs->cluster_size * Fs->sector_size; + for(i=2; i< Fs->num_clus + 2; i++){ + if(got_signal) + break; + if(Fs->fat_decode((Fs_t*)Fs,i)) + continue; + start = (i - 2) * Fs->cluster_size + Fs->clus_start; + ret = force_read(Fs->Next, in_buf, + sectorsToBytes((Stream_t*)Fs, start), in_len); + if(ret < in_len ){ + printf("Bad cluster %d found\n", i); + fatEncode((Fs_t*)Fs, i, 0xfff7); + continue; + } + } + FREE(&Dir); + exit(0); +} diff --git a/mcat.1 b/mcat.1 new file mode 100644 index 0000000..0fb7dff --- /dev/null +++ b/mcat.1 @@ -0,0 +1,103 @@ +.TH mcat 1 "03Nov09" mtools-4.0.12 +.SH Name +mcat - dump raw disk image +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.PP +The \fR\&\f(CWmcat\fR command is used to copy an entire disk image from or +to the floppy device. It uses the following syntax: +.PP +\&\fR\&\f(CWmcat\fR [\fR\&\f(CW-w\fR] \fIdrive\fR\fR\&\f(CW:\fR +.iX "p mcat" +.iX "c Copying an entire disk image" +.iX "c Disk image" +.iX "c Floppyd cat" +.PP +\&\fR\&\f(CWMcat\fR performs the same task as the unix \fR\&\f(CWcat\fR command. It +is included into the mtools package, since \fR\&\f(CWcat\fR cannot access +remote floppy devices offered by the mtools floppy daemon. +Now it is possible to create boot floppies remotely. +.PP +The default operation is reading. The output is written to stdout. +.PP +If the \fR\&\f(CW-w\fR option is specified, mcat reads a disk-image from +stdin and writes it to the given device. +\&\fBUse this carefully!\fR Because of the lowlevel nature of this +command, it will happily destroy any data written before on the +disk without warning! +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mcat.c b/mcat.c new file mode 100644 index 0000000..1adead5 --- /dev/null +++ b/mcat.c @@ -0,0 +1,162 @@ +/* Copyright 1999-2003,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mcat.c + * Same thing as cat /dev/fd0 or cat file >/dev/fd0 + * Something, that isn't possible with floppyd anymore. + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "mainloop.h" +#include "fsP.h" +#include "xdf_io.h" +#include "floppyd_io.h" +#include "plain_io.h" + +static void usage(void) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, "Usage: mcat [-V] [-w] device\n"); + fprintf(stderr, " -w write on device else read\n"); + exit(1); +} + +#ifdef __CYGWIN__ +#define BUF_SIZE 512 +#else +#define BUF_SIZE 16000 +#endif + +static size_t bufLen(size_t blocksize, mt_size_t totalSize, mt_off_t address) +{ + if(totalSize == 0) + return blocksize; + if(address + blocksize > totalSize) + return totalSize - address; + return blocksize; +} + +void mcat(int argc, char **argv, int type) +{ + struct device *dev; + struct device out_dev; + char drive, name[EXPAND_BUF]; + char errmsg[200]; + Stream_t *Stream; + char buf[BUF_SIZE]; + + mt_off_t address = 0; + + char mode = O_RDONLY; + int optindex = 1; + size_t len; + + noPrivileges = 1; + + if (argc < 2) { + usage(); + } + + if (argv[1][0] == '-') { + if (argv[1][1] != 'w') { + usage(); + } + mode = O_WRONLY; + optindex++; + } + + if (argc - optindex < 1) + usage(); + + + if (!argv[optindex][0] || argv[optindex][1] != ':' + || argv[optindex][2]) { + usage(); + } + + drive = toupper(argv[optindex][0]); + + /* check out a drive whose letter and parameters match */ + sprintf(errmsg, "Drive '%c:' not supported", drive); + Stream = NULL; + for (dev=devices; dev->name; dev++) { + FREE(&Stream); + if (dev->drive != drive) + continue; + out_dev = *dev; + expand(dev->name,name); +#ifdef USING_NEW_VOLD + strcpy(name, getVoldName(dev, name)); +#endif + + Stream = 0; +#ifdef USE_XDF + Stream = XdfOpen(&out_dev, name, mode, errmsg, 0); + if(Stream) + out_dev.use_2m = 0x7f; + +#endif + +#ifdef USE_FLOPPYD + if(!Stream) + Stream = FloppydOpen(&out_dev, dev, name, + mode, errmsg, 0, 1); +#endif + + + if (!Stream) + Stream = SimpleFileOpen(&out_dev, dev, name, mode, + errmsg, 0, 1, 0); + + if( !Stream) + continue; + break; + } + + /* print error msg if needed */ + if ( dev->drive == 0 ){ + FREE(&Stream); + fprintf(stderr,"%s\n",errmsg); + exit(1); + } + + + if (mode == O_WRONLY) { + mt_size_t size=0; + size = out_dev.sectors * out_dev.heads * out_dev.tracks; + size *= 512; + while ((len = fread(buf, 1, + bufLen(BUF_SIZE, size, address), + stdin)) > 0) { + int r = WRITES(Stream, buf, address, len); + fprintf(stderr, "Wrote to %d\n", (int) address); + if(r < 0) + break; + address += len; + } + } else { + while ((len = READS(Stream, buf, address, BUF_SIZE)) > 0) { + fwrite(buf, 1, len, stdout); + address += len; + } + } + + FREE(&Stream); + exit(0); +} diff --git a/mcd.1 b/mcd.1 new file mode 100644 index 0000000..a0cc7ba --- /dev/null +++ b/mcd.1 @@ -0,0 +1,116 @@ +.TH mcd 1 "03Nov09" mtools-4.0.12 +.SH Name +mcd - change MSDOS directory +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mcd" +.iX "c Directory (changing)" +.iX "c Working directory" +.iX "c Current working directory (changing the)" +.iX "c Default directory (changing the)" +.iX "c Mcwd file" +.PP +The \fR\&\f(CWmcd\fR command is used to change the mtools working directory +on the MS-DOS disk. It uses the following syntax: +.PP + +.nf +.ft 3 +.in +0.3i +\&\fR\&\f(CWmcd [\fImsdosdirectory\fR\&\f(CW] +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +Without arguments, \fR\&\f(CWmcd\fR reports the current device and working +directory. Otherwise, \fR\&\f(CWmcd\fR changes the current device and current +working directory relative to an MS-DOS filesystem. +.PP +The environmental variable \fR\&\f(CWMCWD\fR may be used to locate the file +where the device and current working directory information is stored. +The default is \fR\&\f(CW\(if$HOME/.mcwd\(is\fR. Information in this file is ignored +if the file is more than 6 hours old. +.PP +\&\fR\&\f(CWMcd\fR returns 0 on success or 1 on failure. +.PP +Unlike MS-DOS versions of \fR\&\f(CWCD\fR, \fR\&\f(CWmcd\fR can be used to change to +another device. It may be wise to remove old \fR\&\f(CW\(if.mcwd\(is\fR files at logout. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mcd.c b/mcd.c new file mode 100644 index 0000000..21f5e44 --- /dev/null +++ b/mcd.c @@ -0,0 +1,62 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996,1997,2000-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mcd.c: Change MSDOS directories + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mainloop.h" +#include "mtools.h" + + +static int mcd_callback(direntry_t *entry, MainParam_t *mp) +{ + FILE *fp; + + if (!(fp = open_mcwd("w"))){ + fprintf(stderr,"mcd: Can't open mcwd .file for writing\n"); + return ERROR_ONE; + } + + fprintPwd(fp, entry,0); + fprintf(fp, "\n"); + fclose(fp); + return GOT_ONE | STOP_NOW; +} + + +void mcd(int argc, char **argv, int type) +{ + struct MainParam_t mp; + + if (argc > 2) { + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, "Usage: %s: [-V] msdosdirectory\n", argv[0]); + exit(1); + } + + init_mp(&mp); + mp.lookupflags = ACCEPT_DIR | NO_DOTS; + mp.dirCallback = mcd_callback; + if (argc == 1) { + printf("%s\n", mp.mcwd); + exit(0); + } else + exit(main_loop(&mp, argv + 1, 1)); +} diff --git a/mclasserase.1 b/mclasserase.1 new file mode 100644 index 0000000..9a7675c --- /dev/null +++ b/mclasserase.1 @@ -0,0 +1,115 @@ +.TH mclasserase 1 "03Nov09" mtools-4.0.12 +.SH Name +mclasserase - erase memory cards +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mclasserase" +.iX "c Memory Card" +.iX "c Physically erase" +.PP +The \fR\&\f(CWmclasserase\fR command is used to wipe memory cards by +overwriting it three times: first with \fR\&\f(CW0xff\fR, then with +\&\fR\&\f(CW0x00\fR, then with \fR\&\f(CW0xff\fR again. The command uses the following +syntax: +.PP + +.nf +.ft 3 +.in +0.3i +\&\fR\&\f(CWmclasserase [\fR\&\f(CW-d] \fImsdosdrive\fR\&\f(CW +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +Dos drive is optional, if none is specified, use \fR\&\f(CWA:\fR. If more than +one drive are specified, all but the last are ignored. +.PP +\&\fR\&\f(CWMclasserase\fR accepts the following command line options: +.TP +\&\fR\&\f(CWd\fR\ +Stop after each erase cycle, for testing purposes +.TP +\&\fR\&\f(CWp\fR\ +Not yet implemented +.PP +\&\fR\&\f(CWMclasserase\fR returns 0 on success or -1 on failure. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP +mclasserase diff --git a/mclasserase.c b/mclasserase.c new file mode 100644 index 0000000..1cbe023 --- /dev/null +++ b/mclasserase.c @@ -0,0 +1,351 @@ +/* Copyright 2003 Stefan Feuz, Lukas Meyer, Thomas Locher + * Copyright 2004,2006,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Filename: + * mclasserase.c + * + * Original Creation Date: + * 05.III.2003 + * + * Copyright: + * GPL + * + * Programmer: + * Stefan Feuz, Lukas Meyer, Thomas Locher + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "fsP.h" + +#ifdef HAVE_GETOPT_H +#include +#endif + +#include "file.h" + +#include +#include + +/** + * Prints the Usage Message to STDOUT
+ * + * @author stefan feuz
+ * stefan.feuz@ruag.com + * + * @param n.a. + * + * @returns n.a. + * + */ +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, "Usage: %s [-d] drive:\n", progname); + exit(ret); +} + +/** + * Delete all files on a Drive.
+ * + * @author Lukas Meyer
+ * lukas.meyer@ruag.com + * @version 0.4, 11.12.2003 + * + * @param drive the drive to erase + * @param debug 1: stop after each erase cycle, 0: normal mode + * + * @returns n.a. + * + */ +static void do_mclasserase(char drive,int debug) +{ + struct device dev; /* Device information structure */ + union bootsector boot; + + int media; /* Just used to enter some in find_device */ + char name[EXPAND_BUF]; + Stream_t *Stream; + struct label_blk_t *labelBlock; + + FILE * fDevice; /* Stores device's file descriptor */ + + char cCardType[12]; + + char drivel[2]; /* Stores the drive letter */ + + + int i = 0; + + /* FILE *forf; */ + + char dummy[2]; /* dummy input for debugging purposes.. */ + int icount=0; + int iTotalErase = 0; + + const int cycles = 3; /* How many times we'll overwrite the media */ + char odat[cycles]; /* Data for each overwrite procedure */ + + /* Creating values for overwrite */ + odat[0]=0xff; + odat[1]=0x00; + odat[2]=0xff; + + + if (debug == 1) + printf("cycles: %i, odats: %i,%i,%i\n",cycles,odat[0],odat[1],odat[2]); + + + + /* Reading parameters from card. Exit with -1 if failed. */ + if(! (Stream = find_device(drive, O_RDONLY, &dev, &boot, + name, &media, 0, NULL))) + exit(1); + + FREE(&Stream); + + /* Determine the FAT - type */ +#if 0 + if(WORD(fatlen)) { + labelBlock = &bbelBlock = &boot->ext.old.labelBlock; + } else { + labelBlock = &boot->ext.fat32.labelBlock; + } +#endif + + /* we use only FAT12/16 ...*/ + labelBlock = &boot.boot.ext.old.labelBlock; + + /* store card type */ + sprintf(cCardType, "%11.11s", labelBlock->label); + + if (debug == 1) + { + printf("Using Device: %s\n",name); + printf("Card-Type detected: %s\n",cCardType); + } + + /* Forming cat command to overwrite the medias content. */ + sprintf( drivel, "%c:", tolower(drive) ); + +#if 0 + media_sectors = dev.tracks * dev.sectors; + sector_size = WORD(secsiz) * dev.heads; + + + printf(mcat); + printf("\n%d\n", media_sectors); + printf("%d\n", sector_size); +#endif + + /* + * Overwrite device + */ + for( i=0; i < cycles; i++){ + + if (debug==1) + { + printf("Erase Cycle %i, writing data: 0x%2.2x...\n",i+1,odat[i]); + } + + fDevice = fopen(name,"ab+"); + + if (fDevice == 0) + { + perror("Error opening device"); + exit(-1); + } + + + if (debug==1) + { + printf("Open successful...\n"); + printf("Flushing device after 32 kBytes of data...\n"); + printf("Erasing:"); + fflush( stdout ); + } + + /* iTotalErase = 0; */ + + /* + * overwrite the whole device + */ + while ((feof(fDevice)==0) && (ferror(fDevice)==0)) + { + + fputc(odat[i],fDevice); + + icount++; + if (icount > (32 * 1024)) + { + /* flush device every 32KB of data...*/ + fflush( fDevice ); + + iTotalErase += icount; + if (debug == 1) + { + printf("."); + fflush( stdout ); + } + icount=0; + } + } + + if (debug==1) + { + printf("\nPress to continue\n"); + printf("Press and to abort\n"); + + if(scanf("%c",dummy) < 1) + printf("Input error\n"); + fflush( stdin ); + + if (strcmp(dummy,"x") == 0) + { + printf("exiting.\n"); + exit(0); + } + } + + fclose(fDevice); + + } + + + /* + * Format device using shell script + */ + if (debug == 0) + { + /* redirect STDERR and STDOUT to the black hole... */ + if (dup2(open("/dev/null", O_WRONLY), STDERR_FILENO) != STDERR_FILENO) + printf("Error with dup2() stdout\n"); + if (dup2(open("/dev/null", O_WRONLY), STDOUT_FILENO) != STDOUT_FILENO) + printf("Error with dup2() stdout\n"); + } + + if (debug == 1) + printf("Calling amuFormat.sh with args: %s,%s\n",cCardType,drivel); + + execlp("amuFormat.sh","",cCardType,drivel,NULL); + + /* we never come back...(we shouldn't come back ...) */ + exit(-1); + +} + + +/** + * Total Erase of Data on a Disk. After using mclasserase there wont + * be ANY bits of old files on the disk.
+ * + * @author stefan feuz
+ * thomas locher
+ * stefan.feuz@ruag.com + * thomas.locher@ruag.com + * @version 0.3, 02.12.2003 + * + * @param argc generated automatically by operating systems + * @param **argv1 generated automatically by operating systems + * @param type generated automatically by operating systems + * + * @param -d stop after each erase cycle, for testing purposes + * + * @returns int 0 if all is well done
+ * int -1 if there is something wrong + * + * @info mclasserase [-p tempFilePath] [-d] drive: + * + * + */ +void mclasserase(int argc, char **argv, int type) +{ + /* declaration of all variables */ + int c; + int debug=0; + /* char* tempFilePath=NULL; */ + char drive='a'; + + int extern optind; + + destroy_privs(); + + /* check and read command line arguments */ +#ifdef DEBUG + printf("mclasserase: argc = %i\n",argc); +#endif + /* check num of arguments */ + if(helpFlag(argc, argv)) + usage(0); + if ( (argc != 2) & (argc != 3) & (argc != 4)) + { /* wrong num of arguments */ + printf ("mclasserase: wrong num of args\n"); + usage(1); + } + else + { /* correct num of arguments */ + while ((c = getopt(argc, argv, "+p:dh")) != EOF) + { + switch (c) + { + + case 'd': + + printf("=============\n"); + printf("Debug Mode...\n"); + printf("=============\n"); + debug = 1; + break; + case 'p': + printf("option -p not implemented yet\n"); + break; + case 'h': + usage(0); + case '?': + usage(1); + default: + break; + } + } +#ifdef DEBUG + printf("mclasserase: optind = %i\n",optind); + /* look for the drive to erase */ + printf("mclasserase: searching drive\n"); +#endif + for(; optind < argc; optind++) + { + if(!argv[optind][0] || argv[optind][1] != ':') + { + usage(1); + } + drive = toupper(argv[optind][0]); + } + } +#ifdef DEBUG + printf("mclasserase: found drive %c\n", drive); +#endif + /* remove all data on drive, you never come back if drive does + * not exist */ + + do_mclasserase(drive,debug); + + exit (0); +} diff --git a/mcopy.1 b/mcopy.1 new file mode 100644 index 0000000..3aa488b --- /dev/null +++ b/mcopy.1 @@ -0,0 +1,183 @@ +.TH mcopy 1 "03Nov09" mtools-4.0.12 +.SH Name +mcopy - copy MSDOS files to/from Unix +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mcopy" +.iX "c Reading MS-DOS files" +.iX "c Writing MS-DOS files" +.iX "c Copying MS-DOS files" +.iX "c Concatenating MS-DOS files" +.iX "c Text files" +.iX "c CR/LF conversions" +.PP +The \fR\&\f(CWmcopy\fR command is used to copy MS-DOS files to and from +Unix. It uses the following syntax: +.PP + +.nf +.ft 3 +.in +0.3i +\&\fR\&\f(CWmcopy [\fR\&\f(CW-bspanvmQT] [\fR\&\f(CW-D \fIclash_option\fR\&\f(CW] \fIsourcefile\fR\&\f(CW \fItargetfile\fR\&\f(CW +\&\fR\&\f(CWmcopy [\fR\&\f(CW-bspanvmQT] [\fR\&\f(CW-D \fIclash_option\fR\&\f(CW] \fIsourcefile\fR\&\f(CW [ \fIsourcefiles\fR\&\f(CW\&... ] \fItargetdirectory\fR\&\f(CW +\&\fR\&\f(CWmcopy [\fR\&\f(CW-tnvm] \fIMSDOSsourcefile\fR\&\f(CW +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +\&\fR\&\f(CWMcopy\fR copies the specified file to the named file, or copies +multiple files to the named directory. The source and target can be +either MS-DOS or Unix files. +.PP +The use of a drive letter designation on the MS-DOS files, 'a:' for +example, determines the direction of the transfer. A missing drive +designation implies a Unix file whose path starts in the current +directory. If a source drive letter is specified with no attached file +name (e.g. \fR\&\f(CWmcopy a: .\fR), all files are copied from that drive. +.PP +If only a single, MS-DOS source parameter is provided (e.g. "mcopy +a:foo.exe"), an implied destination of the current directory +(`\fR\&\f(CW.\fR') is assumed. +.PP +A filename of `\fR\&\f(CW-\fR' means standard input or standard output, depending +on its position on the command line. +.PP +\&\fR\&\f(CWMcopy\fR accepts the following command line options: +.TP +\&\fR\&\f(CWt\fR\ +Text file transfer. Mcopy translates incoming carriage return/line +feeds to line feeds when copying from Dos to Unix, and vice-versa when +copying from Unix to Dos. +.TP +\&\fR\&\f(CWb\fR\ +Batch mode. Optimized for huge recursive copies, but less secure if a +crash happens during the copy. +.TP +\&\fR\&\f(CWs\fR\ +Recursive copy. Also copies directories and their contents +.TP +\&\fR\&\f(CWp\fR\ +Preserves the attributes of the copied files +.TP +\&\fR\&\f(CWQ\fR\ +When mcopying multiple files, quits as soon as one copy fails (for +example due to lacking storage space on the target disk) +.TP +\&\fR\&\f(CWa\fR\ +Text (Ascii) file transfer. \fR\&\f(CWMcopy\fR translates incoming carriage +return/line feeds to line feeds. +.TP +\&\fR\&\f(CWT\fR\ +Text (Ascii) file transfer with charset conversion. Differs from +\&\fR\&\f(CW-a\fR in the \fR\&\f(CWMcopy\fR also translates incoming PC-8 characters +to ISO-8859-1 equivalents as far as possible. When reading DOS files, +untranslatable characters are replaced by '\fR\&\f(CW#\fR'; when writing DOS files, +untranslatable characters are replaced by '\fR\&\f(CW.\fR'. +.TP +\&\fR\&\f(CWn\fR\ +No confirmation when overwriting Unix files. \fR\&\f(CWMcopy\fR doesn't warn +the user when overwriting an existing Unix file. If the target file already exists, +and the \fR\&\f(CW-n\fR option is not in effect, \fR\&\f(CWmcopy\fR asks whether to +overwrite the file or to rename the new file (\(ifname clashes\(is) for +details). In order to switch off confirmation for DOS files, use \fR\&\f(CW-o\fR. +.TP +\&\fR\&\f(CWm\fR\ +Preserve the file modification time. +.TP +\&\fR\&\f(CWv\fR\ +Verbose. Displays the name of each file as it is copied. +.PP +.SH Bugs +Unlike MS-DOS, the '+' operator (append) from MS-DOS is not +supported. However, you may use \fR\&\f(CWmtype\fR to produce the same effect: + +.nf +.ft 3 +.in +0.3i +mtype a:file1 a:file2 a:file3 >unixfile +mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mcopy.c b/mcopy.c new file mode 100644 index 0000000..0074489 --- /dev/null +++ b/mcopy.c @@ -0,0 +1,635 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1994,1996-2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mcopy.c + * Copy an MSDOS files to and from Unix + * + */ + + +#define LOWERCASE + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "plain_io.h" +#include "nameclash.h" +#include "file.h" +#include "fs.h" + + +/* + * Preserve the file modification times after the fclose() + */ + +static void set_mtime(const char *target, time_t mtime) +{ + if (target && strcmp(target, "-") && mtime != 0L) { +#ifdef HAVE_UTIMES + struct timeval tv[2]; + tv[0].tv_sec = mtime; + tv[0].tv_usec = 0; + tv[1].tv_sec = mtime; + tv[1].tv_usec = 0; + utimes((char *)target, tv); +#else +#ifdef HAVE_UTIME + struct utimbuf utbuf; + + utbuf.actime = mtime; + utbuf.modtime = mtime; + utime(target, &utbuf); +#endif +#endif + } + return; +} + +typedef struct Arg_t { + int recursive; + int preserveAttributes; + int preserveTime; + unsigned char attr; + char *path; + int textmode; + int needfilter; + int nowarn; + int verbose; + int type; + int convertCharset; + MainParam_t mp; + ClashHandling_t ch; + int noClobber; +} Arg_t; + +static int _unix_write(direntry_t *entry, MainParam_t *mp, int needfilter, + const char *unixFile); + +/* Write the Unix file */ +static int unix_write(direntry_t *entry, MainParam_t *mp, int needfilter) +{ + Arg_t *arg=(Arg_t *) mp->arg; + + if(arg->type) + return _unix_write(entry, mp, needfilter, "-"); + else { + char *unixFile = mpBuildUnixFilename(mp); + int ret; + if(!unixFile) { + printOom(); + return ERROR_ONE; + } + ret = _unix_write(entry, mp, needfilter, unixFile); + free(unixFile); + return ret; + } +} + + +/* Write the Unix file */ +static int _unix_write(direntry_t *entry, MainParam_t *mp, int needfilter, + const char *unixFile) +{ + Arg_t *arg=(Arg_t *) mp->arg; + time_t mtime; + Stream_t *File=mp->File; + Stream_t *Target, *Source; + struct MT_STAT stbuf; + int ret; + char errmsg[80]; + + File->Class->get_data(File, &mtime, 0, 0, 0); + + if (!arg->preserveTime) + mtime = 0L; + + /* if we are creating a file, check whether it already exists */ + if(!arg->type) { + if (!arg->nowarn && &arg->type && !access(unixFile, 0)){ + if(arg->noClobber) { + fprintf(stderr, "File \"%s\" exists. To overwrite, try again, and explicitly specify target directory\n",unixFile); + return ERROR_ONE; + } + + /* sanity checking */ + if (!MT_STAT(unixFile, &stbuf)) { + struct MT_STAT srcStbuf; + int sFd; /* Source file descriptor */ + if(!S_ISREG(stbuf.st_mode)) { + fprintf(stderr,"\"%s\" is not a regular file\n", + unixFile); + + return ERROR_ONE; + } + sFd = get_fd(File); + if(sFd == -1) { + fprintf(stderr, "Not ok Unix file ==> good\n"); + } + if((!MT_FSTAT(sFd, &srcStbuf)) && + stbuf.st_dev == srcStbuf.st_dev && + stbuf.st_ino == srcStbuf.st_ino) { + fprintf(stderr, "Attempt to copy file on itself\n"); + return ERROR_ONE; + } + } + + if( ask_confirmation("File \"%s\" exists, overwrite (y/n) ? ", + unixFile)) { + return ERROR_ONE; + } + + } + } + + if(!arg->type && arg->verbose) { + fprintf(stderr,"Copying "); + mpPrintFilename(stderr,mp); + fprintf(stderr,"\n"); + } + + if(got_signal) { + return ERROR_ONE; + } + + if ((Target = SimpleFileOpen(0, 0, unixFile, + O_WRONLY | O_CREAT | O_TRUNC, + errmsg, 0, 0, 0))) { + ret = 0; + if(needfilter && arg->textmode){ + Source = open_filter(COPY(File),arg->convertCharset); + if (!Source) + ret = -1; + } else + Source = COPY(File); + + if (ret == 0 ) + ret = copyfile(Source, Target); + FREE(&Source); + FREE(&Target); + if(ret <= -1){ + if(!arg->type) + unlink(unixFile); + return ERROR_ONE; + } + if(!arg->type) + set_mtime(unixFile, mtime); + return GOT_ONE; + } else { + fprintf(stderr,"%s\n", errmsg); + return ERROR_ONE; + } +} + +static int makeUnixDir(char *filename) +{ + if(!mkdir(filename +#ifndef OS_mingw32msvc + , 0777 +#endif + )) + return 0; + if(errno == EEXIST) { + struct MT_STAT buf; + if(MT_STAT(filename, &buf) < 0) + return -1; + if(S_ISDIR(buf.st_mode)) + return 0; + errno = ENOTDIR; + } + return -1; +} + +/* Copy a directory to Unix */ +static int unix_copydir(direntry_t *entry, MainParam_t *mp) +{ + Arg_t *arg=(Arg_t *) mp->arg; + time_t mtime; + Stream_t *File=mp->File; + int ret; + char *unixFile; + + if (!arg->recursive && mp->basenameHasWildcard) + return 0; + + File->Class->get_data(File, &mtime, 0, 0, 0); + if (!arg->preserveTime) + mtime = 0L; + if(!arg->type && arg->verbose) { + fprintf(stderr,"Copying "); + fprintPwd(stderr, entry,0); + fprintf(stderr, "\n"); + } + if(got_signal) + return ERROR_ONE; + unixFile = mpBuildUnixFilename(mp); + if(!unixFile) { + printOom(); + return ERROR_ONE; + } + if(arg->type || !*mpPickTargetName(mp) || !makeUnixDir(unixFile)) { + Arg_t newArg; + + newArg = *arg; + newArg.mp.arg = (void *) &newArg; + newArg.mp.unixTarget = unixFile; + newArg.mp.targetName = 0; + newArg.mp.basenameHasWildcard = 1; + + ret = mp->loop(File, &newArg.mp, "*"); + set_mtime(unixFile, mtime); + free(unixFile); + return ret | GOT_ONE; + } else { + perror("mkdir"); + fprintf(stderr, + "Failure to make directory %s\n", + unixFile); + free(unixFile); + return ERROR_ONE; + } +} + +static int dos_to_unix(direntry_t *entry, MainParam_t *mp) +{ + return unix_write(entry, mp, 1); +} + + +static int unix_to_unix(MainParam_t *mp) +{ + return unix_write(0, mp, 0); +} + + +static int directory_dos_to_unix(direntry_t *entry, MainParam_t *mp) +{ + return unix_copydir(entry, mp); +} + +/* + * Open the named file for read, create the cluster chain, return the + * directory structure or NULL on error. + */ +static int writeit(struct dos_name_t *dosname, + char *longname, + void *arg0, + direntry_t *entry) +{ + Stream_t *Target; + time_t now; + int type, fat, ret; + time_t date; + mt_size_t filesize, newsize; + Arg_t *arg = (Arg_t *) arg0; + + + + if (arg->mp.File->Class->get_data(arg->mp.File, + & date, &filesize, &type, 0) < 0 ){ + fprintf(stderr, "Can't stat source file\n"); + return -1; + } + + if(fileTooBig(filesize)) { + fprintf(stderr, "File \"%s\" too big\n", longname); + return 1; + } + + if (type){ + if (arg->verbose) + fprintf(stderr, "\"%s\" is a directory\n", longname); + return -1; + } + + /*if (!arg->single || arg->recursive)*/ + if(arg->verbose) + fprintf(stderr,"Copying %s\n", longname); + if(got_signal) + return -1; + + /* will it fit? */ + if (!getfreeMinBytes(arg->mp.targetDir, filesize)) + return -1; + + /* preserve mod time? */ + if (arg->preserveTime) + now = date; + else + getTimeNow(&now); + + mk_entry(dosname, arg->attr, 1, 0, now, &entry->dir); + + Target = OpenFileByDirentry(entry); + if(!Target){ + fprintf(stderr,"Could not open Target\n"); + exit(1); + } + if (arg->needfilter & arg->textmode) + Target = open_filter(Target,arg->convertCharset); + + + + ret = copyfile(arg->mp.File, Target); + GET_DATA(Target, 0, &newsize, 0, &fat); + FREE(&Target); + if (arg->needfilter & arg->textmode) + newsize++; /* ugly hack: we gathered the size before the Ctrl-Z + * was written. Increment it manually */ + if(ret < 0 ){ + fat_free(arg->mp.targetDir, fat); + return -1; + } else { + mk_entry(dosname, arg->attr, fat, truncBytes32(newsize), + now, &entry->dir); + return 0; + } +} + + + +static int dos_write(direntry_t *entry, MainParam_t *mp, int needfilter) +/* write a messy dos file to another messy dos file */ +{ + int result; + Arg_t * arg = (Arg_t *) (mp->arg); + const char *targetName = mpPickTargetName(mp); + + if(entry && arg->preserveAttributes) + arg->attr = entry->dir.attr; + else + arg->attr = ATTR_ARCHIVE; + + arg->needfilter = needfilter; + if (entry && mp->targetDir == entry->Dir){ + arg->ch.ignore_entry = -1; + arg->ch.source = entry->entry; + } else { + arg->ch.ignore_entry = -1; + arg->ch.source = -2; + } + result = mwrite_one(mp->targetDir, targetName, 0, + writeit, (void *)arg, &arg->ch); + if(result == 1) + return GOT_ONE; + else + return ERROR_ONE; +} + +static Stream_t *subDir(Stream_t *parent, const char *filename) +{ + direntry_t entry; + initializeDirentry(&entry, parent); + + switch(vfat_lookup(&entry, filename, -1, ACCEPT_DIR, 0, 0)) { + case 0: + return OpenFileByDirentry(&entry); + case -1: + return NULL; + default: /* IO Error */ + return NULL; + } +} + +static int dos_copydir(direntry_t *entry, MainParam_t *mp) +/* copyes a directory to Dos */ +{ + Arg_t * arg = (Arg_t *) (mp->arg); + Arg_t newArg; + time_t now; + time_t date; + int ret; + const char *targetName = mpPickTargetName(mp); + + if (!arg->recursive && mp->basenameHasWildcard) + return 0; + + if(entry && isSubdirOf(mp->targetDir, mp->File)) { + fprintf(stderr, "Cannot recursively copy directory "); + fprintPwd(stderr, entry,0); + fprintf(stderr, " into one of its own subdirectories "); + fprintPwd(stderr, getDirentry(mp->targetDir),0); + fprintf(stderr, "\n"); + return ERROR_ONE; + } + + if (arg->mp.File->Class->get_data(arg->mp.File, + & date, 0, 0, 0) < 0 ){ + fprintf(stderr, "Can't stat source file\n"); + return ERROR_ONE; + } + + if(!arg->type && arg->verbose) + fprintf(stderr,"Copying %s\n", mpGetBasename(mp)); + + if(entry && arg->preserveAttributes) + arg->attr = entry->dir.attr; + else + arg->attr = 0; + + if (entry && (mp->targetDir == entry->Dir)){ + arg->ch.ignore_entry = -1; + arg->ch.source = entry->entry; + } else { + arg->ch.ignore_entry = -1; + arg->ch.source = -2; + } + + /* preserve mod time? */ + if (arg->preserveTime) + now = date; + else + getTimeNow(&now); + + newArg = *arg; + newArg.mp.arg = &newArg; + newArg.mp.targetName = 0; + newArg.mp.basenameHasWildcard = 1; + if(*targetName) { + /* maybe the directory already exist. Use it */ + newArg.mp.targetDir = subDir(mp->targetDir, targetName); + if(!newArg.mp.targetDir) + newArg.mp.targetDir = createDir(mp->targetDir, + targetName, + &arg->ch, arg->attr, + now); + } else + newArg.mp.targetDir = mp->targetDir; + + if(!newArg.mp.targetDir) + return ERROR_ONE; + + ret = mp->loop(mp->File, &newArg.mp, "*"); + if(*targetName) + FREE(&newArg.mp.targetDir); + return ret | GOT_ONE; +} + + +static int dos_to_dos(direntry_t *entry, MainParam_t *mp) +{ + return dos_write(entry, mp, 0); +} + +static int unix_to_dos(MainParam_t *mp) +{ + return dos_write(0, mp, 1); +} + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-spatnmQVBT] [-D clash_option] sourcefile targetfile\n", progname); + fprintf(stderr, + " %s [-spatnmQVBT] [-D clash_option] sourcefile [sourcefiles...] targetdirectory\n", + progname); + exit(ret); +} + +void mcopy(int argc, char **argv, int mtype) +{ + Arg_t arg; + int c, ret, fastquit; + int todir; + + + /* get command line options */ + + init_clash_handling(& arg.ch); + + /* get command line options */ + todir = 0; + arg.recursive = 0; + arg.preserveTime = 0; + arg.preserveAttributes = 0; + arg.nowarn = 0; + arg.textmode = 0; + arg.verbose = 0; + arg.convertCharset = 0; + arg.type = mtype; + fastquit = 0; + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:abB/sptTnmvQD:oh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 's': + case '/': + arg.recursive = 1; + break; + case 'p': + arg.preserveAttributes = 1; + break; + case 'T': + arg.convertCharset = 1; + case 'a': + case 't': + arg.textmode = 1; + break; + case 'n': + arg.nowarn = 1; + break; + case 'm': + arg.preserveTime = 1; + break; + case 'v': + arg.verbose = 1; + break; + case 'Q': + fastquit = 1; + break; + case 'B': + case 'b': + batchmode = 1; + break; + case 'o': + handle_clash_options(&arg.ch, c); + break; + case 'D': + if(handle_clash_options(&arg.ch, *optarg)) + usage(1); + break; + case 'h': + usage(0); + case '?': + usage(1); + default: + break; + } + } + + if (argc - optind < 1) + usage(1); + + init_mp(&arg.mp); + arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN | NO_DOTS; + arg.mp.fast_quit = fastquit; + arg.mp.arg = (void *) &arg; + arg.mp.openflags = O_RDONLY; + arg.noClobber = 0; + + /* last parameter is "-", use mtype mode */ + if(!mtype && !strcmp(argv[argc-1], "-")) { + arg.type = mtype = 1; + argc--; + } + + if(mtype){ + /* Mtype = copying to stdout */ + arg.mp.targetName = strdup("-"); + arg.mp.unixTarget = strdup(""); + arg.mp.callback = dos_to_unix; + arg.mp.dirCallback = unix_copydir; + arg.mp.unixcallback = unix_to_unix; + } else { + const char *target; + if (argc - optind == 1) { + /* copying to the current directory */ + target = "."; + arg.noClobber = 1; + } else { + /* target is the last item mentioned */ + argc--; + target = argv[argc]; + } + + ret = target_lookup(&arg.mp, target); + if(!arg.mp.targetDir && !arg.mp.unixTarget) { + fprintf(stderr,"Bad target %s\n", target); + exit(1); + } + + /* callback functions */ + if(arg.mp.unixTarget) { + arg.mp.callback = dos_to_unix; + arg.mp.dirCallback = directory_dos_to_unix; + arg.mp.unixcallback = unix_to_unix; + } else { + arg.mp.dirCallback = dos_copydir; + arg.mp.callback = dos_to_dos; + arg.mp.unixcallback = unix_to_dos; + } + } + + exit(main_loop(&arg.mp, argv + optind, argc - optind)); +} diff --git a/mdel.1 b/mdel.1 new file mode 100644 index 0000000..b2391c7 --- /dev/null +++ b/mdel.1 @@ -0,0 +1,100 @@ +.TH mdel 1 "03Nov09" mtools-4.0.12 +.SH Name +mdel - delete an MSDOS file +mdeltree - recursively delete an MSDOS directory and its contents +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mdel" +.iX "c removing MS-DOS files" +.iX "c erasing MS-DOS files" +.iX "c deleting MS-DOS files" +.PP +The \fR\&\f(CWmdel\fR command is used to delete an MS-DOS file. Its syntax +is: +.PP +.ft I +.nf +\&\fR\&\f(CWmdel\fR [\fR\&\f(CW-v\fR] \fImsdosfile\fR [ \fImsdosfiles\fR \&... ] +.fi +.ft R + +.PP +\&\fR\&\f(CWMdel\fR deletes files on an MS-DOS filesystem. +.PP +\&\fR\&\f(CWMdel\fR asks for verification prior to removing a read-only file. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mdel.c b/mdel.c new file mode 100644 index 0000000..e59a2cd --- /dev/null +++ b/mdel.c @@ -0,0 +1,208 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2002,2005,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mdel.c + * Delete an MSDOS file + * + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "stream.h" +#include "mainloop.h" +#include "fs.h" +#include "file.h" +#include "file_name.h" + +typedef struct Arg_t { + int deltype; + int verbose; +} Arg_t; + +/** + * Wiped the given entry + */ +void wipeEntry(direntry_t *entry) +{ + direntry_t longNameEntry; + int i; + initializeDirentry(&longNameEntry, entry->Dir); + for(i=entry->beginSlot; i< entry->endSlot; i++) { + int error; + longNameEntry.entry=i; + dir_read(&longNameEntry, &error); + if(error) + break; + longNameEntry.dir.name[0] = (char) DELMARK; + dir_write(&longNameEntry); + } + entry->dir.name[0] = (char) DELMARK; + dir_write(entry); +} + +static int del_entry(direntry_t *entry, MainParam_t *mp) +{ + Arg_t *arg=(Arg_t *) mp->arg; + + if(got_signal) + return ERROR_ONE; + + if(entry->entry == -3) { + fprintf(stderr, "Cannot remove root directory\n"); + return ERROR_ONE; + } + + if (arg->verbose) { + fprintf(stderr,"Removing "); + fprintPwd(stderr, entry,0); + fputc('\n', stderr); + } + + if (entry->dir.attr & (ATTR_READONLY | ATTR_SYSTEM)) { + char tmp[4*MAX_VNAMELEN+1]; + wchar_to_native(entry->name,tmp,MAX_VNAMELEN); + if (ask_confirmation("%s: \"%s\" is read only, erase anyway (y/n) ? ", + progname, tmp)) + return ERROR_ONE; + } + if (fatFreeWithDirentry(entry)) + return ERROR_ONE; + + wipeEntry(entry); + return GOT_ONE; +} + +static int del_file(direntry_t *entry, MainParam_t *mp) +{ + char shortname[13]; + direntry_t subEntry; + Stream_t *SubDir; + Arg_t *arg = (Arg_t *) mp->arg; + MainParam_t sonmp; + int ret; + int r; + + sonmp = *mp; + sonmp.arg = mp->arg; + + r = 0; + if (IS_DIR(entry)){ + /* a directory */ + SubDir = OpenFileByDirentry(entry); + initializeDirentry(&subEntry, SubDir); + ret = 0; + while((r=vfat_lookup(&subEntry, "*", 1, + ACCEPT_DIR | ACCEPT_PLAIN, + shortname, NULL)) == 0 ){ + if(shortname[0] != DELMARK && + shortname[0] && + shortname[0] != '.' ){ + if(arg->deltype != 2){ + fprintf(stderr, + "Directory "); + fprintPwd(stderr, entry,0); + fprintf(stderr," non empty\n"); + ret = ERROR_ONE; + break; + } + if(got_signal) { + ret = ERROR_ONE; + break; + } + ret = del_file(&subEntry, &sonmp); + if( ret & ERROR_ONE) + break; + ret = 0; + } + } + FREE(&SubDir); + if (r == -2) + return ERROR_ONE; + if(ret) + return ret; + } + return del_entry(entry, mp); +} + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-v] msdosfile [msdosfiles...]\n", progname); + exit(ret); +} + +void mdel(int argc, char **argv, int deltype) +{ + Arg_t arg; + MainParam_t mp; + int c,i; + + arg.verbose = 0; + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:vh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'v': + arg.verbose = 1; + break; + case 'h': + usage(0); + default: + usage(1); + } + } + + if(argc == optind) + usage(1); + + init_mp(&mp); + mp.callback = del_file; + mp.arg = (void *) &arg; + mp.openflags = O_RDWR; + arg.deltype = deltype; + switch(deltype){ + case 0: + mp.lookupflags = ACCEPT_PLAIN; /* mdel */ + break; + case 1: + mp.lookupflags = ACCEPT_DIR; /* mrd */ + break; + case 2: + mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN; /* mdeltree */ + break; + } + mp.lookupflags |= NO_DOTS; + for(i=optind;i 1 && argv[i][b+l-1] == '/') + argv[i][b+l-1] = '\0'; + } + + exit(main_loop(&mp, argv + optind, argc - optind)); +} diff --git a/mdeltree.1 b/mdeltree.1 new file mode 100644 index 0000000..f8dd5e8 --- /dev/null +++ b/mdeltree.1 @@ -0,0 +1,100 @@ +.TH mdeltree 1 "03Nov09" mtools-4.0.12 +.SH Name +mdeltree - recursively delete an MSDOS directory and its contents +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mdeltree" +.iX "c removing an MS-DOS directory recursively" +.iX "c erasing an MS-DOS directory recursively" +.iX "c deleting an MS-DOS directory recursively" +.iX "c recursively removing an MS-DOS directory" +.PP +The \fR\&\f(CWmdeltree\fR command is used to delete an MS-DOS file. Its syntax +is: +.PP +.ft I +.nf +\&\fR\&\f(CWmdeltree\fR [\fR\&\f(CW-v\fR] \fImsdosdirectory\fR [\fImsdosdirectories\fR\&...] +.fi +.ft R + +.PP +\&\fR\&\f(CWMdeltree\fR removes a directory and all the files and subdirectories +it contains from an MS-DOS filesystem. An error occurs if the directory +to be removed does not exist. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mdir.1 b/mdir.1 new file mode 100644 index 0000000..e08a751 --- /dev/null +++ b/mdir.1 @@ -0,0 +1,121 @@ +.TH mdir 1 "03Nov09" mtools-4.0.12 +.SH Name +mdir - display an MSDOS directory +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mdir" +.iX "c Read-only files (listing them)" +.iX "c Listing a directory" +.iX "c Directory listing" +.PP +The \fR\&\f(CWmdir\fR command is used to display an MS-DOS directory. Its +syntax is: +.PP +\&\fR\&\f(CWmdir\fR [\fR\&\f(CW-/\fR] [\fR\&\f(CW-f\fR] [\fR\&\f(CW-w\fR] [\fR\&\f(CW-a\fR] [\fR\&\f(CW-b\fR] \fImsdosfile\fR [ \fImsdosfiles\fR\&...] +.PP +\&\fR\&\f(CWMdir\fR +displays the contents of MS-DOS directories, or the entries for some +MS-DOS files. +.PP +\&\fR\&\f(CWMdir\fR supports the following command line options: +.TP +\&\fR\&\f(CW/\fR\ +Recursive output, just like Dos' \fR\&\f(CW-s\fR option +.TP +\&\fR\&\f(CWw\fR\ +Wide output. With this option, \fR\&\f(CWmdir\fR prints the filenames across +the page without displaying the file size or creation date. +.TP +\&\fR\&\f(CWa\fR\ +Also list hidden files. +.TP +\&\fR\&\f(CWf\fR\ +Fast. Do not try to find out free space. On larger disks, finding out +the amount of free space takes up some non trivial amount of time, as +the whole FAT must be read in and scanned. The \fR\&\f(CW-f\fR flag bypasses +this step. This flag is not needed on FAT32 filesystems, which store +the size explicitely. +.TP +\&\fR\&\f(CWb\fR\ +Concise listing. Lists each directory name or filename, one per line +(including the filename extension). This switch displays no heading +information and no summary. Only a newline separated list of pathnames +is displayed. +.PP +An error occurs if a component of the path is not a directory. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mdir.c b/mdir.c new file mode 100644 index 0000000..0bd2aed --- /dev/null +++ b/mdir.c @@ -0,0 +1,618 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2002,2004,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mdir.c: + * Display an MSDOS directory + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "vfat.h" +#include "mtools.h" +#include "file.h" +#include "mainloop.h" +#include "fs.h" +#include "codepage.h" +#include "file_name.h" + +#ifdef TEST_SIZE +#include "fsP.h" +#endif + +static int recursive; +static int wide; +static int all; +static int concise; +static int fast=0; +#if 0 +static int testmode = 0; +#endif +static const char *dirPath; +static char *dynDirPath; +static char currentDrive; +static Stream_t *currentDir; + +static int filesInDir; /* files in current dir */ +static int filesOnDrive; /* files on drive */ + +static int dirsOnDrive; /* number of listed directories on this drive */ + +static int debug = 0; /* debug mode */ + +static mt_size_t bytesInDir; +static mt_size_t bytesOnDrive; +static Stream_t *RootDir; + + +static char global_shortname[13]; +static char global_longname[VBUFSIZE]; + + +/* + * Print an MSDOS directory date stamp. + */ +static __inline__ void print_date(struct directory *dir) +{ + char year[5]; + char day[3]; + char month[3]; + const char *p; + + sprintf(year, "%04d", DOS_YEAR(dir)); + sprintf(day, "%02d", DOS_DAY(dir)); + sprintf(month, "%02d", DOS_MONTH(dir)); + + for(p=mtools_date_string; *p; p++) { + if(!strncasecmp(p, "yyyy", 4)) { + printf("%04d", DOS_YEAR(dir)); + p+= 3; + continue; + } else if(!strncasecmp(p, "yy", 2)) { + printf("%02d", DOS_YEAR(dir) % 100); + p++; + continue; + } else if(!strncasecmp(p, "dd", 2)) { + printf("%02d", DOS_DAY(dir)); + p++; + continue; + } else if(!strncasecmp(p, "mm", 2)) { + printf("%02d", DOS_MONTH(dir)); + p++; + continue; + } + putchar(*p); + } +} + +/* + * Print an MSDOS directory time stamp. + */ +static __inline__ void print_time(struct directory *dir) +{ + char am_pm; + int hour = DOS_HOUR(dir); + + if(!mtools_twenty_four_hour_clock) { + am_pm = (hour >= 12) ? 'p' : 'a'; + if (hour > 12) + hour = hour - 12; + if (hour == 0) + hour = 12; + } else + am_pm = ' '; + + printf("%2d:%02d%c", hour, DOS_MINUTE(dir), am_pm); +} + +/* + * Return a number in dotted notation + */ +static const char *dotted_num(mt_size_t num, int width, char **buf) +{ + int len; + register char *srcp, *dstp; + int size; + + unsigned long numlo; + unsigned long numhi; + + if (num < 0) { + /* warn about negative numbers here. They should not occur */ + fprintf(stderr, "Invalid negative number\n"); + } + + size = width + width; + *buf = malloc(size+1); + + if (*buf == NULL) + return ""; + + /* Create the number in maximum width; make sure that the string + * length is not exceeded (in %6ld, the result can be longer than 6!) + */ + + numlo = num % 1000000000; + numhi = num / 1000000000; + + if(numhi && size > 9) { + sprintf(*buf, "%.*lu%09lu", size-9, numhi, numlo); + } else { + sprintf(*buf, "%.*lu", size, numlo); + } + + for (srcp=*buf; srcp[1] != '\0'; ++srcp) + if (srcp[0] == '0') + srcp[0] = ' '; + else + break; + + len = strlen(*buf); + srcp = (*buf)+len; + dstp = (*buf)+len+1; + + for ( ; dstp >= (*buf)+4 && isdigit (srcp[-1]); ) { + srcp -= 3; /* from here we copy three digits */ + dstp -= 4; /* that's where we put these 3 digits */ + } + + /* now finally copy the 3-byte blocks to their new place */ + while (dstp < (*buf) + len) { + dstp[0] = srcp[0]; + dstp[1] = srcp[1]; + dstp[2] = srcp[2]; + if (dstp + 3 < (*buf) + len) + /* use spaces instead of dots: they please both + * Americans and Europeans */ + dstp[3] = ' '; + srcp += 3; + dstp += 4; + } + + return (*buf) + len-width; +} + +static __inline__ int print_volume_label(Stream_t *Dir, char drive) +{ + Stream_t *Stream = GetFs(Dir); + direntry_t entry; + DeclareThis(FsPublic_t); + char shortname[13]; + char longname[VBUFSIZE]; + int r; + + RootDir = OpenRoot(Stream); + if(concise) + return 0; + + /* find the volume label */ + + initializeDirentry(&entry, RootDir); + if((r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY, + shortname, longname)) ) { + if (r == -2) { + /* I/O Error */ + return -1; + } + printf(" Volume in drive %c has no label", drive); + } else if (*longname) + printf(" Volume in drive %c is %s (abbr=%s)", + drive, longname, shortname); + else + printf(" Volume in drive %c is %s", + drive, shortname); + if(This->serialized) + printf("\n Volume Serial Number is %04lX-%04lX", + (This->serial_number >> 16) & 0xffff, + This->serial_number & 0xffff); + return 0; +} + + +static void printSummary(int files, mt_size_t bytes) +{ + if(!filesInDir) + printf("No files\n"); + else { + char *s1 = NULL; + printf(" %3d file", files); + if(files == 1) + putchar(' '); + else + putchar('s'); + printf(" %s bytes\n", + dotted_num(bytes, 13, &s1)); + if(s1) + free(s1); + } +} + +static void leaveDirectory(int haveError); + +static void leaveDrive(int haveError) +{ + if(!currentDrive) + return; + leaveDirectory(haveError); + if(!concise && !haveError) { + + if(dirsOnDrive > 1) { + printf("\nTotal files listed:\n"); + printSummary(filesOnDrive, bytesOnDrive); + } + if(RootDir && !fast) { + char *s1 = NULL; + mt_off_t bytes = getfree(RootDir); + if(bytes == -1) { + fprintf(stderr, "Fat error\n"); + goto exit_1; + } + printf(" %s bytes free\n\n", + dotted_num(bytes,17, &s1)); +#ifdef TEST_SIZE + ((Fs_t*)GetFs(RootDir))->freeSpace = 0; + bytes = getfree(RootDir); + printf(" %s bytes free\n\n", + dotted_num(bytes,17, &s1)); +#endif + if(s1) + free(s1); + } + } + exit_1: + FREE(&RootDir); + currentDrive = '\0'; +} + + +static int enterDrive(Stream_t *Dir, char drive) +{ + int r; + if(currentDrive == drive) + return 0; /* still the same */ + + leaveDrive(0); + currentDrive = drive; + + r = print_volume_label(Dir, drive); + if (r) + return r; + + + bytesOnDrive = 0; + filesOnDrive = 0; + dirsOnDrive = 0; + return 0; +} + +static const char *emptyString=""; + +static void leaveDirectory(int haveError) +{ + if(!currentDir) + return; + + if (!haveError) { + if(dirPath && dirPath != emptyString) + free(dynDirPath); + if(wide) + putchar('\n'); + + if(!concise) + printSummary(filesInDir, bytesInDir); + } + FREE(¤tDir); +} + +static int enterDirectory(Stream_t *Dir) +{ + int r; + char drive; + if(currentDir == Dir) + return 0; /* still the same directory */ + + leaveDirectory(0); + + drive = getDrive(Dir); + r=enterDrive(Dir, drive); + if(r) + return r; + currentDir = COPY(Dir); + + dynDirPath = getPwd(getDirentry(Dir)); + if(!dynDirPath) + dirPath=emptyString; + else { + if(!dynDirPath[3] && concise) + dynDirPath[2]='\0'; + dirPath=dynDirPath; + } + + /* print directory title */ + if(!concise) + printf("\nDirectory for %s\n", dirPath); + + if(!wide && !concise) + printf("\n"); + + dirsOnDrive++; + bytesInDir = 0; + filesInDir = 0; + return 0; +} + +static int list_file(direntry_t *entry, MainParam_t *mp) +{ + unsigned long size; + int i; + int Case; + int r; + + wchar_t ext[4]; + wchar_t name[9]; + doscp_t *cp; + + if(!all && (entry->dir.attr & 0x6)) + return 0; + + if(concise && isSpecialW(entry->name)) + return 0; + + r=enterDirectory(entry->Dir); + if (r) + return ERROR_ONE; + if (wide) { + if(filesInDir % 5) + putchar(' '); + else + putchar('\n'); + } + + if(IS_DIR(entry)){ + size = 0; + } else + size = FILE_SIZE(&entry->dir); + + Case = entry->dir.Case; + if(!(Case & (BASECASE | EXTCASE)) && + mtools_ignore_short_case) + Case |= BASECASE | EXTCASE; + + cp = GET_DOSCONVERT(entry->Dir); + dos_to_wchar(cp, entry->dir.ext, ext, 3); + if(Case & EXTCASE){ + for(i=0; i<3;i++) + ext[i] = towlower(ext[i]); + } + ext[3] = '\0'; + dos_to_wchar(cp, entry->dir.name, name, 8); + if(Case & BASECASE){ + for(i=0; i<8;i++) + name[i] = towlower(name[i]); + } + name[8]='\0'; + if(wide){ + if(IS_DIR(entry)) + printf("[%s]%*s", global_shortname, + (int) (15 - 2 - strlen(global_shortname)), ""); + else + printf("%-15s", global_shortname); + } else if(!concise) { + char tmpBasename[4*8+1]; + char tmpExt[4*8+1]; + wchar_to_native(name,tmpBasename,8); + wchar_to_native(ext,tmpExt,3); + + if (name[0] == ' ') + printf(" "); + else if(mtools_dotted_dir) + printf("%s", global_shortname); + else + printf("%s %s ", tmpBasename, tmpExt); + /* is a subdirectory */ + if(IS_DIR(entry)) + printf(" "); + else + printf(" %8ld", (long) size); + printf(" "); + print_date(&entry->dir); + printf(" "); + print_time(&entry->dir); + + if(debug) + printf(" %s %d ", tmpBasename, START(&entry->dir)); + + if(*global_longname) + printf(" %s", global_longname); + printf("\n"); + } else { + char tmp[4*MAX_VNAMELEN+1]; + wchar_to_native(entry->name,tmp,MAX_VNAMELEN); + + printf("%s/%s", dirPath, tmp); + if(IS_DIR(entry)) + putchar('/'); + putchar('\n'); + } + + filesOnDrive++; + filesInDir++; + + bytesOnDrive += (mt_size_t) size; + bytesInDir += (mt_size_t) size; + return GOT_ONE; +} + +static int list_non_recurs_directory(direntry_t *entry, MainParam_t *mp) +{ + int r; + /* list top-level directory + * If this was matched by wildcard in the basename, list it as + * file, otherwise, list it as directory */ + if (mp->basenameHasWildcard) { + /* wildcard, list it as file */ + return list_file(entry, mp); + } else { + /* no wildcard, list it as directory */ + MainParam_t subMp; + + r=enterDirectory(mp->File); + if(r) + return ERROR_ONE; + + subMp = *mp; + subMp.dirCallback = subMp.callback; + return mp->loop(mp->File, &subMp, "*") | GOT_ONE; + } +} + + +static int list_recurs_directory(direntry_t *entry, MainParam_t *mp) +{ + MainParam_t subMp; + int ret; + + /* first list the files */ + subMp = *mp; + subMp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN; + subMp.dirCallback = list_file; + subMp.callback = list_file; + + ret = mp->loop(mp->File, &subMp, "*"); + + /* then list subdirectories */ + subMp = *mp; + subMp.lookupflags = ACCEPT_DIR | NO_DOTS | NO_MSG | DO_OPEN; + return ret | mp->loop(mp->File, &subMp, "*"); +} + +#if 0 +static int test_directory(direntry_t *entry, MainParam_t *mp) +{ + Stream_t *File=mp->File; + Stream_t *Target; + char errmsg[80]; + + if ((Target = SimpleFileOpen(0, 0, "-", + O_WRONLY, + errmsg, 0, 0, 0))) { + copyfile(File, Target); + FREE(&Target); + } + return GOT_ONE; +} +#endif + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, "Usage: %s: [-V] [-w] [-a] [-b] [-s] [-f] msdosdirectory\n", + progname); + fprintf(stderr, + " %s: [-V] [-w] [-a] [-b] [-s] [-f] msdosfile [msdosfiles...]\n", + progname); + exit(ret); +} + + +void mdir(int argc, char **argv, int type) +{ + int ret; + MainParam_t mp; + int faked; + int c; + const char *fakedArgv[] = { "." }; + + concise = 0; + recursive = 0; + wide = all = 0; + /* first argument */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:waXbfds/h")) != EOF) { + switch(c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'w': + wide = 1; + break; + case 'a': + all = 1; + break; + case 'b': + case 'X': + concise = 1; + /*recursive = 1;*/ + break; + case 's': + case '/': + recursive = 1; + break; + case 'f': + fast = 1; + break; + case 'd': + debug = 1; + break; +#if 0 + case 't': /* test mode */ + testmode = 1; + break; +#endif + case 'h': + usage(0); + default: + usage(1); + } + } + + /* fake an argument */ + faked = 0; + if (optind == argc) { + argv = (char **)fakedArgv; + argc = 1; + optind = 0; + } + + init_mp(&mp); + currentDrive = '\0'; + currentDir = 0; + RootDir = 0; + dirPath = 0; +#if 0 + if (testmode) { + mp.lookupflags = ACCEPT_DIR | NO_DOTS; + mp.dirCallback = test_directory; + } else +#endif + if(recursive) { + mp.lookupflags = ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS; + mp.dirCallback = list_recurs_directory; + } else { + mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN | DO_OPEN_DIRS; + mp.dirCallback = list_non_recurs_directory; + mp.callback = list_file; + } + mp.longname = global_longname; + mp.shortname = global_shortname; + ret=main_loop(&mp, argv + optind, argc - optind); + leaveDirectory(ret); + leaveDrive(ret); + exit(ret); +} diff --git a/mdoctorfat.c b/mdoctorfat.c new file mode 100644 index 0000000..7f5c5f1 --- /dev/null +++ b/mdoctorfat.c @@ -0,0 +1,183 @@ +/* Copyright 1999,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Test program for doctoring the fat + */ + + +#define LOWERCASE + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "plain_io.h" +#include "nameclash.h" +#include "file.h" +#include "fs.h" +#include "fsP.h" + +typedef struct Arg_t { + char *target; + MainParam_t mp; + ClashHandling_t ch; + Stream_t *sourcefile; + unsigned long fat; + int markbad; + int setsize; + unsigned long size; + Fs_t *Fs; +} Arg_t; + +static int dos_doctorfat(direntry_t *entry, MainParam_t *mp) +{ + Fs_t *Fs = getFs(mp->File); + Arg_t *arg=(Arg_t *) mp->arg; + + if(!arg->markbad && entry->entry != -3) { + /* if not root directory, change it */ + set_word(entry->dir.start, arg->fat & 0xffff); + set_word(entry->dir.startHi, arg->fat >> 16); + if(arg->setsize) + set_dword(entry->dir.size, arg->size); + dir_write(entry); + } + arg->Fs = Fs; + return GOT_ONE; +} + +static int unix_doctorfat(MainParam_t *mp) +{ + fprintf(stderr,"File does not reside on a Dos fs\n"); + return ERROR_ONE; +} + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: [-b] %s file fat\n", progname); + exit(ret); +} + +void mdoctorfat(int argc, char **argv, int mtype) +{ + Arg_t arg; + int c, ret; + long address, begin, end; + char *number, *eptr; + int i, j; + long offset; + + /* get command line options */ + + init_clash_handling(& arg.ch); + + offset = 0; + + arg.markbad = 0; + arg.setsize = 0; + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:bo:s:h")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'b': + arg.markbad = 1; + break; + case 'o': + offset = strtoul(optarg,0,0); + break; + case 's': + arg.setsize=1; + arg.size = strtoul(optarg,0,0); + break; + case 'h': + usage(0); + case '?': + usage(1); + break; + } + } + + if (argc - optind < 2) + usage(1); + + + /* only 1 file to copy... */ + init_mp(&arg.mp); + arg.mp.arg = (void *) &arg; + + arg.mp.callback = dos_doctorfat; + arg.mp.unixcallback = unix_doctorfat; + + arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN; + arg.mp.openflags = O_RDWR; + arg.fat = strtoul(argv[optind+1], 0, 0) + offset; + ret=main_loop(&arg.mp, argv + optind, 1); + if(ret) + exit(ret); + address = 0; + for(i=optind+1; i < argc; i++) { + number = argv[i]; + if (*number == '<') { + number++; + } + begin = strtoul(number, &eptr, 0); + if (eptr && *eptr == '-') { + number = eptr+1; + end = strtoul(number, &eptr, 0); + } else { + end = begin; + } + if (eptr == number) { + fprintf(stderr, "Not a number: %s\n", number); + exit(-1); + } + + if (eptr && *eptr == '>') { + eptr++; + } + if (eptr && *eptr) { + fprintf(stderr, "Not a number: %s\n", eptr); + exit(-1); + } + + for (j=begin; j <= end; j++) { + if(arg.markbad) { + arg.Fs->fat_encode(arg.Fs, j+offset, arg.Fs->last_fat ^ 6 ^ 8); + } else { + if(address) { + arg.Fs->fat_encode(arg.Fs, address, j+offset); + } + address = j+offset; + } + } + } + + if (address && !arg.markbad) { + arg.Fs->fat_encode(arg.Fs, address, arg.Fs->end_fat); + } + + exit(ret); +} diff --git a/mdu.1 b/mdu.1 new file mode 100644 index 0000000..1641297 --- /dev/null +++ b/mdu.1 @@ -0,0 +1,99 @@ +.TH mdu 1 "03Nov09" mtools-4.0.12 +.SH Name +mdu - display the amount of space occupied by an MSDOS directory +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mdu" +.iX "c Space occupied by directories and files" +.iX "c du" +.iX "c Listing space occupied by directories and files" +.iX "c Occupation of space by directories and files" +.PP +\&\fR\&\f(CWMdu\fR is used to list the space occupied by a directory, its +subdirectories and its files. It is similar to the \fR\&\f(CWdu\fR command on +Unix. The unit used are clusters. Use the minfo command to find out +the cluster size. +.PP +\&\fR\&\f(CWmdu\fR [\fR\&\f(CW-a\fR] [ \fImsdosfiles\fR \&... ] +.TP +\&\fR\&\f(CWa\fR\ +All files. List also the space occupied for individual files. +.TP +\&\fR\&\f(CWs\fR\ +Only list the total space, don't give details for each subdirectory. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mdu.c b/mdu.c new file mode 100644 index 0000000..87ddeaf --- /dev/null +++ b/mdu.c @@ -0,0 +1,140 @@ +/* Copyright 1997,2000-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mdu.c: + * Display the space occupied by an MSDOS directory + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "vfat.h" +#include "mtools.h" +#include "file.h" +#include "mainloop.h" +#include "fs.h" +#include "codepage.h" + + +typedef struct Arg_t { + int all; + int inDir; + int summary; + struct Arg_t *parent; + char *target; + char *path; + unsigned int blocks; + MainParam_t mp; +} Arg_t; + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, "Usage: %s: msdosdirectory\n", + progname); + exit(ret); +} + +static int file_mdu(direntry_t *entry, MainParam_t *mp) +{ + unsigned int blocks; + Arg_t * arg = (Arg_t *) (mp->arg); + + blocks = countBlocks(entry->Dir,getStart(entry->Dir, &entry->dir)); + if(arg->all || !arg->inDir) { + fprintPwd(stdout, entry,0); + printf(" %d\n", blocks); + } + arg->blocks += blocks; + return GOT_ONE; +} + + +static int dir_mdu(direntry_t *entry, MainParam_t *mp) +{ + Arg_t *parentArg = (Arg_t *) (mp->arg); + Arg_t arg; + int ret; + + arg = *parentArg; + arg.mp.arg = (void *) &arg; + arg.parent = parentArg; + arg.inDir = 1; + + /* account for the space occupied by the directory itself */ + if(!isRootDir(entry->Dir)) { + arg.blocks = countBlocks(entry->Dir, + getStart(entry->Dir, &entry->dir)); + } else { + arg.blocks = 0; + } + + /* recursion */ + ret = mp->loop(mp->File, &arg.mp, "*"); + if(!arg.summary || !parentArg->inDir) { + fprintPwd(stdout, entry,0); + printf(" %d\n", arg.blocks); + } + arg.parent->blocks += arg.blocks; + return ret; +} + +void mdu(int argc, char **argv, int type) +{ + Arg_t arg; + int c; + + arg.all = 0; + arg.inDir = 0; + arg.summary = 0; + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:ash")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'a': + arg.all = 1; + break; + case 's': + arg.summary = 1; + break; + case 'h': + usage(0); + case '?': + usage(1); + } + } + + if (optind >= argc) + usage(1); + + if(arg.summary && arg.all) { + fprintf(stderr,"-a and -s options are mutually exclusive\n"); + usage(1); + } + + init_mp(&arg.mp); + arg.mp.callback = file_mdu; + arg.mp.openflags = O_RDONLY; + arg.mp.dirCallback = dir_mdu; + + arg.mp.arg = (void *) &arg; + arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS; + exit(main_loop(&arg.mp, argv + optind, argc - optind)); +} diff --git a/mformat.1 b/mformat.1 new file mode 100644 index 0000000..7184486 --- /dev/null +++ b/mformat.1 @@ -0,0 +1,282 @@ +.TH mformat 1 "03Nov09" mtools-4.0.12 +.SH Name +mformat - add an MSDOS filesystem to a low-level formatted floppy disk +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mformat" +.iX "c Initializing disks" +.iX "c Formatting disks" +.iX "c Filesystem creation" +.PP +The \fR\&\f(CWmformat\fR command is used to add an MS-DOS filesystem to a +low-level formatted diskette. Its syntax is: +.PP +.ft I +.nf +\&\fR\&\f(CWmformat\fR [\fR\&\f(CW-t\fR \fIcylinders\fR] [\fR\&\f(CW-h\fR \fIheads\fR] [\fR\&\f(CW-s\fR \fIsectors\fR] + [\fR\&\f(CW-f\fR \fIsize\fR] [\fR\&\f(CW-1\fR] [\fR\&\f(CW-4\fR] [\fR\&\f(CW-8\fR] + [\fR\&\f(CW-v\fR \fIvolume_label\fR] + [\fR\&\f(CW-F\fR] [\fR\&\f(CW-S\fR \fIsizecode\fR] [\fR\&\f(CW-X\fR] + [\fR\&\f(CW-2\fR \fIsectors_on_track_0\fR] [\fR\&\f(CW-3\fR] + [\fR\&\f(CW-0\fR \fIrate_on_track_0\fR] [\fR\&\f(CW-A\fR \fIrate_on_other_tracks\fR] + [\fR\&\f(CW-M\fR \fIsoftware_sector_size\fR] + [\fR\&\f(CW-N\fR \fIserial_number\fR] [\fR\&\f(CW-a\fR] + [\fR\&\f(CW-C\fR] [\fR\&\f(CW-H\fR \fIhidden_sectors\fR] [\fR\&\f(CW-I\fR \fIfsVersion\fR] + [\fR\&\f(CW-r\fR \fIroot_sectors\fR] [\fR\&\f(CW-L\fR \fIfat_len\fR] + [\fR\&\f(CW-B\fR \fIboot_sector\fR] [\fR\&\f(CW-k\fR] + [\fR\&\f(CW-m\fR \fImedia_descriptor\fR] + \fIdrive:\fR +.fi +.ft R + +.PP +\&\fR\&\f(CWMformat\fR adds a minimal MS-DOS filesystem (boot sector, FAT, and +root directory) to a diskette that has already been formatted by a Unix +low-level format. +.PP +The following options are supported: (The S, 2, 1 and M options may not +exist if this copy of mtools has been compiled without the USE_2M +option) +.PP +The following options are the same as for Dos's format command: +.PP +.SH Options +.TP +\&\fR\&\f(CWv\fR\ +Specifies the volume label. A volume label identifies the disk and can +be a maximum of 11 characters. If you omit the -v switch, mlabel will +assign no label to the disk. +.TP +\&\fR\&\f(CWf\fR\ +Specifies the size of the DOS filesystem to format. Only a certain +number of predefined sizes are supported by this flag; for others use +the -h/-t/-s flags. The following sizes are supported: +.RS +.TP +160\ +160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD) +.TP +180\ +160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD) +.TP +320\ +320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD) +.TP +360\ +360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD) +.TP +720\ +720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD) +.TP +1200\ +1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD) +.TP +1440\ +1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD) +.TP +2880\ +2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED) +.RE +.TP +\&\fR\&\f(CWt\fR\ +Specifies the number of tracks on the disk. +.TP +\&\fR\&\f(CWh\fR\ +The number of heads (sides). +.TP +\&\fR\&\f(CWn\fR\ +Specifies the number of sectors per track. If the 2m option is given, +number of 512-byte sector equivalents on generic tracks (i.e. not head 0 +track 0). If the 2m option is not given, number of physical sectors per +track (which may be bigger than 512 bytes). +.TP +\&\fR\&\f(CW1\fR\ +Formats a single side (equivalent to -h 1) +.TP +\&\fR\&\f(CW4\fR\ +Formats a 360K double-sided disk (equivalent to -f 360). When used +together with -the 1 switch, this switch formats a 180K disk +.TP +\&\fR\&\f(CW8\fR\ +Formats a disk with 8 sectors per track. +.PP +MSDOS format's \fR\&\f(CWq\fR, \fR\&\f(CWu\fR and \fR\&\f(CWb\fR options are not +supported, and \fR\&\f(CWs\fR has a different meaning. +.PP +The following options are specific to mtools: +.IP +.TP +\&\fR\&\f(CWF\fR\ +Format the partition as FAT32. +.TP +\&\fR\&\f(CWS\fR\ +The sizecode. The size of the sector is 2 ^ (sizecode + 7). +.TP +\&\fR\&\f(CWX\fR\ +formats the disk as an XDF disk. See section XDF, for more details. The disk +has first to be low-level formatted using the xdfcopy utility included +in the fdutils package. XDF disks are used for instance for OS/2 install +disks. +.TP +\&\fR\&\f(CW2\fR\ +2m format. The parameter to this option describes the number of +sectors on track 0, head 0. This option is recommended for sectors +bigger than normal. +.TP +\&\fR\&\f(CW3\fR\ +don't use a 2m format, even if the current geometry of the disk is a 2m +geometry. +.TP +\&\fR\&\f(CW0\fR\ +Data transfer rate on track 0 +.TP +\&\fR\&\f(CWA\fR\ +Data transfer rate on tracks other than 0 +.TP +\&\fR\&\f(CWM\fR\ +software sector size. This parameter describes the sector size in bytes used +by the MS-DOS filesystem. By default it is the physical sector size. +.TP +\&\fR\&\f(CWN\fR\ +Uses the requested serial number, instead of generating one +automatically +.TP +\&\fR\&\f(CWa\fR\ +If this option is given, an Atari style serial number is generated. +Ataris store their serial number in the OEM label. +.TP +\&\fR\&\f(CWC\fR\ +creates the disk image file to install the MS-DOS filesystem on +it. Obviously, this is useless on physical devices such as floppies +and hard disk partitions, but is interesting for image files. +.TP +\&\fR\&\f(CWH\fR\ +number of hidden sectors. This parameter is useful for formatting hard +disk partition, which are not aligned on track boundaries (i.e. first +head of first track doesn't belong to the partition, but contains a +partition table). In that case the number of hidden sectors is in +general the number of sectors per cylinder. This is untested. +.TP +\&\fR\&\f(CWI\fR\ +Sets the fsVersion id when formatting a FAT32 drive. In order to find +this out, run minfo on an existing FAT32 drive, and mail me about it, so +I can include the correct value in future versions of mtools. +.TP +\&\fR\&\f(CWc\fR\ +Sets the size of a cluster (in sectors). If this cluster size would +generate a FAT that too big for its number of bits, mtools automatically +increases the cluster size, until the FAT is small enough. +.TP +\&\fR\&\f(CWd\fR\ +Sets the number of FAT copies. Default is 2. This setting can also be +specified using the \fR\&\f(CWMTOOLS_NFATS\fR environment variable. +.TP +\&\fR\&\f(CWr\fR\ +Sets the size of the root directory (in sectors). Only applicable to 12 +and 16 bit FATs. This setting can also be specified using the +\&\fR\&\f(CWMTOOLS_DIR_LEN\fR environment variable. +.TP +\&\fR\&\f(CWL\fR\ +Sets the length of the FAT. +.TP +\&\fR\&\f(CWB\fR\ +Use the bootsector stored in the given file or device, instead of using +its own. Only the geometry fields are updated to match the target disks +parameters. +.TP +\&\fR\&\f(CWk\fR\ +Keep the existing boot sector as much as possible. Only the geometry +fields and other similar filesystem data are updated to match the target +disks parameters. +.TP +\&\fR\&\f(CWm\fR\ +Use a non-standard media descriptor byte for this disk. The media +descriptor is stored at position 21 of the boot sector, and as first +byte in each FAT copy. Using this option may confuse DOS or older mtools +version, and may make the disk unreadable. Only use if you know what you +are doing. +.PP +To format a diskette at a density other than the default, you must supply +(at least) those command line parameters that are different from the +default. +.PP +\&\fR\&\f(CWMformat\fR returns 0 on success or 1 on failure. +.PP +It doesn't record bad block information to the Fat, use +\&\fR\&\f(CWmbadblocks\fR for that. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mformat.c b/mformat.c new file mode 100644 index 0000000..c60f65d --- /dev/null +++ b/mformat.c @@ -0,0 +1,1324 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1994,1996-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mformat.c + */ + +#define DONT_NEED_WAIT + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "mainloop.h" +#include "fsP.h" +#include "file.h" +#include "plain_io.h" +#include "floppyd_io.h" +#include "nameclash.h" +#include "buffer.h" +#ifdef HAVE_ASSERT_H +#include +#endif +#ifdef USE_XDF +#include "xdf_io.h" +#endif +#include "partition.h" +#include "file_name.h" + +#ifndef abs +#define abs(x) ((x)>0?(x):-(x)) +#endif + +#ifdef OS_linux +#include "linux/hdreg.h" + +#define _LINUX_STRING_H_ +#define kdev_t int +#include "linux/fs.h" +#undef _LINUX_STRING_H_ + +#endif + + +static int init_geometry_boot(union bootsector *boot, struct device *dev, + int sectors0, int rate_0, int rate_any, + unsigned long *tot_sectors, int keepBoot) +{ + int i; + int nb_renum; + int sector2; + int size2; + int j; + int sum; + + set_word(boot->boot.nsect, dev->sectors); + set_word(boot->boot.nheads, dev->heads); + + *tot_sectors = dev->heads * dev->sectors * dev->tracks - DWORD(nhs); + + if (*tot_sectors < 0x10000){ + set_word(boot->boot.psect, *tot_sectors); + set_dword(boot->boot.bigsect, 0); + } else { + set_word(boot->boot.psect, 0); + set_dword(boot->boot.bigsect, *tot_sectors); + } + + if (dev->use_2m & 0x7f){ + int bootOffset; + strncpy(boot->boot.banner, "2M-STV04", 8); + boot->boot.ext.old.res_2m = 0; + boot->boot.ext.old.fmt_2mf = 6; + if ( dev->sectors % ( ((1 << dev->ssize) + 3) >> 2 )) + boot->boot.ext.old.wt = 1; + else + boot->boot.ext.old.wt = 0; + boot->boot.ext.old.rate_0= rate_0; + boot->boot.ext.old.rate_any= rate_any; + if (boot->boot.ext.old.rate_any== 2 ) + boot->boot.ext.old.rate_any= 1; + i=76; + + /* Infp0 */ + set_word(boot->boot.ext.old.Infp0, i); + boot->bytes[i++] = sectors0; + boot->bytes[i++] = 108; + for(j=1; j<= sectors0; j++) + boot->bytes[i++] = j; + + set_word(boot->boot.ext.old.InfpX, i); + + boot->bytes[i++] = 64; + boot->bytes[i++] = 3; + nb_renum = i++; + sector2 = dev->sectors; + size2 = dev->ssize; + j=1; + while( sector2 ){ + while ( sector2 < (1 << size2) >> 2 ) + size2--; + boot->bytes[i++] = 128 + j; + boot->bytes[i++] = j++; + boot->bytes[i++] = size2; + sector2 -= (1 << size2) >> 2; + } + boot->bytes[nb_renum] = ( i - nb_renum - 1 ) / 3; + + set_word(boot->boot.ext.old.InfTm, i); + + sector2 = dev->sectors; + size2= dev->ssize; + while(sector2){ + while ( sector2 < 1 << ( size2 - 2) ) + size2--; + boot->bytes[i++] = size2; + sector2 -= 1 << (size2 - 2 ); + } + + set_word(boot->boot.ext.old.BootP,i); + bootOffset = i; + + /* checksum */ + for (sum=0, j=64; jbytes[j];/* checksum */ + boot->boot.ext.old.CheckSum=-sum; + return bootOffset; + } else { + if(!keepBoot) { + boot->boot.jump[0] = 0xeb; + boot->boot.jump[1] = 0; + boot->boot.jump[2] = 0x90; + strncpy(boot->boot.banner, mformat_banner, 8); + /* It looks like some versions of DOS are + * rather picky about this, and assume default + * parameters without this, ignoring any + * indication about cluster size et al. */ + } + return 0; + } +} + + +static int comp_fat_bits(Fs_t *Fs, int estimate, + unsigned long tot_sectors, int fat32) +{ + int needed_fat_bits; + + needed_fat_bits = 12; + +#define MAX_DISK_SIZE(bits,clusters) \ + TOTAL_DISK_SIZE((bits), Fs->sector_size, (clusters), \ + Fs->num_fat, MAX_BYTES_PER_CLUSTER/Fs->sector_size) + + if(tot_sectors > MAX_DISK_SIZE(12, FAT12-1)) + needed_fat_bits = 16; + if(fat32 || tot_sectors > MAX_DISK_SIZE(16, FAT16-1)) + needed_fat_bits = 32; + +#undef MAX_DISK_SIZE + + if(abs(estimate) && abs(estimate) < needed_fat_bits) { + if(fat32) { + fprintf(stderr, + "Contradiction between FAT size on command line and FAT size in conf file\n"); + exit(1); + } + fprintf(stderr, + "Device too big for a %d bit FAT\n", + estimate); + exit(1); + } + + if(!estimate) { + unsigned int min_fat16_size; + + if(needed_fat_bits > 12) + return needed_fat_bits; + min_fat16_size = DISK_SIZE(16, Fs->sector_size, FAT12, + Fs->num_fat, 1); + if(tot_sectors < min_fat16_size) + return 12; + else if(tot_sectors >= 2* min_fat16_size) + return 16; /* heuristics */ + } + + return estimate; +} + + +/* + * According to Microsoft "Hardware White Paper", "Microsoft + * Extensible Formware Initiative", "FAT32 File System Specification", + * Version 1.03, December 6, 2000: + * If (CountofClusters < 4085) { + * // Volume is FAT12 + * } else if (CountofClusters < 65525) { + * // Volume is FAT16 + * } else { + * //Volume is FAT32 + * } + * + * This document can be found at the following URL + * http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf + * The relevant passus is on page 15. + * + * Actually, experimentations with Windows NT 4 show that the + * cutoff is 4087 rather than 4085... This is Microsoft after all. + * Not sure what the other Microsoft OS'es do though... + */ +static void calc_fat_bits2(Fs_t *Fs, unsigned long tot_sectors, int fat_bits, + int may_change_cluster_size, + int may_change_root_size) +{ + unsigned long rem_sect; + + /* + * the "remaining sectors" after directory and boot + * hasve been accounted for. + */ + rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start; + switch(abs(fat_bits)) { + case 0: + +#define MY_DISK_SIZE(bits,clusters) \ + DISK_SIZE( (bits), Fs->sector_size, (clusters), \ + Fs->num_fat, Fs->cluster_size) + + if(rem_sect >= MY_DISK_SIZE(16, FAT12+2)) + /* big enough for FAT16 + * We take a margin of 2, because NT4 + * misbehaves, and starts considering a disk + * as FAT16 only if it is larger than 4086 + * sectors, rather than 4084 as it should + */ + set_fat16(Fs); + else if(rem_sect <= MY_DISK_SIZE(12, FAT12-1)) + /* small enough for FAT12 */ + set_fat12(Fs); + else { + /* "between two chairs", + * augment cluster size, and + * settle it */ + if(may_change_cluster_size && + Fs->cluster_size * Fs->sector_size * 2 + <= MAX_BYTES_PER_CLUSTER) + Fs->cluster_size <<= 1; + else if(may_change_root_size) { + Fs->dir_len += + rem_sect - MY_DISK_SIZE(12, FAT12-1); + } + set_fat12(Fs); + } + break; +#undef MY_DISK_SIZE + + case 12: + set_fat12(Fs); + break; + case 16: + set_fat16(Fs); + break; + case 32: + set_fat32(Fs); + break; + } +} + +static __inline__ void format_root(Fs_t *Fs, char *label, union bootsector *boot) +{ + Stream_t *RootDir; + char *buf; + int i; + struct ClashHandling_t ch; + int dirlen; + + init_clash_handling(&ch); + ch.name_converter = label_name; + ch.ignore_entry = -2; + + buf = safe_malloc(Fs->sector_size); + RootDir = OpenRoot((Stream_t *)Fs); + if(!RootDir){ + fprintf(stderr,"Could not open root directory\n"); + exit(1); + } + + memset(buf, '\0', Fs->sector_size); + + if(Fs->fat_bits == 32) { + /* on a FAT32 system, we only write one sector, + * as the directory can be extended at will...*/ + dirlen = Fs->cluster_size; + fatAllocate(Fs, Fs->rootCluster, Fs->end_fat); + } else + dirlen = Fs->dir_len; + for (i = 0; i < dirlen; i++) + WRITES(RootDir, buf, sectorsToBytes((Stream_t*)Fs, i), + Fs->sector_size); + + ch.ignore_entry = 1; + if(label[0]) + mwrite_one(RootDir,label, 0, labelit, NULL,&ch); + + FREE(&RootDir); + if(Fs->fat_bits == 32) + set_word(boot->boot.dirents, 0); + else + set_word(boot->boot.dirents, Fs->dir_len * (Fs->sector_size / 32)); + free(buf); +} + + +static void xdf_calc_fat_size(Fs_t *Fs, unsigned long tot_sectors, + int fat_bits) +{ + unsigned int rem_sect; + + rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start - 2 * Fs->fat_len; + + if(Fs->fat_len) { + /* an XDF disk, we know the fat_size and have to find + * out the rest. We start with a cluster size of 1 and + * keep doubling until everything fits into the + * FAT. This will occur eventually, as our FAT has a + * minimal size of 1 */ + for(Fs->cluster_size = 1; 1 ; Fs->cluster_size <<= 1) { + Fs->num_clus = rem_sect / Fs->cluster_size; + if(abs(fat_bits) == 16 || Fs->num_clus >= FAT12) + set_fat16(Fs); + else + set_fat12(Fs); + if (Fs->fat_len >= NEEDED_FAT_SIZE(Fs)) + return; + } + } + fprintf(stderr,"Internal error while calculating Xdf fat size\n"); + exit(1); +} + + +static void calc_fat_size(Fs_t *Fs, unsigned long tot_sectors) +{ + unsigned long rem_sect; + unsigned long real_rem_sect; + unsigned long numerator; + unsigned long denominator; + int fat_nybbles; + unsigned int slack; + int printGrowMsg=1; /* Should we print "growing FAT" messages ?*/ + +#ifdef DEBUG + fprintf(stderr, "Fat start=%d\n", Fs->fat_start); + fprintf(stderr, "tot_sectors=%lu\n", tot_sectors); + fprintf(stderr, "dir_len=%d\n", Fs->dir_len); +#endif + real_rem_sect = rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start; + + /* Cheat a little bit to address the _really_ common case of + odd number of remaining sectors while both nfat and cluster size + are even... */ + if(rem_sect %2 == 1 && + Fs->num_fat %2 == 0 && + Fs->cluster_size %2 == 0) + rem_sect--; + +#ifdef DEBUG + fprintf(stderr, "Rem sect=%lu\n", rem_sect); +#endif + + if(Fs->fat_bits == 0) { + fprintf(stderr, "Weird, fat bits = 0\n"); + exit(1); + } + + + /* See fat_size_calculation.tex or + (http://ftp.gnu.org/software/mtools/manual/fat_size_calculation.pdf) + for an explantation about why the stuff below works... + */ + + fat_nybbles = Fs->fat_bits / 4; + numerator = rem_sect+2*Fs->cluster_size; + denominator = + Fs->cluster_size * Fs->sector_size * 2 + + Fs->num_fat * fat_nybbles; + + if(fat_nybbles == 3) + numerator *= fat_nybbles; + else + /* Avoid numerical overflows, divide the denominator + * rather than multiplying the numerator */ + denominator = denominator / fat_nybbles; + +#ifdef DEBUG + fprintf(stderr, "Numerator=%lu denominator=%lu\n", + numerator, denominator); +#endif + + Fs->fat_len = (numerator-1)/denominator+1; + Fs->num_clus = (rem_sect-(Fs->fat_len*Fs->num_fat))/Fs->cluster_size; + + /* Apply upper bounds for FAT bits */ + if(Fs->fat_bits == 16 && Fs->num_clus >= FAT16) + Fs->num_clus = FAT16-1; + if(Fs->fat_bits == 12 && Fs->num_clus >= FAT12) + Fs->num_clus = FAT12-1; + + /* A safety, if above math is correct, this should not be happen...*/ + if(Fs->num_clus > (Fs->fat_len * Fs->sector_size * 2 / + fat_nybbles - 2)) { + fprintf(stderr, + "Fat size miscalculation, shrinking num_clus from %d ", + Fs->num_clus); + Fs->num_clus = (Fs->fat_len * Fs->sector_size * 2 / + fat_nybbles - 2); + fprintf(stderr, " to %d\n", Fs->num_clus); + } +#ifdef DEBUG + fprintf(stderr, "Num_clus=%d fat_len=%d nybbles=%d\n", + Fs->num_clus, Fs->fat_len, fat_nybbles); +#endif + + if ( Fs->num_clus < FAT16 && Fs->fat_bits > 16 ){ + fprintf(stderr,"Too few clusters for this fat size." + " Please choose a 16-bit fat in your /etc/mtools.conf" + " or .mtoolsrc file\n"); + exit(1); + } + + /* As the number of clusters is specified nowhere in the boot sector, + * it will be calculated by removing everything else from total number + * of sectors. This means that if we reduced the number of clusters + * above, we will have to grow the FAT in order to take up any excess + * sectors... */ +#ifdef HAVE_ASSERT_H + assert(rem_sect >= Fs->num_clus * Fs->cluster_size + + Fs->fat_len * Fs->num_fat); +#endif + slack = rem_sect - + Fs->num_clus * Fs->cluster_size - + Fs->fat_len * Fs->num_fat; + if(slack >= Fs->cluster_size) { + /* This can happen under two circumstances: + 1. We had to reduce num_clus because we reached maximum + number of cluster for FAT12 or FAT16 + */ + if(printGrowMsg) { + fprintf(stderr, "Slack=%d\n", slack); + fprintf(stderr, "Growing fat size from %d", + Fs->fat_len); + } + Fs->fat_len += + (slack - Fs->cluster_size) / Fs->num_fat + 1; + if(printGrowMsg) { + fprintf(stderr, + " to %d in order to take up excess cluster area\n", + Fs->fat_len); + } + Fs->num_clus = (rem_sect-(Fs->fat_len*Fs->num_fat))/ + Fs->cluster_size; + + } + +#ifdef HAVE_ASSERT_H + /* Fat must be big enough for all clusters */ + assert( ((Fs->num_clus+2) * fat_nybbles) <= + (Fs->fat_len*Fs->sector_size*2)); + + /* num_clus must be big enough to cover rest of disk, or else further + * users of the filesystem will assume a bigger num_clus, which might + * be too big for fat_len */ + assert(Fs->num_clus == + (real_rem_sect - Fs->num_fat * Fs->fat_len) / Fs->cluster_size); +#endif +} + + +static unsigned char bootprog[]= +{0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01, + 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00, + 0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00, + 0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00, + 0x00, 0xcd, 0x19}; + +static __inline__ void inst_boot_prg(union bootsector *boot, int offset) +{ + memcpy((char *) boot->boot.jump + offset, + (char *) bootprog, sizeof(bootprog) /sizeof(bootprog[0])); + if(offset - 2 < 0x80) { + /* short jump */ + boot->boot.jump[0] = 0xeb; + boot->boot.jump[1] = offset -2; + boot->boot.jump[2] = 0x90; + } else { + /* long jump, if offset is too large */ + boot->boot.jump[0] = 0xe9; + boot->boot.jump[1] = offset -3; + boot->boot.jump[2] = 0x00; + } + set_word(boot->boot.jump + offset + 20, offset + 24); +} + +static void calc_cluster_size(struct Fs_t *Fs, unsigned long tot_sectors, + int fat_bits) + +{ + unsigned int max_clusters; /* maximal possible number of sectors for + * this FAT entry length (12/16/32) */ + unsigned int max_fat_size; /* maximal size of the FAT for this FAT + * entry length (12/16/32) */ + unsigned int rem_sect; /* remaining sectors after we accounted for + * the root directory and boot sector(s) */ + + switch(abs(fat_bits)) { + case 12: + max_clusters = FAT12-1; + max_fat_size = Fs->num_fat * + FAT_SIZE(12, Fs->sector_size, max_clusters); + break; + case 16: + case 0: /* still hesititating between 12 and 16 */ + max_clusters = FAT16-1; + max_fat_size = Fs->num_fat * + FAT_SIZE(16, Fs->sector_size, max_clusters); + break; + case 32: + Fs->cluster_size = 8; + /* According to + * http://support.microsoft.com/support/kb/articles/q154/9/97.asp + * Micro$oft does not support FAT32 with less than 4K + */ + return; + default: + fprintf(stderr,"Bad fat size\n"); + exit(1); + } + + rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start; + + /* double the cluster size until we can fill up the disk with + * the maximal number of sectors of this size */ + while(Fs->cluster_size * max_clusters + max_fat_size < rem_sect) { + if(Fs->cluster_size > 64) { + /* bigger than 64. Should fit */ + fprintf(stderr, + "Internal error while calculating cluster size\n"); + exit(1); + } + Fs->cluster_size <<= 1; + } +} + + +struct OldDos_t old_dos[]={ +{ 40, 9, 1, 4, 1, 2, 0xfc }, +{ 40, 9, 2, 7, 2, 2, 0xfd }, +{ 40, 8, 1, 4, 1, 1, 0xfe }, +{ 40, 8, 2, 7, 2, 1, 0xff }, +{ 80, 9, 2, 7, 2, 3, 0xf9 }, +{ 80, 15, 2,14, 1, 7, 0xf9 }, +{ 80, 18, 2,14, 1, 9, 0xf0 }, +{ 80, 36, 2,15, 2, 9, 0xf0 }, +{ 1, 8, 1, 1, 1, 1, 0xf0 }, +}; + +static int old_dos_size_to_geom(size_t size, int *cyls, int *heads, int *sects) +{ + unsigned int i; + size = size * 2; + for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){ + if (old_dos[i].sectors * + old_dos[i].tracks * + old_dos[i].heads == size) { + *cyls = old_dos[i].tracks; + *heads = old_dos[i].heads; + *sects = old_dos[i].sectors; + return 0; + } + } + return 1; +} + + +static void calc_fs_parameters(struct device *dev, unsigned long tot_sectors, + struct Fs_t *Fs, union bootsector *boot) +{ + unsigned int i; + + for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){ + if (dev->sectors == old_dos[i].sectors && + dev->tracks == old_dos[i].tracks && + dev->heads == old_dos[i].heads && + (dev->fat_bits == 0 || abs(dev->fat_bits) == 12) && + (Fs->dir_len == 0 || Fs->dir_len == old_dos[i].dir_len) && + (Fs->cluster_size == 0 || + Fs->cluster_size == old_dos[i].cluster_size)) { + boot->boot.descr = old_dos[i].media; + Fs->cluster_size = old_dos[i].cluster_size; + Fs->dir_len = old_dos[i].dir_len; + Fs->fat_len = old_dos[i].fat_len; + Fs->fat_bits = 12; + break; + } + } + if (i == sizeof(old_dos) / sizeof(old_dos[0]) ){ + int may_change_cluster_size = (Fs->cluster_size == 0); + int may_change_root_size = (Fs->dir_len == 0); + + /* a non-standard format */ + if(DWORD(nhs)) + boot->boot.descr = 0xf8; + else + boot->boot.descr = 0xf0; + + + if(!Fs->cluster_size) { + if (dev->heads == 1) + Fs->cluster_size = 1; + else { + Fs->cluster_size = (tot_sectors > 2000 ) ? 1:2; + if (dev->use_2m & 0x7f) + Fs->cluster_size = 1; + } + } + + if(!Fs->dir_len) { + if (dev->heads == 1) + Fs->dir_len = 4; + else + Fs->dir_len = (tot_sectors > 2000) ? 32 : 7; + } + + calc_cluster_size(Fs, tot_sectors, dev->fat_bits); + if(Fs->fat_len) + xdf_calc_fat_size(Fs, tot_sectors, dev->fat_bits); + else { + calc_fat_bits2(Fs, tot_sectors, dev->fat_bits, + may_change_cluster_size, + may_change_root_size); + calc_fat_size(Fs, tot_sectors); + } + } + + set_word(boot->boot.fatlen, Fs->fat_len); +} + + + +static void calc_fs_parameters_32(unsigned long tot_sectors, + struct Fs_t *Fs, union bootsector *boot) +{ + if(DWORD(nhs)) + boot->boot.descr = 0xf8; + else + boot->boot.descr = 0xf0; + if(!Fs->cluster_size) + /* According to + * http://www.microsoft.com/kb/articles/q154/9/97.htm, + * Micro$oft does not support FAT32 with less than 4K + */ + Fs->cluster_size = 8; + + Fs->dir_len = 0; + Fs->num_clus = tot_sectors / Fs->cluster_size; + set_fat32(Fs); + calc_fat_size(Fs, tot_sectors); + set_word(boot->boot.fatlen, 0); + set_dword(boot->boot.ext.fat32.bigFat, Fs->fat_len); +} + + + + +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-V] [-t tracks] [-h heads] [-n sectors] " + "[-v label] [-1] [-4] [-8] [-f size] " + "[-N serialnumber] " + "[-k] [-B bootsector] [-r root_dir_len] [-L fat_len] " + "[-F] [-I fsVersion] [-C] [-c cluster_size] " + "[-H hidden_sectors] " +#ifdef USE_XDF + "[-X] " +#endif + "[-S hardsectorsize] [-M softsectorsize] [-3] " + "[-2 track0sectors] [-0 rate0] [-A rateany] [-a]" + "device\n", progname); + exit(ret); +} + +#ifdef OS_linux +static int get_block_geom(int fd, struct MT_STAT *buf, struct device *dev, + char *errmsg) { + struct hd_geometry geom; + long size; + int heads=dev->heads; + int sectors=dev->sectors; + int sect_per_track; + + if (ioctl(fd, HDIO_GETGEO, &geom) < 0) { + sprintf(errmsg, "Could not get geometry of device (%s)", + strerror(errno)); + return -1; + } + + if (ioctl(fd, BLKGETSIZE, &size) < 0) { + sprintf(errmsg, "Could not get size of device (%s)", + strerror(errno)); + return -1; + } + + if(!heads) + heads = geom.heads; + if(!sectors) + sectors = geom.sectors; + + sect_per_track = heads * sectors; + if(!dev->hidden) { + int hidden; + hidden = geom.start % sect_per_track; + if(hidden && hidden != sectors) { + sprintf(errmsg, + "Hidden (%d) does not match sectors (%d)\n", + hidden, sectors); + return -1; + } + dev->hidden = hidden; + } + dev->heads = heads; + dev->sectors = sectors; + if(!dev->tracks) + dev->tracks = (size + dev->hidden) / sect_per_track; + size = dev->tracks * dev->heads * dev->sectors + dev->hidden; + return 0; +} +#endif + +void mformat(int argc, char **argv, int dummy) +{ + int r; /* generic return value */ + Fs_t Fs; + int hs, hs_set; + int arguse_2m = 0; + int sectors0=18; /* number of sectors on track 0 */ + int create = 0; + int rate_0, rate_any; + int mangled; + int argssize=0; /* sector size */ + int msize=0; + int fat32 = 0; + struct label_blk_t *labelBlock; + int bootOffset; + +#ifdef USE_XDF + unsigned int i; + int format_xdf = 0; + struct xdf_info info; +#endif + union bootsector boot; + char *bootSector=0; + int c; + int keepBoot = 0; + struct device used_dev; + int argtracks, argheads, argsectors; + unsigned long tot_sectors; + int blocksize; + + char drive, name[EXPAND_BUF]; + + char label[VBUFSIZE]; + + dos_name_t shortlabel; + struct device *dev; + char errmsg[200]; + + unsigned long serial; + int serial_set; + int fsVersion; + int mediaDesc=-1; + + mt_size_t maxSize; + + int Atari = 0; /* should we add an Atari-style serial number ? */ + + hs = hs_set = 0; + argtracks = 0; + argheads = 0; + argsectors = 0; + arguse_2m = 0; + argssize = 0x2; + label[0] = '\0'; + serial_set = 0; + serial = 0; + fsVersion = 0; + + Fs.cluster_size = 0; + Fs.refs = 1; + Fs.dir_len = 0; + if(getenv("MTOOLS_DIR_LEN")) { + Fs.dir_len = atoi(getenv("MTOOLS_DIR_LEN")); + if(Fs.dir_len <= 0) + Fs.dir_len=0; + } + Fs.fat_len = 0; + Fs.num_fat = 2; + if(getenv("MTOOLS_NFATS")) { + Fs.num_fat = atoi(getenv("MTOOLS_NFATS")); + if(Fs.num_fat <= 0) + Fs.num_fat=2; + } + Fs.Class = &FsClass; + rate_0 = mtools_rate_0; + rate_any = mtools_rate_any; + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc,argv, + "i:148f:t:n:v:qub" + "kB:r:L:I:FCc:Xh:s:l:N:H:M:S:2:30:Aad:m:"))!= EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + + /* standard DOS flags */ + case '1': + argheads = 1; + break; + case '4': + argsectors = 9; + argtracks = 40; + break; + case '8': + argsectors = 8; + argtracks = 40; + break; + case 'f': + r=old_dos_size_to_geom(atoi(optarg), + &argtracks, &argheads, + &argsectors); + if(r) { + fprintf(stderr, + "Bad size %s\n", optarg); + exit(1); + } + break; + case 't': + argtracks = atoi(optarg); + break; + + case 'n': /*non-standard*/ + case 's': + argsectors = atoi(optarg); + break; + + case 'l': /* non-standard */ + case 'v': + strncpy(label, optarg, VBUFSIZE-1); + label[VBUFSIZE-1] = '\0'; + break; + + /* flags supported by Dos but not mtools */ + case 'q': + case 'u': + case 'b': + /*case 's': leave this for compatibility */ + fprintf(stderr, + "Flag %c not supported by mtools\n",c); + exit(1); + + + + /* flags added by mtools */ + case 'F': + fat32 = 1; + break; + + + case 'S': + argssize = atoi(optarg) | 0x80; + if(argssize < 0x81) + usage(1); + if(argssize >= 0x87) { + fprintf(stderr, "argssize must be less than 6\n"); + usage(1); + } + break; + +#ifdef USE_XDF + case 'X': + format_xdf = 1; + break; +#endif + + case '2': + arguse_2m = 0xff; + sectors0 = atoi(optarg); + break; + case '3': + arguse_2m = 0x80; + break; + + case '0': /* rate on track 0 */ + rate_0 = atoi(optarg); + break; + case 'A': /* rate on other tracks */ + rate_any = atoi(optarg); + break; + + case 'M': + msize = atoi(optarg); + if(msize != 512 && + msize != 1024 && + msize != 2048 && + msize != 4096) { + fprintf(stderr, "Only sector sizes of 512, 1024, 2048 or 4096 bytes are allowed\n"); + usage(1); + } + break; + + case 'N': + serial = strtoul(optarg,0,16); + serial_set = 1; + break; + case 'a': /* Atari style serial number */ + Atari = 1; + break; + + case 'C': + create = O_CREAT | O_TRUNC; + break; + + case 'H': + hs = atoi(optarg); + hs_set = 1; + break; + + case 'I': + fsVersion = strtoul(optarg,0,0); + break; + + case 'c': + Fs.cluster_size = atoi(optarg); + break; + + case 'r': + Fs.dir_len = strtoul(optarg,0,0); + break; + case 'L': + Fs.fat_len = strtoul(optarg,0,0); + break; + + + case 'B': + bootSector = optarg; + break; + case 'k': + keepBoot = 1; + break; + case 'h': + argheads = atoi(optarg); + break; + case 'd': + Fs.num_fat = atoi(optarg); + break; + case 'm': + mediaDesc = strtoul(optarg,0,0); + break; + default: + usage(1); + } + } + + if (argc - optind != 1 || + !argv[optind][0] || argv[optind][1] != ':') + usage(1); + +#ifdef USE_XDF + if(create && format_xdf) { + fprintf(stderr,"Create and XDF can't be used together\n"); + exit(1); + } +#endif + + drive = toupper(argv[argc -1][0]); + + /* check out a drive whose letter and parameters match */ + sprintf(errmsg, "Drive '%c:' not supported", drive); + Fs.Direct = NULL; + blocksize = 0; + for(dev=devices;dev->drive;dev++) { + FREE(&(Fs.Direct)); + /* drive letter */ + if (dev->drive != drive) + continue; + used_dev = *dev; + + SET_INT(used_dev.tracks, argtracks); + SET_INT(used_dev.heads, argheads); + SET_INT(used_dev.sectors, argsectors); + SET_INT(used_dev.use_2m, arguse_2m); + SET_INT(used_dev.ssize, argssize); + if(hs_set) + used_dev.hidden = hs; + + expand(dev->name, name); +#ifdef USING_NEW_VOLD + strcpy(name, getVoldName(dev, name)); +#endif + +#ifdef USE_XDF + if(!format_xdf) { +#endif + Fs.Direct = 0; +#ifdef USE_FLOPPYD + Fs.Direct = FloppydOpen(&used_dev, dev, name, + O_RDWR | create, + errmsg, 0, 1); + if(Fs.Direct) { + maxSize = max_off_t_31; + } +#endif + if(!Fs.Direct) { + Fs.Direct = SimpleFileOpen(&used_dev, dev, name, + O_RDWR | create, + errmsg, 0, 1, + &maxSize); + } +#ifdef USE_XDF + } else { + used_dev.misc_flags |= USE_XDF_FLAG; + Fs.Direct = XdfOpen(&used_dev, name, O_RDWR, + errmsg, &info); + if(Fs.Direct && !Fs.fat_len) + Fs.fat_len = info.FatSize; + if(Fs.Direct && !Fs.dir_len) + Fs.dir_len = info.RootDirSize; + } +#endif + + if (!Fs.Direct) + continue; + +#ifdef OS_linux + if ((!used_dev.tracks || !used_dev.heads || !used_dev.sectors) && + (!IS_SCSI(dev))) { + int fd= get_fd(Fs.Direct); + struct MT_STAT stbuf; + + if (MT_FSTAT(fd, &stbuf) < 0) { + sprintf(errmsg, "Could not stat file (%s)", strerror(errno)); + continue; + } + + if (S_ISBLK(stbuf.st_mode) && + get_block_geom(fd, &stbuf, &used_dev, errmsg) < 0) + continue; + } +#endif + + /* no way to find out geometry */ + if (!used_dev.tracks || !used_dev.heads || !used_dev.sectors){ + sprintf(errmsg, + "Unknown geometry " + "(You must tell the complete geometry " + "of the disk, \neither in /etc/mtools.conf or " + "on the command line) "); + continue; + } + +#if 0 + /* set parameters, if needed */ + if(SET_GEOM(Fs.Direct, &used_dev, 0xf0, boot)){ + sprintf(errmsg,"Can't set disk parameters: %s", + strerror(errno)); + continue; + } +#endif + Fs.sector_size = 512; + if( !(used_dev.use_2m & 0x7f)) { + Fs.sector_size = 128 << (used_dev.ssize & 0x7f); + } + + SET_INT(Fs.sector_size, msize); + { + unsigned int j; + for(j = 0; j < 31; j++) { + if (Fs.sector_size == (unsigned int) (1 << j)) { + Fs.sectorShift = j; + break; + } + } + Fs.sectorMask = Fs.sector_size - 1; + } + + if(!used_dev.blocksize || used_dev.blocksize < Fs.sector_size) + blocksize = Fs.sector_size; + else + blocksize = used_dev.blocksize; + + if(blocksize > MAX_SECTOR) + blocksize = MAX_SECTOR; + + /* do a "test" read */ + if (!create && + READS(Fs.Direct, &boot.characters, 0, Fs.sector_size) != + (signed int) Fs.sector_size) { + sprintf(errmsg, + "Error reading from '%s', wrong parameters?", + name); + continue; + } + break; + } + + + /* print error msg if needed */ + if ( dev->drive == 0 ){ + FREE(&Fs.Direct); + fprintf(stderr,"%s: %s\n", argv[0],errmsg); + exit(1); + } + + /* calculate the total number of sectors */ + tot_sectors = used_dev.tracks*used_dev.heads*used_dev.sectors - used_dev.hidden; + + /* create the image file if needed */ + if (create) { + WRITES(Fs.Direct, &boot.characters, + sectorsToBytes((Stream_t*)&Fs, tot_sectors-1), + Fs.sector_size); + } + + /* the boot sector */ + if(bootSector) { + int fd; + + fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE); + if(fd < 0) { + perror("open boot sector"); + exit(1); + } + if(read(fd, &boot.bytes, blocksize) < blocksize) { + perror("short read on boot sector"); + exit(1); + } + keepBoot = 1; + } + if(!keepBoot && !(used_dev.use_2m & 0x7f)) { + memset(boot.characters, '\0', Fs.sector_size); + if(Fs.sector_size == 512 && !used_dev.partition) { + /* install fake partition table pointing to itself */ + struct partition *partTable=(struct partition *) + (&boot.bytes[0x1ae]); + setBeginEnd(&partTable[1], 0, + used_dev.heads * used_dev.sectors * used_dev.tracks, + used_dev.heads, used_dev.sectors, 1, 0); + } + } + set_dword(boot.boot.nhs, used_dev.hidden); + + Fs.Next = buf_init(Fs.Direct, + blocksize * used_dev.heads * used_dev.sectors, + blocksize * used_dev.heads * used_dev.sectors, + blocksize); + Fs.Buffer = 0; + + boot.boot.nfat = Fs.num_fat; + if(!keepBoot) + set_word(&boot.bytes[510], 0xaa55); + + /* Initialize the remaining parameters */ + set_word(boot.boot.nsect, used_dev.sectors); + set_word(boot.boot.nheads, used_dev.heads); + + used_dev.fat_bits = comp_fat_bits(&Fs,used_dev.fat_bits, tot_sectors, fat32); + + if(used_dev.fat_bits == 32) { + Fs.primaryFat = 0; + Fs.writeAllFats = 1; + Fs.fat_start = 32; + calc_fs_parameters_32(tot_sectors, &Fs, &boot); + + Fs.clus_start = Fs.num_fat * Fs.fat_len + Fs.fat_start; + + /* extension flags: mirror fats, and use #0 as primary */ + set_word(boot.boot.ext.fat32.extFlags,0); + + /* fs version. What should go here? */ + set_word(boot.boot.ext.fat32.fsVersion,fsVersion); + + /* root directory */ + set_dword(boot.boot.ext.fat32.rootCluster, Fs.rootCluster = 2); + + /* info sector */ + set_word(boot.boot.ext.fat32.infoSector, Fs.infoSectorLoc = 1); + Fs.infoSectorLoc = 1; + + /* no backup boot sector */ + set_word(boot.boot.ext.fat32.backupBoot, 6); + + labelBlock = & boot.boot.ext.fat32.labelBlock; + } else { + Fs.infoSectorLoc = 0; + Fs.fat_start = 1; + calc_fs_parameters(&used_dev, tot_sectors, &Fs, &boot); + Fs.dir_start = Fs.num_fat * Fs.fat_len + Fs.fat_start; + Fs.clus_start = Fs.dir_start + Fs.dir_len; + labelBlock = & boot.boot.ext.old.labelBlock; + + } + + /* Set the codepage */ + Fs.cp = cp_open(used_dev.codepage); + if(Fs.cp == NULL) + exit(1); + + if (!keepBoot) + /* only zero out physdrive if we don't have a template + * bootsector */ + labelBlock->physdrive = 0x00; + labelBlock->reserved = 0; + labelBlock->dos4 = 0x29; + + if (!serial_set || Atari) + srandom((long)time (0)); + if (!serial_set) + serial=random(); + set_dword(labelBlock->serial, serial); + label_name(GET_DOSCONVERT((Stream_t *)&Fs), + label[0] ? label : "NO NAME ", 0, &mangled, &shortlabel); + strncpy(labelBlock->label, shortlabel.base, 11); + sprintf(labelBlock->fat_type, "FAT%2.2d ", Fs.fat_bits); + labelBlock->fat_type[7] = ' '; + + set_word(boot.boot.secsiz, Fs.sector_size); + boot.boot.clsiz = (unsigned char) Fs.cluster_size; + set_word(boot.boot.nrsvsect, Fs.fat_start); + + bootOffset = init_geometry_boot(&boot, &used_dev, sectors0, + rate_0, rate_any, + &tot_sectors, keepBoot); + if(!bootOffset) { + bootOffset = ((unsigned char *) labelBlock) - boot.bytes + + sizeof(struct label_blk_t); + } + if(Atari) { + boot.boot.banner[4] = 0; + boot.boot.banner[5] = random(); + boot.boot.banner[6] = random(); + boot.boot.banner[7] = random(); + } + + if(!keepBoot) + inst_boot_prg(&boot, bootOffset); + /* Mimic 3.8 behavior, else 2m disk do not work (???) + * luferbu@fluidsignal.com (Luis Bustamante), Fri, 14 Jun 2002 + */ + if(used_dev.use_2m & 0x7f) { + boot.boot.jump[0] = 0xeb; + boot.boot.jump[1] = 0x80; + boot.boot.jump[2] = 0x90; + } + if(used_dev.use_2m & 0x7f) + Fs.num_fat = 1; + if(mediaDesc != -1) + boot.boot.descr=mediaDesc; + Fs.lastFatSectorNr = 0; + Fs.lastFatSectorData = 0; + zero_fat(&Fs, boot.boot.descr); + Fs.freeSpace = Fs.num_clus; + Fs.last = 2; + +#ifdef USE_XDF + if(format_xdf) + for(i=0; + i < (info.BadSectors+Fs.cluster_size-1)/Fs.cluster_size; + i++) + fatEncode(&Fs, i+2, 0xfff7); +#endif + + format_root(&Fs, label, &boot); + WRITES((Stream_t *)&Fs, boot.characters, + (mt_off_t) 0, Fs.sector_size); + if(Fs.fat_bits == 32 && WORD_S(ext.fat32.backupBoot) != MAX16) { + WRITES((Stream_t *)&Fs, boot.characters, + sectorsToBytes((Stream_t*)&Fs, + WORD_S(ext.fat32.backupBoot)), + Fs.sector_size); + } + FLUSH((Stream_t *)&Fs); /* flushes Fs. + * This triggers the writing of the FAT */ + FREE(&Fs.Next); + Fs.Class->freeFunc((Stream_t *)&Fs); +#ifdef USE_XDF + if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF")) + fprintf(stderr, + "Note:\n" + "Remember to set the \"MTOOLS_USE_XDF\" environmental\n" + "variable before accessing this disk\n\n" + "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\n" + " export MTOOLS_USE_XDF=1\n\n" + "C shell syntax (csh and tcsh):\n" + " setenv MTOOLS_USE_XDF 1\n" ); +#endif + exit(0); +} diff --git a/minfo.1 b/minfo.1 new file mode 100644 index 0000000..adf7ae0 --- /dev/null +++ b/minfo.1 @@ -0,0 +1,101 @@ +.TH minfo 1 "03Nov09" mtools-4.0.12 +.SH Name +minfo - print the parameters of a MSDOS filesystem +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p minfo" +.iX "c mformat parameters" +.iX "c getting parameters of a Dos fs" +.PP +The \fR\&\f(CWminfo\fR command prints the parameters of a Dos filesystem, such +as number of sectors, heads and cylinders. It also prints an mformat +command line which can be used to create a similar Dos filesystem on +another media. However, this doesn't work with 2m or Xdf media, and +with Dos 1.0 filesystems +.ft I +.nf +\&\fR\&\f(CWminfo\fR \fIdrive\fR: +.fi +.ft R + +.PP +Mlabel supports the following option: +.TP +\&\fR\&\f(CWv\fR\ +Prints a hexdump of the bootsector, in addition to the other information +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/minfo.c b/minfo.c new file mode 100644 index 0000000..641b352 --- /dev/null +++ b/minfo.c @@ -0,0 +1,208 @@ +/* Copyright 1997-2003,2006,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mlabel.c + * Make an MSDOS volume label + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mainloop.h" +#include "vfat.h" +#include "mtools.h" +#include "nameclash.h" + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-v] drive\n", progname); + exit(ret); +} + + +static void displayInfosector(Stream_t *Stream, union bootsector *boot) +{ + InfoSector_t *infosec; + + if(WORD(ext.fat32.infoSector) == MAX16) + return; + + infosec = (InfoSector_t *) safe_malloc(WORD(secsiz)); + force_read(Stream, (char *) infosec, + (mt_off_t) WORD(secsiz) * WORD(ext.fat32.infoSector), + WORD(secsiz)); + printf("\nInfosector:\n"); + printf("signature=0x%08x\n", _DWORD(infosec->signature1)); + if(_DWORD(infosec->count) != MAX32) + printf("free clusters=%u\n", _DWORD(infosec->count)); + if(_DWORD(infosec->pos) != MAX32) + printf("last allocated cluster=%u\n", _DWORD(infosec->pos)); +} + + +void minfo(int argc, char **argv, int type) +{ + union bootsector boot; + + char name[EXPAND_BUF]; + int media; + int tot_sectors; + int size_code; + int sector_size; + int i; + struct device dev; + char drive; + int verbose=0; + int c; + Stream_t *Stream; + struct label_blk_t *labelBlock; + + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:vh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'v': + verbose = 1; + break; + case 'h': + usage(0); + default: + usage(1); + } + } + + if(argc == optind) + usage(1); + + for(;optind < argc; optind++) { + if(!argv[optind][0] || argv[optind][1] != ':') + usage(1); + drive = toupper(argv[optind][0]); + + if(! (Stream = find_device(drive, O_RDONLY, &dev, &boot, + name, &media, 0, NULL))) + exit(1); + + tot_sectors = DWORD_S(bigsect); + SET_INT(tot_sectors, WORD_S(psect)); + sector_size = WORD_S(secsiz); + size_code=2; + for(i=0; i<7; i++) { + if(sector_size == 128 << i) { + size_code = i; + break; + } + } + printf("device information:\n"); + printf("===================\n"); + printf("filename=\"%s\"\n", name); + printf("sectors per track: %d\n", dev.sectors); + printf("heads: %d\n", dev.heads); + printf("cylinders: %d\n\n", dev.tracks); + printf("mformat command line: mformat -t %d -h %d -s %d ", + dev.tracks, dev.heads, dev.sectors); + if(DWORD_S(nhs)) + printf("-H %d ", DWORD_S(nhs)); + if(size_code != 2) + printf("-S %d ",size_code); + printf("%c:\n", tolower(drive)); + printf("\n"); + + printf("bootsector information\n"); + printf("======================\n"); + printf("banner:\"%8s\"\n", boot.boot.banner); + printf("sector size: %d bytes\n", WORD_S(secsiz)); + printf("cluster size: %d sectors\n", boot.boot.clsiz); + printf("reserved (boot) sectors: %d\n", WORD_S(nrsvsect)); + printf("fats: %d\n", boot.boot.nfat); + printf("max available root directory slots: %d\n", + WORD_S(dirents)); + printf("small size: %d sectors\n", WORD_S(psect)); + printf("media descriptor byte: 0x%x\n", boot.boot.descr); + printf("sectors per fat: %d\n", WORD_S(fatlen)); + printf("sectors per track: %d\n", WORD_S(nsect)); + printf("heads: %d\n", WORD_S(nheads)); + printf("hidden sectors: %d\n", DWORD_S(nhs)); + printf("big size: %d sectors\n", DWORD_S(bigsect)); + + if(WORD_S(fatlen)) { + labelBlock = &boot.boot.ext.old.labelBlock; + } else { + labelBlock = &boot.boot.ext.fat32.labelBlock; + } + + printf("physical drive id: 0x%x\n", + labelBlock->physdrive); + printf("reserved=0x%x\n", + labelBlock->reserved); + printf("dos4=0x%x\n", + labelBlock->dos4); + printf("serial number: %08X\n", + _DWORD(labelBlock->serial)); + printf("disk label=\"%11.11s\"\n", + labelBlock->label); + printf("disk type=\"%8.8s\"\n", + labelBlock->fat_type); + + if(!WORD_S(fatlen)){ + printf("Big fatlen=%u\n", + DWORD_S(ext.fat32.bigFat)); + printf("Extended flags=0x%04x\n", + WORD_S(ext.fat32.extFlags)); + printf("FS version=0x%04x\n", + WORD_S(ext.fat32.fsVersion)); + printf("rootCluster=%u\n", + DWORD_S(ext.fat32.rootCluster)); + if(WORD_S(ext.fat32.infoSector) != MAX16) + printf("infoSector location=%d\n", + WORD_S(ext.fat32.infoSector)); + if(WORD_S(ext.fat32.backupBoot) != MAX16) + printf("backup boot sector=%d\n", + WORD_S(ext.fat32.backupBoot)); + displayInfosector(Stream,&boot); + } + + if(verbose) { + int size; + unsigned char *buf; + + printf("\n"); + size = WORD_S(secsiz); + + buf = (unsigned char *) malloc(size); + if(!buf) { + fprintf(stderr, "Out of memory error\n"); + exit(1); + } + + size = READS(Stream, buf, (mt_off_t) 0, size); + if(size < 0) { + perror("read boot sector"); + exit(1); + } + + print_sector("Boot sector hexdump", buf, size); + } + } + FREE(&Stream); + exit(0); +} diff --git a/misc.c b/misc.c new file mode 100644 index 0000000..c27940c --- /dev/null +++ b/misc.c @@ -0,0 +1,235 @@ +/* Copyright 1996-2002,2005,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Miscellaneous routines. + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "vfat.h" +#include "mtools.h" + + +void printOom(void) +{ + fprintf(stderr, "Out of memory error"); +} + +char *get_homedir(void) +{ +#ifndef OS_mingw32msvc + struct passwd *pw; + uid_t uid; + char *homedir; + char *username; + + homedir = getenv ("HOME"); + /* + * first we call getlogin. + * There might be several accounts sharing one uid + */ + if ( homedir ) + return homedir; + + pw = 0; + + username = getenv("LOGNAME"); + if ( !username ) + username = getlogin(); + if ( username ) + pw = getpwnam( username); + + if ( pw == 0 ){ + /* if we can't getlogin, look up the pwent by uid */ + uid = geteuid(); + pw = getpwuid(uid); + } + + /* we might still get no entry */ + if ( pw ) + return pw->pw_dir; + return 0; +#else + return getenv("HOME"); +#endif +} + + +static void get_mcwd_file_name(char *file) +{ + char *mcwd_path; + const char *homedir; + + mcwd_path = getenv("MCWD"); + if (mcwd_path == NULL || *mcwd_path == '\0'){ + homedir= get_homedir(); + if(!homedir) + homedir="/tmp"; + strncpy(file, homedir, MAXPATHLEN-6); + file[MAXPATHLEN-6]='\0'; + strcat( file, "/.mcwd"); + } else { + strncpy(file, mcwd_path, MAXPATHLEN); + file[MAXPATHLEN]='\0'; + } +} + +void unlink_mcwd(void) +{ + char file[MAXPATHLEN+1]; + get_mcwd_file_name(file); + unlink(file); +} + +FILE *open_mcwd(const char *mode) +{ + struct MT_STAT sbuf; + char file[MAXPATHLEN+1]; + time_t now; + + get_mcwd_file_name(file); + if (*mode == 'r'){ + if (MT_STAT(file, &sbuf) < 0) + return NULL; + /* + * Ignore the info, if the file is more than 6 hours old + */ + getTimeNow(&now); + if (now - sbuf.st_mtime > 6 * 60 * 60) { + fprintf(stderr, + "Warning: \"%s\" is out of date, removing it\n", + file); + unlink(file); + return NULL; + } + } + + return fopen(file, mode); +} + + + +void *safe_malloc(size_t size) +{ + void *p; + + p = malloc(size); + if(!p){ + printOom(); + exit(1); + } + return p; +} + +void print_sector(const char *message, unsigned char *data, int size) +{ + int col; + int row; + + printf("%s:\n", message); + + for(row = 0; row * 16 < size; row++){ + printf("%03x ", row * 16); + for(col = 0; col < 16; col++) + printf("%02x ", data [row*16+col]); + for(col = 0; col < 16; col++) { + if(isprint(data [row*16+col])) + printf("%c", data [row*16+col]); + else + printf("."); + } + printf("\n"); + } +} + + +time_t getTimeNow(time_t *now) +{ + static int haveTime = 0; + static time_t sharedNow; + + if(!haveTime) { + time(&sharedNow); + haveTime = 1; + } + if(now) + *now = sharedNow; + return sharedNow; +} + +#if 0 + +#undef free +#undef malloc + +static int total=0; + +void myfree(void *ptr) +{ + int *size = ((int *) ptr)-1; + total -= *size; + fprintf(stderr, "freeing %d bytes at %p total alloced=%d\n", + *size, ptr, total); + free(size); +} + +void *mymalloc(size_t size) +{ + int *ptr; + ptr = (int *)malloc(size+sizeof(int)); + if(!ptr) + return 0; + *ptr = size; + ptr++; + total += size; + fprintf(stderr, "allocating %d bytes at %p total allocated=%d\n", + size, ptr, total); + return (void *) ptr; +} + +void *mycalloc(size_t nmemb, size_t size) +{ + void *ptr = mymalloc(nmemb * size); + if(!ptr) + return 0; + memset(ptr, 0, size); + return ptr; +} + +void *myrealloc(void *ptr, size_t size) +{ + int oldsize = ((int *)ptr) [-1]; + void *new = mymalloc(size); + if(!new) + return 0; + memcpy(new, ptr, oldsize); + myfree(ptr); + return new; +} + +char *mystrdup(char *src) +{ + char *dest; + dest = mymalloc(strlen(src)+1); + if(!dest) + return 0; + strcpy(dest, src); + return dest; +} + + +#endif diff --git a/missFuncs.c b/missFuncs.c new file mode 100644 index 0000000..e16d9e3 --- /dev/null +++ b/missFuncs.c @@ -0,0 +1,477 @@ +/* Copyright 1991 Free Software Foundation, Inc. + * Copyright 1997,1999-2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "sysincludes.h" +#include "mtools.h" + +#ifndef HAVE_STRDUP + + +char *strdup(const char *str) +{ + char *nstr; + + if (str == (char*)0) + return 0; + + nstr = (char*)malloc((strlen(str) + 1)); + + if (nstr == (char*)0) + { + (void)fprintf(stderr, "strdup(): not enough memory to duplicate `%s'\n", + str); + exit(1); + } + + (void)strcpy(nstr, str); + + return nstr; +} +#endif /* HAVE_STRDUP */ + +#ifdef HAVE_WCHAR_H +#ifndef HAVE_WCSDUP +wchar_t *wcsdup(const wchar_t *wcs) +{ + wchar_t *nwcs; + + if (wcs == (wchar_t*)0) + return 0; + + nwcs = (wchar_t*)calloc(wcslen(wcs) + 1, sizeof(wchar_t)); + + if (nwcs == (wchar_t*)0) + { + (void)fprintf(stderr, "wcsdup(): not enough memory to duplicate `%ls'\n", + wcs); + exit(1); + } + + (void)wcscpy(nwcs, wcs); + + return nwcs; +} +#endif /* HAVE_WCSDUP */ +#endif + +#ifndef HAVE_MEMCPY +/* + * Copy contents of memory (with possible overlapping). + */ +char *memcpy(char *s1, const char *s2, size_t n) +{ + bcopy(s2, s1, n); + return(s1); +} +#endif + +#ifndef HAVE_MEMSET +/* + * Copies the character c, n times to string s + */ +char *memset(char *s, char c, size_t n) +{ + char *s1 = s; + + while (n > 0) { + --n; + *s++ = c; + } + return(s1); +} +#endif /* HAVE_MEMSET */ + + +#ifndef HAVE_STRCHR + +char * strchr (const char* s, int c) +{ + if (!s) return NULL; + while (*s && *s != c) s++; + if (*s) + return (char*) s; + else + return NULL; +} + +#endif + +#ifndef HAVE_STRRCHR + +char * strrchr (const char* s1, int c) +{ + char* s = (char*) s1; + char* start = (char*) s; + if (!s) return NULL; + s += strlen(s)-1; + while (*s != c && (unsigned long) s != (unsigned long) start) s--; + if ((unsigned long) s == (unsigned long) start && *s != c) + return NULL; + else + return s; +} + +#endif + +#ifndef HAVE_STRPBRK +/* + * Return ptr to first occurrence of any character from `brkset' + * in the character string `string'; NULL if none exists. + */ +char *strpbrk(const char *string, const char *brkset) +{ + register char *p; + + if (!string || !brkset) + return(0); + do { + for (p = brkset; *p != '\0' && *p != *string; ++p) + ; + if (*p != '\0') + return(string); + } + while (*string++); + return(0); +} +#endif /* HAVE_STRPBRK */ + + +#ifndef HAVE_STRTOUL +static int getdigit(char a, int max) +{ + int dig; + + if(a < '0') + return -1; + if(a <= '9') { + dig = a - '0'; + } else if(a >= 'a') + dig = a - 'a' + 10; + else if(a >= 'A') + dig = a - 'A' + 10; + if(dig >= max) + return -1; + else + return dig; +} + +unsigned long strtoul(const char *string, char **eptr, int base) +{ + int accu, dig; + + if(base < 1 || base > 36) { + if(string[0] == '0') { + switch(string[1]) { + case 'x': + case 'X': + return strtoul(string+2, eptr, 16); + case 'b': + case 'B': + return strtoul(string+2, eptr, 2); + default: + return strtoul(string, eptr, 8); + } + } + return strtoul(string, eptr, 10); + } + if(base == 16 && string[0] == '0' && + (string[1] == 'x' || string[1] == 'X')) + string += 2; + + if(base == 2 && string[0] == '0' && + (string[1] == 'b' || string[1] == 'B')) + string += 2; + accu = 0; + while( (dig = getdigit(*string, base)) != -1 ) { + accu = accu * base + dig; + string++; + } + if(eptr) + *eptr = (char *) string; + return accu; +} +#endif /* HAVE_STRTOUL */ + +#ifndef HAVE_STRTOL +long strtol(const char *string, char **eptr, int base) +{ + long l; + + if(*string == '-') { + return -(long) strtoul(string+1, eptr, base); + } else { + if (*string == '+') + string ++; + return (long) strtoul(string, eptr, base); + } +} +#endif + + + +#ifndef HAVE_STRSPN +/* Return the length of the maximum initial segment + of S which contains only characters in ACCEPT. */ +size_t strspn(const char *s, const char *accept) +{ + register char *p; + register char *a; + register size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + else + ++count; + } + + return count; +} +#endif /* HAVE_STRSPN */ + +#ifndef HAVE_STRCSPN +/* Return the length of the maximum inital segment of S + which contains no characters from REJECT. */ +size_t strcspn (const char *s, const char *reject) +{ + register size_t count = 0; + + while (*s != '\0') + if (strchr (reject, *s++) == NULL) + ++count; + else + return count; + + return count; +} + +#endif /* HAVE_STRCSPN */ + +#ifndef HAVE_STRERROR + +#ifndef DECL_SYS_ERRLIST +extern char *sys_errlist[]; +#endif + +char *strerror(int errno) +{ + return sys_errlist[errno]; +} +#endif + +#ifndef HAVE_STRCASECMP +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexiographically less than, + equal to or greater than S2. */ +int strcasecmp(const char *s1, const char *s2) +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + + if (p1 == p2) + return 0; + + do + { + c1 = tolower (*p1++); + c2 = tolower (*p2++); + if (c1 == '\0') + break; + } + while (c1 == c2); + + return c1 - c2; +} +#endif + +#ifdef HAVE_WCHAR_H +#ifndef HAVE_WCSCASECMP +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexiographically less than, + equal to or greater than S2. */ +int wcscasecmp(const wchar_t *s1, const wchar_t *s2) +{ + register const wchar_t *p1 = s1; + register const wchar_t *p2 = s2; + wchar_t c1, c2; + + if (p1 == p2) + return 0; + + do + { + c1 = towlower (*p1++); + c2 = towlower (*p2++); + if (c1 == '\0') + break; + } + while (c1 == c2); + + return c1 - c2; +} +#endif +#endif + + +#ifndef HAVE_STRCASECMP +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexiographically less than, + equal to or greater than S2. */ +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + + if (p1 == p2) + return 0; + + c1 = c2 = 1; + while (c1 && c1 == c2 && n-- > 0) + { + c1 = tolower (*p1++); + c2 = tolower (*p2++); + } + + return c1 - c2; +} +#endif + +#ifndef HAVE_GETPASS +char *getpass(const char *prompt) +{ + static char password[129]; + int l; + + fprintf(stderr,"%s",prompt); + fgets(password, 128, stdin); + l = strlen(password); + if(l && password[l-1] == '\n') + password[l-1] = '\0'; + return password; + +} +#endif + +#ifndef HAVE_ATEXIT + +#ifdef HAVE_ON_EXIT +int atexit(void (*function)(void)) +{ + return on_exit( (void(*)(int,void*)) function, 0); +} +#else + +typedef struct exitCallback { + void (*function) (void); + struct exitCallback *next; +} exitCallback_t; + +static exitCallback_t *callback = 0; + +int atexit(void (*function) (void)) +{ + exitCallback_t *newCallback; + + newCallback = New(exitCallback_t); + if(!newCallback) { + printOom(); + exit(1); + } + newCallback->function = function; + newCallback->next = callback; + callback = newCallback; + return 0; +} +#undef exit + +void myexit(int code) +{ + void (*function)(void); + + while(callback) { + function = callback->function; + callback = callback->next; + function(); + } + exit(code); +} + +#endif + +#endif + +static const char PATH_SEP = '/'; + +/*#ifndef HAVE_BASENAME*/ +const char *_basename(const char *filename) +{ + char *ptr; + + ptr = strrchr(filename, PATH_SEP); + if(ptr) + filename = ptr + 1; + +#ifdef OS_mingw32msvc + ptr = strrchr(filename, '\\'); + if(ptr) + filename = ptr + 1; +#endif + + return filename; +} +/*#endif*/ + +/* Strip the suffix ".exe" from the argument, if present. */ +void _stripexe(char *filename) +{ + char *ptr; + ptr = strrchr(filename, '.'); + if(ptr && !strcasecmp(ptr, ".exe")) + *ptr = '\0'; +} + +#ifndef HAVE_STRNLEN +size_t strnlen(const char *str, size_t l) +{ + size_t i; + for(i=0; i. + * + * mk_direntry.c + * Make new directory entries, and handles name clashes + * + */ + +/* + * This file is used by those commands that need to create new directory entries + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "nameclash.h" +#include "fs.h" +#include "stream.h" +#include "mainloop.h" +#include "file_name.h" + +/** + * Converts input to shortname + * @param un unix name (in Unix charset) + * + * @return 1 if name had to be mangled + */ +static __inline__ int convert_to_shortname(doscp_t *cp, ClashHandling_t *ch, + const char *un, dos_name_t *dn) +{ + int mangled; + + /* Then do conversion to dn */ + ch->name_converter(cp, un, 0, &mangled, dn); + dn->sentinel = '\0'; + return mangled; +} + +static __inline__ void chomp(char *line) +{ + int l = strlen(line); + while(l > 0 && (line[l-1] == '\n' || line[l-1] == '\r')) { + line[--l] = '\0'; + } +} + +/** + * Asks for an alternative new name for a file, in case of a clash + */ +static __inline__ int ask_rename(doscp_t *cp, ClashHandling_t *ch, + dos_name_t *shortname, + char *longname, + int isprimary) +{ + int mangled; + + /* TODO: Would be nice to suggest "autorenamed" version of name, press + * to get it. + */ +#if 0 + fprintf(stderr,"Entering ask_rename, isprimary=%d.\n", isprimary); +#endif + + if(!opentty(0)) + return 0; + +#define maxsize (isprimary ? MAX_VNAMELEN+1 : 11+1) +#define name (isprimary ? argname : shortname) + + mangled = 0; + do { + char tname[4*MAX_VNAMELEN+1]; + fprintf(stderr, "New %s name for \"%s\": ", + isprimary ? "primary" : "secondary", longname); + fflush(stderr); + if (! fgets(tname, 4*MAX_VNAMELEN+1, opentty(0))) + return 0; + chomp(tname); + if (isprimary) + strcpy(longname, tname); + else + mangled = convert_to_shortname(cp, + ch, tname, shortname); + } while (mangled & 1); + return 1; +#undef maxsize +#undef name +} + +/** + * This function determines the action to be taken in case there is a problem + * with target name (clash, illegal characters, or reserved) + * The decision either comes from the default (ch), or the user will be + * prompted if there is no default + */ +static __inline__ clash_action ask_namematch(doscp_t *cp, + dos_name_t *dosname, + char *longname, + int isprimary, + ClashHandling_t *ch, + int no_overwrite, + int reason) +{ + /* User's answer letter (from keyboard). Only first letter is used, + * but we allocate space for 10 in order to account for extra garbage + * that user may enter + */ + char ans[10]; + + /** + * Return value: action to be taken + */ + clash_action a; + + /** + * Should this decision be made permanent (do no longer ask same + * question) + */ + int perm; + + /** + * Buffer for shortname + */ + char name_buffer[4*13]; + + /** + * Name to be printed + */ + char *name; + +#define EXISTS 0 +#define RESERVED 1 +#define ILLEGALS 2 + + static const char *reasons[]= { + "already exists", + "is reserved", + "contains illegal character(s)"}; + + a = ch->action[isprimary]; + + if(a == NAMEMATCH_NONE && !opentty(1)) { + /* no default, and no tty either . Skip the troublesome file */ + return NAMEMATCH_SKIP; + } + + if (!isprimary) + name = unix_normalize(cp, name_buffer, dosname); + else + name = longname; + + perm = 0; + while (a == NAMEMATCH_NONE) { + fprintf(stderr, "%s file name \"%s\" %s.\n", + isprimary ? "Long" : "Short", name, reasons[reason]); + fprintf(stderr, + "a)utorename A)utorename-all r)ename R)ename-all "); + if(!no_overwrite) + fprintf(stderr,"o)verwrite O)verwrite-all"); + fprintf(stderr, + "\ns)kip S)kip-all q)uit (aArR"); + if(!no_overwrite) + fprintf(stderr,"oO"); + fprintf(stderr,"sSq): "); + fflush(stderr); + fflush(opentty(1)); + if (mtools_raw_tty) { + int rep; + rep = fgetc(opentty(1)); + fputs("\n", stderr); + if(rep == EOF) + ans[0] = 'q'; + else + ans[0] = rep; + } else { + if(fgets(ans, 9, opentty(0)) == NULL) + ans[0] = 'q'; + } + perm = isupper((unsigned char)ans[0]); + switch(tolower((unsigned char)ans[0])) { + case 'a': + a = NAMEMATCH_AUTORENAME; + break; + case 'r': + if(isprimary) + a = NAMEMATCH_PRENAME; + else + a = NAMEMATCH_RENAME; + break; + case 'o': + if(no_overwrite) + continue; + a = NAMEMATCH_OVERWRITE; + break; + case 's': + a = NAMEMATCH_SKIP; + break; + case 'q': + perm = 0; + a = NAMEMATCH_QUIT; + break; + default: + perm = 0; + } + } + + /* Keep track of this action in case this file collides again */ + ch->action[isprimary] = a; + if (perm) + ch->namematch_default[isprimary] = a; + + /* if we were asked to overwrite be careful. We can't set the action + * to overwrite, else we get won't get a chance to specify another + * action, should overwrite fail. Indeed, we'll be caught in an + * infinite loop because overwrite will fail the same way for the + * second time */ + if(a == NAMEMATCH_OVERWRITE) + ch->action[isprimary] = NAMEMATCH_NONE; + return a; +} + +/* + * Processes a name match + * dosname short dosname (ignored if is_primary) + * + * + * Returns: + * 2 if file is to be overwritten + * 1 if file was renamed + * 0 if it was skipped + * + * If a short name is involved, handle conversion between the 11-character + * fixed-length record DOS name and a literal null-terminated name (e.g. + * "COMMAND COM" (no null) <-> "COMMAND.COM" (null terminated)). + * + * Also, immediately copy the original name so that messages can use it. + */ +static __inline__ clash_action process_namematch(doscp_t *cp, + dos_name_t *dosname, + char *longname, + int isprimary, + ClashHandling_t *ch, + int no_overwrite, + int reason) +{ + clash_action action; + +#if 0 + fprintf(stderr, + "process_namematch: name=%s, default_action=%d, ask=%d.\n", + name, default_action, ch->ask); +#endif + + action = ask_namematch(cp, dosname, longname, + isprimary, ch, no_overwrite, reason); + + switch(action){ + case NAMEMATCH_QUIT: + got_signal = 1; + return NAMEMATCH_SKIP; + case NAMEMATCH_SKIP: + return NAMEMATCH_SKIP; + case NAMEMATCH_RENAME: + case NAMEMATCH_PRENAME: + /* We need to rename the file now. This means we must pass + * back through the loop, a) ensuring there isn't a potential + * new name collision, and b) finding a big enough VSE. + * Change the name, so that it won't collide again. + */ + ask_rename(cp, ch, dosname, longname, isprimary); + return action; + case NAMEMATCH_AUTORENAME: + /* Very similar to NAMEMATCH_RENAME, except that we need to + * first generate the name. + * TODO: Remember previous name so we don't + * keep trying the same one. + */ + if (isprimary) { + autorename_long(longname, 1); + return NAMEMATCH_PRENAME; + } else { + autorename_short(dosname, 1); + return NAMEMATCH_RENAME; + } + case NAMEMATCH_OVERWRITE: + if(no_overwrite) + return NAMEMATCH_SKIP; + else + return NAMEMATCH_OVERWRITE; + default: + return NAMEMATCH_NONE; + } +} + +static int contains_illegals(const char *string, const char *illegals, + int len) +{ + for(; *string && len--; string++) + if((*string < ' ' && *string != '\005' && !(*string & 0x80)) || + strchr(illegals, *string)) + return 1; + return 0; +} + +static int is_reserved(char *ans, int islong) +{ + unsigned int i; + static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", " "}; + static const char *dev4[] = {"COM", "LPT" }; + + for (i = 0; i < sizeof(dev3)/sizeof(*dev3); i++) + if (!strncasecmp(ans, dev3[i], 3) && + ((islong && !ans[3]) || + (!islong && !strncmp(ans+3," ",5)))) + return 1; + + for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++) + if (!strncasecmp(ans, dev4[i], 3) && + (ans[3] >= '1' && ans[3] <= '4') && + ((islong && !ans[4]) || + (!islong && !strncmp(ans+4," ",4)))) + return 1; + + return 0; +} + +static __inline__ clash_action get_slots(Stream_t *Dir, + dos_name_t *dosname, + char *longname, + struct scan_state *ssp, + ClashHandling_t *ch) +{ + int error; + clash_action ret; + int match_pos=0; + direntry_t entry; + int isprimary; + int no_overwrite; + int reason; + int pessimisticShortRename; + doscp_t *cp = GET_DOSCONVERT(Dir); + + pessimisticShortRename = (ch->action[0] == NAMEMATCH_AUTORENAME); + + entry.Dir = Dir; + no_overwrite = 1; + if((is_reserved(longname,1)) || + longname[strspn(longname,". ")] == '\0'){ + reason = RESERVED; + isprimary = 1; + } else if(contains_illegals(longname,long_illegals,1024)) { + reason = ILLEGALS; + isprimary = 1; + } else if(is_reserved(dosname->base,0)) { + reason = RESERVED; + ch->use_longname = 1; + isprimary = 0; + } else if(contains_illegals(dosname->base,short_illegals,11)) { + reason = ILLEGALS; + ch->use_longname = 1; + isprimary = 0; + } else { + reason = EXISTS; + switch (lookupForInsert(Dir, + &entry, + dosname, longname, ssp, + ch->ignore_entry, + ch->source_entry, + pessimisticShortRename && + ch->use_longname, + ch->use_longname)) { + case -1: + return NAMEMATCH_ERROR; + + case 0: + return NAMEMATCH_SKIP; + /* Single-file error error or skip request */ + + case 5: + return NAMEMATCH_GREW; + /* Grew directory, try again */ + + case 6: + return NAMEMATCH_SUCCESS; /* Success */ + } + match_pos = -2; + if (ssp->longmatch > -1) { + /* Primary Long Name Match */ +#ifdef debug + fprintf(stderr, + "Got longmatch=%d for name %s.\n", + longmatch, longname); +#endif + match_pos = ssp->longmatch; + isprimary = 1; + } else if ((ch->use_longname & 1) && (ssp->shortmatch != -1)) { + /* Secondary Short Name Match */ +#ifdef debug + fprintf(stderr, + "Got secondary short name match for name %s.\n", + longname); +#endif + + match_pos = ssp->shortmatch; + isprimary = 0; + } else if (ssp->shortmatch >= 0) { + /* Primary Short Name Match */ +#ifdef debug + fprintf(stderr, + "Got primary short name match for name %s.\n", + longname); +#endif + match_pos = ssp->shortmatch; + isprimary = 1; + } else + return NAMEMATCH_RENAME; + + if(match_pos > -1) { + entry.entry = match_pos; + dir_read(&entry, &error); + if (error) + return NAMEMATCH_ERROR; + /* if we can't overwrite, don't propose it */ + no_overwrite = (match_pos == ch->source || IS_DIR(&entry)); + } + } + ret = process_namematch(cp, dosname, longname, + isprimary, ch, no_overwrite, reason); + + if (ret == NAMEMATCH_OVERWRITE && match_pos > -1){ + if((entry.dir.attr & 0x5) && + (ask_confirmation("file is read only, overwrite anyway (y/n) ? "))) + return NAMEMATCH_RENAME; + /* Free up the file to be overwritten */ + if(fatFreeWithDirentry(&entry)) + return NAMEMATCH_ERROR; + +#if 0 + if(isprimary && + match_pos - ssp->match_free + 1 >= ssp->size_needed){ + /* reuse old entry and old short name for overwrite */ + ssp->free_start = match_pos - ssp->size_needed + 1; + ssp->free_size = ssp->size_needed; + ssp->slot = match_pos; + ssp->got_slots = 1; + strncpy(dosname, dir.name, 3); + strncpy(dosname + 8, dir.ext, 3); + return ret; + } else +#endif + { + wipeEntry(&entry); + return NAMEMATCH_RENAME; + } + } + + return ret; +} + + +static __inline__ int write_slots(Stream_t *Dir, + dos_name_t *dosname, + char *longname, + struct scan_state *ssp, + write_data_callback *cb, + void *arg, + int Case) +{ + direntry_t entry; + + /* write the file */ + if (fat_error(Dir)) + return 0; + + entry.Dir = Dir; + entry.entry = ssp->slot; + native_to_wchar(longname, entry.name, MAX_VNAMELEN, 0, 0); + entry.name[MAX_VNAMELEN]='\0'; + entry.dir.Case = Case & (EXTCASE | BASECASE); + if (cb(dosname, longname, arg, &entry) >= 0) { + if ((ssp->size_needed > 1) && + (ssp->free_end - ssp->free_start >= ssp->size_needed)) { + ssp->slot = write_vfat(Dir, dosname, longname, + ssp->free_start, &entry); + } else { + ssp->size_needed = 1; + write_vfat(Dir, dosname, 0, + ssp->free_start, &entry); + } + /* clear_vses(Dir, ssp->free_start + ssp->size_needed, + ssp->free_end); */ + } else + return 0; + + return 1; /* Successfully wrote the file */ +} + +static void stripspaces(char *name) +{ + char *p,*non_space; + + non_space = name; + for(p=name; *p; p++) + if (*p != ' ') + non_space = p; + if(name[0]) + non_space[1] = '\0'; +} + + +static int _mwrite_one(Stream_t *Dir, + char *argname, + char *shortname, + write_data_callback *cb, + void *arg, + ClashHandling_t *ch) +{ + char longname[VBUFSIZE]; + const char *dstname; + dos_name_t dosname; + int expanded; + struct scan_state scan; + clash_action ret; + doscp_t *cp = GET_DOSCONVERT(Dir); + + expanded = 0; + + if(isSpecial(argname)) { + fprintf(stderr, "Cannot create entry named . or ..\n"); + return -1; + } + + if(ch->name_converter == dos_name) { + if(shortname) + stripspaces(shortname); + if(argname) + stripspaces(argname); + } + + if(shortname){ + convert_to_shortname(cp, ch, shortname, &dosname); + if(ch->use_longname & 1){ + /* short name mangled, treat it as a long name */ + argname = shortname; + shortname = 0; + } + } + + if (argname[0] && (argname[1] == ':')) { + /* Skip drive letter */ + dstname = argname + 2; + } else { + dstname = argname; + } + + /* Copy original argument dstname to working value longname */ + strncpy(longname, dstname, VBUFSIZE-1); + + if(shortname) { + ch->use_longname = + convert_to_shortname(cp, ch, shortname, &dosname); + if(strcmp(shortname, longname)) + ch->use_longname |= 1; + } else { + ch->use_longname = + convert_to_shortname(cp, ch, longname, &dosname); + } + + ch->action[0] = ch->namematch_default[0]; + ch->action[1] = ch->namematch_default[1]; + + while (1) { + switch((ret=get_slots(Dir, &dosname, longname, &scan, ch))){ + case NAMEMATCH_ERROR: + return -1; /* Non-file-specific error, + * quit */ + + case NAMEMATCH_SKIP: + return -1; /* Skip file (user request or + * error) */ + + case NAMEMATCH_PRENAME: + ch->use_longname = + convert_to_shortname(cp, ch, + longname, + &dosname); + continue; + case NAMEMATCH_RENAME: + continue; /* Renamed file, loop again */ + + case NAMEMATCH_GREW: + /* No collision, and not enough slots. + * Try to grow the directory + */ + if (expanded) { /* Already tried this + * once, no good */ + fprintf(stderr, + "%s: No directory slots\n", + progname); + return -1; + } + expanded = 1; + + if (dir_grow(Dir, scan.max_entry)) + return -1; + continue; + case NAMEMATCH_OVERWRITE: + case NAMEMATCH_SUCCESS: + return write_slots(Dir, &dosname, longname, + &scan, cb, arg, + ch->use_longname); + default: + fprintf(stderr, + "Internal error: clash_action=%d\n", + ret); + return -1; + } + + } +} + +int mwrite_one(Stream_t *Dir, + const char *_argname, + const char *_shortname, + write_data_callback *cb, + void *arg, + ClashHandling_t *ch) +{ + char *argname; + char *shortname; + int ret; + + if(_argname) + argname = strdup(_argname); + else + argname = 0; + if(_shortname) + shortname = strdup(_shortname); + else + shortname = 0; + ret = _mwrite_one(Dir, argname, shortname, cb, arg, ch); + if(argname) + free(argname); + if(shortname) + free(shortname); + return ret; +} + +void init_clash_handling(ClashHandling_t *ch) +{ + ch->ignore_entry = -1; + ch->source_entry = -2; + ch->nowarn = 0; /*Don't ask, just do default action if name collision */ + ch->namematch_default[0] = NAMEMATCH_AUTORENAME; + ch->namematch_default[1] = NAMEMATCH_NONE; + ch->name_converter = dos_name; /* changed by mlabel */ + ch->source = -2; +} + +int handle_clash_options(ClashHandling_t *ch, char c) +{ + int isprimary; + if(isupper(c)) + isprimary = 0; + else + isprimary = 1; + c = tolower(c); + switch(c) { + case 'o': + /* Overwrite if primary name matches */ + ch->namematch_default[isprimary] = NAMEMATCH_OVERWRITE; + return 0; + case 'r': + /* Rename primary name interactively */ + ch->namematch_default[isprimary] = NAMEMATCH_RENAME; + return 0; + case 's': + /* Skip file if primary name collides */ + ch->namematch_default[isprimary] = NAMEMATCH_SKIP; + return 0; + case 'm': + ch->namematch_default[isprimary] = NAMEMATCH_NONE; + return 0; + case 'a': + ch->namematch_default[isprimary] = NAMEMATCH_AUTORENAME; + return 0; + default: + return -1; + } +} + +void dosnameToDirentry(const struct dos_name_t *dn, struct directory *dir) { + strncpy(dir->name, dn->base, 8); + strncpy(dir->ext, dn->ext, 3); +} diff --git a/mkdosboot b/mkdosboot new file mode 100755 index 0000000..7af3f23 --- /dev/null +++ b/mkdosboot @@ -0,0 +1,34 @@ +#!/bin/sh + +# Copyright 2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +# Example of a script making a Doc boot disk. Image will be t.img, a +# FreeDos boot sector is expected in bootsect.dos, and diag contains +# the system files + +IMAGE=t.img +if [ $# = 1 ] ; then + IMAGE=$1 +fi + +./mformat -i $IMAGE -C -t 80 -s 18 -h 2 -B bootsect.dos :: +./mcopy -i $IMAGE diag/io.sys ::IO.SYS +./mcopy -i $IMAGE diag/msdos.sys ::MSDOS.SYS +./mcopy -i $IMAGE diag/command.com ::COMMAND.COM +./mcopy -i $IMAGE diag/drvspace.bin ::DRVSPACE.BIN + +./mattrib -i $IMAGE +s +h +r ::io.sys ::msdos.sys ::drvspace.bin diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..6a5fd0b --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,50 @@ +#! /bin/sh + +# Copyright 1993 Noah Friedman +# Copyright 1996,1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" || errstatus=$? + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/mkmanifest.1 b/mkmanifest.1 new file mode 100644 index 0000000..33e2126 --- /dev/null +++ b/mkmanifest.1 @@ -0,0 +1,181 @@ +.TH mkmanifest 1 "03Nov09" mtools-4.0.12 +.SH Name +mkmanifest - makes list of file names and their DOS 8+3 equivalent +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mkmanifest" +.iX "c packing list" +.PP +The \fR\&\f(CWmkmanifest\fR command is used to create a shell script (packing +list) to restore Unix filenames. Its syntax is: +.PP +\&\fR\&\f(CWmkmanifest\fR [ \fIfiles\fR ] +.PP +\&\fR\&\f(CWMkmanifest\fR creates a shell script that aids in the restoration of +Unix filenames that got clobbered by the MS-DOS filename restrictions. +MS-DOS filenames are restricted to 8 character names, 3 character +extensions, upper case only, no device names, and no illegal characters. +.PP +The mkmanifest program is compatible with the methods used in +\&\fR\&\f(CWpcomm, arc,\fR and \fR\&\f(CWmtools\fR to change perfectly good Unix +filenames to fit the MS-DOS restrictions. This command is only useful if +the target system which will read the diskette cannot handle vfat long +names. +.PP +.SH Example +You want to copy the following Unix files to a MS-DOS diskette (using the +\&\fR\&\f(CWmcopy\fR command). +.PP + +.nf +.ft 3 +.in +0.3i + very_long_name + 2.many.dots + illegal: + good.c + prn.dev + Capital +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +\&\fR\&\f(CWMcopy\fR +converts the names to: +.PP + +.nf +.ft 3 +.in +0.3i + very_lon + 2xmany.dot + illegalx + good.c + xprn.dev + capital +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The command: + +.nf +.ft 3 +.in +0.3i +mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest +.fi +.in -0.3i +.ft R +.lp + +\&\fRwould produce the following: + +.nf +.ft 3 +.in +0.3i + mv very_lon very_long_name + mv 2xmany.dot 2.many.dots + mv illegalx illegal: + mv xprn.dev prn.dev + mv capital Capital +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +Notice that "good.c" did not require any conversion, so it did not +appear in the output. +.PP +Suppose I've copied these files from the diskette to another Unix +system, and I now want the files back to their original names. If the +file "manifest" (the output captured above) was sent along with those +files, it could be used to convert the filenames. +.PP +.SH Bugs +.PP +The short names generated by \fR\&\f(CWmkmanifest\fR follow the old convention +(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mkmanifest.c b/mkmanifest.c new file mode 100644 index 0000000..1b56b3d --- /dev/null +++ b/mkmanifest.c @@ -0,0 +1,112 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-1998,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * A program to create a manifest (shipping list) that is a shell script + * to return a Unix file name to it's original state after it has been + * clobbered by MSDOS's file name restrictions. + * + * This code also used in arc, mtools, and pcomm + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +static char *dos_name2(const char *name); + +int main(int argc, char **argv) +{ + int i; + const char *name; + char *new_name; + + /* print the version */ + if(argc >= 2 && strcmp(argv[1], "-V") == 0) { + printf("Mtools version %s, dated %s\n", mversion, mdate); + return 0; + } + + if (argc == 1) { + fprintf(stderr, "Usage: mkmanifest [-V] \n"); + return 1; + } + + for (i=1; i=0; i--) { + if (buf[i] == '.' && !dot) { + dot = 1; + buf[i] = '\0'; + ext = &buf[i+1]; + } + if (isupper((unsigned char)buf[i])) + buf[i] = tolower((unsigned char)buf[i]); + } + /* if no name */ + if (*temp == '\0') + strcpy(ans, "x"); + else { + /* if name is a device */ + for (i=0; i<9; i++) { + if (!strcasecmp(temp, dev[i])) + *temp = 'x'; + } + /* name too long? */ + if (strlen(temp) > 8) + *(temp+8) = '\0'; + /* extension too long? */ + if (ext && strlen(ext) > 3) + *(ext+3) = '\0'; + /* illegal characters? */ + while ((s = strpbrk(temp, "^+=/[]:',?*\\<>|\". "))) + *s = 'x'; + + while (ext && (s = strpbrk(ext, "^+=/[]:',?*\\<>|\". "))) + *s = 'x'; + strncpy(ans, temp, 12); + } + if (ext && *ext) { + strcat(ans, "."); + strcat(ans, ext); + } + return(ans); +} diff --git a/mkmanpages b/mkmanpages new file mode 100755 index 0000000..47235c2 --- /dev/null +++ b/mkmanpages @@ -0,0 +1,134 @@ +#!/bin/bash + +# Copyright 1997,1999,2001,2002,2004,2009 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +# TODO +VERSION=`cat version.texi | awk '$2 == "VERSION" {print $3}'` +UPDATED=`cat version.texi | awk '$2 == "UPDATED" {print $3 " " $4}'` + +# extracts the manpage for a given command out of a texinfo doc +unset LANG + +date=`date +%d%b%y` +package="mtools-"`grep mversion patchlevel.c | sed 's/^.*"\(.*\)";/\1/'` + +infile=/tmp/infile.$$ + +extract() +{ + echo extracting $name + command=$1 + outfile=`echo $command | tr '[A-Z]' '[a-z]'`.1 + + echo \'\\\" t >>$outfile +# ' + echo .TH\ $command\ 1\ \"$date\" $package >$outfile + echo .SH Name >>$outfile + grep -i $command cmdname | fgrep -v '#' >>$outfile + #echo ".SH Description" >>$outfile + + cat man-warning.texi mtools.texi man-warning-end.texi | + egrep -v '@end copying|@copying|@insertcopying' | + sed \ + -e "/^@c\(omment\)\? skipskipskip/,/^@node $command/d" \ + -e "/^@node [^,]*, [^,]*, $command, Commands$/,/^@bye/d" \ + -e "/^@node [^,]*, [^,]*, Commands/,/^@bye/d" \ + -e 's/^@section/@chapter/' \ + -e 's/^@subs/@s/' \ + -e 's/^@chapter.*$/@chapter Description/' \ + -e 's/^@section/@chapter/' \ + -e 's/^@subs/@s/' \ + -e 's/^@c\(omment\)\? xMANoptions/@chapter Options/' \ + -e "s/^@c\(omment\)\? MAN/@MAN/" | + texi2roff -ma | + sed -f strip-pp.sed >>$outfile +# echo ".SH See Also" >>$outfile +# echo "Mtools' texinfo doc" >>$outfile +} + + +for name in `fgrep -v '#' cmdname | cut -f1 -d\ ` ; do + extract $name +done + +echo \'\\\" t >mtools.1 +# ' +echo .TH mtools.1 3 \"$date\" $package >>mtools.1 +echo .SH Name >>mtools.1 +echo "mtools - utilities to access DOS disks in Unix." >>mtools.1 +cat mtools.texi | + egrep -v '@end copying|@copying|@insertcopying' | + sed \ + -e "1,/^@c\(omment\)\? MANstart 1/d" \ + -e '/^@c\(omment\)\? MANskip 1/,/^@c\(omment\)\? MANend-skip 1/d' \ + -e '/^@c\(omment\)\? MANend-skip 5/d' \ + -e '/^@c\(omment\)\? MANend 5/d' \ + -e "s/^@c\(omment\)\? MAN/@MAN/" \ + -e "s/@value{VERSION}/$VERSION/g" | + texi2roff -ma | + sed -f strip-pp.sed >>mtools.1 + +echo .SH See also >>mtools.1 +echo floppyd_installtest >>mtools.1 +echo mattrib >>mtools.1 +echo mbadblocks >>mtools.1 +echo mcd >>mtools.1 +echo mclasserase >>mclasserase.1 +echo mcopy >>mtools.1 +echo mdel >>mtools.1 +echo mdeltree >>mtools.1 +echo mdir >>mtools.1 +echo mdu >>mtools.1 +echo mformat >>mtools.1 +echo minfo >>mtools.1 +echo mkmanifest >>mtools.1 +echo mlabel >>mtools.1 +echo mmd >>mtools.1 +echo mmount >>mtools.1 +echo mmove >>mtools.1 +echo mrd >>mtools.1 +echo mren >>mtools.1 +echo mtoolstest >>mtools.1 +echo mtype >>mtools.1 + +echo \'\\\" t >mtools.5 +# ' +echo .TH mtools.1 3 \"$date\" "MTOOLS" "MTOOLS" >>mtools.5 +echo .SH Name >>mtools.5 +echo "mtools.conf - mtools configuration files" >>mtools.5 +cat mtools.texi | + egrep -v '@end copying|@copying|@insertcopying' | + sed \ + -e '1d' \ + -e '/^@c\(omment\)\? MANskip 5/,/^@c\(omment\)\? MANend-skip 5/d' \ + -e '/^@c\(omment\)\? MANend-skip 1/d' \ + -e '/^@c\(omment\)\? MANskip 1/d' \ + -e "s/^@c\(omment\)\? MAN/@MAN/" \ + -e "/@include/ d" \ + -e "s/@value{VERSION}/$VERSION/g" \ + -e "s/@value{UPDATED}/$UPDATED/g" \ + -e "/@top/d" \ + -e "/@format/d" \ + -e "/@end format/d" \ + -e "/@ifnottex/d" \ + -e "/@end ifnottex/d" | + texi2roff -ma | + sed -f strip-pp.sed | + sed 's/\.SS Description/.SH Description/' >>mtools.5 + +echo .SH See also >>mtools.5 +echo mtools >>mtools.5 diff --git a/mlabel.1 b/mlabel.1 new file mode 100644 index 0000000..7453edc --- /dev/null +++ b/mlabel.1 @@ -0,0 +1,117 @@ +.TH mlabel 1 "03Nov09" mtools-4.0.12 +.SH Name +mlabel - make an MSDOS volume label +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mlabel" +.iX "c Labeling a disk" +.iX "c Disk label" +.PP +The \fR\&\f(CWmlabel\fR command adds a volume label to a disk. Its syntax is: +.ft I +.nf +\&\fR\&\f(CWmlabel\fR [\fR\&\f(CW-vcsn\fR] [\fR\&\f(CW-N\fR \fIserial\fR] \fIdrive\fR:[\fInew_label\fR] +.fi +.ft R + +.PP +\&\fR\&\f(CWMlabel\fR displays the current volume label, if present. If +\&\fInew_label\fR is not given, and if neither the \fR\&\f(CWc\fR nor the +\&\fR\&\f(CWs\fR options are set, it prompts the user for a new volume label. +To delete an existing volume label, press return at the prompt. +.PP +Reasonable care is taken to create a valid MS-DOS volume label. If an +invalid label is specified, \fR\&\f(CWmlabel\fR changes the label (and +displays the new label if the verbose mode is set). \fR\&\f(CWMlabel\fR +returns 0 on success or 1 on failure. +.PP +Mlabel supports the following options: +.TP +\&\fR\&\f(CWc\fR\ +Clears an existing label, without prompting the user +.TP +\&\fR\&\f(CWs\fR\ +Shows the existing label, without prompting the user. +.TP +\&\fR\&\f(CWn\ \fR\ +Assigns a new (random) serial number to the disk +.TP +\&\fR\&\f(CWN\ \fIserial\fR\&\f(CW\fR\ +Sets the supplied serial number. The serial number should be supplied as +an 8 digit hexadecimal number, without spaces +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mlabel.c b/mlabel.c new file mode 100644 index 0000000..7ffbed3 --- /dev/null +++ b/mlabel.c @@ -0,0 +1,285 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mlabel.c + * Make an MSDOS volume label + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mainloop.h" +#include "vfat.h" +#include "mtools.h" +#include "nameclash.h" +#include "file_name.h" + +void label_name(doscp_t *cp, const char *filename, int verbose, + int *mangled, dos_name_t *ans) +{ + int len; + int i; + int have_lower, have_upper; + wchar_t wbuffer[12]; + + memset(ans, ' ', sizeof(ans)-1); + ans->sentinel = '\0'; + len = native_to_wchar(filename, wbuffer, 11, 0, 0); + if(len > 11){ + *mangled = 1; + len = 11; + } else + *mangled = 0; + + have_lower = have_upper = 0; + for(i=0; i|\".", wbuffer[i]) +#else + strchr("^+=/[]:,?*\\<>|\".", wbuffer[i]) +#endif + ){ + *mangled = 1; + wbuffer[i] = '~'; + } + } + if (have_lower && have_upper) + *mangled = 1; + wchar_to_dos(cp, wbuffer, ans->base, len, mangled); +} + +int labelit(struct dos_name_t *dosname, + char *longname, + void *arg0, + direntry_t *entry) +{ + time_t now; + + /* find out current time */ + getTimeNow(&now); + mk_entry(dosname, 0x8, 0, 0, now, &entry->dir); + return 0; +} + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, "Usage: %s [-vscVn] [-N serial] drive:\n", progname); + exit(ret); +} + + +void mlabel(int argc, char **argv, int type) +{ + + char *newLabel; + int verbose, clear, interactive, show; + direntry_t entry; + int result=0; + char longname[VBUFSIZE]; + char shortname[45]; + ClashHandling_t ch; + struct MainParam_t mp; + Stream_t *RootDir; + int c; + int mangled; + enum { SER_NONE, SER_RANDOM, SER_SET } set_serial = SER_NONE; + long serial = 0; + int need_write_boot = 0; + int have_boot = 0; + char *eptr; + union bootsector boot; + Stream_t *Fs=0; + int r; + struct label_blk_t *labelBlock; + int isRo=0; + int *isRop=NULL; + + init_clash_handling(&ch); + ch.name_converter = label_name; + ch.ignore_entry = -2; + + verbose = 0; + clear = 0; + show = 0; + + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'v': + verbose = 1; + break; + case 'c': + clear = 1; + break; + case 's': + show = 1; + break; + case 'n': + set_serial = SER_RANDOM; + srandom((long)time (0)); + serial=random(); + break; + case 'N': + set_serial = SER_SET; + serial = strtol(optarg, &eptr, 16); + if(*eptr) { + fprintf(stderr, + "%s not a valid serial number\n", + optarg); + exit(1); + } + break; + case 'h': + usage(0); + default: + usage(1); + } + } + + if (argc - optind != 1 || !argv[optind][0] || argv[optind][1] != ':') + usage(1); + + init_mp(&mp); + newLabel = argv[optind]+2; + if(strlen(newLabel) > VBUFSIZE) { + fprintf(stderr, "Label too long\n"); + FREE(&RootDir); + exit(1); + } + + interactive = !show && !clear &&!newLabel[0] && + (set_serial == SER_NONE); + if(!clear && !newLabel[0]) { + isRop = &isRo; + } + RootDir = open_root_dir(argv[optind][0], isRop ? 0 : O_RDWR, isRop); + if(isRo) { + show = 1; + interactive = 0; + } + if(!RootDir) { + fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]); + exit(1); + } + + initializeDirentry(&entry, RootDir); + r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY, + shortname, longname); + if (r == -2) { + FREE(&RootDir); + exit(1); + } + + if(show || interactive){ + if(isNotFound(&entry)) + printf(" Volume has no label\n"); + else if (*longname) + printf(" Volume label is %s (abbr=%s)\n", + longname, shortname); + else + printf(" Volume label is %s\n", shortname); + + } + + /* ask for new label */ + if(interactive){ + newLabel = longname; + fprintf(stderr,"Enter the new volume label : "); + if(fgets(newLabel, VBUFSIZE, stdin) == NULL) { + newLabel[0] = '\0'; + fprintf(stderr, "\n"); + } + if(newLabel[0]) + newLabel[strlen(newLabel)-1] = '\0'; + } + + if((!show || newLabel[0]) && !isNotFound(&entry)){ + /* if we have a label, wipe it out before putting new one */ + if(interactive && newLabel[0] == '\0') + if(ask_confirmation("Delete volume label (y/n): ")){ + FREE(&RootDir); + exit(0); + } + entry.dir.attr = 0; /* for old mlabel */ + wipeEntry(&entry); + } + + if (newLabel[0] != '\0') { + ch.ignore_entry = 1; + result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ? + 0 : 1; + } + + have_boot = 0; + if( (!show || newLabel[0]) || set_serial != SER_NONE) { + Fs = GetFs(RootDir); + have_boot = (force_read(Fs,boot.characters,0,sizeof(boot)) == + sizeof(boot)); + } + + if(WORD_S(fatlen)) { + labelBlock = &boot.boot.ext.old.labelBlock; + } else { + labelBlock = &boot.boot.ext.fat32.labelBlock; + } + + if(!show || newLabel[0]){ + dos_name_t dosname; + const char *shrtLabel; + doscp_t *cp; + if(!newLabel[0]) + shrtLabel = "NO NAME "; + else + shrtLabel = newLabel; + cp = GET_DOSCONVERT(Fs); + label_name(cp, shrtLabel, verbose, &mangled, &dosname); + + if(have_boot && boot.boot.descr >= 0xf0 && + labelBlock->dos4 == 0x29) { + strncpy(labelBlock->label, dosname.base, 11); + need_write_boot = 1; + + } + } + + if((set_serial != SER_NONE) & have_boot) { + if(have_boot && boot.boot.descr >= 0xf0 && + labelBlock->dos4 == 0x29) { + set_dword(labelBlock->serial, serial); + need_write_boot = 1; + } + } + + if(need_write_boot) { + force_write(Fs, (char *)&boot, 0, sizeof(boot)); + } + + FREE(&RootDir); + exit(result); +} diff --git a/mmd.1 b/mmd.1 new file mode 100644 index 0000000..a642eb8 --- /dev/null +++ b/mmd.1 @@ -0,0 +1,95 @@ +.TH mmd 1 "03Nov09" mtools-4.0.12 +.SH Name +mmd - make an MSDOS subdirectory +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mmd" +.iX "c Making a directory" +.iX "c Creating a directory" +.iX "c Directory creation" +.iX "c Subdirectory creation" +.PP +The \fR\&\f(CWmmd\fR command is used to make an MS-DOS subdirectory. Its +syntax is: +.PP +\&\fR\&\f(CWmmd\fR [\fR\&\f(CW-D\fR \fIclash_option\fR] \fImsdosdirectory\fR [ +\&\fImsdosdirectories\fR\&... ] +.PP +\&\fR\&\f(CWMmd\fR makes a new directory on an MS-DOS filesystem. An error occurs +if the directory already exists. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mmd.c b/mmd.c new file mode 100644 index 0000000..24e4db9 --- /dev/null +++ b/mmd.c @@ -0,0 +1,199 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mmd.c + * Makes an MSDOS directory + */ + + +#define LOWERCASE + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "plain_io.h" +#include "nameclash.h" +#include "file.h" +#include "fs.h" + +/* + * Preserve the file modification times after the fclose() + */ + +typedef struct Arg_t { + char *target; + MainParam_t mp; + + Stream_t *SrcDir; + int entry; + ClashHandling_t ch; + Stream_t *targetDir; +} Arg_t; + + +typedef struct CreateArg_t { + Stream_t *Dir; + Stream_t *NewDir; + unsigned char attr; + time_t mtime; +} CreateArg_t; + +/* + * Open the named file for read, create the cluster chain, return the + * directory structure or NULL on error. + */ +static int makeit(dos_name_t *dosname, + char *longname, + void *arg0, + direntry_t *targetEntry) +{ + Stream_t *Target; + CreateArg_t *arg = (CreateArg_t *) arg0; + int fat; + direntry_t subEntry; + + /* will it fit? At least one cluster must be free */ + if (!getfreeMinClusters(targetEntry->Dir, 1)) + return -1; + + mk_entry(dosname, ATTR_DIR, 1, 0, arg->mtime, &targetEntry->dir); + Target = OpenFileByDirentry(targetEntry); + if(!Target){ + fprintf(stderr,"Could not open Target\n"); + return -1; + } + + /* this allocates the first cluster for our directory */ + + initializeDirentry(&subEntry, Target); + + subEntry.entry = 1; + GET_DATA(targetEntry->Dir, 0, 0, 0, &fat); + if (fat == fat32RootCluster(targetEntry->Dir)) { + fat = 0; + } + mk_entry_from_base(".. ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir); + dir_write(&subEntry); + + FLUSH((Stream_t *) Target); + subEntry.entry = 0; + GET_DATA(Target, 0, 0, 0, &fat); + mk_entry_from_base(". ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir); + dir_write(&subEntry); + + mk_entry(dosname, ATTR_DIR | arg->attr, fat, 0, arg->mtime, + &targetEntry->dir); + arg->NewDir = Target; + return 0; +} + + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-D clash_option] file targetfile\n", progname); + fprintf(stderr, + " %s [-D clash_option] file [files...] target_directory\n", + progname); + exit(ret); +} + +Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch, + unsigned char attr, time_t mtime) +{ + CreateArg_t arg; + int ret; + + arg.Dir = Dir; + arg.attr = attr; + arg.mtime = mtime; + + if (!getfreeMinClusters(Dir, 1)) + return NULL; + + ret = mwrite_one(Dir, filename, 0, makeit, &arg, ch); + if(ret < 1) + return NULL; + else + return arg.NewDir; +} + +static int createDirCallback(direntry_t *entry, MainParam_t *mp) +{ + Stream_t *ret; + time_t now; + + ret = createDir(mp->File, mp->targetName, &((Arg_t *)(mp->arg))->ch, + ATTR_DIR, getTimeNow(&now)); + if(ret == NULL) + return ERROR_ONE; + else { + FREE(&ret); + return GOT_ONE; + } + +} + +void mmd(int argc, char **argv, int type) +{ + Arg_t arg; + int c; + + /* get command line options */ + + init_clash_handling(& arg.ch); + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:D:oh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case '?': + usage(1); + case 'o': + handle_clash_options(&arg.ch, c); + break; + case 'D': + if(handle_clash_options(&arg.ch, *optarg)) + usage(1); + break; + case 'h': + usage(0); + default: + usage(1); + break; + } + } + + if (argc - optind < 1) + usage(1); + + init_mp(&arg.mp); + arg.mp.arg = (void *) &arg; + arg.mp.openflags = O_RDWR; + arg.mp.callback = createDirCallback; + arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS; + exit(main_loop(&arg.mp, argv + optind, argc - optind)); +} diff --git a/mmount.1 b/mmount.1 new file mode 100644 index 0000000..861bdda --- /dev/null +++ b/mmount.1 @@ -0,0 +1,99 @@ +.TH mmount 1 "03Nov09" mtools-4.0.12 +.SH Name +mmount - mount an MSDOS disk +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mmount" +.iX "c Linux enhancements (mmount)" +.iX "c Mounting a disk" +.iX "c High capacity formats, mounting" +.PP +The \fR\&\f(CWmmount\fR command is used to mount an MS-DOS disk. It is only +available on Linux, as it is only useful if the OS kernel allows to +configure the disk geometry. Its syntax is: +.PP +\&\fR\&\f(CWmmount\fR \fImsdosdrive\fR [\fImountargs\fR] +.PP +\&\fR\&\f(CWMmount\fR +reads the boot sector of an MS-DOS disk, configures the drive geometry, +and finally mounts it passing +\&\fR\&\f(CWmountargs\fR to \fR\&\f(CWmount. \fR +If no mount arguments are specified, the name of the device is +used. If the disk is write protected, it is automatically mounted read +only. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mmount.c b/mmount.c new file mode 100644 index 0000000..241e645 --- /dev/null +++ b/mmount.c @@ -0,0 +1,107 @@ +/* Copyright 1994,1996-2002,2005-2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Mount an MSDOS disk + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +#ifdef OS_linux +#include +#include "mainloop.h" +#include "fs.h" + +void mmount(int argc, char **argv, int type) +{ + char drive; + int pid; + int status; + struct device dev; + char name[EXPAND_BUF]; + int media; + union bootsector boot; + Stream_t *Stream; + + if (argc<2 || !argv[1][0] || argv[1][1] != ':' || argv[1][2]){ + fprintf(stderr,"Usage: %s -V drive:\n", argv[0]); + exit(1); + } + drive = toupper(argv[1][0]); + Stream= find_device(drive, O_RDONLY, &dev, &boot, name, &media, 0, NULL); + if(!Stream) + exit(1); + FREE(&Stream); + + destroy_privs(); + + if ( dev.partition ) { + char part_name[4]; + sprintf(part_name, "%d", dev.partition %1000); + strcat(name, part_name); + } + + /* and finally mount it */ + switch((pid=fork())){ + case -1: + fprintf(stderr,"fork failed\n"); + exit(1); + case 0: + close(2); + open("/dev/null", O_RDWR | O_BINARY | O_LARGEFILE); + argv[1] = strdup("mount"); + if ( argc > 2 ) + execvp("mount", argv + 1 ); + else + execlp("mount", "mount", name, NULL); + perror("exec mount"); + exit(1); + default: + while ( wait(&status) != pid ); + } + if ( WEXITSTATUS(status) == 0 ) + exit(0); + argv[0] = strdup("mount"); + argv[1] = strdup("-r"); + if(!argv[0] || !argv[1]){ + printOom(); + exit(1); + } + if ( argc > 2 ) + execvp("mount", argv); + else + execlp("mount", "mount","-r", name, NULL); + exit(1); +} + +#else /* linux */ + +#include "msdos.h" + +void mmount(int argc, char **argv, int type) +{ + fprintf(stderr,"This command is only available for LINUX \n"); + exit(1); +} +#endif /* linux */ + diff --git a/mmove.1 b/mmove.1 new file mode 100644 index 0000000..4d52838 --- /dev/null +++ b/mmove.1 @@ -0,0 +1,101 @@ +.TH mmove 1 "03Nov09" mtools-4.0.12 +.SH Name +mmove - move or rename an MSDOS file or subdirectory +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mmove" +.iX "c Moving files (mmove)" +.iX "c Renaming files (mmove)" +.PP +The \fR\&\f(CWmmove\fR command is used to moves or renames an existing MS-DOS +file or subdirectory. +.ft I +.nf +\&\fR\&\f(CWmmove\fR [\fR\&\f(CW-v\fR] [\fR\&\f(CW-D\fR \fIclash_option\fR] \fIsourcefile\fR \fItargetfile\fR +\&\fR\&\f(CWmmove\fR [\fR\&\f(CW-v\fR] [\fR\&\f(CW-D\fR \fIclash_option\fR] \fIsourcefile\fR [ \fIsourcefiles\fR\&... ] \fItargetdirectory\fR +.fi +.ft R + +\&\fR\&\f(CWMmove\fR moves or renames an existing MS-DOS file or +subdirectory. Unlike the MS-DOS version of \fR\&\f(CWMOVE\fR, \fR\&\f(CWmmove\fR is +able to move subdirectories. Files or directories can only be moved +within one filesystem. Data cannot be moved from Dos to Unix or +vice-versa. If you omit the drive letter from the target file or +directory, the same letter as for the source is assumed. If you omit +the drive letter from all parameters, drive a: is assumed by default. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mmove.c b/mmove.c new file mode 100644 index 0000000..13576dc --- /dev/null +++ b/mmove.c @@ -0,0 +1,323 @@ +/* Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mmove.c + * Renames/moves an MSDOS file + * + */ + + +#define LOWERCASE + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "plain_io.h" +#include "nameclash.h" +#include "file.h" +#include "fs.h" + +/* + * Preserve the file modification times after the fclose() + */ + +typedef struct Arg_t { + const char *fromname; + int verbose; + MainParam_t mp; + + direntry_t *entry; + ClashHandling_t ch; +} Arg_t; + + +/* + * Open the named file for read, create the cluster chain, return the + * directory structure or NULL on error. + */ +static int renameit(dos_name_t *dosname, + char *longname, + void *arg0, + direntry_t *targetEntry) +{ + Arg_t *arg = (Arg_t *) arg0; + int fat; + + targetEntry->dir = arg->entry->dir; + dosnameToDirentry(dosname, &targetEntry->dir); + + if(IS_DIR(targetEntry)) { + direntry_t *movedEntry; + + /* get old direntry. It is important that we do this + * on the actual direntry which is stored in the file, + * and not on a copy, because we will modify it, and the + * modification should be visible at file + * de-allocation time */ + movedEntry = getDirentry(arg->mp.File); + if(movedEntry->Dir != targetEntry->Dir) { + /* we are indeed moving it to a new directory */ + direntry_t subEntry; + Stream_t *oldDir; + /* we have a directory here. Change its parent link */ + + initializeDirentry(&subEntry, arg->mp.File); + + switch(vfat_lookup(&subEntry, "..", 2, ACCEPT_DIR, + NULL, NULL)) { + case -1: + fprintf(stderr, + " Directory has no parent entry\n"); + break; + case -2: + return ERROR_ONE; + case 0: + GET_DATA(targetEntry->Dir, 0, 0, 0, &fat); + if (fat == fat32RootCluster(targetEntry->Dir)) { + fat = 0; + } + + subEntry.dir.start[1] = (fat >> 8) & 0xff; + subEntry.dir.start[0] = fat & 0xff; + dir_write(&subEntry); + if(arg->verbose){ + fprintf(stderr, + "Easy, isn't it? I wonder why DOS can't do this.\n"); + } + break; + } + + wipeEntry(movedEntry); + + /* free the old parent, allocate the new one. */ + oldDir = movedEntry->Dir; + *movedEntry = *targetEntry; + COPY(targetEntry->Dir); + FREE(&oldDir); + return 0; + } + } + + /* wipe out original entry */ + wipeEntry(arg->mp.direntry); + return 0; +} + + + +static int rename_file(direntry_t *entry, MainParam_t *mp) +/* rename a messy DOS file to another messy DOS file */ +{ + int result; + Stream_t *targetDir; + char *shortname; + const char *longname; + + Arg_t * arg = (Arg_t *) (mp->arg); + + arg->entry = entry; + targetDir = mp->targetDir; + + if (targetDir == entry->Dir){ + arg->ch.ignore_entry = -1; + arg->ch.source = entry->entry; + arg->ch.source_entry = entry->entry; + } else { + arg->ch.ignore_entry = -1; + arg->ch.source = -2; + } + + longname = mpPickTargetName(mp); + shortname = 0; + result = mwrite_one(targetDir, longname, shortname, + renameit, (void *)arg, &arg->ch); + if(result == 1) + return GOT_ONE; + else + return ERROR_ONE; +} + + +static int rename_directory(direntry_t *entry, MainParam_t *mp) +{ + int ret; + + /* moves a DOS dir */ + if(isSubdirOf(mp->targetDir, mp->File)) { + fprintf(stderr, "Cannot move directory "); + fprintPwd(stderr, entry,0); + fprintf(stderr, " into one of its own subdirectories ("); + fprintPwd(stderr, getDirentry(mp->targetDir),0); + fprintf(stderr, ")\n"); + return ERROR_ONE; + } + + if(entry->entry == -3) { + fprintf(stderr, "Cannot move a root directory: "); + fprintPwd(stderr, entry,0); + return ERROR_ONE; + } + + ret = rename_file(entry, mp); + if(ret & ERROR_ONE) + return ret; + + return ret; +} + +static int rename_oldsyntax(direntry_t *entry, MainParam_t *mp) +{ + int result; + Stream_t *targetDir; + const char *shortname, *longname; + + Arg_t * arg = (Arg_t *) (mp->arg); + arg->entry = entry; + targetDir = entry->Dir; + + arg->ch.ignore_entry = -1; + arg->ch.source = entry->entry; + arg->ch.source_entry = entry->entry; + +#if 0 + if(!strcasecmp(mp->shortname, arg->fromname)){ + longname = mp->longname; + shortname = mp->targetName; + } else { +#endif + longname = mp->targetName; + shortname = 0; +#if 0 + } +#endif + result = mwrite_one(targetDir, longname, shortname, + renameit, (void *)arg, &arg->ch); + if(result == 1) + return GOT_ONE; + else + return ERROR_ONE; +} + + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-vV] [-D clash_option] file targetfile\n", progname); + fprintf(stderr, + " %s [-vV] [-D clash_option] file [files...] target_directory\n", + progname); + exit(ret); +} + +void mmove(int argc, char **argv, int oldsyntax) +{ + Arg_t arg; + int c; + char shortname[13]; + char longname[VBUFSIZE]; + char def_drive; + int i; + + /* get command line options */ + + init_clash_handling(& arg.ch); + + /* get command line options */ + arg.verbose = 0; + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:vD:oh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'v': /* dummy option for mcopy */ + arg.verbose = 1; + break; + case 'o': + handle_clash_options(&arg.ch, c); + break; + case 'D': + if(handle_clash_options(&arg.ch, *optarg)) + usage(1); + break; + case 'h': + usage(0); + case '?': + usage(1); + default: + break; + } + } + + if (argc - optind < 2) + usage(1); + + init_mp(&arg.mp); + arg.mp.arg = (void *) &arg; + arg.mp.openflags = O_RDWR; + + /* look for a default drive */ + def_drive = '\0'; + for(i=optind; i. + * + * mformat.c + */ +#define DONT_NEED_WAIT + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "mainloop.h" +#include "fsP.h" +#include "file.h" +#include "plain_io.h" +#include "nameclash.h" +#include "buffer.h" +#include "scsi.h" +#include "partition.h" + +#ifdef OS_linux +#include "linux/hdreg.h" + +#define _LINUX_STRING_H_ +#define kdev_t int +#include "linux/fs.h" +#undef _LINUX_STRING_H_ + +#endif + +#define tolinear(x) \ +(sector(x)-1+(head(x)+cyl(x)*used_dev->heads)*used_dev->sectors) + + +static __inline__ void print_hsc(hsc *h) +{ + printf(" h=%d s=%d c=%d\n", + head(*h), sector(*h), cyl(*h)); +} + +static void set_offset(hsc *h, int offset, int heads, int sectors) +{ + int head, sector, cyl; + + if(! heads || !sectors) + head = sector = cyl = 0; /* linear mode */ + else { + sector = offset % sectors; + offset = offset / sectors; + + head = offset % heads; + cyl = offset / heads; + if(cyl > 1023) cyl = 1023; + } + + h->head = head; + h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2); + h->cyl = cyl & 0xff; +} + +void setBeginEnd(struct partition *partTable, int begin, int end, + int heads, int sectors, int activate, int type) +{ + set_offset(&partTable->start, begin, heads, sectors); + set_offset(&partTable->end, end-1, heads, sectors); + set_dword(partTable->start_sect, begin); + set_dword(partTable->nr_sects, end-begin); + if(activate) + partTable->boot_ind = 0x80; + else + partTable->boot_ind = 0; + if(!type) { + if(end-begin < 4096) + type = 1; /* DOS 12-bit FAT */ + else if(end-begin<32*2048) + type = 4; /* DOS 16-bit FAT, <32M */ + else + type = 6; /* DOS 16-bit FAT >= 32M */ + } + partTable->sys_ind = type; +} + +int consistencyCheck(struct partition *partTable, int doprint, int verbose, + int *has_activated, unsigned int *last_end, + unsigned int *j, + struct device *used_dev, int target_partition) +{ + unsigned int i; + unsigned int inconsistency; + + *j = 0; + *last_end = 1; + + /* quick consistency check */ + inconsistency = 0; + *has_activated = 0; + for(i=1; i<5; i++){ + if(!partTable[i].sys_ind) + continue; + if(partTable[i].boot_ind) + (*has_activated)++; + if((used_dev && + (used_dev->heads != head(partTable[i].end)+1 || + used_dev->sectors != sector(partTable[i].end))) || + sector(partTable[i].start) != 1){ + fprintf(stderr, + "Partition %d is not aligned\n", + i); + inconsistency=1; + } + + if(*j && + *last_end > BEGIN(partTable[i])) { + fprintf(stderr, + "Partitions %d and %d badly ordered or overlapping\n", + *j,i); + inconsistency=1; + } + + *last_end = END(partTable[i]); + *j = i; + + if(used_dev && + cyl(partTable[i].start) != 1023 && + tolinear(partTable[i].start) != BEGIN(partTable[i])) { + fprintf(stderr, + "Start position mismatch for partition %d\n", + i); + inconsistency=1; + } + if(used_dev && + cyl(partTable[i].end) != 1023 && + tolinear(partTable[i].end)+1 != END(partTable[i])) { + fprintf(stderr, + "End position mismatch for partition %d\n", + i); + inconsistency=1; + } + + if(doprint && verbose) { + if(i==target_partition) + putchar('*'); + else + putchar(' '); + printf("Partition %d\n",i); + + printf(" active=%x\n", partTable[i].boot_ind); + printf(" start:"); + print_hsc(&partTable[i].start); + printf(" type=0x%x\n", partTable[i].sys_ind); + printf(" end:"); + print_hsc(&partTable[i].end); + printf(" start=%d\n", BEGIN(partTable[i])); + printf(" nr=%d\n", _DWORD(partTable[i].nr_sects)); + printf("\n"); + } + } + return inconsistency; +} + +/* setsize function. Determines scsicam mapping if this cannot be inferred from + * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */ + +/* + * Function : static int setsize(unsigned long capacity,unsigned int *cyls, + * unsigned int *hds, unsigned int *secs); + * + * Purpose : to determine a near-optimal int 0x13 mapping for a + * SCSI disk in terms of lost space of size capacity, storing + * the results in *cyls, *hds, and *secs. + * + * Returns : -1 on failure, 0 on success. + * + * Extracted from + * + * WORKING X3T9.2 + * DRAFT 792D + * + * + * Revision 6 + * 10-MAR-94 + * Information technology - + * SCSI-2 Common access method + * transport and SCSI interface module + * + * ANNEX A : + * + * setsize() converts a read capacity value to int 13h + * head-cylinder-sector requirements. It minimizes the value for + * number of heads and maximizes the number of cylinders. This + * will support rather large disks before the number of heads + * will not fit in 4 bits (or 6 bits). This algorithm also + * minimizes the number of sectors that will be unused at the end + * of the disk while allowing for very large disks to be + * accommodated. This algorithm does not use physical geometry. + */ + +static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds, + unsigned int *secs) { + unsigned int rv = 0; + unsigned long heads, sectors, cylinders, temp; + + cylinders = 1024L; /* Set number of cylinders to max */ + sectors = 62L; /* Maximize sectors per track */ + + temp = cylinders * sectors; /* Compute divisor for heads */ + heads = capacity / temp; /* Compute value for number of heads */ + if (capacity % temp) { /* If no remainder, done! */ + heads++; /* Else, increment number of heads */ + temp = cylinders * heads; /* Compute divisor for sectors */ + sectors = capacity / temp; /* Compute value for sectors per + track */ + if (capacity % temp) { /* If no remainder, done! */ + sectors++; /* Else, increment number of sectors */ + temp = heads * sectors; /* Compute divisor for cylinders */ + cylinders = capacity / temp;/* Compute number of cylinders */ + } + } + if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ + + *cyls = (unsigned int) cylinders; /* Stuff return values */ + *secs = (unsigned int) sectors; + *hds = (unsigned int) heads; + return(rv); +} + +static void setsize0(unsigned long capacity,unsigned int *cyls, + unsigned int *hds, unsigned int *secs) +{ + int r; + + /* 1. First try "Megabyte" sizes */ + if(capacity < 1024 * 2048 && !(capacity % 1024)) { + *cyls = capacity >> 11; + *hds = 64; + *secs = 32; + return; + } + + /* then try scsicam's size */ + r = setsize(capacity,cyls,hds,secs); + if(r || *hds > 255 || *secs > 63) { + /* scsicam failed. Do megabytes anyways */ + *cyls = capacity >> 11; + *hds = 64; + *secs = 32; + return; + } +} + + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s [-pradcv] [-I] [-B bootsect-template] [-s sectors] " + "[-t cylinders] " + "[-h heads] [-T type] [-b begin] [-l length] " + "drive\n", progname); + exit(ret); +} + +void mpartition(int argc, char **argv, int dummy) +{ + Stream_t *Stream; + unsigned int dummy2; + + unsigned int i,j; + + int sec_per_cyl; + int doprint = 0; + int verbose = 0; + int create = 0; + int force = 0; + int length = 0; + int do_remove = 0; + int initialize = 0; + unsigned int tot_sectors=0; + int type = 0; + int begin_set = 0; + int size_set = 0; + int end_set = 0; + unsigned int last_end = 0; + int activate = 0; + int has_activated = 0; + int inconsistency=0; + int begin=0; + int end=0; + int sizetest=0; + int dirty = 0; + int open2flags = NO_OFFSET; + + int c; + struct device used_dev; + int argtracks, argheads, argsectors; + + char drive, name[EXPAND_BUF]; + unsigned char buf[512]; + struct partition *partTable=(struct partition *)(buf+ 0x1ae); + struct device *dev; + char errmsg[200]; + char *bootSector=0; + + argtracks = 0; + argheads = 0; + argsectors = 0; + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'B': + bootSector = optarg; + break; + case 'a': + /* no privs, as it could be abused to + * make other partitions unbootable, or + * to boot a rogue kernel from this one */ + open2flags |= NO_PRIV; + activate = 1; + dirty = 1; + break; + case 'd': + activate = -1; + dirty = 1; + break; + case 'p': + doprint = 1; + break; + case 'r': + do_remove = 1; + dirty = 1; + break; + case 'I': + /* could be abused to nuke all other + * partitions */ + open2flags |= NO_PRIV; + initialize = 1; + dirty = 1; + break; + case 'c': + create = 1; + dirty = 1; + break; + + case 'T': + /* could be abused to "manually" create + * extended partitions */ + open2flags |= NO_PRIV; + type = strtoul(optarg,0,0); + break; + + case 't': + argtracks = atoi(optarg); + break; + case 'h': + argheads = atoi(optarg); + break; + case 's': + argsectors = atoi(optarg); + break; + + case 'f': + /* could be abused by creating overlapping + * partitions and other such Snafu */ + open2flags |= NO_PRIV; + force = 1; + break; + + case 'v': + verbose++; + break; + case 'S': + /* testing only */ + /* could be abused to create partitions + * extending beyond the actual size of the + * device */ + open2flags |= NO_PRIV; + tot_sectors = strtoul(optarg,0,0); + sizetest = 1; + break; + case 'b': + begin_set = 1; + begin = atoi(optarg); + break; + case 'l': + size_set = 1; + length = atoi(optarg); + break; + + default: + usage(1); + } + } + + if (argc - optind != 1 || + !argv[optind][0] || argv[optind][1] != ':') + usage(1); + + drive = toupper(argv[optind][0]); + + /* check out a drive whose letter and parameters match */ + sprintf(errmsg, "Drive '%c:' not supported", drive); + Stream = 0; + for(dev=devices;dev->drive;dev++) { + int mode ; + + FREE(&(Stream)); + /* drive letter */ + if (dev->drive != drive) + continue; + if (dev->partition < 1 || dev->partition > 4) { + sprintf(errmsg, + "Drive '%c:' is not a partition", + drive); + continue; + } + used_dev = *dev; + + SET_INT(used_dev.tracks, argtracks); + SET_INT(used_dev.heads, argheads); + SET_INT(used_dev.sectors, argsectors); + + expand(dev->name, name); + + mode = dirty ? O_RDWR : O_RDONLY; + if(initialize) + mode |= O_CREAT; + +#ifdef USING_NEW_VOLD + strcpy(name, getVoldName(dev, name)); +#endif + Stream = SimpleFileOpen(&used_dev, dev, name, mode, + errmsg, open2flags, 1, 0); + + if (!Stream) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"init: open: %s", strerror(errno)); +#else + sprintf(errmsg,"init: open: %s", strerror(errno)); +#endif + continue; + } + + + /* try to find out the size */ + if(!sizetest) + tot_sectors = 0; + if(IS_SCSI(dev)) { + unsigned char cmd[10]; + unsigned char data[10]; + cmd[0] = SCSI_READ_CAPACITY; + memset ((void *) &cmd[2], 0, 8); + memset ((void *) &data[0], 137, 10); + scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ, + data, 10, get_extra_data(Stream)); + + tot_sectors = 1 + + (data[0] << 24) + + (data[1] << 16) + + (data[2] << 8) + + (data[3] ); + if(verbose) + printf("%d sectors in total\n", tot_sectors); + } + +#ifdef OS_linux + if (tot_sectors == 0) { + ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors); + } +#endif + + /* read the partition table */ + if (READS(Stream, (char *) buf, 0, 512) != 512 && !initialize){ +#ifdef HAVE_SNPRINTF + snprintf(errmsg, 199, + "Error reading from '%s', wrong parameters?", + name); +#else + sprintf(errmsg, + "Error reading from '%s', wrong parameters?", + name); +#endif + continue; + } + if(verbose>=2) + print_sector("Read sector", buf, 512); + break; + } + + /* print error msg if needed */ + if ( dev->drive == 0 ){ + FREE(&Stream); + fprintf(stderr,"%s: %s\n", argv[0],errmsg); + exit(1); + } + + if((used_dev.sectors || used_dev.heads) && + (!used_dev.sectors || !used_dev.heads)) { + fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n"); + fprintf(stderr," or none of them\n"); + exit(1); + } + + if(initialize) { + if (bootSector) { + int fd; + fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE); + if (fd < 0) { + perror("open MBR"); + exit(1); + } + if(read(fd, (char *) buf, 512) < 512) { + perror("read MBR"); + exit(1); + } + } + memset((char *)(partTable+1), 0, 4*sizeof(*partTable)); + set_word(((unsigned char*)buf)+510, 0xaa55); + } + + /* check for boot signature, and place it if needed */ + if((buf[510] != 0x55) || (buf[511] != 0xaa)) { + fprintf(stderr,"Boot signature not set\n"); + fprintf(stderr, + "Use the -I flag to initialize the partition table, and set the boot signature\n"); + inconsistency = 1; + } + + if(do_remove){ + if(!partTable[dev->partition].sys_ind) + fprintf(stderr, + "Partition for drive %c: does not exist\n", + drive); + if((partTable[dev->partition].sys_ind & 0x3f) == 5) { + fprintf(stderr, + "Partition for drive %c: may be an extended partition\n", + drive); + fprintf(stderr, + "Use the -f flag to remove it anyways\n"); + inconsistency = 1; + } + memset(&partTable[dev->partition], 0, sizeof(*partTable)); + } + + if(create && partTable[dev->partition].sys_ind) { + fprintf(stderr, + "Partition for drive %c: already exists\n", drive); + fprintf(stderr, + "Use the -r flag to remove it before attempting to recreate it\n"); + } + + + /* find out number of heads and sectors, and whether there is + * any activated partition */ + has_activated = 0; + for(i=1; i<5; i++){ + if(!partTable[i].sys_ind) + continue; + + if(partTable[i].boot_ind) + has_activated++; + + /* set geometry from entry */ + if (!used_dev.heads) + used_dev.heads = head(partTable[i].end)+1; + if(!used_dev.sectors) + used_dev.sectors = sector(partTable[i].end); + if(ipartition && !begin_set) + begin = END(partTable[i]); + if(i>dev->partition && !end_set && !size_set) { + end = BEGIN(partTable[i]); + end_set = 1; + } + } + +#ifdef OS_linux + if(!used_dev.sectors && !used_dev.heads) { + if(!IS_SCSI(dev)) { + struct hd_geometry geom; + if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) { + used_dev.heads = geom.heads; + used_dev.sectors = geom.sectors; + } + } + } +#endif + + if(!used_dev.sectors && !used_dev.heads) { + if(tot_sectors) + setsize0(tot_sectors,&dummy2,&used_dev.heads, + &used_dev.sectors); + else { + used_dev.heads = 64; + used_dev.sectors = 32; + } + } + + if(verbose) + fprintf(stderr,"sectors: %d heads: %d %d\n", + used_dev.sectors, used_dev.heads, tot_sectors); + + sec_per_cyl = used_dev.sectors * used_dev.heads; + if(create) { + if(!end_set && tot_sectors) { + end = tot_sectors - tot_sectors % sec_per_cyl; + end_set = 1; + } + + /* if the partition starts right at the beginning of + * the disk, keep one track unused to allow place for + * the master boot record */ + if(!begin && !begin_set) + begin = used_dev.sectors; + if(!size_set && used_dev.tracks) { + size_set = 2; + length = sec_per_cyl * used_dev.tracks; + + /* round the size in order to take + * into account any "hidden" sectors */ + + /* do we anchor this at the beginning ?*/ + if(begin_set || dev->partition <= 2 || !end_set) + length -= begin % sec_per_cyl; + else if(end - length < begin) + /* truncate any overlap */ + length = end - begin; + } + if(size_set) { + if(!begin_set && dev->partition >2 && end_set) + begin = end - length; + else + end = begin + length; + } else if(!end_set) { + fprintf(stderr,"Unknown size\n"); + exit(1); + } + + setBeginEnd(&partTable[dev->partition], begin, end, + used_dev.heads, used_dev.sectors, + !has_activated, type); + } + + if(activate) { + if(!partTable[dev->partition].sys_ind) { + fprintf(stderr, + "Partition for drive %c: does not exist\n", + drive); + } else { + switch(activate) { + case 1: + partTable[dev->partition].boot_ind=0x80; + break; + case -1: + partTable[dev->partition].boot_ind=0x00; + break; + } + } + } + + + inconsistency |= consistencyCheck(partTable, doprint, verbose, + &has_activated, &last_end, &j, + &used_dev, dev->partition); + + if(doprint && !inconsistency && partTable[dev->partition].sys_ind) { + printf("The following command will recreate the partition for drive %c:\n", + drive); + used_dev.tracks = + (_DWORD(partTable[dev->partition].nr_sects) + + (BEGIN(partTable[dev->partition]) % sec_per_cyl)) / + sec_per_cyl; + printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n", + used_dev.tracks, used_dev.heads, used_dev.sectors, + BEGIN(partTable[dev->partition]), drive); + } + + if(tot_sectors && last_end >tot_sectors) { + fprintf(stderr, + "Partition %d exceeds beyond end of disk\n", + j); + exit(1); + } + + + switch(has_activated) { + case 0: + fprintf(stderr, + "Warning: no active (bootable) partition present\n"); + break; + case 1: + break; + default: + fprintf(stderr, + "Warning: %d active (bootable) partitions present\n", + has_activated); + fprintf(stderr, + "Usually, a disk should have exactly one active partition\n"); + break; + } + + if(inconsistency && !force) { + fprintf(stderr, + "inconsistency detected!\n" ); + if(dirty) + fprintf(stderr, + "Retry with the -f switch to go ahead anyways\n"); + exit(1); + } + + if(dirty) { + /* write data back to the disk */ + if(verbose>=2) + print_sector("Writing sector", buf, 512); + if (WRITES(Stream, (char *) buf, 0, 512) != 512) { + fprintf(stderr,"Error writing partition table"); + exit(1); + } + if(verbose>=3) + print_sector("Sector written", buf, 512); + } + FREE(&Stream); + exit(0); +} diff --git a/mrd.1 b/mrd.1 new file mode 100644 index 0000000..7d7c6bf --- /dev/null +++ b/mrd.1 @@ -0,0 +1,100 @@ +.TH mrd 1 "03Nov09" mtools-4.0.12 +.SH Name +mrd - remove an MSDOS subdirectory +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mrd" +.iX "c Removing a directory" +.iX "c Erasing a directory" +.iX "c Deleting a directory" +.iX "c Directory removing" +.iX "c Subdirectory removing" +.PP +The \fR\&\f(CWmrd\fR command is used to remove an MS-DOS subdirectory. Its +syntax is: +.PP +.ft I +.nf +\&\fR\&\f(CWmrd\fR [\fR\&\f(CW-v\fR] \fImsdosdirectory\fR [ \fImsdosdirectories\fR\&... ] +.fi +.ft R + +.PP +\&\fR\&\f(CWMrd\fR removes a directory from an MS-DOS filesystem. An error occurs +if the directory does not exist or is not empty. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mren.1 b/mren.1 new file mode 100644 index 0000000..ff42566 --- /dev/null +++ b/mren.1 @@ -0,0 +1,107 @@ +.TH mren 1 "03Nov09" mtools-4.0.12 +.SH Name +mren - rename an existing MSDOS file +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mren" +.iX "c Renaming files (mren)" +.iX "c Moving files (mren)" +.PP +The \fR\&\f(CWmren\fR command is used to rename or move an existing MS-DOS +file or subdirectory. Its syntax is: +.PP +.ft I +.nf +\&\fR\&\f(CWmren\fR [\fR\&\f(CW-voOsSrRA\fR] \fIsourcefile\fR \fItargetfile\fR +.fi +.ft R + +.PP +\&\fR\&\f(CWMren\fR +renames an existing file on an MS-DOS filesystem. +.PP +In verbose mode, \fR\&\f(CWMren\fR displays the new filename if the name +supplied is invalid. +.PP +If the first syntax is used (only one sourcefile), and if the target +name doesn't contain any slashes or colons, the file (or subdirectory) +is renamed in the same directory, instead of being moved to the current +\&\fR\&\f(CWmcd\fR directory as would be the case with \fR\&\f(CWmmove\fR. Unlike the +MS-DOS version of \fR\&\f(CWREN\fR, \fR\&\f(CWmren\fR can be used to rename +directories. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/msdos.h b/msdos.h new file mode 100644 index 0000000..b0dd5ff --- /dev/null +++ b/msdos.h @@ -0,0 +1,278 @@ +#ifndef MTOOLS_MSDOS_H +#define MTOOLS_MSDOS_H + +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996-1998,2000-2003,2006,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * msdos common header file + */ + +#define MAX_SECTOR 8192 /* largest sector size */ +#define MDIR_SIZE 32 /* MSDOS directory entry size in bytes*/ +#define MAX_CLUSTER 8192 /* largest cluster size */ +#ifndef MAX_PATH +#define MAX_PATH 128 /* largest MSDOS path length */ +#endif +#define MAX_DIR_SECS 64 /* largest directory (in sectors) */ +#define MSECTOR_SIZE msector_size + +#define NEW 1 +#define OLD 0 + +#define _WORD(x) ((unsigned short)((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8))) +#define _DWORD(x) ((unsigned int)(_WORD(x) + (_WORD((x)+2) << 16))) + +#define DELMARK ((char) 0xe5) + +struct directory { + char name[8]; /* 0 file name */ + char ext[3]; /* 8 file extension */ + unsigned char attr; /* 11 attribute byte */ + unsigned char Case; /* 12 case of short filename */ + unsigned char ctime_ms; /* 13 creation time, milliseconds (?) */ + unsigned char ctime[2]; /* 14 creation time */ + unsigned char cdate[2]; /* 16 creation date */ + unsigned char adate[2]; /* 18 last access date */ + unsigned char startHi[2]; /* 20 start cluster, Hi */ + unsigned char time[2]; /* 22 time stamp */ + unsigned char date[2]; /* 24 date stamp */ + unsigned char start[2]; /* 26 starting cluster number */ + unsigned char size[4]; /* 28 size of the file */ +}; + +#define EXTCASE 0x10 +#define BASECASE 0x8 + +#define MAX16 0xffff +#define MAX32 0xffffffff +#define MAX_SIZE 0x7fffffff + +#define FILE_SIZE(dir) (_DWORD((dir)->size)) +#define START(dir) (_WORD((dir)->start)) +#define STARTHI(dir) (_WORD((dir)->startHi)) + +/* ASSUMPTION: long is at least 32 bits */ +UNUSED(static __inline__ void set_dword(unsigned char *data, unsigned long value)) +{ + data[3] = (value >> 24) & 0xff; + data[2] = (value >> 16) & 0xff; + data[1] = (value >> 8) & 0xff; + data[0] = (value >> 0) & 0xff; +} + + +/* ASSUMPTION: short is at least 16 bits */ +UNUSED(static __inline__ void set_word(unsigned char *data, unsigned short value)) +{ + data[1] = (value >> 8) & 0xff; + data[0] = (value >> 0) & 0xff; +} + + +/* + * hi byte | low byte + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | + * \ 7 bits /\4 bits/\ 5 bits / + * year +80 month day + */ +#define DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980) +#define DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5))) +#define DOS_DAY(dir) ((dir)->date[0] & 0x1f) + +/* + * hi byte | low byte + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | + * \ 5 bits /\ 6 bits /\ 5 bits / + * hour minutes sec*2 + */ +#define DOS_HOUR(dir) ((dir)->time[1] >> 3) +#define DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5))) +#define DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2) + + +typedef struct InfoSector_t { + unsigned char signature1[4]; + unsigned char filler1[0x1e0]; + unsigned char signature2[4]; + unsigned char count[4]; + unsigned char pos[4]; + unsigned char filler2[14]; + unsigned char signature3[2]; +} InfoSector_t; + +#define INFOSECT_SIGNATURE1 0x41615252 +#define INFOSECT_SIGNATURE2 0x61417272 + + +typedef struct label_blk_t { + unsigned char physdrive; /* 36 physical drive ? */ + unsigned char reserved; /* 37 reserved */ + unsigned char dos4; /* 38 dos > 4.0 diskette */ + unsigned char serial[4]; /* 39 serial number */ + char label[11]; /* 43 disk label */ + char fat_type[8]; /* 54 FAT type */ +} label_blk_t; + +/* FAT32 specific info in the bootsector */ +struct fat32_t { + unsigned char bigFat[4]; /* 36 nb of sectors per FAT */ + unsigned char extFlags[2]; /* 40 extension flags */ + unsigned char fsVersion[2]; /* 42 ? */ + unsigned char rootCluster[4]; /* 44 start cluster of root dir */ + unsigned char infoSector[2]; /* 48 changeable global info */ + unsigned char backupBoot[2]; /* 50 back up boot sector */ + unsigned char reserved[6]; /* 52 ? */ + unsigned char reserved2[6]; /* 52 ? */ + struct label_blk_t labelBlock; +}; /* ends at 58 */ + +typedef struct oldboot_t { + struct label_blk_t labelBlock; + unsigned char res_2m; /* 62 reserved by 2M */ + unsigned char CheckSum; /* 63 2M checksum (not used) */ + unsigned char fmt_2mf; /* 64 2MF format version */ + unsigned char wt; /* 65 1 if write track after format */ + unsigned char rate_0; /* 66 data transfer rate on track 0 */ + unsigned char rate_any; /* 67 data transfer rate on track<>0 */ + unsigned char BootP[2]; /* 68 offset to boot program */ + unsigned char Infp0[2]; /* 70 T1: information for track 0 */ + unsigned char InfpX[2]; /* 72 T2: information for track<>0 */ + unsigned char InfTm[2]; /* 74 T3: track sectors size table */ + unsigned char DateF[2]; /* 76 Format date */ + unsigned char TimeF[2]; /* 78 Format time */ + unsigned char junk[1024 - 80]; /* 80 remaining data */ +} oldboot_t; + +struct bootsector_s { + unsigned char jump[3]; /* 0 Jump to boot code */ + char banner[8]; /* 3 OEM name & version */ + unsigned char secsiz[2]; /* 11 Bytes per sector hopefully 512 */ + unsigned char clsiz; /* 13 Cluster size in sectors */ + unsigned char nrsvsect[2]; /* 14 Number of reserved (boot) sectors */ + unsigned char nfat; /* 16 Number of FAT tables hopefully 2 */ + unsigned char dirents[2]; /* 17 Number of directory slots */ + unsigned char psect[2]; /* 19 Total sectors on disk */ + unsigned char descr; /* 21 Media descriptor=first byte of FAT */ + unsigned char fatlen[2]; /* 22 Sectors in FAT */ + unsigned char nsect[2]; /* 24 Sectors/track */ + unsigned char nheads[2]; /* 26 Heads */ + unsigned char nhs[4]; /* 28 number of hidden sectors */ + unsigned char bigsect[4]; /* 32 big total sectors */ + + union { + struct fat32_t fat32; + struct oldboot_t old; + } ext; +}; + +#define MAX_BOOT 4096 + +union bootsector { + unsigned char bytes[MAX_BOOT]; + char characters[MAX_BOOT]; + struct bootsector_s boot; +}; + +#define CHAR(x) (boot->x[0]) +#define WORD(x) (_WORD(boot->boot.x)) +#define DWORD(x) (_DWORD(boot->boot.x)) + +#define WORD_S(x) (_WORD(boot.boot.x)) +#define DWORD_S(x) (_DWORD(boot.boot.x)) + +#define OFFSET(x) (((char *) (boot->x)) - ((char *)(boot->jump))) + + +extern struct OldDos_t { + unsigned int tracks; + unsigned int sectors; + unsigned int heads; + + unsigned int dir_len; + unsigned int cluster_size; + unsigned int fat_len; + + int media; +} old_dos[]; + +/* max FAT12/FAT16 sizes, according to + + http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf + + interestingly enough, another Microsoft document + [http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b67321] + gives different values, but the first seems to be more sure about + itself, so we believe that one ;-) +*/ +#define FAT12 4085 /* max. number of clusters described by a 12 bit FAT */ +#define FAT16 65525 /* max number of clusters for a 16 bit FAT */ + +#define ATTR_ARCHIVE 0x20 +#define ATTR_DIR 0x10 +#define ATTR_LABEL 0x8 +#define ATTR_SYSTEM 0x4 +#define ATTR_HIDDEN 0x2 +#define ATTR_READONLY 0x1 + +#define HAS_BIT(entry,x) ((entry)->dir.attr & (x)) + +#define IS_ARCHIVE(entry) (HAS_BIT((entry),ATTR_ARCHIVE)) +#define IS_DIR(entry) (HAS_BIT((entry),ATTR_DIR)) +#define IS_LABEL(entry) (HAS_BIT((entry),ATTR_LABEL)) +#define IS_SYSTEM(entry) (HAS_BIT((entry),ATTR_SYSTEM)) +#define IS_HIDDEN(entry) (HAS_BIT((entry),ATTR_HIDDEN)) +#define IS_READONLY(entry) (HAS_BIT((entry),ATTR_READONLY)) + + +#define MAX_BYTES_PER_CLUSTER (32*1024) +/* Experimentally, it turns out that DOS only accepts cluster sizes + * which are powers of two, and less than 128 sectors (else it gets a + * divide overflow) */ + + +#define FAT_SIZE(bits, sec_siz, clusters) \ + ((((clusters)+2) * ((bits)/4) - 1) / 2 / (sec_siz) + 1) + +#define NEEDED_FAT_SIZE(x) FAT_SIZE((x)->fat_bits, (x)->sector_size, \ + (x)->num_clus) + +/* disk size taken by FAT and clusters */ +#define DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \ + ((n) * FAT_SIZE(bits, sec_siz, clusters) + \ + (clusters) * (cluster_size)) + +#define TOTAL_DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \ + (DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) + 2) +/* approx. total disk size: assume 1 boot sector and one directory sector */ + +extern const char *mversion; +extern const char *mdate; +extern const char *mformat_banner; + +extern char *Version; +extern char *Date; + + +int init(char drive, int mode); + +#define MT_READ 1 +#define MT_WRITE 2 + +#endif + diff --git a/mshowfat.1 b/mshowfat.1 new file mode 100644 index 0000000..0f35bfe --- /dev/null +++ b/mshowfat.1 @@ -0,0 +1,94 @@ +.TH mshowfat 1 "03Nov09" mtools-4.0.12 +.SH Name +mshowfat - shows FAT clusters allocated to file +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mshowfat" +.iX "c Clusters of a file" +.iX "c Fat" +.PP +The \fR\&\f(CWmshowfat\fR command is used to display the FAT entries for a +file. Syntax: +.PP +.ft I +.nf +\&\fR\&\f(CW$ mshowfat files\fR +.fi +.ft R + +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mshowfat.c b/mshowfat.c new file mode 100644 index 0000000..4828474 --- /dev/null +++ b/mshowfat.c @@ -0,0 +1,110 @@ +/* Copyright 1997,2000-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mcopy.c + * Copy an MSDOS files to and from Unix + * + */ + + +#define LOWERCASE + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "plain_io.h" +#include "nameclash.h" +#include "file.h" +#include "fs.h" + + + +typedef struct Arg_t { + char *target; + MainParam_t mp; + ClashHandling_t ch; + Stream_t *sourcefile; +} Arg_t; + +static int dos_showfat(direntry_t *entry, MainParam_t *mp) +{ + Stream_t *File=mp->File; + + fprintPwd(stdout, entry,0); + putchar(' '); + printFat(File); + printf("\n"); + return GOT_ONE; +} + +static int unix_showfat(MainParam_t *mp) +{ + fprintf(stderr,"File does not reside on a Dos fs\n"); + return ERROR_ONE; +} + + +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, + "Usage: %s files\n", progname); + exit(ret); +} + +void mshowfat(int argc, char **argv, int mtype) +{ + Arg_t arg; + int c, ret; + + /* get command line options */ + + init_clash_handling(& arg.ch); + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:h")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, 0); + break; + case 'h': + usage(0); + case '?': + usage(1); + break; + } + } + + if (argc - optind < 1) + usage(1); + + /* only 1 file to copy... */ + init_mp(&arg.mp); + arg.mp.arg = (void *) &arg; + + arg.mp.callback = dos_showfat; + arg.mp.unixcallback = unix_showfat; + + arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN; + ret=main_loop(&arg.mp, argv + optind, argc - optind); + exit(ret); +} diff --git a/mtools-4.0.12.tar.bz2 b/mtools-4.0.12.tar.bz2 new file mode 100644 index 0000000..fa745ad Binary files /dev/null and b/mtools-4.0.12.tar.bz2 differ diff --git a/mtools.1 b/mtools.1 new file mode 100644 index 0000000..e099497 --- /dev/null +++ b/mtools.1 @@ -0,0 +1,555 @@ +'\" t +.TH mtools.1 3 "03Nov09" mtools-4.0.12 +.SH Name +mtools - utilities to access DOS disks in Unix. +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.PP +.SH Introduction +Mtools is a collection of tools to allow Unix systems to manipulate +MS-DOS files: read, write, and move around files on an MS-DOS +filesystem (typically a floppy disk). Where reasonable, each program +attempts to emulate the MS-DOS equivalent command. However, +unnecessary restrictions and oddities of DOS are not emulated. For +instance, it is possible to move subdirectories from one subdirectory +to another. +.PP +Mtools is sufficient to give access to MS-DOS filesystems. For +instance, commands such as \fR\&\f(CWmdir a:\fR work on the \fR\&\f(CWa:\fR floppy +without any preliminary mounting or initialization (assuming the default +\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR works on your machine). With mtools, one can +change floppies too without unmounting and mounting. +.PP +.SH Where\ to\ get\ mtools +.iX "c bugs" +.iX "c ALPHA patches" +.iX "c patches" +.iX "c diffs" +.iX "c mailing list" +.PP +Mtools can be found at the following places (and their mirrors): + +.nf +.ft 3 +.in +0.3i +http://ftp.gnu.org/gnu/mtools/mtools-4.0.12.tar.gz +http://mtools.linux.lu/mtools-4.0.12.tar.gz +ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.12.tar.gz +ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.12.tar.gz +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +Before reporting a bug, make sure that it has not yet been fixed in the +Alpha patches which can be found at: + +.nf +.ft 3 +.in +0.3i +http://ftp.gnu.org/gnu/mtools/ +http://mtools.linux.lu/ +ftp://www.tux.org/pub/knaff/mtools +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +These patches are named +\&\fR\&\f(CWmtools-\fR\fIversion\fR\fR\&\f(CW-\fR\fIddmm\fR\fR\&\f(CW.taz\fR, where version +stands for the base version, \fIdd\fR for the day and \fImm\fR for the +month. Due to a lack of space, I usually leave only the most recent +patch. +.PP +There is an mtools mailing list at mtools @ tux.org . Please +send all bug reports to this list. You may subscribe to the list by +sending a message with 'subscribe mtools @ tux.org' in its +body to majordomo @ tux.org . (N.B. Please remove the spaces +around the "@" both times. I left them there in order to fool +spambots.) Announcements of new mtools versions will also be sent to +the list, in addition to the linux announce newsgroups. The mailing +list is archived at http://lists.gnu.org/pipermail/info-mtools/ +.PP +.SH Common\ features\ of\ all\ mtools\ commands +.PP +.SS Options\ and\ filenames +.iX "c Filenames" +.iX "c Options" +MS-DOS filenames are composed of a drive letter followed by a colon, a +subdirectory, and a filename. Only the filename part is mandatory, the +drive letter and the subdirectory are optional. Filenames without a +drive letter refer to Unix files. Subdirectory names can use either the +\&'\fR\&\f(CW/\fR' or '\fR\&\f(CW\e\fR' separator. The use of the '\fR\&\f(CW\e\fR' separator +or wildcards requires the names to be enclosed in quotes to protect them +from the shell. However, wildcards in Unix filenames should not be +enclosed in quotes, because here we \fBwant\fR the shell to expand +them. +.PP +The regular expression "pattern matching" routines follow the Unix-style +rules. For example, `\fR\&\f(CW*\fR' matches all MS-DOS files in lieu of +`\fR\&\f(CW*.*\fR'. The archive, hidden, read-only and system attribute bits +are ignored during pattern matching. +.PP +All options use the \fR\&\f(CW-\fR (minus) as their first character, not +\&\fR\&\f(CW/\fR as you'd expect in MS-DOS. +.PP +Most mtools commands allow multiple filename parameters, which +doesn't follow MS-DOS conventions, but which is more user-friendly. +.PP +Most mtools commands allow options that instruct them how to handle file +name clashes. See section name clashes, for more details on these. All +commands accept the \fR\&\f(CW-V\fR flags which prints the version, and most +accept the \fR\&\f(CW-v\fR flag, which switches on verbose mode. In verbose +mode, these commands print out the name of the MS-DOS files upon which +they act, unless stated otherwise. See section Commands, for a description of +the options which are specific to each command. +.PP +.SS Drive\ letters +.PP +The meaning of the drive letters depends on the target architectures. +However, on most target architectures, drive A is the first floppy +drive, drive B is the second floppy drive (if available), drive J is a +Jaz drive (if available), and drive Z is a Zip drive (if available). On +those systems where the device name is derived from the SCSI id, the Jaz +drive is assumed to be at Scsi target 4, and the Zip at Scsi target 5 +(factory default settings). On Linux, both drives are assumed to be the +second drive on the Scsi bus (/dev/sdb). The default settings can be +changes using a configuration file (see section Configuration). +.PP +The drive letter : (colon) has a special meaning. It is used to access +image files which are directly specified on the command line using the +\&\fR\&\f(CW-i\fR options. +.PP +Example: + +.nf +.ft 3 +.in +0.3i + mcopy -i my-image-file.bin ::file1 ::file2 . +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +This copies \fR\&\f(CWfile1\fR and \fR\&\f(CWfile2\fR from the image file +(\fR\&\f(CWmy-image-file.bin\fR) to the \fR\&\f(CW/tmp\fR directory. +.PP +You can also supply an offset within the image file by including +\&\fR\&\f(CW@@\fR\fIoffset\fR into the file name. +.PP +Example: + +.nf +.ft 3 +.in +0.3i + mcopy -i my-image-file.bin@@1M ::file1 ::file2 . +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +This looks for the image at the offset of 1M in the file, rather than +at its beginning. +.PP +.SS Current\ working\ directory +.iX "p mcd (introduction)" +.iX "c Directory" +.iX "c Working directory" +.iX "c Current working directory" +.iX "c Default directory" +.PP +The \fR\&\f(CWmcd\fR command (\(ifmcd\(is) is used to establish the device and +the current working directory (relative to the MS-DOS filesystem), +otherwise the default is assumed to be \fR\&\f(CWA:/\fR. However, unlike +MS-DOS, there is only one working directory for all drives, and not one +per drive. +.PP +.SS VFAT-style\ long\ file\ names +.iX "c Long file name" +.iX "c Windows 95-style file names" +.iX "c VFAT-style file names" +.iX "c Primary file name (long names)" +.iX "c Secondary file name (long names)" +.PP +This version of mtools supports VFAT style long filenames. If a Unix +filename is too long to fit in a short DOS name, it is stored as a +VFAT long name, and a companion short name is generated. This short +name is what you see when you examine the disk with a pre-7.0 version +of DOS. + The following table shows some examples of short names: +.PP + +.nf +.ft 3 +.in +0.3i +Long name MS-DOS name Reason for the change +--------- ---------- --------------------- +thisisatest THISIS~1 filename too long +alain.knaff ALAIN~1.KNA extension too long +prn.txt PRN~1.TXT PRN is a device name +\&\&.abc ABC~1 null filename +hot+cold HOT_CO~1 illegal character +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP + As you see, the following transformations happen to derive a short +name: +.TP +* \ \ +Illegal characters are replaced by underscores. The illegal characters +are \fR\&\f(CW;+=[]',\e"*\e\e<>/?:|\fR. +.TP +* \ \ +Extra dots, which cannot be interpreted as a main name/extension +separator are removed +.TP +* \ \ +A \fR\&\f(CW~\fR\fIn\fR number is generated, +.TP +* \ \ +The name is shortened so as to fit in the 8+3 limitation +.PP + The initial Unix-style file name (whether long or short) is also called +the \fIprimary\fR name, and the derived short name is also called the +\&\fIsecondary\fR name. +.PP + Example: + +.nf +.ft 3 +.in +0.3i + mcopy /etc/motd a:Reallylongname +.fi +.in -0.3i +.ft R +.lp + +\&\fR Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as +a short name. Reallylongname is the primary name, and REALLYLO is the +secondary name. + +.nf +.ft 3 +.in +0.3i + mcopy /etc/motd a:motd +.fi +.in -0.3i +.ft R +.lp + +\&\fR Motd fits into the DOS filename limits. Mtools doesn't need to +derivate another name. Motd is the primary name, and there is no +secondary name. +.PP + In a nutshell: The primary name is the long name, if one exists, or +the short name if there is no long name. +.PP + Although VFAT is much more flexible than FAT, there are still names +that are not acceptable, even in VFAT. There are still some illegal +characters left (\fR\&\f(CW\e"*\e\e<>/?:|\fR), and device names are still +reserved. +.PP + +.nf +.ft 3 +.in +0.3i +Unix name Long name Reason for the change +--------- ---------- --------------------- +prn prn-1 PRN is a device name +ab:c ab_c-1 illegal character +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP + As you see, the following transformations happen if a long name is +illegal: +.TP +* \ \ +Illegal characters are replaces by underscores, +.TP +* \ \ +A \fR\&\f(CW-\fR\fIn\fR number is generated, +.PP +.SS Name\ clashes +.iX "c Name clashes" +.iX "c Duplicate file names" +.iX "c Overwriting files" +.iX "c Primary file name (name clashes)" +.iX "c Secondary file name (name clashes)" +.PP +When writing a file to disk, its long name or short name may collide +with an already existing file or directory. This may happen for all +commands which create new directory entries, such as \fR\&\f(CWmcopy\fR, +\&\fR\&\f(CWmmd\fR, \fR\&\f(CWmren\fR, \fR\&\f(CWmmove\fR. When a name clash happens, mtools +asks you what it should do. It offers several choices: +.TP +\&\fR\&\f(CWoverwrite\fR\ +Overwrites the existing file. It is not possible to overwrite a +directory with a file. +.TP +\&\fR\&\f(CWrename\fR\ +Renames the newly created file. Mtools prompts for the new filename +.TP +\&\fR\&\f(CWautorename\fR\ +Renames the newly created file. Mtools chooses a name by itself, without +prompting +.TP +\&\fR\&\f(CWskip\fR\ +Gives up on this file, and moves on to the next (if any) +.PP +To chose one of these actions, type its first letter at the prompt. If +you use a lower case letter, the action only applies for this file only, +if you use an upper case letter, the action applies to all files, and +you won't be prompted again. +.PP +You may also chose actions (for all files) on the command line, when +invoking mtools: +.TP +\&\fR\&\f(CW-D\ o\fR\ +Overwrites primary names by default. +.TP +\&\fR\&\f(CW-D\ O\fR\ +Overwrites secondary names by default. +.TP +\&\fR\&\f(CW-D\ r\fR\ +Renames primary name by default. +.TP +\&\fR\&\f(CW-D\ R\fR\ +Renames secondary name by default. +.TP +\&\fR\&\f(CW-D\ a\fR\ +Autorenames primary name by default. +.TP +\&\fR\&\f(CW-D\ A\fR\ +Autorenames secondary name by default. +.TP +\&\fR\&\f(CW-D\ s\fR\ +Skip primary name by default. +.TP +\&\fR\&\f(CW-D\ S\fR\ +Skip secondary name by default. +.TP +\&\fR\&\f(CW-D\ m\fR\ +Ask user what to do with primary name. +.TP +\&\fR\&\f(CW-D\ M\fR\ +Ask user what to do with secondary name. +.PP +Note that for command line switches lower/upper differentiates between +primary/secondary name whereas for interactive choices, lower/upper +differentiates between just-this-time/always. +.PP +The primary name is the name as displayed in Windows 95 or Windows NT: +i.e. the long name if it exists, and the short name otherwise. The +secondary name is the "hidden" name, i.e. the short name if a long name +exists. +.PP +By default, the user is prompted if the primary name clashes, and the +secondary name is autorenamed. +.PP +If a name clash occurs in a Unix directory, mtools only asks whether +to overwrite the file, or to skip it. +.PP +.SS Case\ sensitivity\ of\ the\ VFAT\ filesystem +.iX "c Case sensitivity" +.PP +The VFAT filesystem is able to remember the case of the +filenames. However, filenames which differ only in case are not allowed +to coexist in the same directory. For example if you store a file called +LongFileName on a VFAT filesystem, mdir shows this file as LongFileName, +and not as Longfilename. However, if you then try to add LongFilename to +the same directory, it is refused, because case is ignored for clash +checks. +.PP +The VFAT filesystem allows to store the case of a filename in the +attribute byte, if all letters of the filename are the same case, and if +all letters of the extension are the same case too. Mtools uses this +information when displaying the files, and also to generate the Unix +filename when mcopying to a Unix directory. This may have unexpected +results when applied to files written using an pre-7.0 version of DOS: +Indeed, the old style filenames map to all upper case. This is different +from the behavior of the old version of mtools which used to generate +lower case Unix filenames. +.PP +.SS high\ capacity\ formats +.iX "c Special formats" +.iX "c High capacity formats" +.iX "c Odd formats" +.iX "c Weird formats" +.iX "c Formats, high capacity" +.iX "c Linux enhancements (High Capacity Formats)" +.PP +Mtools supports a number of formats which allow to store more data on +disk as usual. Due to different operating system abilities, these +formats are not supported on all OS'es. Mtools recognizes these formats +transparently where supported. +.PP +In order to format these disks, you need to use an operating system +specific tool. For Linux, suitable floppy tools can be found in the +\&\fR\&\f(CWfdutils\fR package at the following locations~: + +.nf +.ft 3 +.in +0.3i +\&\fR\&\f(CWftp://www.tux.org/pub/knaff/fdutils/. +\&\fR\&\f(CWftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-* +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +See the manpages included in that package for further detail: Use +\&\fR\&\f(CWsuperformat\fR to format all formats except XDF, and use +\&\fR\&\f(CWxdfcopy\fR to format XDF. +.PP +.SS \ \ More\ sectors +.iX "c fdformat" +.iX "c vgacopy" +.iX "c DMF disks" +.iX "c Windows 95 (DMF disks)" +.PP +The oldest method of fitting more data on a disk is to use more sectors +and more cylinders. Although the standard format uses 80 cylinders and +18 sectors (on a 3 1/2 high density disk), it is possible to use up to +83 cylinders (on most drives) and up to 21 sectors. This method allows +to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are +twice as slow as the standard 18 sector disks because the sectors are +packed so close together that we need to interleave them. This problem +doesn't exist for 20 sector formats. +.PP +These formats are supported by numerous DOS shareware utilities such as +\&\fR\&\f(CWfdformat\fR and \fR\&\f(CWvgacopy\fR. In his infinite hybris, Bill Gate$ +believed that he invented this, and called it \fR\&\f(CW\(ifDMF disks\(is\fR, or +\&\fR\&\f(CW\(ifWindows formatted disks\(is\fR. But in reality, it has already existed +years before! Mtools supports these formats on Linux, on SunOs and on +the DELL Unix PC. +.PP +.SS \ \ Bigger\ sectors +.iX "c bigger sectors" +By using bigger sectors it is possible to go beyond the capacity which +can be obtained by the standard 512-byte sectors. This is because of the +sector header. The sector header has the same size, regardless of how +many data bytes are in the sector. Thus, we save some space by using +\&\fIfewer\fR, but bigger sectors. For example, 1 sector of 4K only takes +up header space once, whereas 8 sectors of 512 bytes have also 8 +headers, for the same amount of useful data. +.PP +This method allows to store up to 1992K on a 3 1/2 HD disk. +.PP +Mtools supports these formats only on Linux. +.PP +.SS \ \ 2m +.iX "c 2m" +.PP +The 2m format was originally invented by Ciriaco Garcia de Celis. It +also uses bigger sectors than usual in order to fit more data on the +disk. However, it uses the standard format (18 sectors of 512 bytes +each) on the first cylinder, in order to make these disks easyer to +handle by DOS. Indeed this method allows to have a standard sized +bootsector, which contains a description of how the rest of the disk +should be read. +.PP +However, the drawback of this is that the first cylinder can hold less +data than the others. Unfortunately, DOS can only handle disks where +each track contains the same amount of data. Thus 2m hides the fact that +the first track contains less data by using a \fIshadow +FAT\fR. (Usually, DOS stores the FAT in two identical copies, for +additional safety. XDF stores only one copy, and it tells DOS that it +stores two. Thus the same that would be taken up by the second FAT copy +is saved.) This also means that your should \fBnever use a 2m disk +to store anything else than a DOS fs\fR. +.PP +Mtools supports these format only on Linux. +.PP +.SS \ \ XDF +.iX "c XDF disks" +.iX "c OS/2 (XDF disks)" +.PP +XDF is a high capacity format used by OS/2. It can hold 1840 K per +disk. That's lower than the best 2m formats, but its main advantage is +that it is fast: 600 milliseconds per track. That's faster than the 21 +sector format, and almost as fast as the standard 18 sector format. In +order to access these disks, make sure mtools has been compiled with XDF +support, and set the \fR\&\f(CWuse_xdf\fR variable for the drive in the +configuration file. See section Compiling mtools, and \(ifmisc variables\(is, +for details on how to do this. Fast XDF access is only available for +Linux kernels which are more recent than 1.1.34. +.PP +Mtools supports this format only on Linux. +.PP +\&\fBCaution / Attention distributors\fR: If mtools is compiled on a +Linux kernel more recent than 1.3.34, it won't run on an older +kernel. However, if it has been compiled on an older kernel, it still +runs on a newer kernel, except that XDF access is slower. It is +recommended that distribution authors only include mtools binaries +compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will +be out, mtools binaries compiled on newer kernels may (and should) be +distributed. Mtools binaries compiled on kernels older than 1.3.34 won't +run on any 2.1 kernel or later. +.PP +.SS Exit\ codes +All the Mtools commands return 0 on success, 1 on utter failure, or 2 +on partial failure. All the Mtools commands perform a few sanity +checks before going ahead, to make sure that the disk is indeed an +MS-DOS disk (as opposed to, say an ext2 or minix disk). These checks +may reject partially corrupted disks, which might otherwise still be +readable. To avoid these checks, set the MTOOLS_SKIP_CHECK +environmental variable or the corresponding configuration file variable +(see section global variables) +.SS Bugs +An unfortunate side effect of not guessing the proper device (when +multiple disk capacities are supported) is an occasional error message +from the device driver. These can be safely ignored. +.PP +The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7 +mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the +corresponding configuration file variable, \(ifglobal variables\(is) to +bypass the fat checking. +.PP +.SH See also +floppyd_installtest +mattrib +mbadblocks +mcd +mcopy +mdel +mdeltree +mdir +mdu +mformat +minfo +mkmanifest +mlabel +mmd +mmount +mmove +mrd +mren +mtoolstest +mtype diff --git a/mtools.5 b/mtools.5 new file mode 100644 index 0000000..7f12b64 --- /dev/null +++ b/mtools.5 @@ -0,0 +1,633 @@ +'\" t +.TH mtools.1 3 "03Nov09" MTOOLS MTOOLS +.SH Name +mtools.conf - mtools configuration files +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.ds St Mtools\ 4.0.12 +.oh '\\*(St''%' +.eh '%''\\*(St' +.PP +.SH Description +.PP +This manpage describes the configuration files for mtools. They +are called \fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR. If +the environmental variable \fR\&\f(CWMTOOLSRC\fR is set, its contents is used +as the filename for a third configuration file. These configuration +files describe the following items: +.TP +* \ Global\ configuration\ flags\ and\ variables\ +.TP +* \ Per\ drive\ flags\ and\ variables\ +.PP +.SS Location\ of\ the\ configuration\ files +.PP +.iX "c Configuration file name" +.iX "c Name of configuration files" +.iX "c Location of configuration files" +.PP +\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR is the system-wide configuration file, +and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR is the user's private configuration file. +.PP +On some systems, the system-wide configuration file is called +\&\fR\&\f(CW\(if/etc/default/mtools.conf\(is\fR instead. +.PP +.SS \ \ General\ configuration\ file\ syntax +.iX "c Syntax of the configuration file" +.iX "c Configuration file syntax" +.PP +The configuration files is made up of sections. Each section starts +with a keyword identifying the section followed by a colon. +Then follow variable assignments and flags. Variable assignments take +the following form: +.ft I +.nf +name=value +.fi +.ft R + +Flags are lone keywords without an equal sign and value following +them. A section either ends at the end of the file or where the next +section begins. +.PP +Lines starting with a hash (\fR\&\f(CW#\fR) are comments. Newline characters +are equivalent to whitespace (except where ending a comment). The +configuration file is case insensitive, except for item enclosed in +quotes (such as filenames). +.PP +.SS Default\ values +.iX "c Default values" +.iX "c Default configuration" +.iX "c Configuration file" +For most platforms, mtools contains reasonable compiled-in defaults for +physical floppy drives. Thus, you usually don't need to bother with the +configuration file, if all you want to do with mtools is to access your +floppy drives. On the other hand, the configuration file is needed if +you also want to use mtools to access your hard disk partitions and +dosemu image files. +.PP +.SS Global\ variables +.iX "c Global configuration variables" +.iX "c Drive independent configuration variables" +.iX "c Environmental variables" +.iX "v MTOOLS_SKIP_CHECK" +.iX "v MTOOLS_FAT_COMPATIBILITY" +.iX "v MTOOLS_LOWER_CASE" +.iX "v MTOOLS_NO_VFAT" +.iX "c FreeDos" +.PP +Global flags may be set to 1 or to 0. +.PP +The following global flags are recognized: +.TP +\&\fR\&\f(CWMTOOLS_SKIP_CHECK\fR\ +If this is set to 1, mtools skips most of its sanity checks. This is +needed to read some Atari disks which have been made with the earlier +ROMs, and which would not be recognized otherwise. +.TP +\&\fR\&\f(CWMTOOLS_FAT_COMPATIBILITY\fR\ +If this is set to 1, mtools skips the fat size checks. Some disks have +a bigger FAT than they really need to. These are rejected if this +option is not set. +.TP +\&\fR\&\f(CWMTOOLS_LOWER_CASE\fR\ +If this is set to 1, mtools displays all-upper-case short filenames as +lowercase. This has been done to allow a behavior which is consistent +with older versions of mtools which didn't know about the case bits. +.TP +\&\fR\&\f(CWMTOOLS_NO_VFAT\fR\ +If this is set to 1, mtools won't generate VFAT entries for filenames +which are mixed-case, but otherwise legal dos filenames. This is useful +when working with DOS versions which can't grok VFAT longnames, such as +FreeDos. +.TP +\&\fR\&\f(CWMTOOLS_DOTTED_DIR\fR\ +In a wide directory, prints the short name with a dot instead of spaces +separating the basename and the extension. +.TP +\&\fR\&\f(CWMTOOLS_NAME_NUMERIC_TAIL\fR\ +If this is set to one (default), generate numeric tails for all long +names (~1). If set to zero, only generate numeric tails if otherwise a +clash would have happened. +.TP +\&\fR\&\f(CWMTOOLS_TWENTY_FOUR_HOUR_CLOCK\fR\ +If 1, uses the European notation for times (twenty four hour clock), +else uses the UK/US notation (am/pm) +.PP +Example: +Inserting the following line into your configuration file instructs +mtools to skip the sanity checks: + +.nf +.ft 3 +.in +0.3i + MTOOLS_SKIP_CHECK=1 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +Global variables may also be set via the environment: + +.nf +.ft 3 +.in +0.3i + export MTOOLS_SKIP_CHECK=1 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +Global string variables may be set to any value: +.TP +\&\fR\&\f(CWMTOOLS_DATE_STRING\fR\ +The format used for printing dates of files. By default, is dd-mm-yyyy. +.PP +.SS Per\ drive\ flags\ and\ variables +.iX "c Drive description" +.iX "c Drive configuration" +.PP +.SS \ \ General\ information +.iX "c Drive description, example" +.iX "c Drive configuration, example" +.iX "v drive" +.PP +Per drive flags and values may be described in a drive section. A +drive section starts with +\&\fR\&\f(CWdrive\fR "\fIdriveletter\fR" : +.PP +Then follow variable-value pairs and flags. +.PP +This is a sample drive description: + +.nf +.ft 3 +.in +0.3i + drive a: + file="/dev/fd0" use_xdf=1 +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +.SS \ \ Location\ information +.iX "c Hdimage" +.PP +For each drive, you need to describe where its data is physically +stored (imag file, physical device, partition, offset). +.TP +\&\fR\&\f(CWfile\fR\ +.iX "c Image file" +.iX "c Name of device node" +.iX "c File name of device node" +.iX "v file" +The name of the file or device holding the disk image. This is +mandatory. The file name should be enclosed in quotes. +.TP +\&\fR\&\f(CWpartition\fR\ +.iX "c Dosemu hard disk image" +.iX "c Zip disks (partitions)" +.iX "c Jaz disks (partitions)" +.iX "c Syquest disks" +.iX "c Magneto-optical disks" +.iX "c OS/2 (layout of removable media)" +.iX "c Windows NT (layout of removable media)" +.iX "c Removable media" +.iX "c Partitioned image file" +Tells mtools to treat the drive as a partitioned device, and to use the +given partition. Only primary partitions are accessible using this +method, and they are numbered from 1 to 4. For logical partitions, use +the more general \fR\&\f(CWoffset\fR variable. The \fR\&\f(CWpartition\fR variable +is intended for removable media such as Syquests, ZIP drives, and +magneto-optical disks. Although traditional DOS sees Syquests and +magneto-optical disks as \fR\&\f(CW\(ifgiant floppy disks\(is\fR which are +unpartitioned, OS/2 and Windows NT treat them like hard disks, +i.e. partioned devices. The \fR\&\f(CWpartition\fR flag is also useful DOSEMU +hdimages. It is not recommended for hard disks for which direct access +to partitions is available through mounting. +.TP +\&\fR\&\f(CWoffset\fR\ +.iX "c Ram disk" +.iX "c Atari Ram disk" +Describes where in the file the MS-DOS filesystem starts. This is useful +for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By +default, this is zero, meaning that the filesystem starts right at the +beginning of the device or file. +.PP +.SS \ \ Disk\ Geometry\ Configuration +.iX "c Disk Geometry" +.iX "c Configuration of disk geometry" +.iX "c Description of disk geometry" +.iX "c Format of disk" +.iX "c High density disk" +.iX "c Low density disk" +.iX "p mformat (geometry used for)" +.PP +Geometry information describes the physical characteristics about the +disk. Its has three purposes: +.TP +formatting\ +The geometry information is written into the boot sector of the newly +made disk. However, you may also describe the geometry information on +the command line. See section mformat, for details. +.TP +filtering\ +On some Unices there are device nodes which only support one physical +geometry. For instance, you might need a different node to access a disk +as high density or as low density. The geometry is compared to the +actual geometry stored on the boot sector to make sure that this device +node is able to correctly read the disk. If the geometry doesn't match, +this drive entry fails, and the next drive entry bearing the same drive +letter is tried. See section multiple descriptions, for more details on +supplying several descriptions for one drive letter. +.IP +If no geometry information is supplied in the configuration file, all +disks are accepted. On Linux (and on Sparc) there exist device nodes +with configurable geometry (\fR\&\f(CW\(if/dev/fd0\(is\fR, \fR\&\f(CW\(if/dev/fd1\(is\fR etc), +and thus filtering is not needed (and ignored) for disk drives. (Mtools +still does do filtering on plain files (disk images) in Linux: this is +mainly intended for test purposes, as I don't have access to a Unix +which would actually need filtering). +.IP +If you do not need filtering, but want still a default geometry for +mformatting, you may switch off filtering using the \fR\&\f(CWmformat_only\fR +flag. +.IP +If you want filtering, you should supply the \fR\&\f(CWfilter\fR flag. If you +supply a geometry, you must supply one of both flags. +.TP +initial\ geometry\ +On devices that support it (usually floppy devices), the geometry +information is also used to set the initial geometry. This initial +geometry is applied while reading the boot sector, which contains the +real geometry. If no geometry information is supplied in the +configuration file, or if the \fR\&\f(CWmformat_only\fR flag is supplied, no +initial configuration is done. +.IP +On Linux, initial geometry is not really needed, as the configurable +devices are able to auto-detect the disk type accurately enough (for +most common formats) to read the boot sector. +.PP +Wrong geometry information may lead to very bizarre errors. That's why I +strongly recommend that you add the \fR\&\f(CWmformat_only\fR flag to your +drive description, unless you really need filtering or initial geometry. +.PP +The following geometry related variables are available: +.TP +\&\fR\&\f(CWcylinders\fR\ +.TQ +\&\fR\&\f(CWtracks\fR +.iX "v cylinders" +.iX "v tracks" +The number of cylinders. (\fR\&\f(CWcylinders\fR is the preferred form, +\&\fR\&\f(CWtracks\fR is considered obsolete) +.TP +\&\fR\&\f(CWheads\fR\ +.iX "v heads" +The number of heads (sides). +.TP +\&\fR\&\f(CWsectors\fR\ +.iX "v sectors" +The number of sectors per track. +.PP +Example: the following drive section describes a 1.44M drive: +.PP + +.nf +.ft 3 +.in +0.3i + drive a: + file="/dev/fd0H1440" + fat_bits=12 + cylinders=80 heads=2 sectors=18 + mformat_only +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The following shorthand geometry descriptions are available: +.TP +\&\fR\&\f(CW1.44m\fR\ +high density 3 1/2 disk. Equivalent to: +\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=18\fR +.TP +\&\fR\&\f(CW1.2m\fR\ +high density 5 1/4 disk. Equivalent to: +\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=15\fR +.TP +\&\fR\&\f(CW720k\fR\ +double density 3 1/2 disk. Equivalent to: +\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=9\fR +.TP +\&\fR\&\f(CW360k\fR\ +double density 5 1/4 disk. Equivalent to: +\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=9\fR +.PP +The shorthand format descriptions may be amended. For example, +\&\fR\&\f(CW360k sectors=8\fR +describes a 320k disk and is equivalent to: +\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=8\fR +.PP +.SS \ \ Open\ Flags +.iX "v sync" +.iX "v nodelay" +.iX "v exclusive" +.iX "c open flags" +.iX "c synchronous writing" +.iX "c exclusive access to a drive" +.PP +Moreover, the following flags are available: +.TP +\&\fR\&\f(CWsync\fR\ +All i/o operations are done synchronously +.TP +\&\fR\&\f(CWnodelay\fR\ +The device or file is opened with the O_NDELAY flag. This is needed on +some non-Linux architectures. +.TP +\&\fR\&\f(CWexclusive\fR\ +The device or file is opened with the O_EXCL flag. On Linux, this +ensures exclusive access to the floppy drive. On most other +architectures, and for plain files it has no effect at all. +.PP +.SS \ \ General\ Purpose\ Drive\ Variables +.PP +The following general purpose drive variables are available. Depending +to their type, these variables can be set to a string (precmd) or +an integer (all others) +.TP +\&\fR\&\f(CWfat_bits\fR\ +.iX "v fat_bits" +The number of FAT bits. This may be 12 or 16. This is very rarely +needed, as it can almost always be deduced from information in the +boot sector. On the contrary, describing the number of fat bits may +actually be harmful if you get it wrong. You should only use it if +mtools gets the autodetected number of fat bits wrong, or if you want +to mformat a disk with a weird number of fat bits. +.TP +\&\fR\&\f(CWcodepage\fR\ +Describes the DOS codepage used for short filenames. This is a number +between 1 and 999. By default, codepage 850 is used. The reason for +this is because this codepage contains most of the characters that are +also available in ISO-Latin-1. You may also specify a global codepage +for all drives by using the global \fR\&\f(CWdefault_codepage\fR parameter +(outside of any drive description). This parameters exists starting at +version 4.0.0 +.TP +\&\fR\&\f(CWprecmd\fR\ +.iX "c Solaris (volcheck)" +.iX "c Executing commands before opening the device" +On some variants of Solaris, it is necessary to call 'volcheck -v' +before opening a floppy device, in order for the system to notice that +there is indeed a disk in the drive. \fR\&\f(CWprecmd="volcheck -v"\fR in the +drive clause establishes the desired behavior. +.TP +\&\fR\&\f(CWblocksize\fR\ +.iX "c raw device" +.iX "c character devices" +.iX "c blocksize" +This parameter represents a default block size to be always used on this +device. All I/O is done with multiples of this block size, +independantly of the sector size registered in the filesystem's boot +sector. This is useful for character devices whose sector size is not +512, such as for example CD Rom drives on Solaris. +.PP +Only the \fR\&\f(CWfile\fR variable is mandatory. The other parameters may +be left out. In that case a default value or an autodetected value is +used. +.PP +.SS \ \ General\ Purpose\ Drive\ Flags +.PP +A flag can either be set to 1 (enabled) or 0 (disabled). If the value is +ommitted, it is enabled. For example, \fR\&\f(CWscsi\fR is equivalent to +\&\fR\&\f(CWscsi=1\fR +.TP +\&\fR\&\f(CWnolock\fR\ +.iX "c disable locking" +.iX "c locking (disabling it)" +.iX "c plain floppy: device xxx busy" +Instruct mtools to not use locking on this drive. This is needed on +systems with buggy locking semantics. However, enabling this makes +operation less safe in cases where several users may access the same +drive at the same time. +.TP +\&\fR\&\f(CWscsi\fR\ +.iX "c setuid installation (needed for raw SCSI I/O)" +.iX "c Solaris (Raw access to SCSI devices such as Zip & Jaz)" +.iX "c SunOS (Raw access to SCSI devices such as Zip & Jaz)" +.iX "c Zip disks (raw Scsi access)" +.iX "c Jaz disks (raw Scsi access)" +.iX "c Syquests (raw Scsi access)" +.iX "c SCSI devices" +When set to 1, this option tells mtools to use raw SCSI I/O instead of +the standard read/write calls to access the device. Currently, this is +supported on HP/UX, Solaris and SunOs. This is needed because on some +architectures, such as SunOs or Solaris, PC media can't be accessed +using the \fR\&\f(CWread\fR and \fR\&\f(CWwrite\fR syscalls, because the OS expects +them to contain a Sun specific "disk label". +.IP +As raw Scsi access always uses the whole device, you need to specify the +"partition" flag in addition +.IP +On some architectures, such as Solaris, mtools needs root privileges to +be able to use the \fR\&\f(CWscsi\fR option. Thus mtools should be installed +set uid root on Solaris if you want to access Zip/Jaz drives. Thus, if +the \fR\&\f(CWscsi\fR flag is given, \fR\&\f(CWprivileged\fR is automatically +implied, unless explicitly disabled by \fR\&\f(CWprivileged=0\fR +.IP +Mtools uses its root privileges to open the device, and to issue the +actual SCSI I/O calls. Moreover, root privileges are only used for +drives described in a system-wide configuration file such as +\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR, and not for those described in +\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR or \fR\&\f(CW\(if$MTOOLSRC\(is\fR. +.TP +\&\fR\&\f(CWprivileged\fR\ +.iX "c setuid installation" +.iX "c setgid installation" +When set to 1, this instructs mtools to use its set-uid and set-gid +privileges for opening the given drive. This option is only valid for +drives described in the system-wide configuration files (such as +\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR, not \fR\&\f(CW\(if~/.mtoolsrc\(is\fR or +\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR). Obviously, this option is also a no op if mtools is +not installed setuid or setgid. This option is implied by 'scsi=1', but +again only for drives defined in system-wide configuration files. +Privileged may also be set explicitely to 0, in order to tell mtools not +to use its privileges for a given drive even if \fR\&\f(CWscsi=1\fR is set. +.IP +Mtools only needs to be installed setuid if you use the +\&\fR\&\f(CWprivileged\fR or \fR\&\f(CWscsi\fR drive variables. If you do not use +these options, mtools works perfectly well even when not installed +setuid root. +.TP +\&\fR\&\f(CWvold\fR\ +.iX "c Solaris (vold)" +.iX "c Vold (mediamgr)" +.IP +Instructs mtools to interpret the device name as a vold identifier +rather than as a filename. The vold identifier is translated into a +real filename using the \fR\&\f(CWmedia_findname()\fR and +\&\fR\&\f(CWmedia_oldaliases()\fR functions of the \fR\&\f(CWvolmgt\fR library. This +flag is only available if you configured mtools with the +\&\fR\&\f(CW--enable-new-vold\fR option before compilation. +.TP +\&\fR\&\f(CWswap\fR\ +.iX "c Atari" +.iX "c Wordswapped" +.IP +Consider the media as a word-swapped Atari disk. +.TP +\&\fR\&\f(CWuse_xdf\fR\ +.iX "c XDF disks (how to configure)" +.iX "v use_xdf" +If this is set to a non-zero value, mtools also tries to access this +disk as an XDF disk. XDF is a high capacity format used by OS/2. This +is off by default. See section XDF, for more details. +.TP +\&\fR\&\f(CWmformat_only\fR\ +.iX "v mformat_only" +Tells mtools to use the geometry for this drive only for mformatting and +not for filtering. +.TP +\&\fR\&\f(CWfilter\fR\ +.iX "v filter" +Tells mtools to use the geometry for this drive both for mformatting and +filtering. +.TP +\&\fR\&\f(CWremote\fR\ +Tells mtools to connect to floppyd (see section floppyd). +.PP +.SS \ \ Supplying\ multiple\ descriptions\ for\ a\ drive +.PP +It is possible to supply multiple descriptions for a drive. In that +case, the descriptions are tried in order until one is found that +fits. Descriptions may fail for several reasons: +.TP +1.\ +because the geometry is not appropriate, +.TP +2.\ +because there is no disk in the drive, +.TP +3.\ +or because of other problems. +.PP +Multiple definitions are useful when using physical devices which are +only able to support one single disk geometry. +Example: + +.nf +.ft 3 +.in +0.3i + drive a: file="/dev/fd0H1440" 1.44m + drive a: file="/dev/fd0H720" 720k +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +This instructs mtools to use /dev/fd0H1440 for 1.44m (high density) +disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this +feature is not really needed, as the /dev/fd0 device is able to handle +any geometry. +.PP +You may also use multiple drive descriptions to access both of your +physical drives through one drive letter: +.PP + +.nf +.ft 3 +.in +0.3i + drive z: file="/dev/fd0" + drive z: file="/dev/fd1" +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +With this description, \fR\&\f(CWmdir z:\fR accesses your first physical +drive if it contains a disk. If the first drive doesn't contain a disk, +mtools checks the second drive. +.PP +When using multiple configuration files, drive descriptions in the files +parsed last override descriptions for the same drive in earlier +files. In order to avoid this, use the \fR\&\f(CWdrive+\fR or \fR\&\f(CW+drive\fR +keywords instead of \fR\&\f(CWdrive\fR. The first adds a description to the +end of the list (i.e. it will be tried last), and the first adds it to +the start of the list. +.PP +.SS Location\ of\ configuration\ files\ and\ parsing\ order +.iX "c Parsing order" +.iX "c Configuration file parsing order" +.iX "c Configuration file name (parsing order)" +.iX "c Name of configuration files (parsing order)" +.iX "c Location of configuration files (parsing order)" +.PP +The configuration files are parsed in the following order: +.TP +1.\ +compiled-in defaults +.TP +2.\ +\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR +.TP +3.\ +\&\fR\&\f(CW\(if/etc/mtools\(is\fR +This is for backwards compatibility only, and is only parsed if +\&\fR\&\f(CW\(ifmtools.conf\(is\fR +doesn't exist. +.TP +4.\ +\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR. +.TP +5.\ +\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR (file pointed by the \fR\&\f(CWMTOOLSRC\fR environmental +variable) +.PP +Options described in the later files override those described in the +earlier files. Drives defined in earlier files persist if they are not +overridden in the later files. For instance, drives A and B may be +defined in \fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR and drives C and D may be +defined in \fR\&\f(CW\(if~/.mtoolsrc\(is\fR However, if \fR\&\f(CW\(if~/.mtoolsrc\(is\fR also +defines drive A, this new description would override the description of +drive A in \fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR instead of adding to it. If +you want to add a new description to a drive already described in an +earlier file, you need to use either the \fR\&\f(CW+drive\fR or \fR\&\f(CWdrive+\fR +keyword. +.PP +.SS Backwards\ compatibility\ with\ old\ configuration\ file\ syntax +.iX "c Backwards compatibility" +.iX "c Old configuration file syntax" +.iX "c Configuration file, old syntax" +.PP +The syntax described herein is new for version \fR\&\f(CWmtools-3.0\fR. The +old line-oriented syntax is still supported. Each line beginning with a +single letter is considered to be a drive description using the old +syntax. Old style and new style drive sections may be mixed within the +same configuration file, in order to make upgrading easier. Support for +the old syntax will be phased out eventually, and in order to discourage +its use, I purposefully omit its description here. +.PP +.SH See also +mtools diff --git a/mtools.c b/mtools.c new file mode 100644 index 0000000..4d148b6 --- /dev/null +++ b/mtools.c @@ -0,0 +1,200 @@ +/* Copyright 1996-2004,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "partition.h" +#include "vfat.h" + +const char *progname; + +static const struct dispatch { + const char *cmd; + void (*fn)(int, char **, int); + int type; +} dispatch[] = { + {"mattrib",mattrib, 0}, + {"mbadblocks",mbadblocks, 0}, + {"mcat",mcat, 0}, + {"mcd",mcd, 0}, + {"mclasserase",mclasserase, 0}, + {"mcopy",mcopy, 0}, + {"mdel",mdel, 0}, + {"mdeltree",mdel, 2}, + {"mdir",mdir, 0}, + {"mdoctorfat",mdoctorfat, 0}, + {"mdu",mdu, 0}, + {"mformat",mformat, 0}, + {"minfo", minfo, 0}, + {"mlabel",mlabel, 0}, + {"mmd",mmd, 0}, + {"mmount",mmount, 0}, + {"mpartition",mpartition, 0}, + {"mrd",mdel, 1}, + {"mread",mcopy, 0}, + {"mmove",mmove, 0}, + {"mren",mmove, 1}, + {"mshowfat", mshowfat, 0}, + {"mtoolstest", mtoolstest, 0}, + {"mtype",mcopy, 1}, + {"mwrite",mcopy, 0}, + {"mzip", mzip, 0} +}; +#define NDISPATCH (sizeof dispatch / sizeof dispatch[0]) + +int main(int argc,char **argv) +{ + unsigned int i; + const char *name; + +#ifdef HAVE_SETLOCALE + char *locale; + locale=setlocale(LC_ALL, ""); + if(locale == NULL || !strcmp(locale, "C")) + setlocale(LC_ALL, "en_US"); +#endif + + init_privs(); +#ifdef __EMX__ + _wildcard(&argc,&argv); +#endif + +/*#define PRIV_TEST*/ + +#ifdef PRIV_TEST + { + int euid; + char command[100]; + + printf("INIT: %d %d\n", getuid(), geteuid()); + drop_privs(); + printf("DROP: %d %d\n", getuid(), geteuid()); + reclaim_privs(); + printf("RECLAIM: %d %d\n", getuid(), geteuid()); + euid = geteuid(); + if(argc & 1) { + drop_privs(); + printf("DROP: %d %d\n", getuid(), geteuid()); + } + if(!((argc-1) & 2)) { + destroy_privs(); + printf("DESTROY: %d %d\n", getuid(), geteuid()); + } + sprintf(command, "a.out %d", euid); + system(command); + return 1; + } +#endif + + +#ifdef __EMX__ + _wildcard(&argc,&argv); +#endif + + + /* check whether the compiler lays out structures in a sane way */ + if(sizeof(struct partition) != 16 || + sizeof(struct directory) != 32 || + sizeof(struct vfat_subentry) !=32) { + fprintf(stderr,"Mtools has not been correctly compiled\n"); + fprintf(stderr,"Recompile it using a more recent compiler\n"); + return 137; + } + +#ifdef __EMX__ + argv[0] = _getname(argv[0]); _remext(argv[0]); name = argv[0]; +#else +#ifdef OS_mingw32msvc + _stripexe(argv[0]); +#endif + name = _basename(argv[0]); +#endif + progname = argv[0]; + + /* this allows the different tools to be called as "mtools -c " + ** where is mdir, mdel, mcopy etcetera + ** Mainly done for the BeOS, which doesn't support links yet. + */ + + if(argc >= 3 && + !strcmp(argv[1], "-c") && + !strcmp(name, "mtools")) { + argc-=2; + argv+=2; + name = argv[0]; + } + + + + /* print the version */ + if(argc >= 2 && + (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") ==0)) { + printf("%s (GNU mtools) %s\n", + name, mversion); + printf("configured with the following options: "); +#ifdef USE_XDF + printf("enable-xdf "); +#else + printf("disable-xdf "); +#endif +#ifdef USING_VOLD + printf("enable-vold "); +#else + printf("disable-vold "); +#endif +#ifdef USING_NEW_VOLD + printf("enable-new-vold "); +#else + printf("disable-new-vold "); +#endif +#ifdef DEBUG + printf("enable-debug "); +#else + printf("disable-debug "); +#endif +#ifdef USE_RAWTERM + printf("enable-raw-term "); +#else + printf("disable-raw-term "); +#endif + printf("\n"); + return 0; + } + + read_config(); + setup_signal(); + for (i = 0; i < NDISPATCH; i++) { + if (!strcmp(name,dispatch[i].cmd)) + dispatch[i].fn(argc, argv, dispatch[i].type); + } + if (strcmp(name,"mtools")) + fprintf(stderr,"Unknown mtools command '%s'\n",name); + fprintf(stderr,"Supported commands:"); + for (i = 0; i < NDISPATCH; i++) { + if (i%8 == 0) putc('\n', stderr); + else fprintf(stderr, ", "); + fprintf(stderr, "%s", dispatch[i].cmd); + } + putc('\n', stderr); + + return 1; +} + +int helpFlag(int argc, char **argv) { + return (argc > 1 && !strcmp(argv[1], "--help")); +} diff --git a/mtools.conf b/mtools.conf new file mode 100644 index 0000000..dc186df --- /dev/null +++ b/mtools.conf @@ -0,0 +1,80 @@ +# Copyright 1996-1998,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +# Example mtools.conf files. Uncomment the lines which correspond to +# your architecture and comment out the "SAMPLE FILE" line below +SAMPLE FILE + +# # Linux floppy drives +# drive a: file="/dev/fd0" exclusive +# drive b: file="/dev/fd1" exclusive + +# # First SCSI hard disk partition +# drive c: file="/dev/sda1" + +# # First IDE hard disk partition +# drive c: file="/dev/hda1" + +# # dosemu floppy image +# drive m: file="/var/lib/dosemu/diskimage" + +# # dosemu hdimage +# drive n: file="/var/lib/dosemu/diskimage" offset=3840 + +# # Atari ramdisk image +# drive o: file="/tmp/atari_rd" offset=136 + +# # ZIP disk for Solaris: +# Drive X is ZIP-100 at target 5 +# drive X: file="/dev/rdsk/c0t5d0s2" partition=4 scsi=1 nodelay + +# # ZIP disk for SunOS: +# # Zip drive is at target 5, which default kernel calls tape st1 !! +# drive Y: file="/dev/rsd5c" partition=4 scsi=1 nodelay + +# # autoselect zip drive/floppy on HP-UX 9/10 +# drive a: file="/dev/rdsk/c201d5" exclusive partition=4 +# drive a: file="/dev/rdsk/c201d5s0" exclusive partition=4 +# drive a: file="/dev/rfloppy/c201d0s0" exclusive + +# A/UX target 5 on 1st scsi bus jaz or zip +# drive X: file="/dev/rdsk/c105d0s31" partition=4 + + +# Some examples for BeOS. +# floppy drive. hardcoded in devices.c, so no real need to define it here +#drive a: file="/dev/floppy_disk" exclusive +# ZIP drive on SCSI ID 6 +#drive z: file="/dev/scsi_disk_060" offset=16384 fat_bits=16 + +# SCO Unix 3.2v4 +# # Floppy disk drives +# +# drive a: file="/dev/install" exclusive +# drive b: file="/dev/install1" exclusive +# +# # SCSI hard disk partitions +# +# drive c: file="/dev/dsk/0sC" +# drive d: file="/dev/dsk/0sD" +# drive e: file="/dev/dsk/0sE" +# drive f: file="/dev/dsk/0sF" +# drive g: file="/dev/dsk/0sG" +# drive h: file="/dev/dsk/0sH" + +# # uncomment the following line to display all file names in lower +# # case by default +# mtools_lower_case=1 diff --git a/mtools.h b/mtools.h new file mode 100644 index 0000000..0d4fa6f --- /dev/null +++ b/mtools.h @@ -0,0 +1,275 @@ +#ifndef MTOOLS_MTOOLS_H +#define MTOOLS_MTOOLS_H +/* Copyright 1996-2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "msdos.h" + +typedef struct dos_name_t dos_name_t; + +#if defined(OS_sco3) +#define MAXPATHLEN 1024 +#include +extern int lockf(int, int, off_t); /* SCO has no proper include file for lockf */ +#endif + +#define SCSI_FLAG 1 +#define PRIV_FLAG 2 +#define NOLOCK_FLAG 4 +#define USE_XDF_FLAG 8 +#define MFORMAT_ONLY_FLAG 16 +#define VOLD_FLAG 32 +#define FLOPPYD_FLAG 64 +#define FILTER_FLAG 128 +#define SWAP_FLAG 256 + +#define IS_SCSI(x) ((x) && ((x)->misc_flags & SCSI_FLAG)) +#define IS_PRIVILEGED(x) ((x) && ((x)->misc_flags & PRIV_FLAG)) +#define IS_NOLOCK(x) ((x) && ((x)->misc_flags & NOLOCK_FLAG)) +#define IS_MFORMAT_ONLY(x) ((x) && ((x)->misc_flags & MFORMAT_ONLY_FLAG)) +#define SHOULD_USE_VOLD(x) ((x)&& ((x)->misc_flags & VOLD_FLAG)) +#define SHOULD_USE_XDF(x) ((x)&& ((x)->misc_flags & USE_XDF_FLAG)) +#define DO_SWAP(x) ((x) && ((x)->misc_flags & SWAP_FLAG)) + +typedef struct device { + const char *name; /* full path to device */ + + char drive; /* the drive letter */ + int fat_bits; /* FAT encoding scheme */ + + unsigned int mode; /* any special open() flags */ + unsigned int tracks; /* tracks */ + unsigned int heads; /* heads */ + unsigned int sectors; /* sectors */ + unsigned int hidden; /* number of hidden sectors. Used for + * mformatting partitioned devices */ + + off_t offset; /* skip this many bytes */ + + unsigned int partition; + + unsigned int misc_flags; + + /* Linux only stuff */ + unsigned int ssize; + unsigned int use_2m; + + char *precmd; /* command to be executed before opening + * the drive */ + + /* internal variables */ + int file_nr; /* used during parsing */ + unsigned int blocksize; /* size of disk block in bytes */ + + int codepage; /* codepage for shortname encoding */ + + const char *cfg_filename; /* used for debugging purposes */ +} device_t; + + +#ifndef OS_linux +#define BOOTSIZE 512 +#else +#define BOOTSIZE 256 +#endif + +typedef struct doscp_t doscp_t; + +#include "stream.h" + + +extern const char *short_illegals, *long_illegals; + +#define maximize(target, max) do { \ + if(max < 0) { \ + if(target > 0) \ + target = 0; \ + } else if(target > max) { \ + target = max; \ + } \ +} while(0) + +#define minimize(target, min) do { \ + if(target < min) \ + target = min; \ +} while(0) + +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf); + +int readwrite_sectors(int fd, /* file descriptor */ + int *drive, + int rate, + int seektrack, + int track, int head, int sector, int size, /* address */ + char *data, + int bytes, + int direction, + int retries); + +int lock_dev(int fd, int mode, struct device *dev); + +char *unix_normalize (doscp_t *cp, char *ans, struct dos_name_t *dn); +void dos_name(doscp_t *cp, const char *filename, int verbose, int *mangled, + struct dos_name_t *); +struct directory *mk_entry(const dos_name_t *filename, char attr, + unsigned int fat, size_t size, time_t date, + struct directory *ndir); + +struct directory *mk_entry_from_base(const char *base, char attr, + unsigned int fat, size_t size, time_t date, + struct directory *ndir); + +int copyfile(Stream_t *Source, Stream_t *Target); +int getfreeMinClusters(Stream_t *Stream, size_t ref); + +FILE *opentty(int mode); + +int is_dir(Stream_t *Dir, char *path); +void bufferize(Stream_t **Dir); + +int dir_grow(Stream_t *Dir, int size); +int match(const wchar_t *, const wchar_t *, wchar_t *, int, int); + +wchar_t *unix_name(doscp_t *fromDos, + const char *base, const char *ext, char Case, + wchar_t *answer); +void *safe_malloc(size_t size); +Stream_t *open_filter(Stream_t *Next,int convertCharset); + +extern int got_signal; +/* int do_gotsignal(char *, int); +#define got_signal do_gotsignal(__FILE__, __LINE__) */ + +void setup_signal(void); + + +#define SET_INT(target, source) \ +if(source)target=source + + +UNUSED(static __inline__ int compare (long ref, long testee)) +{ + return (ref && ref != testee); +} + +Stream_t *GetFs(Stream_t *Fs); + +void label_name(doscp_t *cp, const char *filename, int verbose, + int *mangled, dos_name_t *ans); + +/* environmental variables */ +extern unsigned int mtools_skip_check; +extern unsigned int mtools_fat_compatibility; +extern unsigned int mtools_ignore_short_case; +extern unsigned int mtools_no_vfat; +extern unsigned int mtools_numeric_tail; +extern unsigned int mtools_dotted_dir; +extern unsigned int mtools_twenty_four_hour_clock; +extern const char *mtools_date_string; +extern unsigned int mtools_rate_0, mtools_rate_any; +extern unsigned int mtools_default_codepage; +extern int mtools_raw_tty; + +extern int batchmode; + +char get_default_drive(void); +void set_cmd_line_image(char *img, int flags); +void read_config(void); +extern struct device *devices; +extern struct device const_devices[]; +extern const int nr_const_devices; + +#define New(type) ((type*)(calloc(1,sizeof(type)))) +#define Grow(adr,n,type) ((type*)(realloc((char *)adr,n*sizeof(type)))) +#define Free(adr) (free((char *)adr)); +#define NewArray(size,type) ((type*)(calloc((size),sizeof(type)))) + +void mattrib(int argc, char **argv, int type); +void mbadblocks(int argc, char **argv, int type); +void mcat(int argc, char **argv, int type); +void mcd(int argc, char **argv, int type); +void mclasserase(int argc, char **argv, int type); +void mcopy(int argc, char **argv, int type); +void mdel(int argc, char **argv, int type); +void mdir(int argc, char **argv, int type); +void mdoctorfat(int argc, char **argv, int type); +void mdu(int argc, char **argv, int type); +void mformat(int argc, char **argv, int type); +void minfo(int argc, char **argv, int type); +void mlabel(int argc, char **argv, int type); +void mmd(int argc, char **argv, int type); +void mmount(int argc, char **argv, int type); +void mmove(int argc, char **argv, int type); +void mpartition(int argc, char **argv, int type); +void mshowfat(int argc, char **argv, int mtype); +void mtoolstest(int argc, char **argv, int type); +void mzip(int argc, char **argv, int type); + +extern int noPrivileges; +void init_privs(void); +void reclaim_privs(void); +void drop_privs(void); +void destroy_privs(void); +uid_t get_real_uid(void); +void closeExec(int fd); + +extern const char *progname; + +void precmd(struct device *dev); + +void print_sector(const char *message, unsigned char *data, int size); +time_t getTimeNow(time_t *now); + +#ifdef USING_NEW_VOLD +char *getVoldName(struct device *dev, char *name); +#endif + + +Stream_t *OpenDir(Stream_t *Parent, const char *filename); +/* int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); +int unix_loop(MainParam_t *mp, char *arg); */ + +struct dirCache_t **getDirCacheP(Stream_t *Stream); +int isRootDir(Stream_t *Stream); +unsigned int getStart(Stream_t *Dir, struct directory *dir); +unsigned int countBlocks(Stream_t *Dir, unsigned int block); +char getDrive(Stream_t *Stream); + + +void printOom(void); +int ask_confirmation(const char *, ...) __attribute__ ((format (printf, 1, 2))); + +int helpFlag(int, char **); + +char *get_homedir(void); +#define EXPAND_BUF 2048 +const char *expand(const char *, char *); +FILE *open_mcwd(const char *mode); +void unlink_mcwd(void); + +#ifndef OS_mingw32msvc +int safePopenOut(const char **command, char *output, int len); +#endif + +#define ROUND_DOWN(value, grain) ((value) - (value) % (grain)) +#define ROUND_UP(value, grain) ROUND_DOWN((value) + (grain)-1, (grain)) + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#endif diff --git a/mtools.info b/mtools.info new file mode 100644 index 0000000..efdd3bd --- /dev/null +++ b/mtools.info @@ -0,0 +1,2736 @@ +This is mtools.info, produced by makeinfo version 4.11 from mtools.texi. + +This manual is for Mtools (version 4.0.12, November 2009), which is a +collection of tools to allow Unix systems to manipulate MS-DOS files. + + Copyright (C) 2007, 2009 Free Software Foundation, Inc. Copyright +(C) 1996-2005,2007-2009 Alain Knaff. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with no Invariant Sections, with no Front-Cover Texts, + and with no Back-Cover Texts. A copy of the license is included + in the section entitled "GNU Free Documentation License". + +INFO-DIR-SECTION DOS +START-INFO-DIR-ENTRY +* Mtools: (mtools). Mtools: utilities to access DOS disks in Unix. +END-INFO-DIR-ENTRY + + +File: mtools.info, Node: Top, Next: Location, Prev: (dir), Up: (dir) + +Mtools doc +********** + +This is mtools' documentation. + +Introduction +************ + +Mtools is a collection of tools to allow Unix systems to manipulate +MS-DOS files: read, write, and move around files on an MS-DOS +filesystem (typically a floppy disk). Where reasonable, each program +attempts to emulate the MS-DOS equivalent command. However, unnecessary +restrictions and oddities of DOS are not emulated. For instance, it is +possible to move subdirectories from one subdirectory to another. + + Mtools is sufficient to give access to MS-DOS filesystems. For +instance, commands such as `mdir a:' work on the `a:' floppy without +any preliminary mounting or initialization (assuming the default +`/etc/mtools.conf' works on your machine). With mtools, one can change +floppies too without unmounting and mounting. + + This manual is for Mtools (version 4.0.12, November 2009), which is +a collection of tools to allow Unix systems to manipulate MS-DOS files. + + Copyright (C) 2007, 2009 Free Software Foundation, Inc. Copyright +(C) 1996-2005,2007-2009 Alain Knaff. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with no Invariant Sections, with no Front-Cover Texts, + and with no Back-Cover Texts. A copy of the license is included + in the section entitled "GNU Free Documentation License". + +* Menu: + +* Location:: Where to find mtools and early bug fixes +* Common features:: Common features of all mtools commands +* Configuration:: How to configure mtools for your environment +* Commands:: The available mtools commands +* Compiling mtools:: Architecture specific compilation flags +* Porting mtools:: Porting mtools to architectures which are not + yet supported + +* Command Index:: Command Index +* Variable Index:: Variable Index +* Concept Index:: Concept Index + + +File: mtools.info, Node: Location, Next: Common features, Prev: Top, Up: Top + +1 Where to get mtools +********************* + +Mtools can be found at the following places (and their mirrors): + http://ftp.gnu.org/gnu/mtools/mtools-4.0.12.tar.gz + http://mtools.linux.lu/mtools-4.0.12.tar.gz + ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.12.tar.gz + ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.12.tar.gz + + Before reporting a bug, make sure that it has not yet been fixed in +the Alpha patches which can be found at: + http://ftp.gnu.org/gnu/mtools/ + http://mtools.linux.lu/ + ftp://www.tux.org/pub/knaff/mtools + + These patches are named `mtools-'VERSION`-'DDMM`.taz', where version +stands for the base version, DD for the day and MM for the month. Due +to a lack of space, I usually leave only the most recent patch. + + There is an mtools mailing list at mtools @ tux.org . Please send +all bug reports to this list. You may subscribe to the list by sending +a message with 'subscribe mtools @ tux.org' in its body to majordomo @ +tux.org . (N.B. Please remove the spaces around the "@" both times. I +left them there in order to fool spambots.) Announcements of new +mtools versions will also be sent to the list, in addition to the linux +announce newsgroups. The mailing list is archived at +http://lists.gnu.org/pipermail/info-mtools/ + + +File: mtools.info, Node: Common features, Next: Configuration, Prev: Location, Up: Top + +2 Common features of all mtools commands +**************************************** + +* Menu: + +* arguments:: What the command line parameters of mtools + mean +* drive letters:: Which drives are defined by default +* directory:: Current working directory +* long names:: VFAT-style long filenames +* name clashes:: Name clash handling, and associated command + line options +* case sensitivity:: Case sensitivity +* high capacity formats:: How to fit more data on your floppies +* exit codes:: Exit codes +* bugs:: Happens to everybody + + +File: mtools.info, Node: arguments, Next: drive letters, Prev: Common features, Up: Common features + +2.1 Options and filenames +========================= + +MS-DOS filenames are composed of a drive letter followed by a colon, a +subdirectory, and a filename. Only the filename part is mandatory, the +drive letter and the subdirectory are optional. Filenames without a +drive letter refer to Unix files. Subdirectory names can use either the +'`/'' or '`\'' separator. The use of the '`\'' separator or wildcards +requires the names to be enclosed in quotes to protect them from the +shell. However, wildcards in Unix filenames should not be enclosed in +quotes, because here we *want* the shell to expand them. + + The regular expression "pattern matching" routines follow the +Unix-style rules. For example, ``*'' matches all MS-DOS files in lieu +of ``*.*''. The archive, hidden, read-only and system attribute bits +are ignored during pattern matching. + + All options use the `-' (minus) as their first character, not `/' as +you'd expect in MS-DOS. + + Most mtools commands allow multiple filename parameters, which +doesn't follow MS-DOS conventions, but which is more user-friendly. + + Most mtools commands allow options that instruct them how to handle +file name clashes. *Note name clashes::, for more details on these. All +commands accept the `-V' flags which prints the version, and most +accept the `-v' flag, which switches on verbose mode. In verbose mode, +these commands print out the name of the MS-DOS files upon which they +act, unless stated otherwise. *Note Commands::, for a description of +the options which are specific to each command. + + +File: mtools.info, Node: drive letters, Next: directory, Prev: arguments, Up: Common features + +2.2 Drive letters +================= + +The meaning of the drive letters depends on the target architectures. +However, on most target architectures, drive A is the first floppy +drive, drive B is the second floppy drive (if available), drive J is a +Jaz drive (if available), and drive Z is a Zip drive (if available). On +those systems where the device name is derived from the SCSI id, the Jaz +drive is assumed to be at Scsi target 4, and the Zip at Scsi target 5 +(factory default settings). On Linux, both drives are assumed to be the +second drive on the Scsi bus (/dev/sdb). The default settings can be +changes using a configuration file (*note Configuration::). + + The drive letter : (colon) has a special meaning. It is used to +access image files which are directly specified on the command line +using the `-i' options. + + Example: + mcopy -i my-image-file.bin ::file1 ::file2 . + + This copies `file1' and `file2' from the image file +(`my-image-file.bin') to the `/tmp' directory. + + You can also supply an offset within the image file by including +`@@'OFFSET into the file name. + + Example: + mcopy -i my-image-file.bin@@1M ::file1 ::file2 . + + This looks for the image at the offset of 1M in the file, rather than +at its beginning. + + +File: mtools.info, Node: directory, Next: long names, Prev: drive letters, Up: Common features + +2.3 Current working directory +============================= + +The `mcd' command (*note mcd::) is used to establish the device and the +current working directory (relative to the MS-DOS filesystem), +otherwise the default is assumed to be `A:/'. However, unlike MS-DOS, +there is only one working directory for all drives, and not one per +drive. + + +File: mtools.info, Node: long names, Next: name clashes, Prev: directory, Up: Common features + +2.4 VFAT-style long file names +============================== + +This version of mtools supports VFAT style long filenames. If a Unix +filename is too long to fit in a short DOS name, it is stored as a VFAT +long name, and a companion short name is generated. This short name is +what you see when you examine the disk with a pre-7.0 version of DOS. +The following table shows some examples of short names: + + Long name MS-DOS name Reason for the change + --------- ---------- --------------------- + thisisatest THISIS~1 filename too long + alain.knaff ALAIN~1.KNA extension too long + prn.txt PRN~1.TXT PRN is a device name + .abc ABC~1 null filename + hot+cold HOT_CO~1 illegal character + + As you see, the following transformations happen to derive a short +name: + * Illegal characters are replaced by underscores. The illegal + characters are `;+=[]',\"*\\<>/?:|'. + + * Extra dots, which cannot be interpreted as a main name/extension + separator are removed + + * A `~'N number is generated, + + * The name is shortened so as to fit in the 8+3 limitation + + The initial Unix-style file name (whether long or short) is also +called the "primary" name, and the derived short name is also called the +"secondary" name. + + Example: + mcopy /etc/motd a:Reallylongname + Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as +a short name. Reallylongname is the primary name, and REALLYLO is the +secondary name. + mcopy /etc/motd a:motd + Motd fits into the DOS filename limits. Mtools doesn't need to +derivate another name. Motd is the primary name, and there is no +secondary name. + + In a nutshell: The primary name is the long name, if one exists, or +the short name if there is no long name. + + Although VFAT is much more flexible than FAT, there are still names +that are not acceptable, even in VFAT. There are still some illegal +characters left (`\"*\\<>/?:|'), and device names are still reserved. + + Unix name Long name Reason for the change + --------- ---------- --------------------- + prn prn-1 PRN is a device name + ab:c ab_c-1 illegal character + + As you see, the following transformations happen if a long name is +illegal: + * Illegal characters are replaces by underscores, + + * A `-'N number is generated, + + +File: mtools.info, Node: name clashes, Next: case sensitivity, Prev: long names, Up: Common features + +2.5 Name clashes +================ + +When writing a file to disk, its long name or short name may collide +with an already existing file or directory. This may happen for all +commands which create new directory entries, such as `mcopy', `mmd', +`mren', `mmove'. When a name clash happens, mtools asks you what it +should do. It offers several choices: + +`overwrite' + Overwrites the existing file. It is not possible to overwrite a + directory with a file. + +`rename' + Renames the newly created file. Mtools prompts for the new filename + +`autorename' + Renames the newly created file. Mtools chooses a name by itself, + without prompting + +`skip' + Gives up on this file, and moves on to the next (if any) + + To chose one of these actions, type its first letter at the prompt. +If you use a lower case letter, the action only applies for this file +only, if you use an upper case letter, the action applies to all files, +and you won't be prompted again. + + You may also chose actions (for all files) on the command line, when +invoking mtools: + +`-D o' + Overwrites primary names by default. + +`-D O' + Overwrites secondary names by default. + +`-D r' + Renames primary name by default. + +`-D R' + Renames secondary name by default. + +`-D a' + Autorenames primary name by default. + +`-D A' + Autorenames secondary name by default. + +`-D s' + Skip primary name by default. + +`-D S' + Skip secondary name by default. + +`-D m' + Ask user what to do with primary name. + +`-D M' + Ask user what to do with secondary name. + + Note that for command line switches lower/upper differentiates +between primary/secondary name whereas for interactive choices, +lower/upper differentiates between just-this-time/always. + + The primary name is the name as displayed in Windows 95 or Windows +NT: i.e. the long name if it exists, and the short name otherwise. The +secondary name is the "hidden" name, i.e. the short name if a long name +exists. + + By default, the user is prompted if the primary name clashes, and the +secondary name is autorenamed. + + If a name clash occurs in a Unix directory, mtools only asks whether +to overwrite the file, or to skip it. + + +File: mtools.info, Node: case sensitivity, Next: high capacity formats, Prev: name clashes, Up: Common features + +2.6 Case sensitivity of the VFAT filesystem +=========================================== + +The VFAT filesystem is able to remember the case of the filenames. +However, filenames which differ only in case are not allowed to coexist +in the same directory. For example if you store a file called +LongFileName on a VFAT filesystem, mdir shows this file as LongFileName, +and not as Longfilename. However, if you then try to add LongFilename to +the same directory, it is refused, because case is ignored for clash +checks. + + The VFAT filesystem allows to store the case of a filename in the +attribute byte, if all letters of the filename are the same case, and if +all letters of the extension are the same case too. Mtools uses this +information when displaying the files, and also to generate the Unix +filename when mcopying to a Unix directory. This may have unexpected +results when applied to files written using an pre-7.0 version of DOS: +Indeed, the old style filenames map to all upper case. This is different +from the behavior of the old version of mtools which used to generate +lower case Unix filenames. + + +File: mtools.info, Node: high capacity formats, Next: exit codes, Prev: case sensitivity, Up: Common features + +2.7 high capacity formats +========================= + +Mtools supports a number of formats which allow to store more data on +disk as usual. Due to different operating system abilities, these +formats are not supported on all OS'es. Mtools recognizes these formats +transparently where supported. + + In order to format these disks, you need to use an operating system +specific tool. For Linux, suitable floppy tools can be found in the +`fdutils' package at the following locations~: + `ftp://www.tux.org/pub/knaff/fdutils/'. + `ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-*' + + See the manpages included in that package for further detail: Use +`superformat' to format all formats except XDF, and use `xdfcopy' to +format XDF. + +* Menu: + +* more sectors:: Putting more sectors per track on the disk +* bigger sectors:: Use bigger sectors to save header space +* 2m:: Use a standard first track +* XDF:: OS/2's eXtended density format + + +File: mtools.info, Node: more sectors, Next: bigger sectors, Prev: high capacity formats, Up: high capacity formats + +2.7.1 More sectors +------------------ + +The oldest method of fitting more data on a disk is to use more sectors +and more cylinders. Although the standard format uses 80 cylinders and +18 sectors (on a 3 1/2 high density disk), it is possible to use up to +83 cylinders (on most drives) and up to 21 sectors. This method allows +to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are +twice as slow as the standard 18 sector disks because the sectors are +packed so close together that we need to interleave them. This problem +doesn't exist for 20 sector formats. + + These formats are supported by numerous DOS shareware utilities such +as `fdformat' and `vgacopy'. In his infinite hybris, Bill Gate$ +believed that he invented this, and called it `DMF disks', or `Windows +formatted disks'. But in reality, it has already existed years before! +Mtools supports these formats on Linux, on SunOs and on the DELL Unix +PC. + + +File: mtools.info, Node: bigger sectors, Next: 2m, Prev: more sectors, Up: high capacity formats + +2.7.2 Bigger sectors +-------------------- + +By using bigger sectors it is possible to go beyond the capacity which +can be obtained by the standard 512-byte sectors. This is because of the +sector header. The sector header has the same size, regardless of how +many data bytes are in the sector. Thus, we save some space by using +_fewer_, but bigger sectors. For example, 1 sector of 4K only takes up +header space once, whereas 8 sectors of 512 bytes have also 8 headers, +for the same amount of useful data. + + This method allows to store up to 1992K on a 3 1/2 HD disk. + + Mtools supports these formats only on Linux. + + +File: mtools.info, Node: 2m, Next: XDF, Prev: bigger sectors, Up: high capacity formats + +2.7.3 2m +-------- + +The 2m format was originally invented by Ciriaco Garcia de Celis. It +also uses bigger sectors than usual in order to fit more data on the +disk. However, it uses the standard format (18 sectors of 512 bytes +each) on the first cylinder, in order to make these disks easyer to +handle by DOS. Indeed this method allows to have a standard sized +bootsector, which contains a description of how the rest of the disk +should be read. + + However, the drawback of this is that the first cylinder can hold +less data than the others. Unfortunately, DOS can only handle disks +where each track contains the same amount of data. Thus 2m hides the +fact that the first track contains less data by using a "shadow FAT". +(Usually, DOS stores the FAT in two identical copies, for additional +safety. XDF stores only one copy, and it tells DOS that it stores two. +Thus the same that would be taken up by the second FAT copy is saved.) +This also means that your should *never use a 2m disk to store anything +else than a DOS fs*. + + Mtools supports these format only on Linux. + + +File: mtools.info, Node: XDF, Prev: 2m, Up: high capacity formats + +2.7.4 XDF +--------- + +XDF is a high capacity format used by OS/2. It can hold 1840 K per +disk. That's lower than the best 2m formats, but its main advantage is +that it is fast: 600 milliseconds per track. That's faster than the 21 +sector format, and almost as fast as the standard 18 sector format. In +order to access these disks, make sure mtools has been compiled with XDF +support, and set the `use_xdf' variable for the drive in the +configuration file. *Note Compiling mtools::, and *note misc +variables::, for details on how to do this. Fast XDF access is only +available for Linux kernels which are more recent than 1.1.34. + + Mtools supports this format only on Linux. + + *Caution / Attention distributors*: If mtools is compiled on a Linux +kernel more recent than 1.3.34, it won't run on an older kernel. +However, if it has been compiled on an older kernel, it still runs on a +newer kernel, except that XDF access is slower. It is recommended that +distribution authors only include mtools binaries compiled on kernels +older than 1.3.34 until 2.0 comes out. When 2.0 will be out, mtools +binaries compiled on newer kernels may (and should) be distributed. +Mtools binaries compiled on kernels older than 1.3.34 won't run on any +2.1 kernel or later. + + +File: mtools.info, Node: exit codes, Next: bugs, Prev: high capacity formats, Up: Common features + +2.8 Exit codes +============== + +All the Mtools commands return 0 on success, 1 on utter failure, or 2 +on partial failure. All the Mtools commands perform a few sanity +checks before going ahead, to make sure that the disk is indeed an +MS-DOS disk (as opposed to, say an ext2 or minix disk). These checks +may reject partially corrupted disks, which might otherwise still be +readable. To avoid these checks, set the MTOOLS_SKIP_CHECK +environmental variable or the corresponding configuration file variable +(*note global variables::) + + +File: mtools.info, Node: bugs, Prev: exit codes, Up: Common features + +2.9 Bugs +======== + +An unfortunate side effect of not guessing the proper device (when +multiple disk capacities are supported) is an occasional error message +from the device driver. These can be safely ignored. + + The fat checking code chokes on 1.72 Mb disks mformatted with +pre-2.0.7 mtools. Set the environmental variable +MTOOLS_FAT_COMPATIBILITY (or the corresponding configuration file +variable, *note global variables::) to bypass the fat checking. + + +File: mtools.info, Node: Configuration, Next: Commands, Prev: Common features, Up: Top + +3 How to configure mtools for your environment +********************************************** + +3.1 Description +=============== + +This sections explains the syntax of the configurations files for +mtools. The configuration files are called `/usr/local/etc/mtools.conf' +and `~/.mtoolsrc'. If the environmental variable `MTOOLSRC' is set, its +contents is used as the filename for a third configuration file. These +configuration files describe the following items: + + * Global configuration flags and variables + + * Per drive flags and variables + +* Menu: + +* config file location:: Where mtools looks for its configuration files +* general syntax:: The layout of the configuration files +* default values:: Why you don't need a config file in most cases +* global variables:: Variables that are independent of the drive +* per drive variables:: Variables that are specific to a given drive +* parsing order:: Location of configuration files and parsing order +* old style config:: Backwards compatibility + + +File: mtools.info, Node: config file location, Next: general syntax, Prev: Configuration, Up: Configuration + +3.2 Location of the configuration files +======================================= + +`/usr/local/etc/mtools.conf' is the system-wide configuration file, and +`~/.mtoolsrc' is the user's private configuration file. + + On some systems, the system-wide configuration file is called +`/etc/default/mtools.conf' instead. + + +File: mtools.info, Node: general syntax, Next: default values, Prev: config file location, Up: Configuration + +3.2.1 General configuration file syntax +--------------------------------------- + +The configuration files is made up of sections. Each section starts +with a keyword identifying the section followed by a colon. Then +follow variable assignments and flags. Variable assignments take the +following form: + name=value + Flags are lone keywords without an equal sign and value following +them. A section either ends at the end of the file or where the next +section begins. + + Lines starting with a hash (`#') are comments. Newline characters +are equivalent to whitespace (except where ending a comment). The +configuration file is case insensitive, except for item enclosed in +quotes (such as filenames). + + +File: mtools.info, Node: default values, Next: global variables, Prev: general syntax, Up: Configuration + +3.3 Default values +================== + +For most platforms, mtools contains reasonable compiled-in defaults for +physical floppy drives. Thus, you usually don't need to bother with the +configuration file, if all you want to do with mtools is to access your +floppy drives. On the other hand, the configuration file is needed if +you also want to use mtools to access your hard disk partitions and +dosemu image files. + + +File: mtools.info, Node: global variables, Next: per drive variables, Prev: default values, Up: Configuration + +3.4 Global variables +==================== + +Global flags may be set to 1 or to 0. + + The following global flags are recognized: + +`MTOOLS_SKIP_CHECK' + If this is set to 1, mtools skips most of its sanity checks. This + is needed to read some Atari disks which have been made with the + earlier ROMs, and which would not be recognized otherwise. + +`MTOOLS_FAT_COMPATIBILITY' + If this is set to 1, mtools skips the fat size checks. Some disks + have a bigger FAT than they really need to. These are rejected if + this option is not set. + +`MTOOLS_LOWER_CASE' + If this is set to 1, mtools displays all-upper-case short + filenames as lowercase. This has been done to allow a behavior + which is consistent with older versions of mtools which didn't + know about the case bits. + +`MTOOLS_NO_VFAT' + If this is set to 1, mtools won't generate VFAT entries for + filenames which are mixed-case, but otherwise legal dos filenames. + This is useful when working with DOS versions which can't grok + VFAT longnames, such as FreeDos. + +`MTOOLS_DOTTED_DIR' + In a wide directory, prints the short name with a dot instead of + spaces separating the basename and the extension. + +`MTOOLS_NAME_NUMERIC_TAIL' + If this is set to one (default), generate numeric tails for all + long names (~1). If set to zero, only generate numeric tails if + otherwise a clash would have happened. + +`MTOOLS_TWENTY_FOUR_HOUR_CLOCK' + If 1, uses the European notation for times (twenty four hour + clock), else uses the UK/US notation (am/pm) + + Example: Inserting the following line into your configuration file +instructs mtools to skip the sanity checks: + MTOOLS_SKIP_CHECK=1 + + Global variables may also be set via the environment: + export MTOOLS_SKIP_CHECK=1 + + Global string variables may be set to any value: +`MTOOLS_DATE_STRING' + The format used for printing dates of files. By default, is + dd-mm-yyyy. + + +File: mtools.info, Node: per drive variables, Next: parsing order, Prev: global variables, Up: Configuration + +3.5 Per drive flags and variables +================================= + +* Menu: + +* general information:: What a drive description looks like +* location information:: Where is the drive data physically stored +* geometry description:: Describes the physical characteristics of + the media +* open flags:: Flags passed to the open system call when the + device is opened +* misc variables:: Variables which don't fit in either category +* misc flags:: Switch variables, which can be enabled or disabled +* multiple descriptions:: How to supply several descriptions for a + drive, to be tried one after the other. + + +File: mtools.info, Node: general information, Next: location information, Prev: per drive variables, Up: per drive variables + +3.5.1 General information +------------------------- + +Per drive flags and values may be described in a drive section. A drive +section starts with `drive' "DRIVELETTER" : + + Then follow variable-value pairs and flags. + + This is a sample drive description: + drive a: + file="/dev/fd0" use_xdf=1 + + +File: mtools.info, Node: location information, Next: geometry description, Prev: general information, Up: per drive variables + +3.5.2 Location information +-------------------------- + +For each drive, you need to describe where its data is physically +stored (imag file, physical device, partition, offset). + +`file' + The name of the file or device holding the disk image. This is + mandatory. The file name should be enclosed in quotes. + +`partition' + Tells mtools to treat the drive as a partitioned device, and to + use the given partition. Only primary partitions are accessible + using this method, and they are numbered from 1 to 4. For logical + partitions, use the more general `offset' variable. The + `partition' variable is intended for removable media such as + Syquests, ZIP drives, and magneto-optical disks. Although + traditional DOS sees Syquests and magneto-optical disks as `giant + floppy disks' which are unpartitioned, OS/2 and Windows NT treat + them like hard disks, i.e. partioned devices. The `partition' flag + is also useful DOSEMU hdimages. It is not recommended for hard + disks for which direct access to partitions is available through + mounting. + +`offset' + Describes where in the file the MS-DOS filesystem starts. This is + useful for logical partitions in DOSEMU hdimages, and for ATARI + ram disks. By default, this is zero, meaning that the filesystem + starts right at the beginning of the device or file. + + +File: mtools.info, Node: geometry description, Next: open flags, Prev: location information, Up: per drive variables + +3.5.3 Disk Geometry Configuration +--------------------------------- + +Geometry information describes the physical characteristics about the +disk. Its has three purposes: + +formatting + The geometry information is written into the boot sector of the + newly made disk. However, you may also describe the geometry + information on the command line. *Note mformat::, for details. + +filtering + On some Unices there are device nodes which only support one + physical geometry. For instance, you might need a different node + to access a disk as high density or as low density. The geometry + is compared to the actual geometry stored on the boot sector to + make sure that this device node is able to correctly read the + disk. If the geometry doesn't match, this drive entry fails, and + the next drive entry bearing the same drive letter is tried. *Note + multiple descriptions::, for more details on supplying several + descriptions for one drive letter. + + If no geometry information is supplied in the configuration file, + all disks are accepted. On Linux (and on Sparc) there exist device + nodes with configurable geometry (`/dev/fd0', `/dev/fd1' etc), and + thus filtering is not needed (and ignored) for disk drives. + (Mtools still does do filtering on plain files (disk images) in + Linux: this is mainly intended for test purposes, as I don't have + access to a Unix which would actually need filtering). + + If you do not need filtering, but want still a default geometry for + mformatting, you may switch off filtering using the `mformat_only' + flag. + + If you want filtering, you should supply the `filter' flag. If you + supply a geometry, you must supply one of both flags. + +initial geometry + On devices that support it (usually floppy devices), the geometry + information is also used to set the initial geometry. This initial + geometry is applied while reading the boot sector, which contains + the real geometry. If no geometry information is supplied in the + configuration file, or if the `mformat_only' flag is supplied, no + initial configuration is done. + + On Linux, initial geometry is not really needed, as the + configurable devices are able to auto-detect the disk type + accurately enough (for most common formats) to read the boot + sector. + + Wrong geometry information may lead to very bizarre errors. That's +why I strongly recommend that you add the `mformat_only' flag to your +drive description, unless you really need filtering or initial geometry. + + The following geometry related variables are available: + +`cylinders' +`tracks' + The number of cylinders. (`cylinders' is the preferred form, + `tracks' is considered obsolete) + +`heads' + The number of heads (sides). + +`sectors' + The number of sectors per track. + + Example: the following drive section describes a 1.44M drive: + + drive a: + file="/dev/fd0H1440" + fat_bits=12 + cylinders=80 heads=2 sectors=18 + mformat_only + + The following shorthand geometry descriptions are available: + +`1.44m' + high density 3 1/2 disk. Equivalent to: `fat_bits=12 cylinders=80 + heads=2 sectors=18' + +`1.2m' + high density 5 1/4 disk. Equivalent to: `fat_bits=12 cylinders=80 + heads=2 sectors=15' + +`720k' + double density 3 1/2 disk. Equivalent to: `fat_bits=12 + cylinders=80 heads=2 sectors=9' + +`360k' + double density 5 1/4 disk. Equivalent to: `fat_bits=12 + cylinders=40 heads=2 sectors=9' + + The shorthand format descriptions may be amended. For example, `360k +sectors=8' describes a 320k disk and is equivalent to: `fat_bits=12 +cylinders=40 heads=2 sectors=8' + + +File: mtools.info, Node: open flags, Next: misc variables, Prev: geometry description, Up: per drive variables + +3.5.4 Open Flags +---------------- + +Moreover, the following flags are available: + +`sync' + All i/o operations are done synchronously + +`nodelay' + The device or file is opened with the O_NDELAY flag. This is + needed on some non-Linux architectures. + +`exclusive' + The device or file is opened with the O_EXCL flag. On Linux, this + ensures exclusive access to the floppy drive. On most other + architectures, and for plain files it has no effect at all. + + +File: mtools.info, Node: misc variables, Next: misc flags, Prev: open flags, Up: per drive variables + +3.5.5 General Purpose Drive Variables +------------------------------------- + +The following general purpose drive variables are available. Depending +to their type, these variables can be set to a string (precmd) or an +integer (all others) + +`fat_bits' + The number of FAT bits. This may be 12 or 16. This is very rarely + needed, as it can almost always be deduced from information in the + boot sector. On the contrary, describing the number of fat bits may + actually be harmful if you get it wrong. You should only use it if + mtools gets the autodetected number of fat bits wrong, or if you + want to mformat a disk with a weird number of fat bits. + +`codepage' + Describes the DOS codepage used for short filenames. This is a + number between 1 and 999. By default, codepage 850 is used. The + reason for this is because this codepage contains most of the + characters that are also available in ISO-Latin-1. You may also + specify a global codepage for all drives by using the global + `default_codepage' parameter (outside of any drive description). + This parameters exists starting at version 4.0.0 + +`precmd' + On some variants of Solaris, it is necessary to call 'volcheck -v' + before opening a floppy device, in order for the system to notice + that there is indeed a disk in the drive. `precmd="volcheck -v"' + in the drive clause establishes the desired behavior. + +`blocksize' + This parameter represents a default block size to be always used + on this device. All I/O is done with multiples of this block size, + independantly of the sector size registered in the filesystem's + boot sector. This is useful for character devices whose sector + size is not 512, such as for example CD Rom drives on Solaris. + + + Only the `file' variable is mandatory. The other parameters may be +left out. In that case a default value or an autodetected value is used. + + +File: mtools.info, Node: misc flags, Next: multiple descriptions, Prev: misc variables, Up: per drive variables + +3.5.6 General Purpose Drive Flags +--------------------------------- + +A flag can either be set to 1 (enabled) or 0 (disabled). If the value is +ommitted, it is enabled. For example, `scsi' is equivalent to `scsi=1' + +`nolock' + Instruct mtools to not use locking on this drive. This is needed + on systems with buggy locking semantics. However, enabling this + makes operation less safe in cases where several users may access + the same drive at the same time. + +`scsi' + When set to 1, this option tells mtools to use raw SCSI I/O + instead of the standard read/write calls to access the device. + Currently, this is supported on HP/UX, Solaris and SunOs. This is + needed because on some architectures, such as SunOs or Solaris, PC + media can't be accessed using the `read' and `write' syscalls, + because the OS expects them to contain a Sun specific "disk label". + + As raw Scsi access always uses the whole device, you need to + specify the "partition" flag in addition + + On some architectures, such as Solaris, mtools needs root + privileges to be able to use the `scsi' option. Thus mtools + should be installed set uid root on Solaris if you want to access + Zip/Jaz drives. Thus, if the `scsi' flag is given, `privileged' + is automatically implied, unless explicitly disabled by + `privileged=0' + + Mtools uses its root privileges to open the device, and to issue + the actual SCSI I/O calls. Moreover, root privileges are only + used for drives described in a system-wide configuration file such + as `/usr/local/etc/mtools.conf', and not for those described in + `~/.mtoolsrc' or `$MTOOLSRC'. + +`privileged' + When set to 1, this instructs mtools to use its set-uid and set-gid + privileges for opening the given drive. This option is only valid + for drives described in the system-wide configuration files (such + as `/usr/local/etc/mtools.conf', not `~/.mtoolsrc' or + `$MTOOLSRC'). Obviously, this option is also a no op if mtools is + not installed setuid or setgid. This option is implied by + 'scsi=1', but again only for drives defined in system-wide + configuration files. Privileged may also be set explicitely to 0, + in order to tell mtools not to use its privileges for a given + drive even if `scsi=1' is set. + + Mtools only needs to be installed setuid if you use the + `privileged' or `scsi' drive variables. If you do not use these + options, mtools works perfectly well even when not installed + setuid root. + +`vold' + Instructs mtools to interpret the device name as a vold identifier + rather than as a filename. The vold identifier is translated into + a real filename using the `media_findname()' and + `media_oldaliases()' functions of the `volmgt' library. This flag + is only available if you configured mtools with the + `--enable-new-vold' option before compilation. + +`swap' + Consider the media as a word-swapped Atari disk. + +`use_xdf' + If this is set to a non-zero value, mtools also tries to access + this disk as an XDF disk. XDF is a high capacity format used by + OS/2. This is off by default. *Note XDF::, for more details. + +`mformat_only' + Tells mtools to use the geometry for this drive only for + mformatting and not for filtering. + +`filter' + Tells mtools to use the geometry for this drive both for + mformatting and filtering. + +`remote' + Tells mtools to connect to floppyd (*note floppyd::). + + +File: mtools.info, Node: multiple descriptions, Prev: misc flags, Up: per drive variables + +3.5.7 Supplying multiple descriptions for a drive +------------------------------------------------- + +It is possible to supply multiple descriptions for a drive. In that +case, the descriptions are tried in order until one is found that fits. +Descriptions may fail for several reasons: + + 1. because the geometry is not appropriate, + + 2. because there is no disk in the drive, + + 3. or because of other problems. + + Multiple definitions are useful when using physical devices which are +only able to support one single disk geometry. Example: + drive a: file="/dev/fd0H1440" 1.44m + drive a: file="/dev/fd0H720" 720k + + This instructs mtools to use /dev/fd0H1440 for 1.44m (high density) +disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this +feature is not really needed, as the /dev/fd0 device is able to handle +any geometry. + + You may also use multiple drive descriptions to access both of your +physical drives through one drive letter: + + drive z: file="/dev/fd0" + drive z: file="/dev/fd1" + + With this description, `mdir z:' accesses your first physical drive +if it contains a disk. If the first drive doesn't contain a disk, +mtools checks the second drive. + + When using multiple configuration files, drive descriptions in the +files parsed last override descriptions for the same drive in earlier +files. In order to avoid this, use the `drive+' or `+drive' keywords +instead of `drive'. The first adds a description to the end of the list +(i.e. it will be tried last), and the first adds it to the start of the +list. + + +File: mtools.info, Node: parsing order, Next: old style config, Prev: per drive variables, Up: Configuration + +3.6 Location of configuration files and parsing order +===================================================== + +The configuration files are parsed in the following order: + 1. compiled-in defaults + + 2. `/usr/local/etc/mtools.conf' + + 3. `/etc/mtools' This is for backwards compatibility only, and is + only parsed if `mtools.conf' doesn't exist. + + 4. `~/.mtoolsrc'. + + 5. `$MTOOLSRC' (file pointed by the `MTOOLSRC' environmental variable) + + Options described in the later files override those described in the +earlier files. Drives defined in earlier files persist if they are not +overridden in the later files. For instance, drives A and B may be +defined in `/usr/local/etc/mtools.conf' and drives C and D may be +defined in `~/.mtoolsrc' However, if `~/.mtoolsrc' also defines drive +A, this new description would override the description of drive A in +`/usr/local/etc/mtools.conf' instead of adding to it. If you want to +add a new description to a drive already described in an earlier file, +you need to use either the `+drive' or `drive+' keyword. + + +File: mtools.info, Node: old style config, Prev: parsing order, Up: Configuration + +3.7 Backwards compatibility with old configuration file syntax +============================================================== + +The syntax described herein is new for version `mtools-3.0'. The old +line-oriented syntax is still supported. Each line beginning with a +single letter is considered to be a drive description using the old +syntax. Old style and new style drive sections may be mixed within the +same configuration file, in order to make upgrading easier. Support for +the old syntax will be phased out eventually, and in order to discourage +its use, I purposefully omit its description here. + + +File: mtools.info, Node: Commands, Next: Compiling mtools, Prev: Configuration, Up: Top + +4 Command list +************** + +This section describes the available mtools commands, and the command +line parameters that each of them accepts. Options which are common to +all mtools commands are not described here, *note arguments:: for a +description of those. + +* Menu: + +* floppyd:: floppy daemon to run on your X server box +* floppyd_installtest:: small utility to check for the presence of floppyd +* mattrib:: change MS-DOS file attribute flags +* mbadblocks:: tests a floppy disk, and marks the bad blocks in the FAT +* mcat:: same as cat. Only usefull with floppyd. +* mcd:: change MS-DOS directory +* mclasserase:: erase memory card +* mcopy:: copy MS-DOS files to/from Unix +* mdel:: delete an MS-DOS file +* mdeltree:: recursively delete an MS-DOS directory +* mdir:: display an MS-DOS directory +* mdu:: list space occupied by directory and its contents +* mformat:: add an MS-DOS filesystem to a low-level formatted floppy disk +* minfo:: get information about an MS-DOS filesystem. +* mlabel:: make an MS-DOS volume label +* mkmanifest:: makes a list of short name equivalents +* mmd:: make an MS-DOS subdirectory +* mmount:: mount an MS-DOS disk +* mpartition:: create an MS-DOS as a partition +* mrd:: remove an MS-DOS subdirectory +* mmove:: move or rename an MS-DOS file or subdirectory +* mren:: rename an existing MS-DOS file +* mshowfat:: shows the FAT map of a file +* mtoolstest:: tests and displays the configuration +* mtype:: display contents of an MS-DOS file +* mzip:: zip disk specific commands + + +File: mtools.info, Node: floppyd, Next: floppyd_installtest, Prev: Commands, Up: Commands + +4.1 Floppyd +=========== + +`Floppyd' is used as a server to grant access to the floppy drive to +clients running on a remote machine, just as an X server grants access +to the display to remote clients. It has the following syntax: + + `floppyd' [`-d'] [`-l'] [`-s' PORT] [`-r' USER] [`-b' IPADDR] [`-x' +DISPLAY] DEVICENAMES + + `floppyd' is always associated with an X server. It runs on the +same machine as its X server, and listens on port 5703 and above. + +4.1.1 Authentication +-------------------- + +`floppyd' authenticates remote clients using the `Xauthority' protocol. +Xhost authentication is not supported. Each floppyd is associated with +an X server. When a remote client attempts to connect to floppyd, it +sends floppyd the X authority record corresponding to floppyd's X +server. Floppyd in turn then tries to open up a connection to the X +server in order to verify the authenticity of the xauth record. If the +connection to the X server succeeds, the client is granted access. +`DISPLAY'. + + *Caution*: In order to make authentication work correctly, the local +host should *not* be listed in the `xhost' list of allowed hosts. +Indeed, hosts listed in `xhost' do not need a correct `Xauthority' +cookie to connect to the X server. As `floppyd' runs on the same host +as the X server, all its probe connection would succeed even for +clients who supplied a bad cookie. This means that your floppy drive +would be open to the world, i.e. a huge security hole. If your X +server does not allow you to remove `localhost:0' and `:0' from the +`xhost' list, you can prevent floppyd from probing those display names +with the `-l' option. + +4.1.2 Command line options +-------------------------- + +`d' + Daemon mode. Floppyd runs its own server loop. Do not supply this + if you start floppyd from `inetd.conf' + +`s PORT' + Port number for deamon mode. Default is 5703 + DISPLAYNUMBER. + This flag implies daemon mode. For example, for display + `hitchhiker:5', the port would be 5708. + +`b IPADDR' + Bind address (for multihomed hosts). This flag implies daemon mode + +`r USER' + Run the server under as the given user + +`x DISPLAY' + X display to use for authentication. By default, this is taken + from the `DISPLAY' variable. If neither the `x' attribute is + present nor `DISPLAY' is set, floppyd uses `:0.0'. + + DEVICENAMES is a list of device nodes to be opened. Default is +`/dev/fd0'. Multiple devices are only supported on mtools versions +newer than 3.9.11. + +4.1.3 Connecting to floppyd +--------------------------- + +In order to use floppyd, add the flag `remote' to the device +description in your `~/.mtoolsrc' file. If the flag `remote' is given, +the `file' parameter of the device description is taken to be a remote +address. It's format is the following: +HOSTNAME`:'DISPLAYNUMBER[`/'[BASEPORT][`/'DRIVE]]. When using this +entry, mtools connects to port BASEPORT+DISPLAYNUMBER at HOSTNAME. By +default BASEPORT is 5703. The drive parameter is to distinguish among +multiple drives associated with a single display (only mtools versions +more recent than 3.9.11) + +4.1.4 Examples: +--------------- + +The following starts a floppy daemon giving access to `/dev/fd0', +listening on the default port 5703, tied to the default X servers: + + floppyd -d /dev/fd0 + + Each of the following starts a floppy daemon giving access to +`/dev/fd1', tied to the :1 local X servers, and listening on port 5704. +We assume that the local host is named `hitchhiker'. + + floppyd -d /dev/fd0 + floppyd -d -x :1 -p 5704 /dev/fd0 + + If you want to start floppyd by `inetd' instead of running it as a +daemon, insert the following lines into `/etc/services': + # floppy daemon + floppyd-0 5703/tcp # floppy daemon for X server :0 + floppyd-1 5704/tcp # floppy daemon for X server :1 + + And insert the following into `/etc/inetd.conf' (assuming that you +have defined a user named floppy in your `/etc/passwd'): + + # floppy daemon + floppyd-0 stream tcp wait floppy /usr/sbin/floppyd floppyd /dev/fd0 + floppyd-1 stream tcp wait floppy /usr/sbin/floppyd floppyd -x :1 /dev/fd0 + + Note that you need to supply the X display names for the second +floppyd. This is because the port is opened by inetd.conf, and hence +floppyd cannot know its number to interfere the display number. + + On the client side, insert the following into your `~/.mtoolsrc' to +define a drive letter accessing floppy drive in your X terminal: + drive x: file="$DISPLAY" remote + + If your X terminal has more than one drive, you may access the +additional drives as follows: + drive y: file="$DISPLAY//1" remote + drive z: file="$DISPLAY//2" remote + + +File: mtools.info, Node: floppyd_installtest, Next: mattrib, Prev: floppyd, Up: Commands + +4.2 Floppyd_installtest +======================= + +`Floppyd_installtest' is used to check for the presence of a running +floppyd daemon. This is usefull, if you have a small frontend script to +mtools, which decides whether to use floppyd or not. + + `floppyd_installtest' [`-f'] Connect-String + + If the `-f' option is specified, `floppyd_installtest' does a full +X-Cookie authentication and complains if this does not work. + + The connect-String has the format described in the floppyd-section: +HOSTNAME`:'DISPLAYNUMBER[`/'BASEPORT] + + +File: mtools.info, Node: mattrib, Next: mbadblocks, Prev: floppyd_installtest, Up: Commands + +4.3 Mattrib +=========== + +`Mattrib' is used to change MS-DOS file attribute flags. It has the +following syntax: + + `mattrib' [`-a|+a'] [`-h|+h'] [`-r|+r'] [`-s|+s'] [`-/'] [`-p'] +[`-X'] MSDOSFILE [ MSDOSFILES ... ] + + `Mattrib' adds attribute flags to an MS-DOS file (with the ``+'' +operator) or remove attribute flags (with the ``-'' operator). + + `Mattrib' supports the following attribute bits: + +`a' + Archive bit. Used by some backup programs to indicate a new file. + +`r' + Read-only bit. Used to indicate a read-only file. Files with + this bit set cannot be erased by `DEL' nor modified. + +`s' + System bit. Used by MS-DOS to indicate a operating system file. + +`h' + Hidden bit. Used to make files hidden from `DIR'. + + `Mattrib' supports the following command line flags: +`/' + Recursive. Recursively list the attributes of the files in the + subdirectories. + +`X' + Concise. Prints the attributes whithout any whitespace padding. If + neither the "/" option is given, nor the MSDOSFILE contains a + wildcard, and there is only one Msdos file parameter on the command + line, only the attribute is printed, and not the filename. This + option is convenient for scripts + +`p' + Replay mode. Outputs a series of mformat commands that will + reproduce the current situation, starting from a situation as left + by untarring the Dos filesystem. Commands are only output for + attribute settings that differ from the default (archive bit set + for files, unset for directories). This option is intended to be + used in addition to tar. The `readonly' attribute is not taken + into account, as tar can set that one itself. + + +File: mtools.info, Node: mbadblocks, Next: mcat, Prev: mattrib, Up: Commands + +4.4 Mbadblocks +============== + +The `mbadblocks' command is used to scan an MS-DOS floppy and mark its +unused bad blocks as bad. It uses the following syntax: + + `mbadblocks' DRIVE`:' + + `Mbadblocks' scans an MS-DOS floppy for bad blocks. All unused bad +blocks are marked as such in the FAT. This is intended to be used right +after `mformat'. It is not intended to salvage bad disks. + +4.4.1 Bugs +---------- + +`Mbadblocks' should (but doesn't yet :-( ) also try to salvage bad +blocks which are in use by reading them repeatedly, and then mark them +bad. + + +File: mtools.info, Node: mcat, Next: mcd, Prev: mbadblocks, Up: Commands + +4.5 Mcat +======== + +The `mcat' command is used to copy an entire disk image from or to the +floppy device. It uses the following syntax: + + `mcat' [`-w'] DRIVE`:' + + `Mcat' performs the same task as the unix `cat' command. It is +included into the mtools package, since `cat' cannot access remote +floppy devices offered by the mtools floppy daemon. Now it is possible +to create boot floppies remotely. + + The default operation is reading. The output is written to stdout. + + If the `-w' option is specified, mcat reads a disk-image from stdin +and writes it to the given device. *Use this carefully!* Because of +the lowlevel nature of this command, it will happily destroy any data +written before on the disk without warning! + + +File: mtools.info, Node: mcd, Next: mclasserase, Prev: mcat, Up: Commands + +4.6 Mcd +======= + +The `mcd' command is used to change the mtools working directory on the +MS-DOS disk. It uses the following syntax: + + `mcd' [MSDOSDIRECTORY] + + Without arguments, `mcd' reports the current device and working +directory. Otherwise, `mcd' changes the current device and current +working directory relative to an MS-DOS filesystem. + + The environmental variable `MCWD' may be used to locate the file +where the device and current working directory information is stored. +The default is `$HOME/.mcwd'. Information in this file is ignored if +the file is more than 6 hours old. + + `Mcd' returns 0 on success or 1 on failure. + + Unlike MS-DOS versions of `CD', `mcd' can be used to change to +another device. It may be wise to remove old `.mcwd' files at logout. + + +File: mtools.info, Node: mclasserase, Next: mcopy, Prev: mcd, Up: Commands + +4.7 Mclasserase +=============== + +The `mclasserase' command is used to wipe memory cards by overwriting +it three times: first with `0xff', then with `0x00', then with `0xff' +again. The command uses the following syntax: + + `mclasserase' [`-d'] MSDOSDRIVE + + Dos drive is optional, if none is specified, use `A:'. If more than +one drive are specified, all but the last are ignored. + + `Mclasserase' accepts the following command line options: + +`d' + Stop after each erase cycle, for testing purposes + +`p' + Not yet implemented + + `Mclasserase' returns 0 on success or -1 on failure. + + +File: mtools.info, Node: mcopy, Next: mdel, Prev: mclasserase, Up: Commands + +4.8 Mcopy +========= + +The `mcopy' command is used to copy MS-DOS files to and from Unix. It +uses the following syntax: + + `mcopy' [`-bspanvmQT'] [`-D' CLASH_OPTION] SOURCEFILE TARGETFILE + `mcopy' [`-bspanvmQT'] [`-D' CLASH_OPTION] SOURCEFILE [ SOURCEFILES... ] TARGETDIRECTORY + `mcopy' [`-tnvm'] MSDOSSOURCEFILE + + `Mcopy' copies the specified file to the named file, or copies +multiple files to the named directory. The source and target can be +either MS-DOS or Unix files. + + The use of a drive letter designation on the MS-DOS files, 'a:' for +example, determines the direction of the transfer. A missing drive +designation implies a Unix file whose path starts in the current +directory. If a source drive letter is specified with no attached file +name (e.g. `mcopy a: .'), all files are copied from that drive. + + If only a single, MS-DOS source parameter is provided (e.g. "mcopy +a:foo.exe"), an implied destination of the current directory (``.'') is +assumed. + + A filename of ``-'' means standard input or standard output, +depending on its position on the command line. + + `Mcopy' accepts the following command line options: + +`t' + Text file transfer. Mcopy translates incoming carriage return/line + feeds to line feeds when copying from Dos to Unix, and vice-versa + when copying from Unix to Dos. + +`b' + Batch mode. Optimized for huge recursive copies, but less secure + if a crash happens during the copy. + +`s' + Recursive copy. Also copies directories and their contents + +`p' + Preserves the attributes of the copied files + +`Q' + When mcopying multiple files, quits as soon as one copy fails (for + example due to lacking storage space on the target disk) + +`a' + Text (Ascii) file transfer. `Mcopy' translates incoming carriage + return/line feeds to line feeds. + +`T' + Text (Ascii) file transfer with charset conversion. Differs from + `-a' in the `Mcopy' also translates incoming PC-8 characters to + ISO-8859-1 equivalents as far as possible. When reading DOS files, + untranslatable characters are replaced by '`#''; when writing DOS + files, untranslatable characters are replaced by '`.''. + +`n' + No confirmation when overwriting Unix files. `Mcopy' doesn't warn + the user when overwriting an existing Unix file. If the target + file already exists, and the `-n' option is not in effect, `mcopy' + asks whether to overwrite the file or to rename the new file + (*note name clashes::) for details). In order to switch off + confirmation for DOS files, use `-o'. + +`m' + Preserve the file modification time. + +`v' + Verbose. Displays the name of each file as it is copied. + +4.8.1 Bugs +---------- + +Unlike MS-DOS, the '+' operator (append) from MS-DOS is not supported. +However, you may use `mtype' to produce the same effect: + mtype a:file1 a:file2 a:file3 >unixfile + mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile + + +File: mtools.info, Node: mdel, Next: mdeltree, Prev: mcopy, Up: Commands + +4.9 Mdel +======== + +The `mdel' command is used to delete an MS-DOS file. Its syntax is: + + `mdel' [`-v'] MSDOSFILE [ MSDOSFILES ... ] + + `Mdel' deletes files on an MS-DOS filesystem. + + `Mdel' asks for verification prior to removing a read-only file. + + +File: mtools.info, Node: mdeltree, Next: mdir, Prev: mdel, Up: Commands + +4.10 Mdeltree +============= + +The `mdeltree' command is used to delete an MS-DOS file. Its syntax is: + + `mdeltree' [`-v'] MSDOSDIRECTORY [MSDOSDIRECTORIES...] + + `Mdeltree' removes a directory and all the files and subdirectories +it contains from an MS-DOS filesystem. An error occurs if the directory +to be removed does not exist. + + +File: mtools.info, Node: mdir, Next: mdu, Prev: mdeltree, Up: Commands + +4.11 Mdir +========= + +The `mdir' command is used to display an MS-DOS directory. Its syntax +is: + + `mdir' [`-/'] [`-f'] [`-w'] [`-a'] [`-b'] MSDOSFILE [ MSDOSFILES...] + + `Mdir' displays the contents of MS-DOS directories, or the entries +for some MS-DOS files. + + `Mdir' supports the following command line options: + +`/' + Recursive output, just like Dos' `-s' option + +`w' + Wide output. With this option, `mdir' prints the filenames across + the page without displaying the file size or creation date. + +`a' + Also list hidden files. + +`f' + Fast. Do not try to find out free space. On larger disks, + finding out the amount of free space takes up some non trivial + amount of time, as the whole FAT must be read in and scanned. The + `-f' flag bypasses this step. This flag is not needed on FAT32 + filesystems, which store the size explicitely. + +`b' + Concise listing. Lists each directory name or filename, one per + line (including the filename extension). This switch displays no + heading information and no summary. Only a newline separated list + of pathnames is displayed. + + An error occurs if a component of the path is not a directory. + + +File: mtools.info, Node: mdu, Next: mformat, Prev: mdir, Up: Commands + +4.12 Mdu +======== + +`Mdu' is used to list the space occupied by a directory, its +subdirectories and its files. It is similar to the `du' command on +Unix. The unit used are clusters. Use the minfo command to find out +the cluster size. + + `mdu' [`-a'] [ MSDOSFILES ... ] + +`a' + All files. List also the space occupied for individual files. + +`s' + Only list the total space, don't give details for each + subdirectory. + + +File: mtools.info, Node: mformat, Next: mkmanifest, Prev: mdu, Up: Commands + +4.13 Mformat +============ + +The `mformat' command is used to add an MS-DOS filesystem to a +low-level formatted diskette. Its syntax is: + + `mformat' [`-t' CYLINDERS] [`-h' HEADS] [`-s' SECTORS] + [`-f' SIZE] [`-1'] [`-4'] [`-8'] + [`-v' VOLUME_LABEL] + [`-F'] [`-S' SIZECODE] [`-X'] + [`-2' SECTORS_ON_TRACK_0] [`-3'] + [`-0' RATE_ON_TRACK_0] [`-A' RATE_ON_OTHER_TRACKS] + [`-M' SOFTWARE_SECTOR_SIZE] + [`-N' SERIAL_NUMBER] [`-a'] + [`-C'] [`-H' HIDDEN_SECTORS] [`-I' FSVERSION] + [`-r' ROOT_SECTORS] [`-L' FAT_LEN] + [`-B' BOOT_SECTOR] [`-k'] + [`-m' MEDIA_DESCRIPTOR] + DRIVE: + + `Mformat' adds a minimal MS-DOS filesystem (boot sector, FAT, and +root directory) to a diskette that has already been formatted by a Unix +low-level format. + + The following options are supported: (The S, 2, 1 and M options may +not exist if this copy of mtools has been compiled without the USE_2M +option) + + The following options are the same as for Dos's format command: + +`v' + Specifies the volume label. A volume label identifies the disk and + can be a maximum of 11 characters. If you omit the -v switch, + mlabel will assign no label to the disk. + +`f' + Specifies the size of the DOS filesystem to format. Only a certain + number of predefined sizes are supported by this flag; for others + use the -h/-t/-s flags. The following sizes are supported: + 160 + 160K, single-sided, 8 sectors per track, 40 cylinders (for 5 + 1/4 DD) + + 180 + 160K, single-sided, 9 sectors per track, 40 cylinders (for 5 + 1/4 DD) + + 320 + 320K, double-sided, 8 sectors per track, 40 cylinders (for 5 + 1/4 DD) + + 360 + 360K, double-sided, 9 sectors per track, 40 cylinders (for 5 + 1/4 DD) + + 720 + 720K, double-sided, 9 sectors per track, 80 cylinders (for 3 + 1/2 DD) + + 1200 + 1200K, double-sided, 15 sectors per track, 80 cylinders (for + 5 1/4 HD) + + 1440 + 1440K, double-sided, 18 sectors per track, 80 cylinders (for + 3 1/2 HD) + + 2880 + 2880K, double-sided, 36 sectors per track, 80 cylinders (for + 3 1/2 ED) + +`t' + Specifies the number of tracks on the disk. + +`h' + The number of heads (sides). + +`n' + Specifies the number of sectors per track. If the 2m option is + given, number of 512-byte sector equivalents on generic tracks + (i.e. not head 0 track 0). If the 2m option is not given, number + of physical sectors per track (which may be bigger than 512 bytes). + +`1' + Formats a single side (equivalent to -h 1) + +`4' + Formats a 360K double-sided disk (equivalent to -f 360). When used + together with -the 1 switch, this switch formats a 180K disk + +`8' + Formats a disk with 8 sectors per track. + + + MSDOS format's `q', `u' and `b' options are not supported, and `s' +has a different meaning. + + The following options are specific to mtools: + +`F' + Format the partition as FAT32. + +`S' + The sizecode. The size of the sector is 2 ^ (sizecode + 7). + +`X' + formats the disk as an XDF disk. *Note XDF::, for more details. + The disk has first to be low-level formatted using the xdfcopy + utility included in the fdutils package. XDF disks are used for + instance for OS/2 install disks. + +`2' + 2m format. The parameter to this option describes the number of + sectors on track 0, head 0. This option is recommended for sectors + bigger than normal. + +`3' + don't use a 2m format, even if the current geometry of the disk is + a 2m geometry. + +`0' + Data transfer rate on track 0 + +`A' + Data transfer rate on tracks other than 0 + +`M' + software sector size. This parameter describes the sector size in + bytes used by the MS-DOS filesystem. By default it is the physical + sector size. + +`N' + Uses the requested serial number, instead of generating one + automatically + +`a' + If this option is given, an Atari style serial number is generated. + Ataris store their serial number in the OEM label. + +`C' + creates the disk image file to install the MS-DOS filesystem on + it. Obviously, this is useless on physical devices such as floppies + and hard disk partitions, but is interesting for image files. + +`H' + number of hidden sectors. This parameter is useful for formatting + hard disk partition, which are not aligned on track boundaries + (i.e. first head of first track doesn't belong to the partition, + but contains a partition table). In that case the number of hidden + sectors is in general the number of sectors per cylinder. This is + untested. + +`I' + Sets the fsVersion id when formatting a FAT32 drive. In order to + find this out, run minfo on an existing FAT32 drive, and mail me + about it, so I can include the correct value in future versions of + mtools. + +`c' + Sets the size of a cluster (in sectors). If this cluster size + would generate a FAT that too big for its number of bits, mtools + automatically increases the cluster size, until the FAT is small + enough. + +`d' + Sets the number of FAT copies. Default is 2. This setting can also + be specified using the `MTOOLS_NFATS' environment variable. + +`r' + Sets the size of the root directory (in sectors). Only applicable + to 12 and 16 bit FATs. This setting can also be specified using the + `MTOOLS_DIR_LEN' environment variable. + +`L' + Sets the length of the FAT. + +`B' + Use the bootsector stored in the given file or device, instead of + using its own. Only the geometry fields are updated to match the + target disks parameters. + +`k' + Keep the existing boot sector as much as possible. Only the + geometry fields and other similar filesystem data are updated to + match the target disks parameters. + +`m' + Use a non-standard media descriptor byte for this disk. The media + descriptor is stored at position 21 of the boot sector, and as + first byte in each FAT copy. Using this option may confuse DOS or + older mtools version, and may make the disk unreadable. Only use + if you know what you are doing. + + + To format a diskette at a density other than the default, you must +supply (at least) those command line parameters that are different from +the default. + + `Mformat' returns 0 on success or 1 on failure. + + It doesn't record bad block information to the Fat, use `mbadblocks' +for that. + + +File: mtools.info, Node: mkmanifest, Next: minfo, Prev: mformat, Up: Commands + +4.14 Mkmanifest +=============== + +The `mkmanifest' command is used to create a shell script (packing +list) to restore Unix filenames. Its syntax is: + + `mkmanifest' [ FILES ] + + `Mkmanifest' creates a shell script that aids in the restoration of +Unix filenames that got clobbered by the MS-DOS filename restrictions. +MS-DOS filenames are restricted to 8 character names, 3 character +extensions, upper case only, no device names, and no illegal characters. + + The mkmanifest program is compatible with the methods used in +`pcomm, arc,' and `mtools' to change perfectly good Unix filenames to +fit the MS-DOS restrictions. This command is only useful if the target +system which will read the diskette cannot handle vfat long names. + +4.14.1 Example +-------------- + +You want to copy the following Unix files to a MS-DOS diskette (using +the `mcopy' command). + + very_long_name + 2.many.dots + illegal: + good.c + prn.dev + Capital + + `Mcopy' converts the names to: + + very_lon + 2xmany.dot + illegalx + good.c + xprn.dev + capital + + The command: + mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest + would produce the following: + mv very_lon very_long_name + mv 2xmany.dot 2.many.dots + mv illegalx illegal: + mv xprn.dev prn.dev + mv capital Capital + + Notice that "good.c" did not require any conversion, so it did not +appear in the output. + + Suppose I've copied these files from the diskette to another Unix +system, and I now want the files back to their original names. If the +file "manifest" (the output captured above) was sent along with those +files, it could be used to convert the filenames. + +4.14.2 Bugs +----------- + +The short names generated by `mkmanifest' follow the old convention +(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0. + + +File: mtools.info, Node: minfo, Next: mlabel, Prev: mkmanifest, Up: Commands + +4.15 Minfo +========== + +The `minfo' command prints the parameters of a Dos filesystem, such as +number of sectors, heads and cylinders. It also prints an mformat +command line which can be used to create a similar Dos filesystem on +another media. However, this doesn't work with 2m or Xdf media, and +with Dos 1.0 filesystems + `minfo' DRIVE: + + Mlabel supports the following option: +`v' + Prints a hexdump of the bootsector, in addition to the other + information + + +File: mtools.info, Node: mlabel, Next: mmd, Prev: minfo, Up: Commands + +4.16 Mlabel +=========== + +The `mlabel' command adds a volume label to a disk. Its syntax is: + `mlabel' [`-vcsn'] [`-N' SERIAL] DRIVE:[NEW_LABEL] + + `Mlabel' displays the current volume label, if present. If NEW_LABEL +is not given, and if neither the `c' nor the `s' options are set, it +prompts the user for a new volume label. To delete an existing volume +label, press return at the prompt. + + Reasonable care is taken to create a valid MS-DOS volume label. If +an invalid label is specified, `mlabel' changes the label (and displays +the new label if the verbose mode is set). `Mlabel' returns 0 on +success or 1 on failure. + + Mlabel supports the following options: +`c' + Clears an existing label, without prompting the user + +`s' + Shows the existing label, without prompting the user. + +`n' + Assigns a new (random) serial number to the disk + +`N SERIAL' + Sets the supplied serial number. The serial number should be + supplied as an 8 digit hexadecimal number, without spaces + + +File: mtools.info, Node: mmd, Next: mmount, Prev: mlabel, Up: Commands + +4.17 Mmd +======== + +The `mmd' command is used to make an MS-DOS subdirectory. Its syntax is: + + `mmd' [`-D' CLASH_OPTION] MSDOSDIRECTORY [ MSDOSDIRECTORIES... ] + + `Mmd' makes a new directory on an MS-DOS filesystem. An error occurs +if the directory already exists. + + +File: mtools.info, Node: mmount, Next: mmove, Prev: mmd, Up: Commands + +4.18 Mmount +=========== + +The `mmount' command is used to mount an MS-DOS disk. It is only +available on Linux, as it is only useful if the OS kernel allows to +configure the disk geometry. Its syntax is: + + `mmount' MSDOSDRIVE [MOUNTARGS] + + `Mmount' reads the boot sector of an MS-DOS disk, configures the +drive geometry, and finally mounts it passing `mountargs' to `mount. ' +If no mount arguments are specified, the name of the device is used. If +the disk is write protected, it is automatically mounted read only. + + +File: mtools.info, Node: mmove, Next: mpartition, Prev: mmount, Up: Commands + +4.19 Mmove +========== + +The `mmove' command is used to moves or renames an existing MS-DOS file +or subdirectory. + `mmove' [`-v'] [`-D' CLASH_OPTION] SOURCEFILE TARGETFILE + `mmove' [`-v'] [`-D' CLASH_OPTION] SOURCEFILE [ SOURCEFILES... ] TARGETDIRECTORY + `Mmove' moves or renames an existing MS-DOS file or subdirectory. +Unlike the MS-DOS version of `MOVE', `mmove' is able to move +subdirectories. Files or directories can only be moved within one +filesystem. Data cannot be moved from Dos to Unix or vice-versa. If +you omit the drive letter from the target file or directory, the same +letter as for the source is assumed. If you omit the drive letter from +all parameters, drive a: is assumed by default. + + +File: mtools.info, Node: mpartition, Next: mrd, Prev: mmove, Up: Commands + +4.20 Mpartition +=============== + +The `mpartition' command is used to create MS-DOS filesystems as +partitions. This is intended to be used on non-Linux systems, i.e. +systems where fdisk and easy access to Scsi devices are not available. +This command only works on drives whose partition variable is set. + + `mpartition' `-p' DRIVE + `mpartition' `-r' DRIVE + `mpartition' `-I' [`-B' BOOTSECTOR] DRIVE + `mpartition' `-a' DRIVE + `mpartition' `-d' DRIVE + `mpartition' `-c' [`-s' SECTORS] [`-h' HEADS] + [`-t' CYLINDERS] [`-v' [`-T' TYPE] [`-b' + BEGIN] [`-l' length] [`-f'] + + Mpartition supports the following operations: + +`p' + Prints a command line to recreate the partition for the drive. + Nothing is printed if the partition for the drive is not defined, + or an inconsistency has been detected. If verbose (`-v') is also + set, prints the current partition table. + +`r' + Removes the partition described by DRIVE. + +`I' + Initializes the partition table, and removes all partitions. + +`c' + Creates the partition described by DRIVE. + +`a' + "Activates" the partition, i.e. makes it bootable. Only one + partition can be bootable at a time. + +`d' + "Desactivates" the partition, i.e. makes it unbootable. + + If no operation is given, the current settings are printed. + + For partition creations, the following options are available: +`s SECTORS' + The number of sectors per track of the partition (which is also the + number of sectors per track for the whole drive). + +`h HEADS' + The number of heads of the partition (which is also the number of + heads for the whole drive). By default, the geometry information + (number of sectors and heads) is figured out from neighbouring + partition table entries, or guessed from the size. + +`t CYLINDERS' + The number of cylinders of the partition (not the number of + cylinders of the whole drive. + +`b BEGIN' + The starting offset of the partition, expressed in sectors. If + begin is not given, mpartition lets the partition begin at the + start of the disk (partition number 1), or immediately after the + end of the previous partition. + +`l LENGTH' + The size (length) of the partition, expressed in sectors. If end + is not given, mpartition figures out the size from the number of + sectors, heads and cylinders. If these are not given either, it + gives the partition the biggest possible size, considering disk + size and start of the next partition. + + The following option is available for all operation which modify the +partition table: +`f' + Usually, before writing back any changes to the partition, + mpartition performs certain consistenct checks, such as checking + for overlaps and proper alignment of the partitions. If any of + these checks fails, the partition table is not changes. The `-f' + allows you to override these safeguards. + + The following options are available for all operations: +`v' + Together with `-p' prints the partition table as it is now (no + change operation), or as it is after it is modified. + +`vv' + If the verbosity flag is given twice, mpartition will print out a + hexdump of the partition table when reading it from and writing it + to the device. + + The following option is available for partition table initialization: +`B BOOTSECTOR' + Reads the template master boot record from file BOOTSECTOR. + + +File: mtools.info, Node: mrd, Next: mren, Prev: mpartition, Up: Commands + +4.21 Mrd +======== + +The `mrd' command is used to remove an MS-DOS subdirectory. Its syntax +is: + + `mrd' [`-v'] MSDOSDIRECTORY [ MSDOSDIRECTORIES... ] + + `Mrd' removes a directory from an MS-DOS filesystem. An error occurs +if the directory does not exist or is not empty. + + +File: mtools.info, Node: mren, Next: mshowfat, Prev: mrd, Up: Commands + +4.22 Mren +========= + +The `mren' command is used to rename or move an existing MS-DOS file or +subdirectory. Its syntax is: + + `mren' [`-voOsSrRA'] SOURCEFILE TARGETFILE + + `Mren' renames an existing file on an MS-DOS filesystem. + + In verbose mode, `Mren' displays the new filename if the name +supplied is invalid. + + If the first syntax is used (only one sourcefile), and if the target +name doesn't contain any slashes or colons, the file (or subdirectory) +is renamed in the same directory, instead of being moved to the current +`mcd' directory as would be the case with `mmove'. Unlike the MS-DOS +version of `REN', `mren' can be used to rename directories. + + +File: mtools.info, Node: mshowfat, Next: mtoolstest, Prev: mren, Up: Commands + +4.23 Mshowfat +============= + +The `mshowfat' command is used to display the FAT entries for a file. +Syntax: + + `$ mshowfat files' + + +File: mtools.info, Node: mtoolstest, Next: mtype, Prev: mshowfat, Up: Commands + +4.24 Mtoolstest +=============== + +The `mtoolstest' command is used to tests the mtools configuration +files. To invoke it, just type `mtoolstest' without any arguments. +`Mtoolstest' reads the mtools configuration files, and prints the +cumulative configuration to `stdout'. The output can be used as a +configuration file itself (although you might want to remove redundant +clauses). You may use this program to convert old-style configuration +files into new style configuration files. + + +File: mtools.info, Node: mtype, Next: mzip, Prev: mtoolstest, Up: Commands + +4.25 Mtype +========== + +The `mtype' command is used to display contents of an MS-DOS file. Its +syntax is: + + `mtype' [`-ts'] MSDOSFILE [ MSDOSFILES... ] + + `Mtype' displays the specified MS-DOS file on the screen. + + In addition to the standard options, `Mtype' allows the following +command line options: + +`t' + Text file viewing. `Mtype' translates incoming carriage + return/line feeds to line feeds. + +`s' + `Mtype' strips the high bit from the data. + + The `mcd' command may be used to establish the device and the +current working directory (relative to MS-DOS), otherwise the default is +`A:/'. + + `Mtype' returns 0 on success, 1 on utter failure, or 2 on partial +failure. + + Unlike the MS-DOS version of `TYPE', `mtype' allows multiple +arguments. + + +File: mtools.info, Node: mzip, Prev: mtype, Up: Commands + +4.26 Mzip +========= + +The `mzip' command is used to issue ZIP disk specific commands on +Linux, Solaris or HPUX. Its syntax is: + + `mzip' [`-epqrwx'] + + `Mzip' allows the following command line options: + +`e' + Ejects the disk. + +`f' + Force eject even if the disk is mounted (must be given in addition + to `-e'). + +`r' + Write protect the disk. + +`w' + Remove write protection. + +`p' + Password write protect. + +`x' + Password protect + +`u' + Temporarily unprotect the disk until it is ejected. The disk + becomes writable, and reverts back to its old state when ejected. + +`q' + Queries the status + + To remove the password, set it to one of the passwordless modes `-r' +or `-w': mzip will then ask you for the password, and unlock the disk. +If you have forgotten the password, you can get rid of it by low-level +formatting the disk (using your SCSI adaptor's BIOS setup). + + The ZipTools disk shipped with the drive is also password protected. +On Dos or on a Mac, this password is automatically removed once the +ZipTools have been installed. From various articles posted to Usenet, I +learned that the password for the tools disk is +`APlaceForYourStuff'(1). Mzip knows about this password, and tries it +first, before prompting you for a password. Thus `mzip -w z:' unlocks +the tools disk(2). The tools disk is formatted in a special way so as +to be usable both in a PC and in a Mac. On a PC, the Mac filesystem +appears as a hidden file named `partishn.mac'. You may erase it to +reclaim the 50 Megs of space taken up by the Mac filesystem. + +4.26.1 Bugs +----------- + +This command is a big kludge. A proper implementation would take a +rework of significant parts of mtools, but unfortunately I don't have +the time for this right now. The main downside of this implementation is +that it is inefficient on some architectures (several successive calls +to mtools, which defeats mtools' caching). + + ---------- Footnotes ---------- + + (1) To see the articles, search for `APlaceForYourStuff' using +Dejanews + + (2) I didn't know about this yet when I bought my own Zip drive. +Thus I ended up reformatting my tools disk, and hence I haven't had the +opportunity to test the password yet. If anybody still has their tools +disk with the original password, could you try it out? Thanks in advance + + +File: mtools.info, Node: Compiling mtools, Next: Porting mtools, Prev: Commands, Up: Top + +5 Architecture specific compilation flags +***************************************** + +To compile mtools, first invoke `./configure' before `make'. In +addition to the standard `autoconfigure' flags, there are two +architecture specific flags available. + +`./configure --enable-xdf' +`./configure --disable-xdf' + Enables support for XDF disks. This is on by default. *Note XDF::, + for details. + +`./configure --enable-vold' +`./configure --disable-vold' + Enables support for vold on Solaris. When used in conjunction with + vold, mtools should use different device nodes than for direct + access. + +`./configure --enable-new-vold' +`./configure --disable-new-vold' + Enables new support for vold on Solaris. This is supposed to work + more smoothly than the old support. + +`./configure --enable-floppyd' +`./configure --disable-floppyd' + Enables support for floppyd. By default, floppyd support is + enabled as long as the necessary X includes and libraries are + available. + + +File: mtools.info, Node: Porting mtools, Next: Command Index, Prev: Compiling mtools, Up: Top + +6 Porting mtools to architectures which are not supported yet +************************************************************* + +This chapter is only interesting for those who want to port mtools to +an architecture which is not yet supported. For most common systems, +default drives are already defined. If you want to add default drives +for a still unsupported system, run config.guess, to see which +identification autoconf uses for that system. This identification is of +the form cpu-vendor-os (for example sparc-sun-sunos). The cpu and the +os parts are passed to the compiler as preprocessor flags. The OS +part is passed to the compiler in three forms. + 1. The complete os name, with dots replaced by underscores. sco3.2v2 + would yield sco3_2v2 + + 2. The base os name. Sco3.2v2 would yield Sco + + 3. The base os name plus its major version. Sco3.2v2 would yield Sco3 + + All three versions are passed, if they are different. + + To define the devices, use the entries for the systems that are +already present as templates. In general, they have the following form: + + #if (defined (my_cpu) && defined(my_os)) + #define predefined_devices + struct device devices[] = { + { "/dev/first_drive", 'drive_letter', drive_description}, + ... + { "/dev/last_drive", 'drive_letter', drive_description} + } + #define INIT_NOOP + #endif + + "/dev/first_drive" is the name of the device or image file +representing the drive. Drive_letter is a letter ranging from a to z +giving access to the drive. Drive_description describes the type of the +drive: +`ED312' + extra density (2.88M) 3 1/2 disk + +`HD312' + high density 3 1/2 disk + +`DD312' + double density 3 1/2 disk + +`HD514' + high density 5 1/4 disk + +`DD514' + double density 5 1/4 disk + +`DDsmall' + 8 sector double density 5 1/4 disk + +`SS514' + single sided double density 5 1/4 disk + +`SSsmall' + single sided 8 sector double density 5 1/4 disk + +`GENFD' + generic floppy drive (12 bit FAT) + +`GENHD' + generic hard disk (16 bit FAT) + +`GEN' + generic device (all parameters match) + +`ZIPJAZ(flags)' + generic ZIP drive using normal access. This uses partition 4. + `Flags' are any special flags to be passed to open. + +`RZIPJAZ(flags)' + generic ZIP drive using raw SCSI access. This uses partition 4. + `Flags' are any special flags to be passed to open. + +`REMOTE' + the remote drive used for floppyd. Unlike the other items, this + macro also includes the file name ($DISPLAY) and the drive letter + (X) + + Entries may be described in more detail: + fat_bits,open_flags,cylinders,heads,sectors,DEF_ARG + or, if you need to describe an offset (filesystem doesn't start at +beginning of filesystem) + fat_bits, open_flags, cylinders, heads, sectors, offset, DEF_ARG0 + +`fat_bits' + is either 12, 16 or 0. 0 means that the device accepts both types + of FAT. + +`open_flags' + may include flags such as O_NDELAY, or O_RDONLY, which might be + necessary to open the device. 0 means no special flags are needed. + +`cylinders,heads,sectors' + describe the geometry of the disk. If cylinders is 0, the heads + and sectors parameters are ignored, and the drive accepts any + geometry. + +`offset' + is used if the DOS filesystem doesn't begin at the start of the + device or image file. This is mostly useful for Atari Ram disks + (which contain their device driver at the beginning of the file) + or for DOS emulator images (which may represent a partitioned + device. + + Definition of defaults in the devices file should only be done if +these same devices are found on a large number of hosts of this type. +In that case, could you also let me know about your new definitions, so +that I can include them into the next release. For purely local file, I +recommend that you use the `/usr/local/etc/mtools.conf' and +`~/.mtoolsrc' configuration files. + + However, the devices files also allows to supply geometry setting +routines. These are necessary if you want to access high capacity disks. + + Two routines should be supplied: + + 1. Reading the current parameters + static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) + + This probes the current configured geometry, and return it in the + structure generic_floppy_struct (which must also be declared). + Fd is an open file descriptor for the device, and buf is an already + filled in stat structure, which may be useful. This routine + should return 1 if the probing fails, and 0 otherwise. + + 2. Setting new parameters + static inline int set_parameters(int fd, struct generic_floppy_struct *floppy) + struct stat *buf) + This configures the geometry contained in floppy on the file + descriptor fd. Buf is the result of a stat call (already filled + in). This should return 1 if the new geometry cannot be + configured, and 0 otherwise. + + A certain number of preprocessor macros should also be supplied: + +`TRACKS(floppy)' + refers to the track field in the floppy structure + +`HEADS(floppy)' + refers to the heads field in the floppy structure + +`SECTORS(floppy)' + refers to the sectors per track field in the floppy structure + +`SECTORS_PER_DISK(floppy)' + refers to the sectors per disk field in the floppy structure (if + applicable, otherwise leave undefined) + +`BLOCK_MAJOR' + major number of the floppy device, when viewed as a block device + +`CHAR_MAJOR' + major number of the floppy device, when viewed as a character + device (a.k.a. "raw" device, used for fsck) (leave this undefined, + if your OS doesn't have raw devices) + + For the truly high capacity formats (XDF, 2m, etc), there is no clean +and documented interface yet. + + +File: mtools.info, Node: Command Index, Next: Variable Index, Prev: Porting mtools, Up: Top + +Command Index +************* + +[index] +* Menu: + +File: mtools.info, Node: Variable Index, Next: Concept Index, Prev: Command Index, Up: Top + +Variable index +************** + +[index] +* Menu: + +* cylinders: geometry description. (line 61) +* drive: general information. (line 6) +* exclusive: open flags. (line 6) +* fat_bits: misc variables. (line 11) +* file: location information. (line 10) +* filter: misc flags. (line 77) +* heads: geometry description. (line 65) +* mformat_only: misc flags. (line 73) +* MTOOLS_FAT_COMPATIBILITY: global variables. (line 6) +* MTOOLS_LOWER_CASE: global variables. (line 6) +* MTOOLS_NO_VFAT: global variables. (line 6) +* MTOOLS_SKIP_CHECK: global variables. (line 6) +* MTOOLSRC: Configuration. (line 9) +* nodelay: open flags. (line 6) +* sectors: geometry description. (line 68) +* sync: open flags. (line 6) +* tracks: geometry description. (line 61) +* use_xdf: misc flags. (line 68) + + +File: mtools.info, Node: Concept Index, Prev: Variable Index, Up: Top + +Concept index +************* + +[index] +* Menu: + +* 2m: 2m. (line 6) +* ALPHA patches: Location. (line 6) +* APlaceForYourStuff: mzip. (line 6) +* Archive bit: mattrib. (line 6) +* Atari: misc flags. (line 65) +* Atari Ram disk: location information. (line 28) +* Backwards compatibility: old style config. (line 6) +* Bad blocks: mbadblocks. (line 9) +* bigger sectors: bigger sectors. (line 6) +* blocksize: misc variables. (line 34) +* bugs: Location. (line 6) +* Case sensitivity: case sensitivity. (line 6) +* Changing file attributes: mattrib. (line 6) +* character devices: misc variables. (line 34) +* Checking configuration file: mtoolstest. (line 6) +* Clusters of a file: mshowfat. (line 6) +* Command list: Commands. (line 6) +* Compile time configuration: Compiling mtools. (line 6) +* Compiled-in defaults: Porting mtools. (line 6) +* Concatenating MS-DOS files: mcopy. (line 6) +* Configuration file: default values. (line 6) +* Configuration file name: config file location. (line 6) +* Configuration file name (parsing order): parsing order. (line 6) +* Configuration file parsing order: parsing order. (line 6) +* Configuration file syntax: general syntax. (line 6) +* Configuration file, old syntax: old style config. (line 6) +* Configuration files: Configuration. (line 9) +* Configuration of disk geometry: geometry description. (line 6) +* Copying an entire disk image: mcat. (line 9) +* Copying MS-DOS files: mcopy. (line 6) +* CR/LF conversions: mcopy. (line 6) +* Creating a directory: mmd. (line 6) +* Current working directory: directory. (line 6) +* Current working directory (changing the): mcd. (line 6) +* Default configuration: default values. (line 6) +* Default directory: directory. (line 6) +* Default directory (changing the): mcd. (line 6) +* Default values: default values. (line 6) +* Deleting a directory: mrd. (line 6) +* deleting an MS-DOS directory recursively: mdeltree. (line 6) +* deleting MS-DOS files: mdel. (line 6) +* Description of disk geometry: geometry description. (line 6) +* diffs: Location. (line 6) +* Directory: directory. (line 6) +* Directory (changing): mcd. (line 6) +* Directory creation: mmd. (line 6) +* Directory listing: mdir. (line 6) +* Directory removing: mrd. (line 6) +* disable locking: misc flags. (line 10) +* Disk Geometry: geometry description. (line 6) +* Disk image: mcat. (line 9) +* Disk label: mlabel. (line 6) +* DMF disks: more sectors. (line 6) +* Dosemu hard disk image: location information. (line 14) +* Drive configuration: per drive variables. (line 6) +* Drive configuration, example: general information. (line 6) +* Drive description: per drive variables. (line 6) +* Drive description, example: general information. (line 6) +* Drive independent configuration variables: global variables. (line 6) +* du: mdu. (line 6) +* Duplicate file names: name clashes. (line 6) +* Ejecting a Zip/Jaz disk: mzip. (line 6) +* Environmental variables: global variables. (line 6) +* Erasing a directory: mrd. (line 6) +* erasing an MS-DOS directory recursively: mdeltree. (line 6) +* erasing MS-DOS files: mdel. (line 6) +* exclusive access to a drive: open flags. (line 6) +* Executing commands before opening the device: misc variables. + (line 28) +* Fat: mshowfat. (line 6) +* fdformat: more sectors. (line 6) +* File name of device node: location information. (line 10) +* Filenames: arguments. (line 6) +* Filesystem creation: mformat. (line 6) +* floppyd: floppyd. (line 6) +* Floppyd cat: mcat. (line 9) +* floppyd_installtest: floppyd_installtest. (line 6) +* Format of disk: geometry description. (line 6) +* Formats, high capacity: high capacity formats. + (line 6) +* Formatting disks: mformat. (line 6) +* FreeDos: global variables. (line 6) +* getting parameters of a Dos fs: minfo. (line 6) +* Global configuration variables: global variables. (line 6) +* Hdimage: location information. (line 6) +* Hidden files: mattrib. (line 6) +* High capacity formats: high capacity formats. + (line 6) +* High capacity formats, mounting: mmount. (line 6) +* High density disk: geometry description. (line 6) +* Image file: location information. (line 10) +* Initializing disks: mformat. (line 6) +* Jaz disk (utilities): mzip. (line 6) +* Jaz disks (partitioning them): mpartition. (line 6) +* Jaz disks (partitions): location information. (line 14) +* Jaz disks (raw Scsi access): misc flags. (line 16) +* Labeling a disk: mlabel. (line 6) +* Linux enhancements (High Capacity Formats): high capacity formats. + (line 6) +* Linux enhancements (mmount): mmount. (line 6) +* List of available commands: Commands. (line 6) +* Listing a directory: mdir. (line 6) +* Listing space occupied by directories and files: mdu. (line 6) +* Location of configuration files: config file location. (line 6) +* Location of configuration files (parsing order): parsing order. + (line 6) +* locking (disabling it): misc flags. (line 10) +* Long file name: long names. (line 6) +* Low density disk: geometry description. (line 6) +* Magneto-optical disks: location information. (line 14) +* mailing list: Location. (line 6) +* Making a directory: mmd. (line 6) +* Marking blocks as bad: mbadblocks. (line 9) +* mattrib: mattrib. (line 6) +* mbadblocks: mbadblocks. (line 9) +* mcat: mcat. (line 9) +* mcd: mcd. (line 6) +* mcd (introduction): directory. (line 6) +* mclasserase: mclasserase. (line 6) +* mcopy: mcopy. (line 6) +* Mcwd file: mcd. (line 6) +* mdel: mdel. (line 6) +* mdeltree: mdeltree. (line 6) +* mdir: mdir. (line 6) +* mdu: mdu. (line 6) +* Memory Card: mclasserase. (line 6) +* mformat: mformat. (line 6) +* mformat (geometry used for): geometry description. (line 6) +* mformat parameters: minfo. (line 6) +* minfo: minfo. (line 6) +* mkmanifest: mkmanifest. (line 6) +* mlabel: mlabel. (line 6) +* mmd: mmd. (line 6) +* mmount: mmount. (line 6) +* mmove: mmove. (line 6) +* Mounting a disk: mmount. (line 6) +* Moving files (mmove): mmove. (line 6) +* Moving files (mren): mren. (line 6) +* mpartition: mpartition. (line 6) +* mrd: mrd. (line 6) +* mren: mren. (line 6) +* mshowfat: mshowfat. (line 6) +* mtoolstest: mtoolstest. (line 6) +* mzip: mzip. (line 6) +* Name clashes: name clashes. (line 6) +* Name of configuration files: config file location. (line 6) +* Name of configuration files (parsing order): parsing order. (line 6) +* Name of device node: location information. (line 10) +* Occupation of space by directories and files: mdu. (line 6) +* Odd formats: high capacity formats. + (line 6) +* Old configuration file syntax: old style config. (line 6) +* open flags: open flags. (line 6) +* Options: arguments. (line 6) +* OS/2 (layout of removable media): location information. (line 14) +* OS/2 (XDF disks): XDF. (line 6) +* Overwriting files: name clashes. (line 6) +* packing list: mkmanifest. (line 6) +* Parsing order: parsing order. (line 6) +* Partitioned image file: location information. (line 14) +* partitions (creating): mpartition. (line 6) +* password protected Zip disks: mzip. (line 6) +* patches: Location. (line 6) +* Physically erase: mclasserase. (line 6) +* plain floppy: device xxx busy: misc flags. (line 10) +* Porting: Porting mtools. (line 6) +* Primary file name (long names): long names. (line 6) +* Primary file name (name clashes): name clashes. (line 6) +* Ram disk: location information. (line 28) +* raw device: misc variables. (line 34) +* Read errors: mbadblocks. (line 9) +* Read-only files (changing the attribute): mattrib. (line 6) +* Read-only files (listing them): mdir. (line 6) +* Reading MS-DOS files: mcopy. (line 6) +* recursively removing an MS-DOS directory: mdeltree. (line 6) +* remote floppy access <1>: floppyd_installtest. (line 6) +* remote floppy access: floppyd. (line 6) +* Removable media: location information. (line 14) +* Removing a directory: mrd. (line 6) +* removing an MS-DOS directory recursively: mdeltree. (line 6) +* removing MS-DOS files: mdel. (line 6) +* Renaming files (mmove): mmove. (line 6) +* Renaming files (mren): mren. (line 6) +* SCSI devices: misc flags. (line 16) +* Secondary file name (long names): long names. (line 6) +* Secondary file name (name clashes): name clashes. (line 6) +* setgid installation: misc flags. (line 40) +* setuid installation: misc flags. (line 40) +* setuid installation (needed for raw SCSI I/O): misc flags. (line 16) +* Solaris (compile time configuration of vold): Compiling mtools. + (line 6) +* Solaris (Raw access to SCSI devices such as Zip & Jaz): misc flags. + (line 16) +* Solaris (volcheck): misc variables. (line 28) +* Solaris (vold): misc flags. (line 57) +* Space occupied by directories and files: mdu. (line 6) +* Special formats: high capacity formats. + (line 6) +* Subdirectory creation: mmd. (line 6) +* Subdirectory removing: mrd. (line 6) +* SunOS (Raw access to SCSI devices such as Zip & Jaz): misc flags. + (line 16) +* synchronous writing: open flags. (line 6) +* Syntax of the configuration file: general syntax. (line 6) +* Syquest disks: location information. (line 14) +* Syquests (raw Scsi access): misc flags. (line 16) +* System files: mattrib. (line 6) +* Testing configuration file for correctness: mtoolstest. (line 6) +* Text files: mcopy. (line 6) +* Tools disk (Zip and Jaz drives): mzip. (line 6) +* Verifying configuration file: mtoolstest. (line 6) +* VFAT-style file names: long names. (line 6) +* vgacopy: more sectors. (line 6) +* Vold (compile time configuration): Compiling mtools. (line 6) +* Vold (mediamgr): misc flags. (line 57) +* Weird formats: high capacity formats. + (line 6) +* Windows 95 (DMF disks): more sectors. (line 6) +* Windows 95-style file names: long names. (line 6) +* Windows NT (layout of removable media): location information. + (line 14) +* Wordswapped: misc flags. (line 65) +* Working directory <1>: mcd. (line 6) +* Working directory: directory. (line 6) +* Write protecting a Zip/Jaz disk: mzip. (line 6) +* Writing MS-DOS files: mcopy. (line 6) +* X terminal <1>: floppyd_installtest. (line 6) +* X terminal: floppyd. (line 6) +* XDF disks: XDF. (line 6) +* XDF disks (compile time configuration): Compiling mtools. (line 6) +* XDF disks (how to configure): misc flags. (line 68) +* Zip disk (utilities): mzip. (line 6) +* Zip disks (partitioning them): mpartition. (line 6) +* Zip disks (partitions): location information. (line 14) +* Zip disks (raw Scsi access): misc flags. (line 16) +* ZipTools disk: mzip. (line 6) + + + +Tag Table: +Node: Top869 +Node: Location2948 +Node: Common features4334 +Node: arguments5098 +Node: drive letters6752 +Node: directory8104 +Node: long names8548 +Node: name clashes11094 +Node: case sensitivity13377 +Node: high capacity formats14601 +Node: more sectors15704 +Node: bigger sectors16753 +Node: 2m17475 +Node: XDF18646 +Node: exit codes19972 +Node: bugs20608 +Node: Configuration21140 +Node: config file location22264 +Node: general syntax22691 +Node: default values23511 +Node: global variables24038 +Node: per drive variables26118 +Node: general information26935 +Node: location information27376 +Node: geometry description28879 +Node: open flags32731 +Node: misc variables33321 +Node: misc flags35364 +Node: multiple descriptions38999 +Node: parsing order40660 +Node: old style config41832 +Node: Commands42520 +Node: floppyd44387 +Node: floppyd_installtest49171 +Node: mattrib49802 +Node: mbadblocks51595 +Node: mcat52234 +Node: mcd53044 +Node: mclasserase53904 +Node: mcopy54580 +Node: mdel57601 +Node: mdeltree57938 +Node: mdir58354 +Node: mdu59627 +Node: mformat60133 +Node: mkmanifest66700 +Node: minfo68672 +Node: mlabel69230 +Node: mmd70307 +Node: mmount70653 +Node: mmove71249 +Node: mpartition72051 +Node: mrd75573 +Node: mren75928 +Node: mshowfat76671 +Node: mtoolstest76889 +Node: mtype77459 +Node: mzip78310 +Ref: mzip-Footnote-180335 +Ref: mzip-Footnote-280411 +Node: Compiling mtools80697 +Node: Porting mtools81792 +Node: Command Index87707 +Node: Variable Index87855 +Node: Concept Index89320 + +End Tag Table diff --git a/mtools.spec b/mtools.spec new file mode 100644 index 0000000..d38619d --- /dev/null +++ b/mtools.spec @@ -0,0 +1,128 @@ +Summary: mtools, read/write/list/format DOS disks under Unix +Name: mtools +Version: 4.0.12 +Release: 1 +Group: Utilities/System +URL: http://mtools.linux.lu +Source0: mtools-%{version}.tar.gz +#Patch1: mtools-%{version}-20071226.diff.gz +Buildroot: %{_tmppath}/%{name}-%{version}-buildroot +License: GPL +%description +Mtools is a collection of utilities to access MS-DOS disks from GNU +and Unix without mounting them. It supports long file names, OS/2 Xdf +disks, ZIP/JAZ disks and 2m disks (store up to 1992k on a high density +3 1/2 disk). + + +%prep +%setup -q +#%patch1 -p1 +./configure --prefix=%{buildroot}%{_prefix} --sysconfdir=/etc --infodir=%{buildroot}%{_infodir} --mandir=%{buildroot}%{_mandir} --enable-floppyd + +%build +make + +%clean +[ X%{buildroot} != X ] && [ X%{buildroot} != X/ ] && rm -r %{buildroot} + +%install +make install +make install-info +strip %{buildroot}%{_bindir}/mtools %{buildroot}%{_bindir}/mkmanifest %{buildroot}%{_bindir}/floppyd +rm %{buildroot}%{_infodir}/dir + +%files +%defattr(-,root,root) +%{_infodir}/mtools.info* +%{_mandir}/man1/floppyd.1* +%{_mandir}/man1/floppyd_installtest.1.gz +%{_mandir}/man1/mattrib.1* +%{_mandir}/man1/mbadblocks.1* +%{_mandir}/man1/mcat.1* +%{_mandir}/man1/mcd.1* +%{_mandir}/man1/mclasserase.1* +%{_mandir}/man1/mcopy.1* +%{_mandir}/man1/mdel.1* +%{_mandir}/man1/mdeltree.1* +%{_mandir}/man1/mdir.1* +%{_mandir}/man1/mdu.1* +%{_mandir}/man1/mformat.1* +%{_mandir}/man1/minfo.1* +%{_mandir}/man1/mkmanifest.1* +%{_mandir}/man1/mlabel.1* +%{_mandir}/man1/mmd.1* +%{_mandir}/man1/mmount.1* +%{_mandir}/man1/mmove.1* +%{_mandir}/man1/mpartition.1* +%{_mandir}/man1/mrd.1* +%{_mandir}/man1/mren.1* +%{_mandir}/man1/mshowfat.1* +%{_mandir}/man1/mtools.1* +%{_mandir}/man5/mtools.5* +%{_mandir}/man1/mtoolstest.1* +%{_mandir}/man1/mtype.1* +%{_mandir}/man1/mzip.1* +%{_bindir}/amuFormat.sh +%{_bindir}/mattrib +%{_bindir}/mbadblocks +%{_bindir}/mcat +%{_bindir}/mcd +%{_bindir}/mclasserase +%{_bindir}/mcopy +%{_bindir}/mdel +%{_bindir}/mdeltree +%{_bindir}/mdir +%{_bindir}/mdu +%{_bindir}/mformat +%{_bindir}/minfo +%{_bindir}/mkmanifest +%{_bindir}/mlabel +%{_bindir}/mmd +%{_bindir}/mmount +%{_bindir}/mmove +%{_bindir}/mpartition +%{_bindir}/mrd +%{_bindir}/mren +%{_bindir}/mshowfat +%{_bindir}/mtools +%{_bindir}/mtoolstest +%{_bindir}/mtype +%{_bindir}/mzip +%{_bindir}/floppyd +%{_bindir}/floppyd_installtest +%{_bindir}/mcheck +%{_bindir}/mcomp +%{_bindir}/mxtar +%{_bindir}/tgz +%{_bindir}/uz +%{_bindir}/lz + +%pre +groupadd floppy 2>/dev/null || echo -n "" + +%post +if [ -f %{_bindir}/install-info ] ; then + if [ -f %{_infodir}/dir ] ; then + %{_bindir}/install-info %{_infodir}/mtools.info %{_infodir}/dir + fi + if [ -f %{_infodir}/dir.info ] ; then + %{_bindir}/install-info %{_infodir}/mtools.info %{_infodir}/dir.info + fi +fi + + +%preun +install-info --delete %{_infodir}/mtools.info %{_infodir}/dir.info +if [ -f %{_bindir}/install-info ] ; then + if [ -f %{_infodir}/dir ] ; then + %{_bindir}/install-info --delete %{_infodir}/mtools.info %{_infodir}/dir + fi + if [ -f %{_infodir}/dir.info ] ; then + %{_bindir}/install-info --delete %{_infodir}/mtools.info %{_infodir}/dir.info + fi +fi + +%changelog +* Tue Nov 03 2009 Alain Knaff +- Mingw compatibility fixes diff --git a/mtools.texi b/mtools.texi new file mode 100644 index 0000000..250d195 --- /dev/null +++ b/mtools.texi @@ -0,0 +1,2589 @@ +\input texinfo @c -*-texinfo-*- +@comment %**start of header +@setfilename mtools.info +@include version.texi +@settitle Mtools @value{VERSION} +@syncodeindex pg cp +@comment %**end of header + +@comment MANskip 5 + +@copying +This manual is for Mtools (version @value{VERSION}, @value{UPDATED}), +which is a collection of tools to allow Unix systems to manipulate +MS-DOS files. + +Copyright @copyright{} 2007, 2009 Free Software Foundation, Inc. +Copyright @copyright{} 1996-2005,2007-2009 Alain Knaff. + +@quotation +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +Texts. A copy of the license is included in the section entitled +``GNU Free Documentation License''. +@end quotation +@end copying + +@ignore +@unnumbered Name +mtools - utilities to access DOS disks in Unix. +@end ignore + +@iftex +@finalout +@end iftex + +@dircategory DOS +@direntry +* Mtools: (mtools). Mtools: utilities to access DOS disks in Unix. +@end direntry + + +@titlepage +@title Mtools + +@c The following two commands start the copyright page. +@page +@vskip 0pt plus 1filll +@insertcopying +@end titlepage + +@c Output the table contents at the beginning +@contents + +@ifnottex +@node Top, Location, (dir), (dir) +@top Mtools doc + +This is mtools' documentation. +@end ifnottex + +@comment MANstart 1 + +@unnumbered Introduction +Mtools is a collection of tools to allow Unix systems to manipulate +MS-DOS files: read, write, and move around files on an MS-DOS +filesystem (typically a floppy disk). Where reasonable, each program +attempts to emulate the MS-DOS equivalent command. However, +unnecessary restrictions and oddities of DOS are not emulated. For +instance, it is possible to move subdirectories from one subdirectory +to another. + +Mtools is sufficient to give access to MS-DOS filesystems. For +instance, commands such as @code{mdir a:} work on the @code{a:} floppy +without any preliminary mounting or initialization (assuming the default +@file{/etc/mtools.conf} works on your machine). With mtools, one can +change floppies too without unmounting and mounting. + +@insertcopying + +@menu +* Location:: Where to find mtools and early bug fixes +* Common features:: Common features of all mtools commands +* Configuration:: How to configure mtools for your environment +* Commands:: The available mtools commands +* Compiling mtools:: Architecture specific compilation flags +* Porting mtools:: Porting mtools to architectures which are not + yet supported + +* Command Index:: Command Index +* Variable Index:: Variable Index +* Concept Index:: Concept Index +@end menu + +@node Location, Common features, Top, Top +@chapter Where to get mtools +@cindex bugs +@cindex ALPHA patches +@cindex patches +@cindex diffs +@cindex mailing list + +Mtools can be found at the following places (and their mirrors): +@example +http://ftp.gnu.org/gnu/mtools/mtools-@value{VERSION}.tar.gz +http://mtools.linux.lu/mtools-@value{VERSION}.tar.gz +ftp://www.tux.org/pub/knaff/mtools/mtools-@value{VERSION}.tar.gz +ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-@value{VERSION}.tar.gz +@end example + +Before reporting a bug, make sure that it has not yet been fixed in the +Alpha patches which can be found at: +@example +http://ftp.gnu.org/gnu/mtools/ +http://mtools.linux.lu/ +ftp://www.tux.org/pub/knaff/mtools +@end example + +These patches are named +@code{mtools-}@var{version}@code{-}@var{ddmm}@code{.taz}, where version +stands for the base version, @var{dd} for the day and @var{mm} for the +month. Due to a lack of space, I usually leave only the most recent +patch. + +There is an mtools mailing list at mtools @@ tux.org . Please +send all bug reports to this list. You may subscribe to the list by +sending a message with 'subscribe mtools @@ tux.org' in its +body to majordomo @@ tux.org . (N.B. Please remove the spaces +around the "@@" both times. I left them there in order to fool +spambots.) Announcements of new mtools versions will also be sent to +the list, in addition to the linux announce newsgroups. The mailing +list is archived at http://lists.gnu.org/pipermail/info-mtools/ + + +@node Common features, Configuration, Location, Top +@chapter Common features of all mtools commands + +@menu +* arguments:: What the command line parameters of mtools + mean +* drive letters:: Which drives are defined by default +* directory:: Current working directory +* long names:: VFAT-style long filenames +* name clashes:: Name clash handling, and associated command + line options +* case sensitivity:: Case sensitivity +* high capacity formats:: How to fit more data on your floppies +* exit codes:: Exit codes +* bugs:: Happens to everybody +@end menu + +@node arguments, drive letters, Common features, Common features +@section Options and filenames +@cindex Filenames +@cindex Options +MS-DOS filenames are composed of a drive letter followed by a colon, a +subdirectory, and a filename. Only the filename part is mandatory, the +drive letter and the subdirectory are optional. Filenames without a +drive letter refer to Unix files. Subdirectory names can use either the +'@code{/}' or '@code{\}' separator. The use of the '@code{\}' separator +or wildcards requires the names to be enclosed in quotes to protect them +from the shell. However, wildcards in Unix filenames should not be +enclosed in quotes, because here we @strong{want} the shell to expand +them. + +The regular expression "pattern matching" routines follow the Unix-style +rules. For example, `@code{*}' matches all MS-DOS files in lieu of +`@code{*.*}'. The archive, hidden, read-only and system attribute bits +are ignored during pattern matching. + +All options use the @code{-} (minus) as their first character, not +@code{/} as you'd expect in MS-DOS. + +Most mtools commands allow multiple filename parameters, which +doesn't follow MS-DOS conventions, but which is more user-friendly. + +Most mtools commands allow options that instruct them how to handle file +name clashes. @xref{name clashes}, for more details on these. All +commands accept the @code{-V} flags which prints the version, and most +accept the @code{-v} flag, which switches on verbose mode. In verbose +mode, these commands print out the name of the MS-DOS files upon which +they act, unless stated otherwise. @xref{Commands}, for a description of +the options which are specific to each command. + + +@node drive letters, directory, arguments, Common features +@section Drive letters + +The meaning of the drive letters depends on the target architectures. +However, on most target architectures, drive A is the first floppy +drive, drive B is the second floppy drive (if available), drive J is a +Jaz drive (if available), and drive Z is a Zip drive (if available). On +those systems where the device name is derived from the SCSI id, the Jaz +drive is assumed to be at Scsi target 4, and the Zip at Scsi target 5 +(factory default settings). On Linux, both drives are assumed to be the +second drive on the Scsi bus (/dev/sdb). The default settings can be +changes using a configuration file (@pxref{Configuration}). + +The drive letter : (colon) has a special meaning. It is used to access +image files which are directly specified on the command line using the +@code{-i} options. + +Example: +@example + mcopy -i my-image-file.bin ::file1 ::file2 . +@end example + +This copies @code{file1} and @code{file2} from the image file +(@code{my-image-file.bin}) to the @code{/tmp} directory. + +You can also supply an offset within the image file by including +@code{@@@@}@var{offset} into the file name. + +Example: +@example + mcopy -i my-image-file.bin@@@@1M ::file1 ::file2 . +@end example + +This looks for the image at the offset of 1M in the file, rather than +at its beginning. + +@node directory, long names, drive letters, Common features +@section Current working directory +@pindex mcd (introduction) +@cindex Directory +@cindex Working directory +@cindex Current working directory +@cindex Default directory + +The @code{mcd} command (@ref{mcd}) is used to establish the device and +the current working directory (relative to the MS-DOS filesystem), +otherwise the default is assumed to be @code{A:/}. However, unlike +MS-DOS, there is only one working directory for all drives, and not one +per drive. + +@node long names, name clashes, directory, Common features +@section VFAT-style long file names +@cindex Long file name +@cindex Windows 95-style file names +@cindex VFAT-style file names +@cindex Primary file name (long names) +@cindex Secondary file name (long names) + +This version of mtools supports VFAT style long filenames. If a Unix +filename is too long to fit in a short DOS name, it is stored as a +VFAT long name, and a companion short name is generated. This short +name is what you see when you examine the disk with a pre-7.0 version +of DOS. + The following table shows some examples of short names: + +@example +Long name MS-DOS name Reason for the change +--------- ---------- --------------------- +thisisatest THISIS~1 filename too long +alain.knaff ALAIN~1.KNA extension too long +prn.txt PRN~1.TXT PRN is a device name +.abc ABC~1 null filename +hot+cold HOT_CO~1 illegal character +@end example + + As you see, the following transformations happen to derive a short +name: +@itemize @bullet +@item +Illegal characters are replaced by underscores. The illegal characters +are @code{;+=[]',\"*\\<>/?:|}. +@item +Extra dots, which cannot be interpreted as a main name/extension +separator are removed +@item +A @code{~}@var{n} number is generated, +@item +The name is shortened so as to fit in the 8+3 limitation +@end itemize + + The initial Unix-style file name (whether long or short) is also called +the @dfn{primary} name, and the derived short name is also called the +@dfn{secondary} name. + + Example: +@example + mcopy /etc/motd a:Reallylongname +@end example + Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as +a short name. Reallylongname is the primary name, and REALLYLO is the +secondary name. +@example + mcopy /etc/motd a:motd +@end example + Motd fits into the DOS filename limits. Mtools doesn't need to +derivate another name. Motd is the primary name, and there is no +secondary name. + + In a nutshell: The primary name is the long name, if one exists, or +the short name if there is no long name. + + Although VFAT is much more flexible than FAT, there are still names +that are not acceptable, even in VFAT. There are still some illegal +characters left (@code{\"*\\<>/?:|}), and device names are still +reserved. + +@example +Unix name Long name Reason for the change +--------- ---------- --------------------- +prn prn-1 PRN is a device name +ab:c ab_c-1 illegal character +@end example + + As you see, the following transformations happen if a long name is +illegal: +@itemize @bullet +@item +Illegal characters are replaces by underscores, +@item +A @code{-}@var{n} number is generated, +@end itemize + +@node name clashes, case sensitivity, long names, Common features +@section Name clashes +@cindex Name clashes +@cindex Duplicate file names +@cindex Overwriting files +@cindex Primary file name (name clashes) +@cindex Secondary file name (name clashes) + +When writing a file to disk, its long name or short name may collide +with an already existing file or directory. This may happen for all +commands which create new directory entries, such as @code{mcopy}, +@code{mmd}, @code{mren}, @code{mmove}. When a name clash happens, mtools +asks you what it should do. It offers several choices: + +@table @code +@item overwrite +Overwrites the existing file. It is not possible to overwrite a +directory with a file. +@item rename +Renames the newly created file. Mtools prompts for the new filename +@item autorename +Renames the newly created file. Mtools chooses a name by itself, without +prompting +@item skip +Gives up on this file, and moves on to the next (if any) +@end table + +To chose one of these actions, type its first letter at the prompt. If +you use a lower case letter, the action only applies for this file only, +if you use an upper case letter, the action applies to all files, and +you won't be prompted again. + +You may also chose actions (for all files) on the command line, when +invoking mtools: + +@table @code +@item -D o +Overwrites primary names by default. +@item -D O +Overwrites secondary names by default. +@item -D r +Renames primary name by default. +@item -D R +Renames secondary name by default. +@item -D a +Autorenames primary name by default. +@item -D A +Autorenames secondary name by default. +@item -D s +Skip primary name by default. +@item -D S +Skip secondary name by default. +@item -D m +Ask user what to do with primary name. +@item -D M +Ask user what to do with secondary name. +@end table + +Note that for command line switches lower/upper differentiates between +primary/secondary name whereas for interactive choices, lower/upper +differentiates between just-this-time/always. + +The primary name is the name as displayed in Windows 95 or Windows NT: +i.e. the long name if it exists, and the short name otherwise. The +secondary name is the "hidden" name, i.e. the short name if a long name +exists. + +By default, the user is prompted if the primary name clashes, and the +secondary name is autorenamed. + +If a name clash occurs in a Unix directory, mtools only asks whether +to overwrite the file, or to skip it. + +@node case sensitivity, high capacity formats, name clashes, Common features +@section Case sensitivity of the VFAT filesystem +@cindex Case sensitivity + +The VFAT filesystem is able to remember the case of the +filenames. However, filenames which differ only in case are not allowed +to coexist in the same directory. For example if you store a file called +LongFileName on a VFAT filesystem, mdir shows this file as LongFileName, +and not as Longfilename. However, if you then try to add LongFilename to +the same directory, it is refused, because case is ignored for clash +checks. + +The VFAT filesystem allows to store the case of a filename in the +attribute byte, if all letters of the filename are the same case, and if +all letters of the extension are the same case too. Mtools uses this +information when displaying the files, and also to generate the Unix +filename when mcopying to a Unix directory. This may have unexpected +results when applied to files written using an pre-7.0 version of DOS: +Indeed, the old style filenames map to all upper case. This is different +from the behavior of the old version of mtools which used to generate +lower case Unix filenames. + +@node high capacity formats, exit codes, case sensitivity, Common features +@section high capacity formats +@cindex Special formats +@cindex High capacity formats +@cindex Odd formats +@cindex Weird formats +@cindex Formats, high capacity +@cindex Linux enhancements (High Capacity Formats) + +Mtools supports a number of formats which allow to store more data on +disk as usual. Due to different operating system abilities, these +formats are not supported on all OS'es. Mtools recognizes these formats +transparently where supported. + +In order to format these disks, you need to use an operating system +specific tool. For Linux, suitable floppy tools can be found in the +@code{fdutils} package at the following locations~: +@example +@code{ftp://www.tux.org/pub/knaff/fdutils/}. +@code{ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-*} +@end example + +See the manpages included in that package for further detail: Use +@code{superformat} to format all formats except XDF, and use +@code{xdfcopy} to format XDF. + +@menu +* more sectors:: Putting more sectors per track on the disk +* bigger sectors:: Use bigger sectors to save header space +* 2m:: Use a standard first track +* XDF:: OS/2's eXtended density format +@end menu + +@node more sectors, bigger sectors, high capacity formats, high capacity formats +@subsection More sectors +@cindex fdformat +@cindex vgacopy +@cindex DMF disks +@cindex Windows 95 (DMF disks) + +The oldest method of fitting more data on a disk is to use more sectors +and more cylinders. Although the standard format uses 80 cylinders and +18 sectors (on a 3 1/2 high density disk), it is possible to use up to +83 cylinders (on most drives) and up to 21 sectors. This method allows +to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are +twice as slow as the standard 18 sector disks because the sectors are +packed so close together that we need to interleave them. This problem +doesn't exist for 20 sector formats. + +These formats are supported by numerous DOS shareware utilities such as +@code{fdformat} and @code{vgacopy}. In his infinite hybris, Bill Gate$ +believed that he invented this, and called it @samp{DMF disks}, or +@samp{Windows formatted disks}. But in reality, it has already existed +years before! Mtools supports these formats on Linux, on SunOs and on +the DELL Unix PC. + +@node bigger sectors, 2m, more sectors, high capacity formats +@subsection Bigger sectors +@cindex bigger sectors +By using bigger sectors it is possible to go beyond the capacity which +can be obtained by the standard 512-byte sectors. This is because of the +sector header. The sector header has the same size, regardless of how +many data bytes are in the sector. Thus, we save some space by using +@emph{fewer}, but bigger sectors. For example, 1 sector of 4K only takes +up header space once, whereas 8 sectors of 512 bytes have also 8 +headers, for the same amount of useful data. + +This method allows to store up to 1992K on a 3 1/2 HD disk. + +Mtools supports these formats only on Linux. + +@node 2m, XDF, bigger sectors, high capacity formats +@subsection 2m +@cindex 2m + +The 2m format was originally invented by Ciriaco Garcia de Celis. It +also uses bigger sectors than usual in order to fit more data on the +disk. However, it uses the standard format (18 sectors of 512 bytes +each) on the first cylinder, in order to make these disks easyer to +handle by DOS. Indeed this method allows to have a standard sized +bootsector, which contains a description of how the rest of the disk +should be read. + +However, the drawback of this is that the first cylinder can hold less +data than the others. Unfortunately, DOS can only handle disks where +each track contains the same amount of data. Thus 2m hides the fact that +the first track contains less data by using a @dfn{shadow +FAT}. (Usually, DOS stores the FAT in two identical copies, for +additional safety. XDF stores only one copy, and it tells DOS that it +stores two. Thus the same that would be taken up by the second FAT copy +is saved.) This also means that your should @strong{never use a 2m disk +to store anything else than a DOS fs}. + +Mtools supports these format only on Linux. + +@node XDF, , 2m, high capacity formats +@subsection XDF +@cindex XDF disks +@cindex OS/2 (XDF disks) + +XDF is a high capacity format used by OS/2. It can hold 1840 K per +disk. That's lower than the best 2m formats, but its main advantage is +that it is fast: 600 milliseconds per track. That's faster than the 21 +sector format, and almost as fast as the standard 18 sector format. In +order to access these disks, make sure mtools has been compiled with XDF +support, and set the @code{use_xdf} variable for the drive in the +configuration file. @xref{Compiling mtools}, and @ref{misc variables}, +for details on how to do this. Fast XDF access is only available for +Linux kernels which are more recent than 1.1.34. + +Mtools supports this format only on Linux. + +@strong{Caution / Attention distributors}: If mtools is compiled on a +Linux kernel more recent than 1.3.34, it won't run on an older +kernel. However, if it has been compiled on an older kernel, it still +runs on a newer kernel, except that XDF access is slower. It is +recommended that distribution authors only include mtools binaries +compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will +be out, mtools binaries compiled on newer kernels may (and should) be +distributed. Mtools binaries compiled on kernels older than 1.3.34 won't +run on any 2.1 kernel or later. + +@node exit codes, bugs, high capacity formats, Common features +@section Exit codes +All the Mtools commands return 0 on success, 1 on utter failure, or 2 +on partial failure. All the Mtools commands perform a few sanity +checks before going ahead, to make sure that the disk is indeed an +MS-DOS disk (as opposed to, say an ext2 or minix disk). These checks +may reject partially corrupted disks, which might otherwise still be +readable. To avoid these checks, set the MTOOLS_SKIP_CHECK +environmental variable or the corresponding configuration file variable +(@pxref{global variables}) +@node bugs, , exit codes, Common features +@section Bugs +An unfortunate side effect of not guessing the proper device (when +multiple disk capacities are supported) is an occasional error message +from the device driver. These can be safely ignored. + +The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7 +mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the +corresponding configuration file variable, @ref{global variables}) to +bypass the fat checking. + +@comment MANskip 1 + +@ignore +@unnumbered Name +mtools.conf - mtools configuration files + +@comment MANend-skip 5 +@section Description + +This manpage describes the configuration files for mtools. They +@comment MANskip 5 +@end ignore + + +@node Configuration, Commands, Common features, Top + + +@chapter How to configure mtools for your environment +@section Description +@cindex Configuration files +@vindex MTOOLSRC + + This sections explains the syntax of the configurations files for +mtools. The configuration files +@comment MANend-skip 5 +are called @file{/usr/local/etc/mtools.conf} and @file{~/.mtoolsrc}. If +the environmental variable @code{MTOOLSRC} is set, its contents is used +as the filename for a third configuration file. These configuration +files describe the following items: + +@itemize @bullet +@item Global configuration flags and variables +@item Per drive flags and variables +@end itemize + + +@menu +* config file location:: Where mtools looks for its configuration files +* general syntax:: The layout of the configuration files +* default values:: Why you don't need a config file in most cases +* global variables:: Variables that are independent of the drive +* per drive variables:: Variables that are specific to a given drive +* parsing order:: Location of configuration files and parsing order +* old style config:: Backwards compatibility +@end menu + +@node config file location, general syntax, Configuration, Configuration +@section Location of the configuration files + +@cindex Configuration file name +@cindex Name of configuration files +@cindex Location of configuration files + +@file{/usr/local/etc/mtools.conf} is the system-wide configuration file, +and @file{~/.mtoolsrc} is the user's private configuration file. + +On some systems, the system-wide configuration file is called +@file{/etc/default/mtools.conf} instead. + + +@node general syntax, default values, config file location, Configuration +@subsection General configuration file syntax +@cindex Syntax of the configuration file +@cindex Configuration file syntax + +The configuration files is made up of sections. Each section starts +with a keyword identifying the section followed by a colon. +Then follow variable assignments and flags. Variable assignments take +the following form: +@display +name=value +@end display +Flags are lone keywords without an equal sign and value following +them. A section either ends at the end of the file or where the next +section begins. + +Lines starting with a hash (@code{#}) are comments. Newline characters +are equivalent to whitespace (except where ending a comment). The +configuration file is case insensitive, except for item enclosed in +quotes (such as filenames). + +@node default values, global variables, general syntax, Configuration +@section Default values +@cindex Default values +@cindex Default configuration +@cindex Configuration file +For most platforms, mtools contains reasonable compiled-in defaults for +physical floppy drives. Thus, you usually don't need to bother with the +configuration file, if all you want to do with mtools is to access your +floppy drives. On the other hand, the configuration file is needed if +you also want to use mtools to access your hard disk partitions and +dosemu image files. + +@node global variables, per drive variables, default values, Configuration +@section Global variables +@cindex Global configuration variables +@cindex Drive independent configuration variables +@cindex Environmental variables +@vindex MTOOLS_SKIP_CHECK +@vindex MTOOLS_FAT_COMPATIBILITY +@vindex MTOOLS_LOWER_CASE +@vindex MTOOLS_NO_VFAT +@cindex FreeDos + +Global flags may be set to 1 or to 0. + +The following global flags are recognized: + +@table @code +@item MTOOLS_SKIP_CHECK +If this is set to 1, mtools skips most of its sanity checks. This is +needed to read some Atari disks which have been made with the earlier +ROMs, and which would not be recognized otherwise. +@item MTOOLS_FAT_COMPATIBILITY +If this is set to 1, mtools skips the fat size checks. Some disks have +a bigger FAT than they really need to. These are rejected if this +option is not set. +@item MTOOLS_LOWER_CASE +If this is set to 1, mtools displays all-upper-case short filenames as +lowercase. This has been done to allow a behavior which is consistent +with older versions of mtools which didn't know about the case bits. +@item MTOOLS_NO_VFAT +If this is set to 1, mtools won't generate VFAT entries for filenames +which are mixed-case, but otherwise legal dos filenames. This is useful +when working with DOS versions which can't grok VFAT longnames, such as +FreeDos. +@item MTOOLS_DOTTED_DIR +In a wide directory, prints the short name with a dot instead of spaces +separating the basename and the extension. +@item MTOOLS_NAME_NUMERIC_TAIL +If this is set to one (default), generate numeric tails for all long +names (~1). If set to zero, only generate numeric tails if otherwise a +clash would have happened. +@item MTOOLS_TWENTY_FOUR_HOUR_CLOCK +If 1, uses the European notation for times (twenty four hour clock), +else uses the UK/US notation (am/pm) +@end table + +Example: +Inserting the following line into your configuration file instructs +mtools to skip the sanity checks: +@example + MTOOLS_SKIP_CHECK=1 +@end example + +Global variables may also be set via the environment: +@example + export MTOOLS_SKIP_CHECK=1 +@end example + +Global string variables may be set to any value: +@table @code +@item MTOOLS_DATE_STRING +The format used for printing dates of files. By default, is dd-mm-yyyy. +@end table + +@node per drive variables, parsing order, global variables, Configuration +@section Per drive flags and variables +@cindex Drive description +@cindex Drive configuration + +@menu +* general information:: What a drive description looks like +* location information:: Where is the drive data physically stored +* geometry description:: Describes the physical characteristics of + the media +* open flags:: Flags passed to the open system call when the + device is opened +* misc variables:: Variables which don't fit in either category +* misc flags:: Switch variables, which can be enabled or disabled +* multiple descriptions:: How to supply several descriptions for a + drive, to be tried one after the other. +@end menu + +@node general information, location information, per drive variables, per drive variables +@subsection General information +@cindex Drive description, example +@cindex Drive configuration, example +@vindex drive + +Per drive flags and values may be described in a drive section. A +drive section starts with +@code{drive} "@var{driveletter}" : + +Then follow variable-value pairs and flags. + +This is a sample drive description: +@example + drive a: + file="/dev/fd0" use_xdf=1 +@end example + +@node location information, geometry description, general information, per drive variables +@subsection Location information +@cindex Hdimage + +For each drive, you need to describe where its data is physically +stored (imag file, physical device, partition, offset). + +@table @code +@item file +@cindex Image file +@cindex Name of device node +@cindex File name of device node +@vindex file +The name of the file or device holding the disk image. This is +mandatory. The file name should be enclosed in quotes. + +@item partition +@cindex Dosemu hard disk image +@cindex Zip disks (partitions) +@cindex Jaz disks (partitions) +@cindex Syquest disks +@cindex Magneto-optical disks +@cindex OS/2 (layout of removable media) +@cindex Windows NT (layout of removable media) +@cindex Removable media +@cindex Partitioned image file +Tells mtools to treat the drive as a partitioned device, and to use the +given partition. Only primary partitions are accessible using this +method, and they are numbered from 1 to 4. For logical partitions, use +the more general @code{offset} variable. The @code{partition} variable +is intended for removable media such as Syquests, ZIP drives, and +magneto-optical disks. Although traditional DOS sees Syquests and +magneto-optical disks as @samp{giant floppy disks} which are +unpartitioned, OS/2 and Windows NT treat them like hard disks, +i.e. partioned devices. The @code{partition} flag is also useful DOSEMU +hdimages. It is not recommended for hard disks for which direct access +to partitions is available through mounting. + +@item offset +@cindex Ram disk +@cindex Atari Ram disk +Describes where in the file the MS-DOS filesystem starts. This is useful +for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By +default, this is zero, meaning that the filesystem starts right at the +beginning of the device or file. +@end table + +@node geometry description, open flags, location information, per drive variables +@subsection Disk Geometry Configuration +@cindex Disk Geometry +@cindex Configuration of disk geometry +@cindex Description of disk geometry +@cindex Format of disk +@cindex High density disk +@cindex Low density disk +@pindex mformat (geometry used for) + +Geometry information describes the physical characteristics about the +disk. Its has three purposes: + +@table @asis +@item formatting +The geometry information is written into the boot sector of the newly +made disk. However, you may also describe the geometry information on +the command line. @xref{mformat}, for details. +@item filtering +On some Unices there are device nodes which only support one physical +geometry. For instance, you might need a different node to access a disk +as high density or as low density. The geometry is compared to the +actual geometry stored on the boot sector to make sure that this device +node is able to correctly read the disk. If the geometry doesn't match, +this drive entry fails, and the next drive entry bearing the same drive +letter is tried. @xref{multiple descriptions}, for more details on +supplying several descriptions for one drive letter. + +If no geometry information is supplied in the configuration file, all +disks are accepted. On Linux (and on Sparc) there exist device nodes +with configurable geometry (@file{/dev/fd0}, @file{/dev/fd1} etc), +and thus filtering is not needed (and ignored) for disk drives. (Mtools +still does do filtering on plain files (disk images) in Linux: this is +mainly intended for test purposes, as I don't have access to a Unix +which would actually need filtering). + +If you do not need filtering, but want still a default geometry for +mformatting, you may switch off filtering using the @code{mformat_only} +flag. + +If you want filtering, you should supply the @code{filter} flag. If you +supply a geometry, you must supply one of both flags. + +@item initial geometry +On devices that support it (usually floppy devices), the geometry +information is also used to set the initial geometry. This initial +geometry is applied while reading the boot sector, which contains the +real geometry. If no geometry information is supplied in the +configuration file, or if the @code{mformat_only} flag is supplied, no +initial configuration is done. + +On Linux, initial geometry is not really needed, as the configurable +devices are able to auto-detect the disk type accurately enough (for +most common formats) to read the boot sector. +@end table + +Wrong geometry information may lead to very bizarre errors. That's why I +strongly recommend that you add the @code{mformat_only} flag to your +drive description, unless you really need filtering or initial geometry. + +The following geometry related variables are available: + +@table @code +@item cylinders +@itemx tracks +@vindex cylinders +@vindex tracks +The number of cylinders. (@code{cylinders} is the preferred form, +@code{tracks} is considered obsolete) +@item heads +@vindex heads +The number of heads (sides). +@item sectors +@vindex sectors +The number of sectors per track. +@end table + +Example: the following drive section describes a 1.44M drive: + +@example + drive a: + file="/dev/fd0H1440" + fat_bits=12 + cylinders=80 heads=2 sectors=18 + mformat_only +@end example + +The following shorthand geometry descriptions are available: + +@table @code +@item 1.44m +high density 3 1/2 disk. Equivalent to: +@code{fat_bits=12 cylinders=80 heads=2 sectors=18} +@item 1.2m +high density 5 1/4 disk. Equivalent to: +@code{fat_bits=12 cylinders=80 heads=2 sectors=15} +@item 720k +double density 3 1/2 disk. Equivalent to: +@code{fat_bits=12 cylinders=80 heads=2 sectors=9} +@item 360k +double density 5 1/4 disk. Equivalent to: +@code{fat_bits=12 cylinders=40 heads=2 sectors=9} +@end table + +The shorthand format descriptions may be amended. For example, +@code{360k sectors=8} +describes a 320k disk and is equivalent to: +@code{fat_bits=12 cylinders=40 heads=2 sectors=8} + +@node open flags, misc variables, geometry description, per drive variables +@subsection Open Flags +@vindex sync +@vindex nodelay +@vindex exclusive +@cindex open flags +@cindex synchronous writing +@cindex exclusive access to a drive + +Moreover, the following flags are available: + +@table @code +@item sync +All i/o operations are done synchronously +@item nodelay +The device or file is opened with the O_NDELAY flag. This is needed on +some non-Linux architectures. +@item exclusive +The device or file is opened with the O_EXCL flag. On Linux, this +ensures exclusive access to the floppy drive. On most other +architectures, and for plain files it has no effect at all. +@end table + + +@node misc variables, misc flags, open flags, per drive variables +@subsection General Purpose Drive Variables + +The following general purpose drive variables are available. Depending +to their type, these variables can be set to a string (precmd) or +an integer (all others) + +@table @code +@item fat_bits +@vindex fat_bits +The number of FAT bits. This may be 12 or 16. This is very rarely +needed, as it can almost always be deduced from information in the +boot sector. On the contrary, describing the number of fat bits may +actually be harmful if you get it wrong. You should only use it if +mtools gets the autodetected number of fat bits wrong, or if you want +to mformat a disk with a weird number of fat bits. +@item codepage +Describes the DOS codepage used for short filenames. This is a number +between 1 and 999. By default, codepage 850 is used. The reason for +this is because this codepage contains most of the characters that are +also available in ISO-Latin-1. You may also specify a global codepage +for all drives by using the global @code{default_codepage} parameter +(outside of any drive description). This parameters exists starting at +version 4.0.0 +@item precmd +@cindex Solaris (volcheck) +@cindex Executing commands before opening the device +On some variants of Solaris, it is necessary to call 'volcheck -v' +before opening a floppy device, in order for the system to notice that +there is indeed a disk in the drive. @code{precmd="volcheck -v"} in the +drive clause establishes the desired behavior. + +@item blocksize +@cindex raw device +@cindex character devices +@cindex blocksize +This parameter represents a default block size to be always used on this +device. All I/O is done with multiples of this block size, +independantly of the sector size registered in the filesystem's boot +sector. This is useful for character devices whose sector size is not +512, such as for example CD Rom drives on Solaris. + +@end table + +Only the @code{file} variable is mandatory. The other parameters may +be left out. In that case a default value or an autodetected value is +used. + + + +@node misc flags, multiple descriptions, misc variables, per drive variables +@subsection General Purpose Drive Flags + +A flag can either be set to 1 (enabled) or 0 (disabled). If the value is +ommitted, it is enabled. For example, @code{scsi} is equivalent to +@code{scsi=1} + +@table @code +@item nolock +@cindex disable locking +@cindex locking (disabling it) +@cindex plain floppy: device xxx busy +Instruct mtools to not use locking on this drive. This is needed on +systems with buggy locking semantics. However, enabling this makes +operation less safe in cases where several users may access the same +drive at the same time. + +@item scsi +@cindex setuid installation (needed for raw SCSI I/O) +@cindex Solaris (Raw access to SCSI devices such as Zip & Jaz) +@cindex SunOS (Raw access to SCSI devices such as Zip & Jaz) +@cindex Zip disks (raw Scsi access) +@cindex Jaz disks (raw Scsi access) +@cindex Syquests (raw Scsi access) +@cindex SCSI devices +When set to 1, this option tells mtools to use raw SCSI I/O instead of +the standard read/write calls to access the device. Currently, this is +supported on HP/UX, Solaris and SunOs. This is needed because on some +architectures, such as SunOs or Solaris, PC media can't be accessed +using the @code{read} and @code{write} syscalls, because the OS expects +them to contain a Sun specific "disk label". + +As raw Scsi access always uses the whole device, you need to specify the +"partition" flag in addition + +On some architectures, such as Solaris, mtools needs root privileges to +be able to use the @code{scsi} option. Thus mtools should be installed +set uid root on Solaris if you want to access Zip/Jaz drives. Thus, if +the @code{scsi} flag is given, @code{privileged} is automatically +implied, unless explicitly disabled by @code{privileged=0} + +Mtools uses its root privileges to open the device, and to issue the +actual SCSI I/O calls. Moreover, root privileges are only used for +drives described in a system-wide configuration file such as +@file{/usr/local/etc/mtools.conf}, and not for those described in +@file{~/.mtoolsrc} or @file{$MTOOLSRC}. + +@item privileged +@cindex setuid installation +@cindex setgid installation +When set to 1, this instructs mtools to use its set-uid and set-gid +privileges for opening the given drive. This option is only valid for +drives described in the system-wide configuration files (such as +@file{/usr/local/etc/mtools.conf}, not @file{~/.mtoolsrc} or +@file{$MTOOLSRC}). Obviously, this option is also a no op if mtools is +not installed setuid or setgid. This option is implied by 'scsi=1', but +again only for drives defined in system-wide configuration files. +Privileged may also be set explicitely to 0, in order to tell mtools not +to use its privileges for a given drive even if @code{scsi=1} is set. + +Mtools only needs to be installed setuid if you use the +@code{privileged} or @code{scsi} drive variables. If you do not use +these options, mtools works perfectly well even when not installed +setuid root. + +@item vold +@cindex Solaris (vold) +@cindex Vold (mediamgr) + +Instructs mtools to interpret the device name as a vold identifier +rather than as a filename. The vold identifier is translated into a +real filename using the @code{media_findname()} and +@code{media_oldaliases()} functions of the @code{volmgt} library. This +flag is only available if you configured mtools with the +@code{--enable-new-vold} option before compilation. + +@item swap +@cindex Atari +@cindex Wordswapped + +Consider the media as a word-swapped Atari disk. + +@item use_xdf +@cindex XDF disks (how to configure) +@vindex use_xdf +If this is set to a non-zero value, mtools also tries to access this +disk as an XDF disk. XDF is a high capacity format used by OS/2. This +is off by default. @xref{XDF}, for more details. +@item mformat_only +@vindex mformat_only +Tells mtools to use the geometry for this drive only for mformatting and +not for filtering. + +@item filter +@vindex filter +Tells mtools to use the geometry for this drive both for mformatting and +filtering. + +@item remote +Tells mtools to connect to floppyd (@pxref{floppyd}). +@end table + + +@node multiple descriptions, , misc flags, per drive variables +@subsection Supplying multiple descriptions for a drive + +It is possible to supply multiple descriptions for a drive. In that +case, the descriptions are tried in order until one is found that +fits. Descriptions may fail for several reasons: + +@enumerate +@item +because the geometry is not appropriate, +@item +because there is no disk in the drive, +@item +or because of other problems. +@end enumerate + +Multiple definitions are useful when using physical devices which are +only able to support one single disk geometry. +Example: +@example + drive a: file="/dev/fd0H1440" 1.44m + drive a: file="/dev/fd0H720" 720k +@end example + +This instructs mtools to use /dev/fd0H1440 for 1.44m (high density) +disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this +feature is not really needed, as the /dev/fd0 device is able to handle +any geometry. + +You may also use multiple drive descriptions to access both of your +physical drives through one drive letter: + +@example + drive z: file="/dev/fd0" + drive z: file="/dev/fd1" +@end example + +With this description, @code{mdir z:} accesses your first physical +drive if it contains a disk. If the first drive doesn't contain a disk, +mtools checks the second drive. + +When using multiple configuration files, drive descriptions in the files +parsed last override descriptions for the same drive in earlier +files. In order to avoid this, use the @code{drive+} or @code{+drive} +keywords instead of @code{drive}. The first adds a description to the +end of the list (i.e. it will be tried last), and the first adds it to +the start of the list. + +@node parsing order, old style config, per drive variables, Configuration +@section Location of configuration files and parsing order +@cindex Parsing order +@cindex Configuration file parsing order +@cindex Configuration file name (parsing order) +@cindex Name of configuration files (parsing order) +@cindex Location of configuration files (parsing order) + +The configuration files are parsed in the following order: +@enumerate +@item +compiled-in defaults +@item +@file{/usr/local/etc/mtools.conf} +@item +@file{/etc/mtools} +This is for backwards compatibility only, and is only parsed if +@file{mtools.conf} +doesn't exist. +@item +@file{~/.mtoolsrc}. +@item +@file{$MTOOLSRC} (file pointed by the @code{MTOOLSRC} environmental +variable) +@end enumerate + +Options described in the later files override those described in the +earlier files. Drives defined in earlier files persist if they are not +overridden in the later files. For instance, drives A and B may be +defined in @file{/usr/local/etc/mtools.conf} and drives C and D may be +defined in @file{~/.mtoolsrc} However, if @file{~/.mtoolsrc} also +defines drive A, this new description would override the description of +drive A in @file{/usr/local/etc/mtools.conf} instead of adding to it. If +you want to add a new description to a drive already described in an +earlier file, you need to use either the @code{+drive} or @code{drive+} +keyword. + +@node old style config, , parsing order, Configuration +@section Backwards compatibility with old configuration file syntax +@cindex Backwards compatibility +@cindex Old configuration file syntax +@cindex Configuration file, old syntax + +The syntax described herein is new for version @code{mtools-3.0}. The +old line-oriented syntax is still supported. Each line beginning with a +single letter is considered to be a drive description using the old +syntax. Old style and new style drive sections may be mixed within the +same configuration file, in order to make upgrading easier. Support for +the old syntax will be phased out eventually, and in order to discourage +its use, I purposefully omit its description here. + +@comment MANskip 5 + +@node Commands, Compiling mtools, Configuration, Top +@chapter Command list +@cindex Command list +@cindex List of available commands + + This section describes the available mtools commands, and the command +line parameters that each of them accepts. Options which are common to +all mtools commands are not described here, @ref{arguments} for a +description of those. + +@menu +* floppyd:: floppy daemon to run on your X server box +* floppyd_installtest:: small utility to check for the presence of floppyd +* mattrib:: change MS-DOS file attribute flags +* mbadblocks:: tests a floppy disk, and marks the bad blocks in the FAT +* mcat:: same as cat. Only usefull with floppyd. +* mcd:: change MS-DOS directory +* mclasserase:: erase memory card +* mcopy:: copy MS-DOS files to/from Unix +* mdel:: delete an MS-DOS file +* mdeltree:: recursively delete an MS-DOS directory +* mdir:: display an MS-DOS directory +* mdu:: list space occupied by directory and its contents +* mformat:: add an MS-DOS filesystem to a low-level formatted floppy disk +* minfo:: get information about an MS-DOS filesystem. +* mlabel:: make an MS-DOS volume label +* mkmanifest:: makes a list of short name equivalents +* mmd:: make an MS-DOS subdirectory +* mmount:: mount an MS-DOS disk +* mpartition:: create an MS-DOS as a partition +* mrd:: remove an MS-DOS subdirectory +* mmove:: move or rename an MS-DOS file or subdirectory +* mren:: rename an existing MS-DOS file +* mshowfat:: shows the FAT map of a file +* mtoolstest:: tests and displays the configuration +* mtype:: display contents of an MS-DOS file +* mzip:: zip disk specific commands +@end menu + +@node floppyd, floppyd_installtest, Commands, Commands +@section Floppyd +@pindex floppyd +@cindex X terminal +@cindex remote floppy access + +@code{Floppyd} is used as a server to grant access to the floppy drive +to clients running on a remote machine, just as an X server grants +access to the display to remote clients. It has the following syntax: + +@code{floppyd} [@code{-d}] [@code{-l}] [@code{-s} @var{port}] [@code{-r} +@var{user}] [@code{-b} @var{ipaddr}] [@code{-x} @var{display}] @var{devicenames} + + +@code{floppyd} is always associated with an X server. It runs on the +same machine as its X server, and listens on port 5703 and above. + +@subsection Authentication + +@code{floppyd} authenticates remote clients using the @code{Xauthority} +protocol. Xhost authentication is not supported. Each floppyd is +associated with an X server. When a remote client attempts to connect +to floppyd, it sends floppyd the X authority record corresponding to +floppyd's X server. Floppyd in turn then tries to open up a connection +to the X server in order to verify the authenticity of the xauth record. +If the connection to the X server succeeds, the client is granted +access. +@code{DISPLAY}. + +@strong{Caution}: In order to make authentication work correctly, the +local host should @strong{not} be listed in the @code{xhost} list of +allowed hosts. + Indeed, hosts listed in @code{xhost} do not need a correct +@code{Xauthority} cookie to connect to the X server. As @code{floppyd} +runs on the same host as the X server, all its probe connection would +succeed even for clients who supplied a bad cookie. This means that +your floppy drive would be open to the world, i.e. a huge security hole. + If your X server does not allow you to remove @code{localhost:0} and +@code{:0} from the @code{xhost} list, you can prevent floppyd from +probing those display names with the @code{-l} option. + +@subsection Command line options + +@table @code +@item d +Daemon mode. Floppyd runs its own server loop. Do not supply this if +you start floppyd from @code{inetd.conf} +@item s @var{port} +Port number for deamon mode. Default is 5703 + @var{displaynumber}. +This flag implies daemon mode. For example, for display +@code{hitchhiker:5}, the port would be 5708. +@item b @var{ipaddr} +Bind address (for multihomed hosts). This flag implies daemon mode +@item r @var{user} +Run the server under as the given user +@item x @var{display} +X display to use for authentication. By default, this is taken from the +@code{DISPLAY} variable. If neither the @code{x} attribute is present +nor @code{DISPLAY} is set, floppyd uses @code{:0.0}. +@end table + +@var{devicenames} is a list of device nodes to be opened. Default +is @code{/dev/fd0}. Multiple devices are only supported on mtools +versions newer than 3.9.11. + + +@subsection Connecting to floppyd + + In order to use floppyd, add the flag @code{remote} to the device +description in your @file{~/.mtoolsrc} file. If the flag @code{remote} +is given, the @code{file} parameter of the device description is taken +to be a remote address. It's format is the following: +@var{hostname}@code{:}@var{displaynumber}[@code{/}[@var{baseport}][@code{/}@var{drive}]]. When +using this entry, mtools connects to port +@var{baseport}+@var{displaynumber} at @var{hostname}. By default +@var{baseport} is 5703. The drive parameter is to distinguish among +multiple drives associated with a single display (only mtools versions +more recent than 3.9.11) + +@subsection Examples: + + The following starts a floppy daemon giving access to @file{/dev/fd0}, +listening on the default port 5703, tied to the default X servers: + +@example +floppyd -d /dev/fd0 +@end example + + Each of the following starts a floppy daemon giving access to +@file{/dev/fd1}, tied to the :1 local X servers, and listening on port +5704. We assume that the local host is named @code{hitchhiker}. + +@example +floppyd -d /dev/fd0 +floppyd -d -x :1 -p 5704 /dev/fd0 +@end example + + If you want to start floppyd by @code{inetd} instead of running it as a +daemon, insert the following lines into @file{/etc/services}: +@example +# floppy daemon +floppyd-0 5703/tcp # floppy daemon for X server :0 +floppyd-1 5704/tcp # floppy daemon for X server :1 +@end example + + And insert the following into @file{/etc/inetd.conf} (assuming that you +have defined a user named floppy in your @file{/etc/passwd}): + +@example +# floppy daemon +floppyd-0 stream tcp wait floppy /usr/sbin/floppyd floppyd /dev/fd0 +floppyd-1 stream tcp wait floppy /usr/sbin/floppyd floppyd -x :1 /dev/fd0 +@end example + + Note that you need to supply the X display names for the second +floppyd. This is because the port is opened by inetd.conf, and hence +floppyd cannot know its number to interfere the display number. + + +On the client side, insert the following into your @file{~/.mtoolsrc} +to define a drive letter accessing floppy drive in your X terminal: +@example +drive x: file="$DISPLAY" remote +@end example + +If your X terminal has more than one drive, you may access the +additional drives as follows: +@example +drive y: file="$DISPLAY//1" remote +drive z: file="$DISPLAY//2" remote +@end example + +@node floppyd_installtest, mattrib, floppyd, Commands +@section Floppyd_installtest +@pindex floppyd_installtest +@cindex X terminal +@cindex remote floppy access + +@code{Floppyd_installtest} is used to check for the presence of a running +floppyd daemon. This is usefull, if you have a small frontend script to +mtools, which decides whether to use floppyd or not. + +@code{floppyd_installtest} [@code{-f}] Connect-String + +If the @code{-f} option is specified, @code{floppyd_installtest} does a +full X-Cookie authentication and complains if this does not work. + +The connect-String has the format described in the floppyd-section: +@var{hostname}@code{:}@var{displaynumber}[@code{/}@var{baseport}] + +@node mattrib, mbadblocks, floppyd_installtest, Commands +@section Mattrib +@pindex mattrib +@cindex Changing file attributes +@cindex Hidden files +@cindex Read-only files (changing the attribute) +@cindex System files +@cindex Archive bit + +@code{Mattrib} is used to change MS-DOS file attribute flags. It has the +following syntax: + +@code{mattrib} [@code{-a|+a}] [@code{-h|+h}] [@code{-r|+r}] +[@code{-s|+s}] [@code{-/}] [@code{-p}] [@code{-X}] @var{msdosfile} [ @var{msdosfiles} @dots{} ] + +@code{Mattrib} adds attribute flags to an MS-DOS file (with the +`@code{+}' operator) or remove attribute flags (with the `@code{-}' +operator). + +@code{Mattrib} supports the following attribute bits: + +@table @code +@item a +Archive bit. Used by some backup programs to indicate a new file. +@item r +Read-only bit. Used to indicate a read-only file. Files with this bit +set cannot be erased by @code{DEL} nor modified. +@item s +System bit. Used by MS-DOS to indicate a operating system file. +@item h +Hidden bit. Used to make files hidden from @code{DIR}. +@end table + +@code{Mattrib} supports the following command line flags: +@table @code +@item / +Recursive. Recursively list the attributes of the files in the subdirectories. +@item X +Concise. Prints the attributes whithout any whitespace padding. If +neither the "/" option is given, nor the @var{msdosfile} contains a +wildcard, and there is only one Msdos file parameter on the command +line, only the attribute is printed, and not the filename. This option +is convenient for scripts +@item p +Replay mode. Outputs a series of mformat commands that will reproduce +the current situation, starting from a situation as left by untarring +the Dos filesystem. Commands are only output for attribute settings +that differ from the default (archive bit set for files, unset for +directories). This option is intended to be used in addition to +tar. The @code{readonly} attribute is not taken into account, as tar can +set that one itself. +@end table + +@node mbadblocks, mcat, mattrib, Commands +@section Mbadblocks + +The @code{mbadblocks} command is used to scan an MS-DOS floppy and mark +its unused bad blocks as bad. It uses the following syntax: + +@code{mbadblocks} @var{drive}@code{:} +@pindex mbadblocks +@cindex Marking blocks as bad +@cindex Bad blocks +@cindex Read errors + +@code{Mbadblocks} scans an MS-DOS floppy for bad blocks. All unused bad +blocks are marked as such in the FAT. This is intended to be used right +after @code{mformat}. It is not intended to salvage bad disks. +@subsection Bugs +@code{Mbadblocks} should (but doesn't yet :-( ) also try to salvage bad +blocks which are in use by reading them repeatedly, and then mark them +bad. + +@node mcat, mcd, mbadblocks, Commands +@section Mcat + +The @code{mcat} command is used to copy an entire disk image from or +to the floppy device. It uses the following syntax: + +@code{mcat} [@code{-w}] @var{drive}@code{:} +@pindex mcat +@cindex Copying an entire disk image +@cindex Disk image +@cindex Floppyd cat + +@code{Mcat} performs the same task as the unix @code{cat} command. It +is included into the mtools package, since @code{cat} cannot access +remote floppy devices offered by the mtools floppy daemon. +Now it is possible to create boot floppies remotely. + +The default operation is reading. The output is written to stdout. + +If the @code{-w} option is specified, mcat reads a disk-image from +stdin and writes it to the given device. +@strong{Use this carefully!} Because of the lowlevel nature of this +command, it will happily destroy any data written before on the +disk without warning! + +@node mcd, mclasserase, mcat, Commands +@section Mcd +@pindex mcd +@cindex Directory (changing) +@cindex Working directory +@cindex Current working directory (changing the) +@cindex Default directory (changing the) +@cindex Mcwd file + +The @code{mcd} command is used to change the mtools working directory +on the MS-DOS disk. It uses the following syntax: + +@example +@code{mcd} [@var{msdosdirectory}] +@end example + +Without arguments, @code{mcd} reports the current device and working +directory. Otherwise, @code{mcd} changes the current device and current +working directory relative to an MS-DOS filesystem. + +The environmental variable @code{MCWD} may be used to locate the file +where the device and current working directory information is stored. +The default is @file{$HOME/.mcwd}. Information in this file is ignored +if the file is more than 6 hours old. + +@code{Mcd} returns 0 on success or 1 on failure. + +Unlike MS-DOS versions of @code{CD}, @code{mcd} can be used to change to +another device. It may be wise to remove old @file{.mcwd} files at logout. + +@node mclasserase, mcopy, mcd, Commands +@section Mclasserase +@pindex mclasserase +@cindex Memory Card +@cindex Physically erase + +The @code{mclasserase} command is used to wipe memory cards by +overwriting it three times: first with @code{0xff}, then with +@code{0x00}, then with @code{0xff} again. The command uses the following +syntax: + +@example +@code{mclasserase} [@code{-d}] @var{msdosdrive} +@end example + +Dos drive is optional, if none is specified, use @code{A:}. If more than +one drive are specified, all but the last are ignored. + +@code{Mclasserase} accepts the following command line options: + +@table @code +@item d +Stop after each erase cycle, for testing purposes +@item p +Not yet implemented +@end table + + +@code{Mclasserase} returns 0 on success or -1 on failure. + + +@node mcopy, mdel, mclasserase, Commands +@section Mcopy +@pindex mcopy +@cindex Reading MS-DOS files +@cindex Writing MS-DOS files +@cindex Copying MS-DOS files +@cindex Concatenating MS-DOS files +@cindex Text files +@cindex CR/LF conversions + +The @code{mcopy} command is used to copy MS-DOS files to and from +Unix. It uses the following syntax: + +@example +@code{mcopy} [@code{-bspanvmQT}] [@code{-D} @var{clash_option}] @var{sourcefile} @var{targetfile} +@code{mcopy} [@code{-bspanvmQT}] [@code{-D} @var{clash_option}] @var{sourcefile} [ @var{sourcefiles}@dots{} ] @var{targetdirectory} +@code{mcopy} [@code{-tnvm}] @var{MSDOSsourcefile} +@end example + + + +@code{Mcopy} copies the specified file to the named file, or copies +multiple files to the named directory. The source and target can be +either MS-DOS or Unix files. + +The use of a drive letter designation on the MS-DOS files, 'a:' for +example, determines the direction of the transfer. A missing drive +designation implies a Unix file whose path starts in the current +directory. If a source drive letter is specified with no attached file +name (e.g. @code{mcopy a: .}), all files are copied from that drive. + +If only a single, MS-DOS source parameter is provided (e.g. "mcopy +a:foo.exe"), an implied destination of the current directory +(`@code{.}') is assumed. + +A filename of `@code{-}' means standard input or standard output, depending +on its position on the command line. + +@code{Mcopy} accepts the following command line options: + +@table @code +@item t +Text file transfer. Mcopy translates incoming carriage return/line +feeds to line feeds when copying from Dos to Unix, and vice-versa when +copying from Unix to Dos. +@item b +Batch mode. Optimized for huge recursive copies, but less secure if a +crash happens during the copy. +@item s +Recursive copy. Also copies directories and their contents +@item p +Preserves the attributes of the copied files +@item Q +When mcopying multiple files, quits as soon as one copy fails (for +example due to lacking storage space on the target disk) +@item a +Text (Ascii) file transfer. @code{Mcopy} translates incoming carriage +return/line feeds to line feeds. +@item T +Text (Ascii) file transfer with charset conversion. Differs from +@code{-a} in the @code{Mcopy} also translates incoming PC-8 characters +to ISO-8859-1 equivalents as far as possible. When reading DOS files, +untranslatable characters are replaced by '@code{#}'; when writing DOS files, +untranslatable characters are replaced by '@code{.}'. +@item n +No confirmation when overwriting Unix files. @code{Mcopy} doesn't warn +the user when overwriting an existing Unix file. If the target file already exists, +and the @code{-n} option is not in effect, @code{mcopy} asks whether to +overwrite the file or to rename the new file (@ref{name clashes}) for +details). In order to switch off confirmation for DOS files, use @code{-o}. +@item m +Preserve the file modification time. +@item v +Verbose. Displays the name of each file as it is copied. +@end table + +@subsection Bugs +Unlike MS-DOS, the '+' operator (append) from MS-DOS is not +supported. However, you may use @code{mtype} to produce the same effect: +@example +mtype a:file1 a:file2 a:file3 >unixfile +mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile +@end example + +@node mdel, mdeltree, mcopy, Commands +@section Mdel +@pindex mdel +@cindex removing MS-DOS files +@cindex erasing MS-DOS files +@cindex deleting MS-DOS files + +The @code{mdel} command is used to delete an MS-DOS file. Its syntax +is: + +@display +@code{mdel} [@code{-v}] @var{msdosfile} [ @var{msdosfiles} @dots{} ] +@end display + +@code{Mdel} deletes files on an MS-DOS filesystem. + +@code{Mdel} asks for verification prior to removing a read-only file. + +@node mdeltree, mdir, mdel, Commands +@section Mdeltree +@pindex mdeltree +@cindex removing an MS-DOS directory recursively +@cindex erasing an MS-DOS directory recursively +@cindex deleting an MS-DOS directory recursively +@cindex recursively removing an MS-DOS directory + +The @code{mdeltree} command is used to delete an MS-DOS file. Its syntax +is: + +@display +@code{mdeltree} [@code{-v}] @var{msdosdirectory} [@var{msdosdirectories}@dots{}] +@end display + +@code{Mdeltree} removes a directory and all the files and subdirectories +it contains from an MS-DOS filesystem. An error occurs if the directory +to be removed does not exist. + +@node mdir, mdu, mdeltree, Commands +@section Mdir +@pindex mdir +@cindex Read-only files (listing them) +@cindex Listing a directory +@cindex Directory listing + +The @code{mdir} command is used to display an MS-DOS directory. Its +syntax is: + +@code{mdir} [@code{-/}] [@code{-f}] [@code{-w}] [@code{-a}] [@code{-b}] @var{msdosfile} [ @var{msdosfiles}@dots{}] + +@code{Mdir} +displays the contents of MS-DOS directories, or the entries for some +MS-DOS files. + +@code{Mdir} supports the following command line options: + +@table @code +@item / +Recursive output, just like Dos' @code{-s} option +@item w +Wide output. With this option, @code{mdir} prints the filenames across +the page without displaying the file size or creation date. +@item a +Also list hidden files. +@item f +Fast. Do not try to find out free space. On larger disks, finding out +the amount of free space takes up some non trivial amount of time, as +the whole FAT must be read in and scanned. The @code{-f} flag bypasses +this step. This flag is not needed on FAT32 filesystems, which store +the size explicitely. +@item b +Concise listing. Lists each directory name or filename, one per line +(including the filename extension). This switch displays no heading +information and no summary. Only a newline separated list of pathnames +is displayed. +@end table + +An error occurs if a component of the path is not a directory. + +@node mdu, mformat, mdir, Commands +@section Mdu +@pindex mdu +@cindex Space occupied by directories and files +@cindex du +@cindex Listing space occupied by directories and files +@cindex Occupation of space by directories and files + +@code{Mdu} is used to list the space occupied by a directory, its +subdirectories and its files. It is similar to the @code{du} command on +Unix. The unit used are clusters. Use the minfo command to find out +the cluster size. + +@code{mdu} [@code{-a}] [ @var{msdosfiles} @dots{} ] + + +@table @code +@item a +All files. List also the space occupied for individual files. +@item s +Only list the total space, don't give details for each subdirectory. +@end table + + + +@node mformat, mkmanifest, mdu, Commands +@section Mformat +@pindex mformat +@cindex Initializing disks +@cindex Formatting disks +@cindex Filesystem creation + +The @code{mformat} command is used to add an MS-DOS filesystem to a +low-level formatted diskette. Its syntax is: + +@display +@code{mformat} [@code{-t} @var{cylinders}] [@code{-h} @var{heads}] [@code{-s} @var{sectors}] + [@code{-f} @var{size}] [@code{-1}] [@code{-4}] [@code{-8}] + [@code{-v} @var{volume_label}] + [@code{-F}] [@code{-S} @var{sizecode}] [@code{-X}] + [@code{-2} @var{sectors_on_track_0}] [@code{-3}] + [@code{-0} @var{rate_on_track_0}] [@code{-A} @var{rate_on_other_tracks}] + [@code{-M} @var{software_sector_size}] + [@code{-N} @var{serial_number}] [@code{-a}] + [@code{-C}] [@code{-H} @var{hidden_sectors}] [@code{-I} @var{fsVersion}] + [@code{-r} @var{root_sectors}] [@code{-L} @var{fat_len}] + [@code{-B} @var{boot_sector}] [@code{-k}] + [@code{-m} @var{media_descriptor}] + @var{drive:} +@end display + +@code{Mformat} adds a minimal MS-DOS filesystem (boot sector, FAT, and +root directory) to a diskette that has already been formatted by a Unix +low-level format. + + +The following options are supported: (The S, 2, 1 and M options may not +exist if this copy of mtools has been compiled without the USE_2M +option) + +The following options are the same as for Dos's format command: + +@comment xMANoptions + +@table @code +@item v +Specifies the volume label. A volume label identifies the disk and can +be a maximum of 11 characters. If you omit the -v switch, mlabel will +assign no label to the disk. +@item f +Specifies the size of the DOS filesystem to format. Only a certain +number of predefined sizes are supported by this flag; for others use +the -h/-t/-s flags. The following sizes are supported: +@table @asis +@item 160 +160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD) +@item 180 +160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD) +@item 320 +320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD) +@item 360 +360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD) +@item 720 +720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD) +@item 1200 +1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD) +@item 1440 +1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD) +@item 2880 +2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED) +@end table + +@item t +Specifies the number of tracks on the disk. +@item h +The number of heads (sides). +@item n +Specifies the number of sectors per track. If the 2m option is given, +number of 512-byte sector equivalents on generic tracks (i.e. not head 0 +track 0). If the 2m option is not given, number of physical sectors per +track (which may be bigger than 512 bytes). + +@item 1 +Formats a single side (equivalent to -h 1) + +@item 4 +Formats a 360K double-sided disk (equivalent to -f 360). When used +together with -the 1 switch, this switch formats a 180K disk + +@item 8 +Formats a disk with 8 sectors per track. + +@end table + +MSDOS format's @code{q}, @code{u} and @code{b} options are not +supported, and @code{s} has a different meaning. + +The following options are specific to mtools: + +@table @code + +@item F +Format the partition as FAT32. + +@item S +The sizecode. The size of the sector is 2 ^ (sizecode + 7). +@item X +formats the disk as an XDF disk. @xref{XDF}, for more details. The disk +has first to be low-level formatted using the xdfcopy utility included +in the fdutils package. XDF disks are used for instance for OS/2 install +disks. +@item 2 +2m format. The parameter to this option describes the number of +sectors on track 0, head 0. This option is recommended for sectors +bigger than normal. +@item 3 +don't use a 2m format, even if the current geometry of the disk is a 2m +geometry. +@item 0 +Data transfer rate on track 0 +@item A +Data transfer rate on tracks other than 0 +@item M +software sector size. This parameter describes the sector size in bytes used +by the MS-DOS filesystem. By default it is the physical sector size. +@item N +Uses the requested serial number, instead of generating one +automatically +@item a +If this option is given, an Atari style serial number is generated. +Ataris store their serial number in the OEM label. +@item C +creates the disk image file to install the MS-DOS filesystem on +it. Obviously, this is useless on physical devices such as floppies +and hard disk partitions, but is interesting for image files. +@item H +number of hidden sectors. This parameter is useful for formatting hard +disk partition, which are not aligned on track boundaries (i.e. first +head of first track doesn't belong to the partition, but contains a +partition table). In that case the number of hidden sectors is in +general the number of sectors per cylinder. This is untested. +@item I +Sets the fsVersion id when formatting a FAT32 drive. In order to find +this out, run minfo on an existing FAT32 drive, and mail me about it, so +I can include the correct value in future versions of mtools. +@item c +Sets the size of a cluster (in sectors). If this cluster size would +generate a FAT that too big for its number of bits, mtools automatically +increases the cluster size, until the FAT is small enough. +@item d +Sets the number of FAT copies. Default is 2. This setting can also be +specified using the @code{MTOOLS_NFATS} environment variable. +@item r +Sets the size of the root directory (in sectors). Only applicable to 12 +and 16 bit FATs. This setting can also be specified using the +@code{MTOOLS_DIR_LEN} environment variable. +@item L +Sets the length of the FAT. +@item B +Use the bootsector stored in the given file or device, instead of using +its own. Only the geometry fields are updated to match the target disks +parameters. +@item k +Keep the existing boot sector as much as possible. Only the geometry +fields and other similar filesystem data are updated to match the target +disks parameters. + +@item m +Use a non-standard media descriptor byte for this disk. The media +descriptor is stored at position 21 of the boot sector, and as first +byte in each FAT copy. Using this option may confuse DOS or older mtools +version, and may make the disk unreadable. Only use if you know what you +are doing. + +@end table + +To format a diskette at a density other than the default, you must supply +(at least) those command line parameters that are different from the +default. + +@code{Mformat} returns 0 on success or 1 on failure. + +It doesn't record bad block information to the Fat, use +@code{mbadblocks} for that. + +@node mkmanifest, minfo, mformat, Commands +@section Mkmanifest +@pindex mkmanifest +@cindex packing list + +The @code{mkmanifest} command is used to create a shell script (packing +list) to restore Unix filenames. Its syntax is: + +@code{mkmanifest} [ @var{files} ] + +@code{Mkmanifest} creates a shell script that aids in the restoration of +Unix filenames that got clobbered by the MS-DOS filename restrictions. +MS-DOS filenames are restricted to 8 character names, 3 character +extensions, upper case only, no device names, and no illegal characters. + + +The mkmanifest program is compatible with the methods used in +@code{pcomm, arc,} and @code{mtools} to change perfectly good Unix +filenames to fit the MS-DOS restrictions. This command is only useful if +the target system which will read the diskette cannot handle vfat long +names. + +@subsection Example +You want to copy the following Unix files to a MS-DOS diskette (using the +@code{mcopy} command). + +@example + very_long_name + 2.many.dots + illegal: + good.c + prn.dev + Capital +@end example + +@code{Mcopy} +converts the names to: + +@example + very_lon + 2xmany.dot + illegalx + good.c + xprn.dev + capital +@end example + +The command: +@example +mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest +@end example +would produce the following: +@example + mv very_lon very_long_name + mv 2xmany.dot 2.many.dots + mv illegalx illegal: + mv xprn.dev prn.dev + mv capital Capital +@end example + +Notice that "good.c" did not require any conversion, so it did not +appear in the output. + +Suppose I've copied these files from the diskette to another Unix +system, and I now want the files back to their original names. If the +file "manifest" (the output captured above) was sent along with those +files, it could be used to convert the filenames. + +@subsection Bugs + +The short names generated by @code{mkmanifest} follow the old convention +(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0. + + +@node minfo, mlabel, mkmanifest, Commands +@section Minfo +@pindex minfo +@cindex mformat parameters +@cindex getting parameters of a Dos fs + +The @code{minfo} command prints the parameters of a Dos filesystem, such +as number of sectors, heads and cylinders. It also prints an mformat +command line which can be used to create a similar Dos filesystem on +another media. However, this doesn't work with 2m or Xdf media, and +with Dos 1.0 filesystems +@display +@code{minfo} @var{drive}: +@end display + +Mlabel supports the following option: +@table @code +@item v +Prints a hexdump of the bootsector, in addition to the other information +@end table + + +@node mlabel, mmd, minfo, Commands +@section Mlabel +@pindex mlabel +@cindex Labeling a disk +@cindex Disk label + +The @code{mlabel} command adds a volume label to a disk. Its syntax is: +@display +@code{mlabel} [@code{-vcsn}] [@code{-N} @var{serial}] @var{drive}:[@var{new_label}] +@end display + +@code{Mlabel} displays the current volume label, if present. If +@var{new_label} is not given, and if neither the @code{c} nor the +@code{s} options are set, it prompts the user for a new volume label. +To delete an existing volume label, press return at the prompt. + +Reasonable care is taken to create a valid MS-DOS volume label. If an +invalid label is specified, @code{mlabel} changes the label (and +displays the new label if the verbose mode is set). @code{Mlabel} +returns 0 on success or 1 on failure. + +Mlabel supports the following options: +@table @code +@item c +Clears an existing label, without prompting the user +@item s +Shows the existing label, without prompting the user. +@item n +Assigns a new (random) serial number to the disk +@item N @var{serial} +Sets the supplied serial number. The serial number should be supplied as +an 8 digit hexadecimal number, without spaces +@end table + + +@node mmd, mmount, mlabel, Commands +@section Mmd +@pindex mmd +@cindex Making a directory +@cindex Creating a directory +@cindex Directory creation +@cindex Subdirectory creation + +The @code{mmd} command is used to make an MS-DOS subdirectory. Its +syntax is: + +@code{mmd} [@code{-D} @var{clash_option}] @var{msdosdirectory} [ +@var{msdosdirectories}@dots{} ] + +@code{Mmd} makes a new directory on an MS-DOS filesystem. An error occurs +if the directory already exists. + + +@node mmount, mmove, mmd, Commands +@section Mmount +@pindex mmount +@cindex Linux enhancements (mmount) +@cindex Mounting a disk +@cindex High capacity formats, mounting + +The @code{mmount} command is used to mount an MS-DOS disk. It is only +available on Linux, as it is only useful if the OS kernel allows to +configure the disk geometry. Its syntax is: + +@code{mmount} @var{msdosdrive} [@var{mountargs}] + +@code{Mmount} +reads the boot sector of an MS-DOS disk, configures the drive geometry, +and finally mounts it passing +@code{mountargs} to @code{mount. } +If no mount arguments are specified, the name of the device is +used. If the disk is write protected, it is automatically mounted read +only. + + +@node mmove, mpartition, mmount, Commands +@section Mmove +@pindex mmove +@cindex Moving files (mmove) +@cindex Renaming files (mmove) + +The @code{mmove} command is used to moves or renames an existing MS-DOS +file or subdirectory. +@display +@code{mmove} [@code{-v}] [@code{-D} @var{clash_option}] @var{sourcefile} @var{targetfile} +@code{mmove} [@code{-v}] [@code{-D} @var{clash_option}] @var{sourcefile} [ @var{sourcefiles}@dots{} ] @var{targetdirectory} +@end display +@code{Mmove} moves or renames an existing MS-DOS file or +subdirectory. Unlike the MS-DOS version of @code{MOVE}, @code{mmove} is +able to move subdirectories. Files or directories can only be moved +within one filesystem. Data cannot be moved from Dos to Unix or +vice-versa. If you omit the drive letter from the target file or +directory, the same letter as for the source is assumed. If you omit +the drive letter from all parameters, drive a: is assumed by default. + +@node mpartition, mrd, mmove, Commands +@section Mpartition +@pindex mpartition +@cindex partitions (creating) +@cindex Zip disks (partitioning them) +@cindex Jaz disks (partitioning them) + +The @code{mpartition} command is used to create MS-DOS filesystems as +partitions. This is intended to be used on non-Linux systems, +i.e. systems where fdisk and easy access to Scsi devices are not +available. This command only works on drives whose partition variable +is set. + +@display +@code{mpartition} @code{-p} @var{drive} +@code{mpartition} @code{-r} @var{drive} +@code{mpartition} @code{-I} [@code{-B} @var{bootSector}] @var{drive} +@code{mpartition} @code{-a} @var{drive} +@code{mpartition} @code{-d} @var{drive} +@code{mpartition} @code{-c} [@code{-s} @var{sectors}] [@code{-h} @var{heads}] +[@code{-t} @var{cylinders}] [@code{-v} [@code{-T} @var{type}] [@code{-b} +@var{begin}] [@code{-l} length] [@code{-f}] + +@end display + +Mpartition supports the following operations: + +@table @code +@item p +Prints a command line to recreate the partition for the drive. Nothing +is printed if the partition for the drive is not defined, or an +inconsistency has been detected. If verbose (@code{-v}) is also set, +prints the current partition table. +@item r +Removes the partition described by @var{drive}. +@item I +Initializes the partition table, and removes all partitions. +@item c +Creates the partition described by @var{drive}. +@item a +"Activates" the partition, i.e. makes it bootable. Only one partition +can be bootable at a time. +@item d +"Desactivates" the partition, i.e. makes it unbootable. +@end table + +If no operation is given, the current settings are printed. + +For partition creations, the following options are available: +@table @code +@item s @var{sectors} +The number of sectors per track of the partition (which is also the +number of sectors per track for the whole drive). +@item h @var{heads} +The number of heads of the partition (which is also the number of heads +for the whole drive). By default, the geometry information (number of +sectors and heads) is figured out from neighbouring partition table +entries, or guessed from the size. +@item t @var{cylinders} +The number of cylinders of the partition (not the number of cylinders of +the whole drive. +@item b @var{begin} +The starting offset of the partition, expressed in sectors. If begin is +not given, mpartition lets the partition begin at the start of the disk +(partition number 1), or immediately after the end of the previous +partition. +@item l @var{length} +The size (length) of the partition, expressed in sectors. If end is not +given, mpartition figures out the size from the number of sectors, heads +and cylinders. If these are not given either, it gives the partition +the biggest possible size, considering disk size and start of the next +partition. +@end table + +The following option is available for all operation which modify the +partition table: +@table @code +@item f +Usually, before writing back any changes to the partition, mpartition +performs certain consistenct checks, such as checking for overlaps and +proper alignment of the partitions. If any of these checks fails, the +partition table is not changes. The @code{-f} allows you to override +these safeguards. +@end table + +The following options are available for all operations: +@table @code +@item v +Together with @code{-p} prints the partition table as it is now (no +change operation), or as it is after it is modified. +@item vv +If the verbosity flag is given twice, mpartition will print out a +hexdump of the partition table when reading it from and writing it to +the device. +@end table + +The following option is available for partition table initialization: +@table @code +@item B @var{bootSector} +Reads the template master boot record from file @var{bootSector}. +@end table + + +@node mrd, mren, mpartition, Commands +@section Mrd +@pindex mrd +@cindex Removing a directory +@cindex Erasing a directory +@cindex Deleting a directory +@cindex Directory removing +@cindex Subdirectory removing + +The @code{mrd} command is used to remove an MS-DOS subdirectory. Its +syntax is: + +@display +@code{mrd} [@code{-v}] @var{msdosdirectory} [ @var{msdosdirectories}@dots{} ] +@end display + +@code{Mrd} removes a directory from an MS-DOS filesystem. An error occurs +if the directory does not exist or is not empty. + +@node mren, mshowfat, mrd, Commands +@section Mren +@pindex mren +@cindex Renaming files (mren) +@cindex Moving files (mren) + +The @code{mren} command is used to rename or move an existing MS-DOS +file or subdirectory. Its syntax is: + +@display +@code{mren} [@code{-voOsSrRA}] @var{sourcefile} @var{targetfile} +@end display + +@code{Mren} +renames an existing file on an MS-DOS filesystem. + +In verbose mode, @code{Mren} displays the new filename if the name +supplied is invalid. + +If the first syntax is used (only one sourcefile), and if the target +name doesn't contain any slashes or colons, the file (or subdirectory) +is renamed in the same directory, instead of being moved to the current +@code{mcd} directory as would be the case with @code{mmove}. Unlike the +MS-DOS version of @code{REN}, @code{mren} can be used to rename +directories. + +@node mshowfat, mtoolstest, mren, Commands +@section Mshowfat +@pindex mshowfat +@cindex Clusters of a file +@cindex Fat + +The @code{mshowfat} command is used to display the FAT entries for a +file. Syntax: + +@display +@code{$ mshowfat files} +@end display + +@node mtoolstest, mtype, mshowfat, Commands +@section Mtoolstest +@pindex mtoolstest +@cindex Testing configuration file for correctness +@cindex Checking configuration file +@cindex Verifying configuration file + +The @code{mtoolstest} command is used to tests the mtools configuration +files. To invoke it, just type @code{mtoolstest} without any arguments. +@code{Mtoolstest} reads the mtools configuration files, and prints the +cumulative configuration to @code{stdout}. The output can be used as a +configuration file itself (although you might want to remove redundant +clauses). You may use this program to convert old-style configuration +files into new style configuration files. + +@node mtype, mzip, mtoolstest, Commands +@section Mtype + +The @code{mtype} command is used to display contents of an MS-DOS +file. Its syntax is: + +@display +@code{mtype} [@code{-ts}] @var{msdosfile} [ @var{msdosfiles}@dots{} ] +@end display + +@code{Mtype} displays the specified MS-DOS file on the screen. + +In addition to the standard options, @code{Mtype} allows the following +command line options: + +@table @code +@item t +Text file viewing. @code{Mtype} translates incoming carriage +return/line feeds to line feeds. +@item s +@code{Mtype} strips the high bit from the data. +@end table + +The @code{mcd} command may be used to establish the device and the +current working directory (relative to MS-DOS), otherwise the default is +@code{A:/}. + +@code{Mtype} returns 0 on success, 1 on utter failure, or 2 on partial +failure. + +Unlike the MS-DOS version of @code{TYPE}, @code{mtype} allows multiple +arguments. + + +@node mzip, , mtype, Commands +@section Mzip +@cindex Zip disk (utilities) +@cindex Jaz disk (utilities) +@cindex Ejecting a Zip/Jaz disk +@cindex Write protecting a Zip/Jaz disk +@pindex mzip +@cindex ZipTools disk +@cindex Tools disk (Zip and Jaz drives) +@cindex APlaceForYourStuff +@cindex password protected Zip disks + +The @code{mzip} command is used to issue ZIP disk specific commands on +Linux, Solaris or HPUX. Its syntax is: + +@display +@code{mzip} [@code{-epqrwx}] +@end display + +@code{Mzip} allows the following +command line options: + +@table @code +@item e +Ejects the disk. +@item f +Force eject even if the disk is mounted (must be given in addition to +@code{-e}). +@item r +Write protect the disk. +@item w +Remove write protection. +@item p +Password write protect. +@item x +Password protect +@item u +Temporarily unprotect the disk until it is ejected. The disk becomes +writable, and reverts back to its old state when ejected. +@item q +Queries the status +@end table + +To remove the password, set it to one of the passwordless modes +@code{-r} or @code{-w}: mzip will then ask you for the password, and +unlock the disk. If you have forgotten the password, you can get rid of +it by low-level formatting the disk (using your SCSI adaptor's BIOS +setup). + +The ZipTools disk shipped with the drive is also password protected. On +Dos or on a Mac, this password is automatically removed once the +ZipTools have been installed. From various articles posted to Usenet, I +learned that the password for the tools disk is +@code{APlaceForYourStuff}@footnote{To see the articles, search for +@code{APlaceForYourStuff} using Dejanews}. Mzip knows about this +password, and tries it first, before prompting you for a password. Thus +@code{mzip -w z:} unlocks the tools disk@footnote{I didn't know about +this yet when I bought my own Zip drive. Thus I ended up reformatting +my tools disk, and hence I haven't had the opportunity to test the +password yet. If anybody still has their tools disk with the original +password, could you try it out? Thanks in advance}. The tools disk is +formatted in a special way so as to be usable both in a PC and in a Mac. +On a PC, the Mac filesystem appears as a hidden file named +@file{partishn.mac}. You may erase it to reclaim the 50 Megs of space +taken up by the Mac filesystem. + + +@subsection Bugs + +This command is a big kludge. A proper implementation would take a +rework of significant parts of mtools, but unfortunately I don't have +the time for this right now. The main downside of this implementation is +that it is inefficient on some architectures (several successive calls +to mtools, which defeats mtools' caching). + +@node Compiling mtools, Porting mtools, Commands, Top +@chapter Architecture specific compilation flags +@cindex XDF disks (compile time configuration) +@cindex Solaris (compile time configuration of vold) +@cindex Vold (compile time configuration) +@cindex Compile time configuration + +To compile mtools, first invoke @code{./configure} before +@code{make}. In addition to the standard @code{autoconfigure} flags, +there are two architecture specific flags available. + +@table @code +@item ./configure --enable-xdf +@itemx ./configure --disable-xdf +Enables support for XDF disks. This is on by default. @xref{XDF}, +for details. +@item ./configure --enable-vold +@itemx ./configure --disable-vold +Enables support for vold on Solaris. When used in conjunction with vold, +mtools should use different device nodes than for direct access. + +@item ./configure --enable-new-vold +@itemx ./configure --disable-new-vold +Enables new support for vold on Solaris. This is supposed to work more +smoothly than the old support. + +@item ./configure --enable-floppyd +@itemx ./configure --disable-floppyd +Enables support for floppyd. By default, floppyd support is enabled as +long as the necessary X includes and libraries are available. +@end table + +@node Porting mtools, Command Index, Compiling mtools, Top +@chapter Porting mtools to architectures which are not supported yet +@cindex Porting +@cindex Compiled-in defaults + + This chapter is only interesting for those who want to port mtools to +an architecture which is not yet supported. For most common systems, +default drives are already defined. If you want to add default drives +for a still unsupported system, run config.guess, to see which +identification autoconf uses for that system. This identification is +of the form cpu-vendor-os (for example sparc-sun-sunos). The cpu and +the os parts are passed to the compiler as preprocessor flags. + The OS part is passed to the compiler in three forms. +@enumerate +@item +The complete os name, with dots replaced by underscores. sco3.2v2 would +yield sco3_2v2 +@item +The base os name. Sco3.2v2 would yield Sco +@item +The base os name plus its major version. Sco3.2v2 would yield Sco3 +@end enumerate + + All three versions are passed, if they are different. + + To define the devices, use the entries for the systems that are already +present as templates. In general, they have the following form: + +@example +#if (defined (my_cpu) && defined(my_os)) +#define predefined_devices +struct device devices[] = @{ + @{ "/dev/first_drive", 'drive_letter', drive_description@}, + @dots{} + @{ "/dev/last_drive", 'drive_letter', drive_description@} +@} +#define INIT_NOOP +#endif +@end example + + "/dev/first_drive" is the name of the device or image file +representing the drive. Drive_letter is a letter ranging from a to z +giving access to the drive. Drive_description describes the type of the +drive: +@table @code +@item ED312 +extra density (2.88M) 3 1/2 disk +@item HD312 +high density 3 1/2 disk +@item DD312 +double density 3 1/2 disk +@item HD514 +high density 5 1/4 disk +@item DD514 +double density 5 1/4 disk +@item DDsmall +8 sector double density 5 1/4 disk +@item SS514 +single sided double density 5 1/4 disk +@item SSsmall +single sided 8 sector double density 5 1/4 disk +@item GENFD +generic floppy drive (12 bit FAT) +@item GENHD +generic hard disk (16 bit FAT) +@item GEN +generic device (all parameters match) +@item ZIPJAZ(flags) +generic ZIP drive using normal access. This uses partition 4. +@code{Flags} are any special flags to be passed to open. +@item RZIPJAZ(flags) +generic ZIP drive using raw SCSI access. This uses partition 4. +@code{Flags} are any special flags to be passed to open. +@item REMOTE +the remote drive used for floppyd. Unlike the other items, this macro +also includes the file name ($DISPLAY) and the drive letter (X) +@end table + + Entries may be described in more detail: +@example + fat_bits,open_flags,cylinders,heads,sectors,DEF_ARG +@end example + or, if you need to describe an offset (filesystem doesn't start at +beginning of filesystem) +@example + fat_bits, open_flags, cylinders, heads, sectors, offset, DEF_ARG0 +@end example + +@table @code +@item fat_bits +is either 12, 16 or 0. 0 means that the device accepts both types of +FAT. +@item open_flags +may include flags such as O_NDELAY, or O_RDONLY, which might be +necessary to open the device. 0 means no special flags are needed. +@item cylinders,heads,sectors +describe the geometry of the disk. If cylinders is 0, the heads and sectors +parameters are ignored, and the drive accepts any geometry. +@item offset +is used if the DOS filesystem doesn't begin at the start of the device +or image file. This is mostly useful for Atari Ram disks (which contain +their device driver at the beginning of the file) or for DOS emulator +images (which may represent a partitioned device. +@end table + + Definition of defaults in the devices file should only be done if these +same devices are found on a large number of hosts of this type. In that +case, could you also let me know about your new definitions, so that I +can include them into the next release. For purely local file, I +recommend that you use the @code{/usr/local/etc/mtools.conf} and +@code{~/.mtoolsrc} configuration files. + + However, the devices files also allows to supply geometry setting +routines. These are necessary if you want to access high capacity +disks. + + Two routines should be supplied: + +@enumerate +@item +Reading the current parameters +@example +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +@end example + + This probes the current configured geometry, and return it in +the structure generic_floppy_struct (which must also be declared). + Fd is an open file descriptor for the device, and buf is an already +filled in stat structure, which may be useful. + This routine should return 1 if the probing fails, and 0 otherwise. + +@item +Setting new parameters +@example +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy) + struct stat *buf) +@end example + This configures the geometry contained in floppy on the file descriptor +fd. Buf is the result of a stat call (already filled in). This should +return 1 if the new geometry cannot be configured, and 0 otherwise. +@end enumerate + + A certain number of preprocessor macros should also be supplied: + +@table @code +@item TRACKS(floppy) +refers to the track field in the floppy structure +@item HEADS(floppy) +refers to the heads field in the floppy structure +@item SECTORS(floppy) +refers to the sectors per track field in the floppy structure +@item SECTORS_PER_DISK(floppy) +refers to the sectors per disk field in the floppy structure (if +applicable, otherwise leave undefined) + +@item BLOCK_MAJOR +major number of the floppy device, when viewed as a block device + +@item CHAR_MAJOR +major number of the floppy device, when viewed as a character device +(a.k.a. "raw" device, used for fsck) (leave this undefined, if your OS +doesn't have raw devices) +@end table + + For the truly high capacity formats (XDF, 2m, etc), there is no clean +and documented interface yet. + +@comment MANskip 1 + +@node Command Index, Variable Index, Porting mtools, Top +@unnumbered Command Index +@printindex pg + +@node Variable Index, Concept Index, Command Index, Top +@unnumbered Variable index +@printindex vr + +@node Concept Index, , Variable Index, Top +@unnumbered Concept index +@printindex cp + +@comment MANend-skip 1 +@comment MANend-skip 5 +@bye diff --git a/mtoolsDirentry.h b/mtoolsDirentry.h new file mode 100644 index 0000000..c8e96a5 --- /dev/null +++ b/mtoolsDirentry.h @@ -0,0 +1,69 @@ +#ifndef MTOOLS_DIRENTRY_H +#define MTOOLS_DIRENTRY_H +/* Copyright 1998,2000-2002,2005,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ +#include "sysincludes.h" +#include "vfat.h" + +typedef struct direntry_t { + struct Stream_t *Dir; + /* struct direntry_t *parent; parent level */ + int entry; /* slot in parent directory (-3 if root) */ + struct directory dir; /* descriptor in parent directory (random if + * root)*/ + wchar_t name[MAX_VNAMELEN+1]; /* name in its parent directory, or + * NULL if root */ + int beginSlot; /* begin and end slot, for delete */ + int endSlot; +} direntry_t; + +#include "stream.h" + +int vfat_lookup(direntry_t *entry, const char *filename, int length, + int flags, char *shortname, char *longname); + +struct directory *dir_read(direntry_t *entry, int *error); + +void initializeDirentry(direntry_t *entry, struct Stream_t *Dir); +int isNotFound(direntry_t *entry); +direntry_t *getParent(direntry_t *entry); +void dir_write(direntry_t *entry); +void low_level_dir_write(direntry_t *entry); +int fatFreeWithDirentry(direntry_t *entry); +int labelit(struct dos_name_t *dosname, + char *longname, + void *arg0, + direntry_t *entry); +int isSubdirOf(Stream_t *inside, Stream_t *outside); +char *getPwd(direntry_t *entry); +void fprintPwd(FILE *f, direntry_t *entry, int escape); +int write_vfat(Stream_t *, dos_name_t *, char *, int, direntry_t *); + +void wipeEntry(struct direntry_t *entry); + +void dosnameToDirentry(const struct dos_name_t *n, struct directory *dir); + +int lookupForInsert(Stream_t *Dir, + direntry_t *direntry, + struct dos_name_t *dosname, + char *longname, + struct scan_state *ssp, + int ignore_entry, + int source_entry, + int pessimisticShortRename, + int use_longname); +#endif diff --git a/mtoolsPaths.h b/mtoolsPaths.h new file mode 100644 index 0000000..07a081a --- /dev/null +++ b/mtoolsPaths.h @@ -0,0 +1,47 @@ +/* Copyright 1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Paths of the configuration files. + * This file may be changed by the user as needed. + * There are three empty lines between each definition. + * These ensure that "local" patches and official patches have + * only a very low probability of conflicting. + */ + + +#define CONF_FILE "/etc/mtools.conf" + + +#define OLD_CONF_FILE "/etc/mtools" + + + +#define LOCAL_CONF_FILE "/etc/default/mtools.conf" +/* Use this if you like to keep the configuration file in a non-standard + * place such as /etc/default, /opt/etc, /usr/etc, /usr/local/etc ... + */ + +#define SYS_CONF_FILE SYSCONFDIR "/mtools.conf" + +#define OLD_LOCAL_CONF_FILE "/etc/default/mtools" + + + +#define CFG_FILE1 "/.mtoolsrc" + + + +/* END */ diff --git a/mtoolstest.1 b/mtoolstest.1 new file mode 100644 index 0000000..24b7f9f --- /dev/null +++ b/mtoolstest.1 @@ -0,0 +1,93 @@ +.TH mtoolstest 1 "03Nov09" mtools-4.0.12 +.SH Name +mtoolstest - tests and displays the configuration +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "p mtoolstest" +.iX "c Testing configuration file for correctness" +.iX "c Checking configuration file" +.iX "c Verifying configuration file" +.PP +The \fR\&\f(CWmtoolstest\fR command is used to tests the mtools configuration +files. To invoke it, just type \fR\&\f(CWmtoolstest\fR without any arguments. +\&\fR\&\f(CWMtoolstest\fR reads the mtools configuration files, and prints the +cumulative configuration to \fR\&\f(CWstdout\fR. The output can be used as a +configuration file itself (although you might want to remove redundant +clauses). You may use this program to convert old-style configuration +files into new style configuration files. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mtype.1 b/mtype.1 new file mode 100644 index 0000000..ccf510d --- /dev/null +++ b/mtype.1 @@ -0,0 +1,113 @@ +.TH mtype 1 "03Nov09" mtools-4.0.12 +.SH Name +mtype - display contents of an MSDOS file +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.PP +The \fR\&\f(CWmtype\fR command is used to display contents of an MS-DOS +file. Its syntax is: +.PP +.ft I +.nf +\&\fR\&\f(CWmtype\fR [\fR\&\f(CW-ts\fR] \fImsdosfile\fR [ \fImsdosfiles\fR\&... ] +.fi +.ft R + +.PP +\&\fR\&\f(CWMtype\fR displays the specified MS-DOS file on the screen. +.PP +In addition to the standard options, \fR\&\f(CWMtype\fR allows the following +command line options: +.TP +\&\fR\&\f(CWt\fR\ +Text file viewing. \fR\&\f(CWMtype\fR translates incoming carriage +return/line feeds to line feeds. +.TP +\&\fR\&\f(CWs\fR\ +\&\fR\&\f(CWMtype\fR strips the high bit from the data. +.PP +The \fR\&\f(CWmcd\fR command may be used to establish the device and the +current working directory (relative to MS-DOS), otherwise the default is +\&\fR\&\f(CWA:/\fR. +.PP +\&\fR\&\f(CWMtype\fR returns 0 on success, 1 on utter failure, or 2 on partial +failure. +.PP +Unlike the MS-DOS version of \fR\&\f(CWTYPE\fR, \fR\&\f(CWmtype\fR allows multiple +arguments. +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mzip.1 b/mzip.1 new file mode 100644 index 0000000..19853fc --- /dev/null +++ b/mzip.1 @@ -0,0 +1,155 @@ +.TH mzip 1 "03Nov09" mtools-4.0.12 +.SH Name +mzip - change protection mode and eject disk on Zip/Jaz drive +'\" t +.de TQ +.br +.ns +.TP \\$1 +.. + +.tr \(is' +.tr \(if` +.tr \(pd" + +.SH Note\ of\ warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. +.PP +.SH Description +.iX "c Zip disk (utilities)" +.iX "c Jaz disk (utilities)" +.iX "c Ejecting a Zip/Jaz disk" +.iX "c Write protecting a Zip/Jaz disk" +.iX "p mzip" +.iX "c ZipTools disk" +.iX "c Tools disk (Zip and Jaz drives)" +.iX "c APlaceForYourStuff" +.iX "c password protected Zip disks" +.PP +The \fR\&\f(CWmzip\fR command is used to issue ZIP disk specific commands on +Linux, Solaris or HPUX. Its syntax is: +.PP +.ft I +.nf +\&\fR\&\f(CWmzip\fR [\fR\&\f(CW-epqrwx\fR] +.fi +.ft R + +.PP +\&\fR\&\f(CWMzip\fR allows the following +command line options: +.TP +\&\fR\&\f(CWe\fR\ +Ejects the disk. +.TP +\&\fR\&\f(CWf\fR\ +Force eject even if the disk is mounted (must be given in addition to +\&\fR\&\f(CW-e\fR). +.TP +\&\fR\&\f(CWr\fR\ +Write protect the disk. +.TP +\&\fR\&\f(CWw\fR\ +Remove write protection. +.TP +\&\fR\&\f(CWp\fR\ +Password write protect. +.TP +\&\fR\&\f(CWx\fR\ +Password protect +.TP +\&\fR\&\f(CWu\fR\ +Temporarily unprotect the disk until it is ejected. The disk becomes +writable, and reverts back to its old state when ejected. +.TP +\&\fR\&\f(CWq\fR\ +Queries the status +.PP +To remove the password, set it to one of the passwordless modes +\&\fR\&\f(CW-r\fR or \fR\&\f(CW-w\fR: mzip will then ask you for the password, and +unlock the disk. If you have forgotten the password, you can get rid of +it by low-level formatting the disk (using your SCSI adaptor's BIOS +setup). +.PP +The ZipTools disk shipped with the drive is also password protected. On +Dos or on a Mac, this password is automatically removed once the +ZipTools have been installed. From various articles posted to Usenet, I +learned that the password for the tools disk is +\&\fR\&\f(CWAPlaceForYourStuff\fR\fR. Mzip knows about this +password, and tries it first, before prompting you for a password. Thus +\&\fR\&\f(CWmzip -w z:\fR unlocks the tools disk. The tools disk is +formatted in a special way so as to be usable both in a PC and in a Mac. +On a PC, the Mac filesystem appears as a hidden file named +\&\fR\&\f(CW\(ifpartishn.mac\(is\fR. You may erase it to reclaim the 50 Megs of space +taken up by the Mac filesystem. +.PP +.SH Bugs +.PP +This command is a big kludge. A proper implementation would take a +rework of significant parts of mtools, but unfortunately I don't have +the time for this right now. The main downside of this implementation is +that it is inefficient on some architectures (several successive calls +to mtools, which defeats mtools' caching). +.PP +.SH See\ Also +Mtools' texinfo doc +.SH Viewing\ the\ texi\ doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. +.TP +* \ \ +To generate a printable copy from the texinfo doc, run the following +commands: + +.nf +.ft 3 +.in +0.3i + ./configure; make dvi; dvips mtools.dvi +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.TP +* \ \ +To generate a html copy, run: + +.nf +.ft 3 +.in +0.3i + ./configure; make html +.fi +.in -0.3i +.ft R +.lp + +\&\fRA premade html can be found at +\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR +.TP +* \ \ +To generate an info copy (browsable using emacs' info mode), run: + +.nf +.ft 3 +.in +0.3i + ./configure; make info +.fi +.in -0.3i +.ft R +.lp + +\&\fR +.PP +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. +.PP diff --git a/mzip.c b/mzip.c new file mode 100644 index 0000000..83a2b66 --- /dev/null +++ b/mzip.c @@ -0,0 +1,552 @@ +/* Copyright 1996 Grant R. Guenther, based on work of Itai Nahshon + * http://www.torque.net/ziptool.html + * Copyright 1997-2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * mzip.c + * Iomega Zip/Jaz drive tool + * change protection mode and eject disk + */ + +/* mzip.c by Markus Gyger */ +/* This code is based on ftp://gear.torque.net/pub/ziptool.c */ +/* by Grant R. Guenther with the following copyright notice: */ + +/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */ +/* http://www.torque.net/ziptool.html */ + + +/* Unprotect-till-eject modes and mount tests added + * by Ilya Ovchinnikov + */ + +#include "sysincludes.h" +#include "mtools.h" +#include "scsi.h" + +#ifndef _PASSWORD_LEN +#define _PASSWORD_LEN 33 +#endif + +#ifdef OS_linux + +#if __GLIBC__ >=2 +#include +#else +#define _LINUX_KDEV_T_H 1 /* don't redefine MAJOR/MINOR */ +#include +#endif + +#include "devices.h" + +#endif + + +static int zip_cmd(int priv, int fd, unsigned char cdb[6], int clen, + scsi_io_mode_t mode, void *data, size_t len, + void *extra_data) +{ + int r; + + if(priv) + reclaim_privs(); + r = scsi_cmd(fd, cdb, clen, mode, data, len, extra_data); + if(priv) + drop_privs(); + return r; +} + +static int test_mounted ( char *dev ) +{ +#ifdef HAVE_MNTENT_H + struct mntent *mnt; + struct MT_STAT st_dev, st_mnt; + FILE *mtab; +/* + * Now check if any partition of this device is already mounted (this + * includes checking if the device is mounted under a different name). + */ + + if (MT_STAT (dev, &st_dev)) { + fprintf (stderr, "%s: stat(%s) failed: %s.\n", + progname, dev, strerror (errno)); + exit(1); + } + + if (!S_ISBLK (st_dev.st_mode)) /* not a block device, cannot + * be mounted */ + return 0; + +#ifndef _PATH_MOUNTED +# define _PATH_MOUNTED "/etc/mtab" +#endif + + if ((mtab = setmntent (_PATH_MOUNTED, "r")) == NULL) { + fprintf (stderr, "%s: can't open %s.\n", + progname, _PATH_MOUNTED); + exit(1); + } + + while ( ( mnt = getmntent (mtab) ) ) { + if (!mnt->mnt_fsname + +#ifdef MNTTYPE_SWAP + || !strcmp (mnt->mnt_type, MNTTYPE_SWAP) +#endif +#ifdef MNTTYPE_NFS + || !strcmp (mnt->mnt_type, MNTTYPE_NFS) +#endif + || !strcmp (mnt->mnt_type, "proc") + || !strcmp (mnt->mnt_type, "smbfs") +#ifdef MNTTYPE_IGNORE + || !strcmp (mnt->mnt_type, MNTTYPE_IGNORE) +#endif + ) + continue; + + if (MT_STAT (mnt->mnt_fsname, &st_mnt)) { + continue; + } + + if (S_ISBLK (st_mnt.st_mode)) { +#ifdef OS_linux + /* on Linux, warn also if the device is on the same + * partition */ + if (MAJOR(st_mnt.st_rdev) == MAJOR(st_dev.st_rdev) && + MINOR(st_mnt.st_rdev) >= MINOR(st_dev.st_rdev) && + MINOR(st_mnt.st_rdev) <= MINOR(st_dev.st_rdev)+15){ + fprintf (stderr, + "Device %s%d is mounted on %s.\n", + dev, + MINOR(st_mnt.st_rdev) - + MINOR(st_dev.st_rdev), + mnt->mnt_dir); +#else + if(st_mnt.st_rdev != st_dev.st_rdev) { +#endif + endmntent (mtab); + return 1; + } +#if 0 + } /* keep Emacs indentation happy */ +#endif + } + } + endmntent (mtab); +#endif + return 0; +} + + +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, + "Usage: %s [-V] [-q] [-e] [-u] [-r|-w|-p|-x] [drive:]\n" + "\t-q print status\n" + "\t-e eject disk\n" + "\t-f eject disk even when mounted\n" + "\t-r write protected (read-only)\n" + "\t-w not write-protected (read-write)\n" + "\t-p password write protected\n" + "\t-x password protected\n" + "\t-u unprotect till disk ejecting\n", + progname); + exit(ret); +} + + +enum mode_t { + ZIP_RW = 0, + ZIP_RO = 2, + ZIP_RO_PW = 3, + ZIP_PW = 5, + ZIP_UNLOCK_TIL_EJECT = 8 +}; + +static enum mode_t get_zip_status(int priv, int fd, void *extra_data) +{ + unsigned char status[128]; + unsigned char cdb[6] = { 0x06, 0, 0x02, 0, sizeof status, 0 }; + + if (zip_cmd(priv, fd, cdb, 6, SCSI_IO_READ, + status, sizeof status, extra_data) == -1) { + perror("status: "); + exit(1); + } + return status[21] & 0xf; +} + + +static int short_command(int priv, int fd, int cmd1, int cmd2, + int cmd3, const char *data, void *extra_data) +{ + unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 }; + + cdb[0] = cmd1; + cdb[1] = cmd2; + cdb[4] = cmd3; + + return zip_cmd(priv, fd, cdb, 6, SCSI_IO_WRITE, + (char *) data, data ? strlen(data) : 0, extra_data); +} + + +static int iomega_command(int priv, int fd, int mode, const char *data, + void *extra_data) +{ + return short_command(priv, fd, + SCSI_IOMEGA, mode, data ? strlen(data) : 0, + data, extra_data); +} + +static int door_command(int priv, int fd, int cmd1, int cmd2, + void *extra_data) +{ + return short_command(priv, fd, cmd1, 0, cmd2, 0, extra_data); +} + +void mzip(int argc, char **argv, int type) +{ + void *extra_data; + int c; + char drive; + device_t *dev; + int fd = -1; + char name[EXPAND_BUF]; + enum { ZIP_NIX = 0, + ZIP_STATUS = 1 << 0, + ZIP_EJECT = 1 << 1, + ZIP_MODE_CHANGE = 1 << 2, + ZIP_FORCE = 1 << 3 + } request = ZIP_NIX; + + enum mode_t newMode = ZIP_RW; + enum mode_t oldMode = ZIP_RW; + +#define setMode(x) \ + if(request & ZIP_MODE_CHANGE) usage(1); \ + request |= ZIP_MODE_CHANGE; \ + newMode = x; \ + break; + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:efpqrwxuh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg, SCSI_FLAG); + break; + case 'f': + if (get_real_uid()) { + fprintf(stderr, + "Only root can use force. Sorry.\n"); + exit(1); + } + request |= ZIP_FORCE; + break; + case 'e': /* eject */ + request |= ZIP_EJECT; + break; + case 'q': /* status query */ + request |= ZIP_STATUS; + break; + + case 'p': /* password read-only */ + setMode(ZIP_RO_PW); + case 'r': /* read-only */ + setMode(ZIP_RO); + case 'w': /* read-write */ + setMode(ZIP_RW); + case 'x': /* password protected */ + setMode(ZIP_PW); + case 'u': /* password protected */ + setMode(ZIP_UNLOCK_TIL_EJECT) + case 'h': + usage(0); + default: /* unrecognized */ + usage(1); + + } + } + + if (request == ZIP_NIX) request = ZIP_STATUS; /* default action */ + + if (argc - optind > 1 || + (argc - optind == 1 && + (!argv[optind][0] || argv[optind][1] != ':'))) + usage(1); + + drive = toupper(argc - optind == 1 ? argv[argc - 1][0] : ':'); + + for (dev = devices; dev->name; dev++) { + unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 }; + struct { + char type, + type_modifier, + scsi_version, + data_format, + length, + reserved1[2], + capabilities, + vendor[8], + product[16], + revision[4], + vendor_specific[20], + reserved2[40]; + } inq_data; + + if (dev->drive != drive) + continue; + expand(dev->name, name); + if ((request & (ZIP_MODE_CHANGE | ZIP_EJECT)) && + !(request & ZIP_FORCE) && + test_mounted(name)) { + fprintf(stderr, + "Can\'t change status of/eject mounted device\n"); + exit(1); + } + precmd(dev); + + if(IS_PRIVILEGED(dev)) + reclaim_privs(); + fd = scsi_open(name, O_RDONLY +#ifdef O_NDELAY + | O_NDELAY +#endif + , 0644, + &extra_data); + if(IS_PRIVILEGED(dev)) + drop_privs(); + + /* need readonly, else we can't + * open the drive on Solaris if + * write-protected */ + if (fd == -1) + continue; + closeExec(fd); + + if (!(request & (ZIP_MODE_CHANGE | ZIP_STATUS))) + /* if no mode change or ZIP specific status is + * involved, the command (eject) is applicable + * on all drives */ + break; + + cdb[0] = SCSI_INQUIRY; + cdb[4] = sizeof inq_data; + if (zip_cmd(IS_PRIVILEGED(dev), fd, cdb, 6, SCSI_IO_READ, + &inq_data, sizeof inq_data, extra_data) != 0) { + close(fd); + continue; + } + +#ifdef DEBUG + fprintf(stderr, "device: %s\n\tvendor: %.8s\n\tproduct: %.16s\n" + "\trevision: %.4s\n", name, inq_data.vendor, + inq_data.product, inq_data.revision); +#endif /* DEBUG */ + + if (strncasecmp("IOMEGA ", inq_data.vendor, + sizeof inq_data.vendor) || + (strncasecmp("ZIP 100 ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("ZIP 100 PLUS ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("ZIP 250 ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("ZIP 750 ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("JAZ 1GB ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("JAZ 2GB ", + inq_data.product, sizeof inq_data.product))) { + + /* debugging */ + fprintf(stderr,"Skipping drive with vendor='"); + fwrite(inq_data.vendor,1, sizeof(inq_data.vendor), + stderr); + fprintf(stderr,"' product='"); + fwrite(inq_data.product,1, sizeof(inq_data.product), + stderr); + fprintf(stderr,"'\n"); + /* end debugging */ + close(fd); + continue; + } + break; /* found Zip/Jaz drive */ + } + + if (dev->drive == 0) { + fprintf(stderr, "%s: drive '%c:' is not a Zip or Jaz drive\n", + argv[0], drive); + exit(1); + } + + if (request & (ZIP_MODE_CHANGE | ZIP_STATUS)) + oldMode = get_zip_status(IS_PRIVILEGED(dev), fd, extra_data); + + if (request & ZIP_MODE_CHANGE) { + /* request temp unlock, and disk is already unlocked */ + if(newMode == ZIP_UNLOCK_TIL_EJECT && + (oldMode & ZIP_UNLOCK_TIL_EJECT)) + request &= ~ZIP_MODE_CHANGE; + + /* no password change requested, and disk is already + * in the requested state */ + if(!(newMode & 0x01) && newMode == oldMode) + request &= ~ZIP_MODE_CHANGE; + } + + if (request & ZIP_MODE_CHANGE) { + int ret; + enum mode_t unlockMode, unlockMask; + const char *passwd; + char dummy[1]; + + if(newMode == ZIP_UNLOCK_TIL_EJECT) { + unlockMode = newMode | oldMode; + unlockMask = 9; + } else { + unlockMode = newMode & ~0x5; + unlockMask = 1; + } + + if ((oldMode & unlockMask) == 1) { /* unlock first */ + char *s; + passwd = "APlaceForYourStuff"; + if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */ + iomega_command(IS_PRIVILEGED(dev), fd, unlockMode, + passwd, extra_data); + } + + if ((get_zip_status(IS_PRIVILEGED(dev), fd, extra_data) & + unlockMask) == 1) { + /* unlock first */ + char *s; + passwd = getpass("Password: "); + if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */ + if((ret=iomega_command(IS_PRIVILEGED(dev), fd, + unlockMode, passwd, + extra_data))){ + if (ret == -1) perror("passwd: "); + else fprintf(stderr, "wrong password\n"); + exit(1); + } + if((get_zip_status(IS_PRIVILEGED(dev), + fd, extra_data) & + unlockMask) == 1) { + fprintf(stderr, "wrong password\n"); + exit(1); + } + } + + if (newMode & 0x1) { + char first_try[_PASSWORD_LEN]; + + passwd = getpass("Enter new password:"); + strncpy(first_try, passwd,_PASSWORD_LEN); + passwd = getpass("Re-type new password:"); + if(strncmp(first_try, passwd, _PASSWORD_LEN)) { + fprintf(stderr, + "You mispelled it. Password not set.\n"); + exit(1); + } + } else { + passwd = dummy; + dummy[0] = '\0'; + } + + if(newMode == ZIP_UNLOCK_TIL_EJECT) + newMode |= oldMode; + + if((ret=iomega_command(IS_PRIVILEGED(dev), fd, + newMode, passwd, extra_data))){ + if (ret == -1) perror("set passwd: "); + else fprintf(stderr, "password not changed\n"); + exit(1); + } +#ifdef OS_linux + ioctl(fd, BLKRRPART); /* revalidate the disk, so that the + kernel notices that its writable + status has changed */ +#endif + } + + if (request & ZIP_STATUS) { + const char *unlocked; + + if(oldMode & 8) + unlocked = " and unlocked until eject"; + else + unlocked = ""; + switch (oldMode & ~8) { + case ZIP_RW: + printf("Drive '%c:' is not write-protected\n", + drive); + break; + case ZIP_RO: + printf("Drive '%c:' is write-protected%s\n", + drive, unlocked); + break; + case ZIP_RO_PW: + printf("Drive '%c:' is password write-protected%s\n", + drive, unlocked); + break; + case ZIP_PW: + printf("Drive '%c:' is password protected%s\n", + drive, unlocked); + break; + default: + printf("Unknown protection mode %d of drive '%c:'\n", + oldMode, drive); + break; + } + } + + if (request & ZIP_EJECT) { + if(request & ZIP_FORCE) + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_ALLOW_MEDIUM_REMOVAL, 0, + extra_data) < 0) { + perror("door unlock: "); + exit(1); + } + + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_START_STOP, 1, + extra_data) < 0) { + perror("stop motor: "); + exit(1); + } + + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_START_STOP, 2, extra_data) < 0) { + perror("eject: "); + exit(1); + } + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_START_STOP, 2, extra_data) < 0) { + perror("second eject: "); + exit(1); + } + } + + close(fd); + exit(0); +} diff --git a/nameclash.h b/nameclash.h new file mode 100644 index 0000000..8ebdb4c --- /dev/null +++ b/nameclash.h @@ -0,0 +1,75 @@ +#ifndef MTOOLS_NAMECLASH_H +#define MTOOLS_NAMECLASH_H + +/* Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "stream.h" + +typedef enum clash_action { + NAMEMATCH_NONE, + NAMEMATCH_AUTORENAME, + NAMEMATCH_QUIT, + NAMEMATCH_SKIP, + NAMEMATCH_RENAME, + NAMEMATCH_PRENAME, /* renaming of primary name */ + NAMEMATCH_OVERWRITE, + NAMEMATCH_ERROR, + NAMEMATCH_SUCCESS, + NAMEMATCH_GREW +} clash_action; + +/* clash handling structure */ +typedef struct ClashHandling_t { + clash_action action[2]; + clash_action namematch_default[2]; + + int nowarn; /* Don't ask, just do default action if name collision*/ + int got_slots; + int mod_time; + /* unsigned int dot; */ + char *myname; + unsigned char *dosname; + int single; + + int use_longname; + int ignore_entry; + int source; /* to prevent the source from overwriting itself */ + int source_entry; /* to account for the space freed up by the original + * name */ + void (*name_converter)(doscp_t *cp, + const char *filename, int verbose, + int *mangled, dos_name_t *ans); +} ClashHandling_t; + +/* write callback */ +typedef int (write_data_callback)(dos_name_t *,char *, void *, struct direntry_t *); + +int mwrite_one(Stream_t *Dir, + const char *argname, + const char *shortname, + write_data_callback *cb, + void *arg, + ClashHandling_t *ch); + +int handle_clash_options(ClashHandling_t *ch, char c); +void init_clash_handling(ClashHandling_t *ch); +Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch, + unsigned char attr, time_t mtime); + + +#endif diff --git a/packaging/fix_mlabel_initialisation.patch b/packaging/fix_mlabel_initialisation.patch new file mode 100644 index 0000000..77a98cf --- /dev/null +++ b/packaging/fix_mlabel_initialisation.patch @@ -0,0 +1,13 @@ +Index: mtools-4.0.12/mlabel.c +=================================================================== +--- mtools-4.0.12.orig/mlabel.c ++++ mtools-4.0.12/mlabel.c +@@ -35,7 +35,7 @@ void label_name(doscp_t *cp, const char + int have_lower, have_upper; + wchar_t wbuffer[12]; + +- memset(ans, ' ', sizeof(ans)-1); ++ memset(ans, ' ', sizeof(*ans)-1); + ans->sentinel = '\0'; + len = native_to_wchar(filename, wbuffer, 11, 0, 0); + if(len > 11){ diff --git a/packaging/mtools-3.9.6-config.patch b/packaging/mtools-3.9.6-config.patch new file mode 100644 index 0000000..89e2a0c --- /dev/null +++ b/packaging/mtools-3.9.6-config.patch @@ -0,0 +1,38 @@ +--- mtools-3.9.6/mtools.conf.fixes Sun Jan 4 04:29:32 1998 ++++ mtools-3.9.6/mtools.conf Wed Feb 9 11:41:36 2000 +@@ -1,22 +1,25 @@ + # Example mtools.conf files. Uncomment the lines which correspond to + # your architecture and comment out the "SAMPLE FILE" line below +-SAMPLE FILE + +-# # Linux floppy drives +-# drive a: file="/dev/fd0" exclusive +-# drive b: file="/dev/fd1" exclusive ++# Linux floppy drives ++drive a: file="/dev/fd0" exclusive 1.44m mformat_only ++drive b: file="/dev/fd1" exclusive 1.44m mformat_only + +-# # First SCSI hard disk partition +-# drive c: file="/dev/sda1" ++# First SCSI hard disk partition ++#drive c: file="/dev/sda1" + +-# # First IDE hard disk partition +-# drive c: file="/dev/hda1" ++# First IDE hard disk partition ++#drive c: file="/dev/hda1" + + # # dosemu floppy image + # drive m: file="/var/lib/dosemu/diskimage" + +-# # dosemu hdimage +-# drive n: file="/var/lib/dosemu/diskimage" offset=3840 ++# dosemu hdimage ++drive n: file="/var/lib/dosemu/hdimage" offset=8832 ++ ++# # HPOJ (ptal-photod) ++mtools_skip_check=1 ++drive p: file=":0" remote + + # # Atari ramdisk image + # drive o: file="/tmp/atari_rd" offset=136 diff --git a/packaging/mtools-3.9.7-bigdisk.patch b/packaging/mtools-3.9.7-bigdisk.patch new file mode 100644 index 0000000..eb5e6cc --- /dev/null +++ b/packaging/mtools-3.9.7-bigdisk.patch @@ -0,0 +1,13 @@ +--- mtools-3.9.7/mtools.conf.big Wed May 16 19:07:57 2001 ++++ mtools-3.9.7/mtools.conf Wed May 16 19:08:12 2001 +@@ -2,8 +2,8 @@ + # your architecture and comment out the "SAMPLE FILE" line below + + # Linux floppy drives +-drive a: file="/dev/fd0" exclusive 1.44m mformat_only +-drive b: file="/dev/fd1" exclusive 1.44m mformat_only ++drive a: file="/dev/fd0" exclusive mformat_only ++drive b: file="/dev/fd1" exclusive mformat_only + + # First SCSI hard disk partition + #drive c: file="/dev/sda1" diff --git a/packaging/mtools.changes b/packaging/mtools.changes new file mode 100644 index 0000000..087aec2 --- /dev/null +++ b/packaging/mtools.changes @@ -0,0 +1,206 @@ +* Fri Jun 01 2012 vivian zhang - 4.0.12 +- Initial import + +* Fri Feb 11 2011 Yi Yang - 4.0.12 +- Fix label set error (BMC#11746) + +* Mon Feb 01 2010 Yi Yang - 4.0.12 +- Update to 4.0.12 + +* Tue Feb 17 2009 Anas Nashif 4.0.4 +- Update to 4.0.4 + +* Fri Sep 12 2008 vivian zhang 3.9.11 +- add check for the info file before installing it in post/preun +- add %doc to man/info in spec file + +* Tue Feb 19 2008 Adam Tkac 3.9.11-4 +- fixed building on x86_64 (build with --disable-floppyd) + +* Mon Feb 18 2008 Fedora Release Engineering - 3.9.11-3.1 +- Autorebuild for GCC 4.3 + +* Mon Jan 14 2008 Adam Tkac 3.9.11-2.1 +- corrected post and preun sections (#428478) +- fix rpmlint errors +- start use autoreconf + +* Wed Aug 22 2007 Adam Tkac 3.9.11-2 +- rebuild (BuildID feature) +- change license to GPLv2+ + +* Wed May 31 2007 Adam Tkac 3.9.11-1 +- updated to latest upstream (3.9.11) + +* Fri May 11 2007 Adam Tkac 3.9.10-7 +- in the end script has been completely rewriten by + +* Fri May 11 2007 Adam Tkac 3.9.10-6 +- some minor changes in sh patch (changed sh to bash) + +* Fri May 11 2007 Adam Tkac 3.9.10-5 +- patch to #239741 by Matej Cepl + (rewrites /usr/bin/amuFormat.sh to /bin/sh) + +* Tue Feb 05 2007 Adam Tkac 3.9.10-4 +- fixed some unstandard statements in spec file (#226162) + +* Mon Jan 22 2007 Adam Tkac 3.9.10-3 +- Resolves: #223712 +- applied Ville Skytta's (ville.skytta "antispam" iki.fi) patch + (install-info scriptlet failures) + +* Wed Aug 09 2006 Jitka Kudrnacova - 3.9.10-2 +- rebuilt to prevent corruption on the 13th character (#195528) + +* Wed Jul 12 2006 Jesse Keating - 3.9.10-1.2.2 +- rebuild + +* Fri Feb 10 2006 Jesse Keating - 3.9.10-1.2.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 3.9.10-1.2 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Fri Dec 09 2005 Jesse Keating +- rebuilt + +* Wed Oct 19 2005 Tim Waugh 3.9.10-1 +- 3.9.10. + +* Mon Mar 21 2005 Tim Waugh 3.9.9-13 +- Fixed memset() usage bug. + +* Tue Mar 15 2005 Tim Waugh 3.9.9-12 +- Fix build (bug #151135). + +* Wed Mar 2 2005 Tim Waugh 3.9.9-11 +- Rebuild for new GCC. + +* Fri Dec 10 2004 Tim Waugh 3.9.9-10 +- Fixed mpartition --help output (bug #65293). + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Thu Jan 8 2004 Tim Waugh 3.9.9-7 +- Fix mistaken use of '&' instead of '&&'. + +* Tue Dec 9 2003 Tim Waugh 3.9.9-6 +- Remove last (incorrect) change. + +* Tue Dec 9 2003 Tim Waugh 3.9.9-5 +- Fix mistaken variable assignment in comparison (bug #110823). + +* Thu Nov 27 2003 Tim Waugh +- Build requires texinfo (bug #111000). + +* Sat Oct 25 2003 Tim Waugh 3.9.9-4 +- Rebuilt. + +* Wed Jun 04 2003 Elliot Lee +- rebuilt + +* Thu May 22 2003 Tim Waugh 3.9.9-2 +- Fix mcomp with no arguments (bug #91372). + +* Tue Mar 18 2003 Tim Waugh 3.9.9-1 +- 3.9.9. +- Add config lines for hpoj photo-card access on drive P:. + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Wed Nov 20 2002 Tim Powers +- rebuilt in current collinst + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Sun Jun 24 2001 Bernhard Rosenkraenzer 3.9.8-2 +- Add patch from maintainer + +* Mon May 28 2001 Bernhard Rosenkraenzer 3.9.8-1 +- 3.9.8 final + +* Mon May 21 2001 Bernhard Rosenkraenzer 3.9.8-0.pre1.0 +- 3.9.8pre1 + +* Wed May 16 2001 Bernhard Rosenkraenzer 3.9.7-6 +- Fix support for disks > 1.44 MB (#40857) + +* Tue May 8 2001 Bernhard Rosenkraenzer 3.9.7-5 +- Update to 20010507 + +* Wed Jan 10 2001 Bernhard Rosenkraenzer +- Apply the author's current patches, fixes among other things + ZIP drive support and doesn't crash when trying to access a BSD disk + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Sat Jun 17 2000 Trond Eivind Glomsrod +- specify ownership + +* Wed Jun 07 2000 Trond Eivind Glomsrod +- Version 3.9.7 +- use %%{_mandir}, %%{_makeinstall}, %%configure, %%makeinstall + and %%{_tmppath} + +* Wed Feb 09 2000 Cristian Gafton +- get rid of mtools.texi as a doc file (we have the info file) +- fix config file so mtools work (#9264) +- fix references to the config file to be /etc/mtools.conf + +* Fri Feb 4 2000 Bill Nottingham +- expunge floppyd + +* Thu Feb 03 2000 Cristian Gafton +- man pages are compressed +- fix description +- version 3.9.6 + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 5) + +* Thu Mar 18 1999 Cristian Gafton +- patch to make the texi sources compile +- fix the spec file group and description +- fixed floppy drive sizes + +* Tue Dec 29 1998 Cristian Gafton +- build for 6.0 +- fixed invalid SAMPLE_FILE configuration file + +* Wed Sep 02 1998 Michael Maher +- Built package for 5.2. +- Updated Source to 3.9.1. +- Cleaned up spec file. + +* Fri Apr 24 1998 Prospector System +- translations modified for de, fr, tr + +* Fri Apr 10 1998 Cristian Gafton +- updated to 3.8 + +* Tue Oct 21 1997 Otto Hammersmith +- changed buildroot to /var/tmp, rather than /tmp +- use install-info + +* Mon Jul 21 1997 Erik Troan +- built against glibc + +* Thu Apr 17 1997 Erik Troan +- Changed sysconfdir to be /etc + +* Mon Apr 14 1997 Michael Fulbright +- Updated to 3.6 diff --git a/packaging/mtools.spec b/packaging/mtools.spec new file mode 100644 index 0000000..fa22613 --- /dev/null +++ b/packaging/mtools.spec @@ -0,0 +1,51 @@ +Summary: Programs for accessing MS-DOS disks without mounting the disks +Name: mtools +Version: 4.0.12 +Release: 4 +License: GPLv2+ +Group: Applications/System +Source: ftp://ftp.gnu.org/gnu/mtools/mtools-%{version}.tar.bz2 +Url: http://mtools.linux.lu/ +Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Patch0: mtools-3.9.6-config.patch +Patch1: mtools-3.9.7-bigdisk.patch +Patch2: fix_mlabel_initialisation.patch + +BuildRequires: texinfo, autoconf + +%description +Mtools is a collection of utilities for accessing MS-DOS files. +Mtools allow you to read, write and move around MS-DOS filesystem +files (normally on MS-DOS floppy disks). Mtools supports Windows95 +style long file names, OS/2 XDF disks, and 2m disks + +Mtools should be installed if you need to use MS-DOS disks + +%prep +%setup -q -n %{name}-%{version} +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 + +%build +autoreconf -fiv +%configure --disable-floppyd +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT/etc $RPM_BUILD_ROOT/%{_infodir} +%makeinstall +install -m644 mtools.conf $RPM_BUILD_ROOT/etc + +# We aren't shipping this. +find $RPM_BUILD_ROOT -name "floppyd*" -exec rm {} \; + +%remove_docs + +%files +%defattr(-,root,root) +%config(noreplace) /etc/mtools.conf +%doc COPYING README Release.notes +/usr/bin/* + diff --git a/partition.h b/partition.h new file mode 100644 index 0000000..5c43739 --- /dev/null +++ b/partition.h @@ -0,0 +1,49 @@ +/* Copyright 1997,1998,2001-2003,2006,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +typedef struct hsc { + unsigned char byte0; + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ +} hsc; + +#define head(x) ((unsigned int)((x).head)) +#define sector(x) ((unsigned int)((x).sector & 0x3f)) +#define cyl(x) ((unsigned int)((x).cyl | (((x).sector & 0xc0)<<2))) + +#define BEGIN(p) _DWORD((p).start_sect) +#define END(p) (_DWORD((p).start_sect)+(_DWORD((p).nr_sects))) + + +struct partition { + hsc start; + hsc end; + unsigned char start_sect[4]; /* starting sector counting from 0 */ + unsigned char nr_sects[4]; /* nr of sectors in partition */ +}; + +#define boot_ind start.byte0 +#define sys_ind end.byte0 + +int consistencyCheck(struct partition *partTable, int doprint, int verbose, + int *has_activated, unsigned int *last_end, + unsigned int *j, + struct device *used_dev, int target_partition); + +void setBeginEnd(struct partition *partTable, int begin, int end, + int heads, int sector, int activate, int type); diff --git a/patchlevel.c b/patchlevel.c new file mode 100644 index 0000000..28e0a08 --- /dev/null +++ b/patchlevel.c @@ -0,0 +1,24 @@ +/* Copyright 1999-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +const char *mversion="4.0.12"; + +/* Multiple releases on same day should be marked with (b), (cd), (d) after + * date string below */ +const char *mdate = "November 3rd, 2009"; + +const char *mformat_banner = "MTOO4012"; diff --git a/plain_io.c b/plain_io.c new file mode 100644 index 0000000..a82f00b --- /dev/null +++ b/plain_io.c @@ -0,0 +1,784 @@ +/* Copyright 1995-2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Io to a plain file or device + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + +#include "sysincludes.h" +#include "stream.h" +#include "mtools.h" +#include "msdos.h" +#include "plain_io.h" +#include "scsi.h" +#include "partition.h" +#include "llong.h" + +typedef struct SimpleFile_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + struct MT_STAT statbuf; + int fd; + mt_off_t offset; + mt_off_t lastwhere; + int seekable; + int privileged; +#ifdef OS_hpux + int size_limited; +#endif + int scsi_sector_size; + void *extra_data; /* extra system dependant information for scsi */ + int swap; /* do the word swapping */ +} SimpleFile_t; + + +#include "lockdev.h" + +typedef int (*iofn) (int, char *, int); + + +static void swap_buffer(char *buf, size_t len) +{ + unsigned int i; + for (i=0; ioffset; + + if (This->seekable && where != This->lastwhere ){ + if(mt_lseek( This->fd, where, SEEK_SET) < 0 ){ + perror("seek"); + This->lastwhere = (mt_off_t) -1; + return -1; + } + } + +#ifdef OS_hpux + /* + * On HP/UX, we can not write more than MAX_LEN bytes in one go. + * If more are written, the write fails with EINVAL + */ + #define MAX_SCSI_LEN (127*1024) + if(This->size_limited && len > MAX_SCSI_LEN) + len = MAX_SCSI_LEN; +#endif + ret = io(This->fd, buf, len); + +#ifdef OS_hpux + if (ret == -1 && + errno == EINVAL && /* if we got EINVAL */ + len > MAX_SCSI_LEN) { + This->size_limited = 1; + len = MAX_SCSI_LEN; + ret = io(This->fd, buf, len); + } +#endif + + if ( ret == -1 ){ + perror("plain_io"); + This->lastwhere = (mt_off_t) -1; + return -1; + } + This->lastwhere = where + ret; + return ret; +} + + + +static int file_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + DeclareThis(SimpleFile_t); + + int result = file_io(Stream, buf, where, len, (iofn) read); + + if ( This->swap ) + swap_buffer( buf, len ); + return result; +} + +static int file_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + DeclareThis(SimpleFile_t); + + if ( !This->swap ) + return file_io(Stream, buf, where, len, (iofn) write); + else { + int result; + char *swapping = malloc( len ); + memcpy( swapping, buf, len ); + swap_buffer( swapping, len ); + + result = file_io(Stream, swapping, where, len, (iofn) write); + + free(swapping); + return result; + } +} + +static int file_flush(Stream_t *Stream) +{ +#if 0 + DeclareThis(SimpleFile_t); + + return fsync(This->fd); +#endif + return 0; +} + +static int file_free(Stream_t *Stream) +{ + DeclareThis(SimpleFile_t); + + if (This->fd > 2) + return close(This->fd); + else + return 0; +} + +static int file_geom(Stream_t *Stream, struct device *dev, + struct device *orig_dev, + int media, union bootsector *boot) +{ + int ret; + DeclareThis(SimpleFile_t); + size_t tot_sectors; + int BootP, Infp0, InfpX, InfTm; + int sectors, j; + unsigned char sum; + int sect_per_track; + struct label_blk_t *labelBlock; + + dev->ssize = 2; /* allow for init_geom to change it */ + dev->use_2m = 0x80; /* disable 2m mode to begin */ + + if(media == 0xf0 || media >= 0x100){ + dev->heads = WORD(nheads); + dev->sectors = WORD(nsect); + tot_sectors = DWORD(bigsect); + SET_INT(tot_sectors, WORD(psect)); + sect_per_track = dev->heads * dev->sectors; + if(sect_per_track == 0) { + if(mtools_skip_check) { + /* add some fake values if sect_per_track is + * zero. Indeed, some atari disks lack the + * geometry values (i.e. have zeroes in their + * place). In order to avoid division by zero + * errors later on, plug 1 everywhere + */ + dev->heads = 1; + dev->sectors = 1; + sect_per_track = 1; + } else { + fprintf(stderr, "The devil is in the details: zero number of heads or sectors\n"); + exit(1); + } + } + tot_sectors += sect_per_track - 1; /* round size up */ + dev->tracks = tot_sectors / sect_per_track; + + BootP = WORD(ext.old.BootP); + Infp0 = WORD(ext.old.Infp0); + InfpX = WORD(ext.old.InfpX); + InfTm = WORD(ext.old.InfTm); + + if(WORD(fatlen)) { + labelBlock = &boot->boot.ext.old.labelBlock; + } else { + labelBlock = &boot->boot.ext.fat32.labelBlock; + } + + if (boot->boot.descr >= 0xf0 && + labelBlock->dos4 == 0x29 && + strncmp( boot->boot.banner,"2M", 2 ) == 0 && + BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 && + BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 && + Infp0 >= 76 ){ + for (sum=0, j=63; j < BootP; j++) + sum += boot->bytes[j];/* checksum */ + dev->ssize = boot->bytes[InfTm]; + if (!sum && dev->ssize <= 7){ + dev->use_2m = 0xff; + dev->ssize |= 0x80; /* is set */ + } + } + } else if (media >= 0xf8){ + media &= 3; + dev->heads = old_dos[media].heads; + dev->tracks = old_dos[media].tracks; + dev->sectors = old_dos[media].sectors; + dev->ssize = 0x80; + dev->use_2m = ~1; + } else { + fprintf(stderr,"Unknown media type\n"); + exit(1); + } + + sectors = dev->sectors; + dev->sectors = dev->sectors * WORD(secsiz) / 512; + +#ifdef JPD + printf("file_geom:media=%0X=>cyl=%d,heads=%d,sects=%d,ssize=%d,use2m=%X\n", + media, dev->tracks, dev->heads, dev->sectors, dev->ssize, + dev->use_2m); +#endif + ret = init_geom(This->fd,dev, orig_dev, &This->statbuf); + dev->sectors = sectors; +#ifdef JPD + printf("f_geom: after init_geom(), sects=%d\n", dev->sectors); +#endif + return ret; +} + + +static int file_data(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + DeclareThis(SimpleFile_t); + + if(date) + *date = This->statbuf.st_mtime; + if(size) + *size = This->statbuf.st_size; + if(type) + *type = S_ISDIR(This->statbuf.st_mode); + if(address) + *address = 0; + return 0; +} + +/* ZIP or other scsi device on Solaris or SunOS system. + Since Sun won't accept a non-Sun label on a scsi disk, we must + bypass Sun's disk interface and use low-level SCSI commands to read + or write the ZIP drive. We thus replace the file_read and file_write + routines with our own scsi_read and scsi_write routines, that use the + uscsi ioctl interface. By James Dugal, jpd@usl.edu, 11-96. Tested + under Solaris 2.5 and SunOS 4.3.1_u1 using GCC. + + Note: the mtools.conf entry for a ZIP drive would look like this: +(solaris) drive C: file="/dev/rdsk/c0t5d0s2" partition=4 FAT=16 nodelay exclusive scsi=& +(sunos) drive C: file="/dev/rsd5c" partition=4 FAT=16 nodelay exclusive scsi=1 + + Note 2: Sol 2.5 wants mtools to be suid-root, to use the ioctl. SunOS is + happy if we just have access to the device, so making mtools sgid to a + group called, say, "ziprw" which has rw permission on /dev/rsd5c, is fine. + */ + +#define MAXBLKSPERCMD 255 + +static void scsi_init(SimpleFile_t *This) +{ + int fd = This->fd; + unsigned char cdb[10],buf[8]; + + memset(cdb, 0, sizeof cdb); + memset(buf,0, sizeof(buf)); + cdb[0]=SCSI_READ_CAPACITY; + if (scsi_cmd(fd, (unsigned char *)cdb, + sizeof(cdb), SCSI_IO_READ, buf, sizeof(buf), This->extra_data)==0) + { + This->scsi_sector_size= + ((unsigned)buf[5]<<16)|((unsigned)buf[6]<<8)|(unsigned)buf[7]; + if (This->scsi_sector_size != 512) + fprintf(stderr," (scsi_sector_size=%d)\n",This->scsi_sector_size); + } +} + +static int scsi_io(Stream_t *Stream, char *buf, + mt_off_t where, size_t len, int rwcmd) +{ + unsigned int firstblock, nsect; + int clen,r; + size_t max; + off_t offset; + unsigned char cdb[10]; + DeclareThis(SimpleFile_t); + + firstblock=truncBytes32((where + This->offset)/This->scsi_sector_size); + /* 512,1024,2048,... bytes/sector supported */ + offset=truncBytes32(where + This->offset - + firstblock*This->scsi_sector_size); + nsect=(offset+len+This->scsi_sector_size-1)/ This->scsi_sector_size; +#if defined(OS_sun) && defined(OS_i386) + if (This->scsi_sector_size>512) + firstblock*=This->scsi_sector_size/512; /* work around a uscsi bug */ +#endif /* sun && i386 */ + + if (len>512) { + /* avoid buffer overruns. The transfer MUST be smaller or + * equal to the requested size! */ + while (nsect*This->scsi_sector_size>len) + --nsect; + if(!nsect) { + fprintf(stderr,"Scsi buffer too small\n"); + exit(1); + } + if(rwcmd == SCSI_IO_WRITE && offset) { + /* there seems to be no memmove before a write */ + fprintf(stderr,"Unaligned write\n"); + exit(1); + } + /* a better implementation should use bounce buffers. + * However, in normal operation no buffer overruns or + * unaligned writes should happen anyways, as the logical + * sector size is (hopefully!) equal to the physical one + */ + } + + + max = scsi_max_length(); + + if (nsect > max) + nsect=max; + + /* set up SCSI READ/WRITE command */ + memset(cdb, 0, sizeof cdb); + + switch(rwcmd) { + case SCSI_IO_READ: + cdb[0] = SCSI_READ; + break; + case SCSI_IO_WRITE: + cdb[0] = SCSI_WRITE; + break; + } + + cdb[1] = 0; + + if (firstblock > 0x1fffff || nsect > 0xff) { + /* I suspect that the ZIP drive also understands Group 1 + * commands. If that is indeed true, we may chose Group 1 + * more agressively in the future */ + + cdb[0] |= SCSI_GROUP1; + clen=10; /* SCSI Group 1 cmd */ + + /* this is one of the rare case where explicit coding is + * more portable than macros... The meaning of scsi command + * bytes is standardised, whereas the preprocessor macros + * handling it might be not... */ + + cdb[2] = (unsigned char) (firstblock >> 24) & 0xff; + cdb[3] = (unsigned char) (firstblock >> 16) & 0xff; + cdb[4] = (unsigned char) (firstblock >> 8) & 0xff; + cdb[5] = (unsigned char) firstblock & 0xff; + cdb[6] = 0; + cdb[7] = (unsigned char) (nsect >> 8) & 0xff; + cdb[8] = (unsigned char) nsect & 0xff; + cdb[9] = 0; + } else { + clen = 6; /* SCSI Group 0 cmd */ + cdb[1] |= (unsigned char) ((firstblock >> 16) & 0x1f); + cdb[2] = (unsigned char) ((firstblock >> 8) & 0xff); + cdb[3] = (unsigned char) firstblock & 0xff; + cdb[4] = (unsigned char) nsect; + cdb[5] = 0; + } + + if(This->privileged) + reclaim_privs(); + + r=scsi_cmd(This->fd, (unsigned char *)cdb, clen, rwcmd, buf, + nsect*This->scsi_sector_size, This->extra_data); + + if(This->privileged) + drop_privs(); + + if(r) { + perror(rwcmd == SCSI_IO_READ ? "SCMD_READ" : "SCMD_WRITE"); + return -1; + } +#ifdef JPD + printf("finished %u for %u\n", firstblock, nsect); +#endif + +#ifdef JPD + printf("zip: read or write OK\n"); +#endif + if (offset>0) memmove(buf,buf+offset,nsect*This->scsi_sector_size-offset); + if (len==256) return 256; + else if (len==512) return 512; + else return nsect*This->scsi_sector_size-offset; +} + +static int scsi_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + +#ifdef JPD + printf("zip: to read %d bytes at %d\n", len, where); +#endif + return scsi_io(Stream, buf, where, len, SCSI_IO_READ); +} + +static int scsi_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ +#ifdef JPD + Printf("zip: to write %d bytes at %d\n", len, where); +#endif + return scsi_io(Stream, buf, where, len, SCSI_IO_WRITE); +} + +static Class_t ScsiClass = { + scsi_read, + scsi_write, + file_flush, + file_free, + file_geom, + file_data, + 0 /* pre-allocate */ +}; + + +static Class_t SimpleFileClass = { + file_read, + file_write, + file_flush, + file_free, + file_geom, + file_data, + 0 /* pre_allocate */ +}; + + +Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev, + const char *name, int mode, char *errmsg, + int mode2, int locked, mt_size_t *maxSize) +{ + SimpleFile_t *This; +#ifdef __EMX__ +HFILE FileHandle; +ULONG Action; +APIRET rc; +#endif + This = New(SimpleFile_t); + if (!This){ + printOom(); + return 0; + } + This->scsi_sector_size = 512; + This->seekable = 1; +#ifdef OS_hpux + This->size_limited = 0; +#endif + This->Class = &SimpleFileClass; + if (!name || strcmp(name,"-") == 0 ){ + if (mode == O_RDONLY) + This->fd = 0; + else + This->fd = 1; + This->seekable = 0; + This->refs = 1; + This->Next = 0; + This->Buffer = 0; + if (MT_FSTAT(This->fd, &This->statbuf) < 0) { + Free(This); + if(errmsg) +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"Can't stat -: %s", + strerror(errno)); +#else + sprintf(errmsg,"Can't stat -: %s", + strerror(errno)); +#endif + return NULL; + } + + return (Stream_t *) This; + } + + + if(dev) { + if(!(mode2 & NO_PRIV)) + This->privileged = IS_PRIVILEGED(dev); + mode |= dev->mode; + } + + precmd(dev); + if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV)) + reclaim_privs(); + +#ifdef __EMX__ +#define DOSOPEN_FLAGS (OPEN_FLAGS_DASD | OPEN_FLAGS_WRITE_THROUGH | \ + OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_RANDOM | \ + OPEN_FLAGS_NO_CACHE) +#define DOSOPEN_FD_ACCESS (OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE) +#define DOSOPEN_HD_ACCESS (OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY) + + if (isalpha(*name) && (*(name+1) == ':')) { + rc = DosOpen( + name, &FileHandle, &Action, 0L, FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS, DOSOPEN_FLAGS | + (IS_NOLOCK(dev)?DOSOPEN_HD_ACCESS:DOSOPEN_FD_ACCESS), + 0L); +#if DEBUG + if (rc != NO_ERROR) fprintf (stderr, "DosOpen() returned %d\n", rc); +#endif + if (!IS_NOLOCK(dev)) { + rc = DosDevIOCtl( + FileHandle, 0x08L, DSK_LOCKDRIVE, 0, 0, 0, 0, 0, 0); +#if DEBUG + if (rc != NO_ERROR) fprintf (stderr, "DosDevIOCtl() returned %d\n", rc); +#endif + } + if (rc == NO_ERROR) + This->fd = _imphandle(FileHandle); else This->fd = -1; + } else +#endif + { + if (IS_SCSI(dev)) + This->fd = scsi_open(name, mode, IS_NOLOCK(dev)?0444:0666, + &This->extra_data); + else + This->fd = open(name, mode | O_LARGEFILE | O_BINARY, + IS_NOLOCK(dev)?0444:0666); + } + + if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV)) + drop_privs(); + + if (This->fd < 0) { + Free(This); + if(errmsg) +#ifdef HAVE_SNPRINTF + snprintf(errmsg, 199, "Can't open %s: %s", + name, strerror(errno)); +#else + sprintf(errmsg, "Can't open %s: %s", + name, strerror(errno)); +#endif + return NULL; + } + + if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV)) + closeExec(This->fd); + +#ifdef __EMX__ + if (*(name+1) != ':') +#endif + if (MT_FSTAT(This->fd, &This->statbuf) < 0 +#ifdef OS_mingw32msvc + && strncmp(name, "\\\\.\\", 4) != 0 +#endif + ) { + Free(This); + if(errmsg) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"Can't stat %s: %s", + name, strerror(errno)); +#else + if(strlen(name) > 50) { + sprintf(errmsg,"Can't stat file: %s", + strerror(errno)); + } else { + sprintf(errmsg,"Can't stat %s: %s", + name, strerror(errno)); + } +#endif + } + return NULL; + } +#ifndef __EMX__ +#ifndef __CYGWIN__ +#ifndef OS_mingw32msvc + /* lock the device on writes */ + if (locked && lock_dev(This->fd, mode == O_RDWR, dev)) { + if(errmsg) +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199, + "plain floppy: device \"%s\" busy (%s):", + dev ? dev->name : "unknown", strerror(errno)); +#else + sprintf(errmsg, + "plain floppy: device \"%s\" busy (%s):", + (dev && strlen(dev->name) < 50) ? + dev->name : "unknown", strerror(errno)); +#endif + + close(This->fd); + Free(This); + return NULL; + } +#endif +#endif +#endif + /* set default parameters, if needed */ + if (dev){ + if ((!IS_MFORMAT_ONLY(dev) && dev->tracks) && + init_geom(This->fd, dev, orig_dev, &This->statbuf)){ + close(This->fd); + Free(This); + if(errmsg) + sprintf(errmsg,"init: set default params"); + return NULL; + } + This->offset = (mt_off_t) dev->offset; + } else + This->offset = 0; + + This->refs = 1; + This->Next = 0; + This->Buffer = 0; + + if(maxSize) { + if (IS_SCSI(dev)) { + *maxSize = MAX_OFF_T_B(31+log_2(This->scsi_sector_size)); + } else { + *maxSize = max_off_t_seek; + } + if(This->offset > *maxSize) { + close(This->fd); + Free(This); + if(errmsg) + sprintf(errmsg,"init: Big disks not supported"); + return NULL; + } + + *maxSize -= This->offset; + } + /* partitioned drive */ + + /* jpd@usl.edu: assume a partitioned drive on these 2 systems is a ZIP*/ + /* or similar drive that must be accessed by low-level scsi commands */ + /* AK: introduce new "scsi=1" statement to specifically set + * this option. Indeed, there could conceivably be partitioned + * devices where low level scsi commands will not be needed */ + if(IS_SCSI(dev)) { + This->Class = &ScsiClass; + if(This->privileged) + reclaim_privs(); + scsi_init(This); + if(This->privileged) + drop_privs(); + } + + This->swap = DO_SWAP( dev ); + + if(!(mode2 & NO_OFFSET) && + dev && (dev->partition > 4 || dev->partition < 0)) + fprintf(stderr, + "Invalid partition %d (must be between 0 and 4), ignoring it\n", + dev->partition); + + while(!(mode2 & NO_OFFSET) && + dev && dev->partition && dev->partition <= 4) { + int has_activated; + unsigned int last_end, j; + unsigned char buf[2048]; + struct partition *partTable=(struct partition *)(buf+ 0x1ae); + size_t partOff; + + /* read the first sector, or part of it */ + if (force_read((Stream_t *)This, (char*) buf, 0, 512) != 512) + break; + if( _WORD(buf+510) != 0xaa55) + break; + + partOff = BEGIN(partTable[dev->partition]); + if (maxSize) { + if (partOff > *maxSize >> 9) { + close(This->fd); + Free(This); + if(errmsg) + sprintf(errmsg,"init: Big disks not supported"); + return NULL; + } + *maxSize -= (mt_off_t) partOff << 9; + } + + This->offset += (mt_off_t) partOff << 9; + if(!partTable[dev->partition].sys_ind) { + if(errmsg) + sprintf(errmsg, + "init: non-existant partition"); + close(This->fd); + Free(This); + return NULL; + } + + if(!dev->tracks) { + dev->heads = head(partTable[dev->partition].end)+1; + dev->sectors = sector(partTable[dev->partition].end); + dev->tracks = cyl(partTable[dev->partition].end) - + cyl(partTable[dev->partition].start)+1; + } + dev->hidden= + dev->sectors*head(partTable[dev->partition].start) + + sector(partTable[dev->partition].start)-1; + if(!mtools_skip_check && + consistencyCheck((struct partition *)(buf+0x1ae), 0, 0, + &has_activated, &last_end, &j, dev, 0)) { + fprintf(stderr, + "Warning: inconsistent partition table\n"); + fprintf(stderr, + "Possibly unpartitioned device\n"); + fprintf(stderr, + "\n*** Maybe try without partition=%d in " + "device definition ***\n\n", + dev->partition); + fprintf(stderr, + "If this is a PCMCIA card, or a disk " + "partitioned on another computer, this " + "message may be in error: add " + "mtools_skip_check=1 to your .mtoolsrc " + "file to suppress this warning\n"); + + } + break; + /* NOTREACHED */ + } + + This->lastwhere = -This->offset; + /* provoke a seek on those devices that don't start on a partition + * boundary */ + + return (Stream_t *) This; +} + +int get_fd(Stream_t *Stream) +{ + Class_t *clazz; + DeclareThis(SimpleFile_t); + clazz = This->Class; + if(clazz != &ScsiClass && + clazz != &SimpleFileClass) + return -1; + else + return This->fd; +} + +void *get_extra_data(Stream_t *Stream) +{ + DeclareThis(SimpleFile_t); + + return This->extra_data; +} diff --git a/plain_io.h b/plain_io.h new file mode 100644 index 0000000..5abb90c --- /dev/null +++ b/plain_io.h @@ -0,0 +1,38 @@ +#ifndef MTOOLS_PLAINIO_H +#define MTOOLS_PLAINIO_H + +/* Copyright 1996,1997,1999,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "stream.h" +#include "msdos.h" +#ifdef __EMX__ +#include +#endif + +/* plain io */ +#define NO_PRIV 1 +#define NO_OFFSET 2 + +Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev, + const char *name, int mode, char *errmsg, int mode2, + int locked, mt_size_t *maxSize); +int check_parameters(struct device *ref, struct device *testee); + +int get_fd(Stream_t *Stream); +void *get_extra_data(Stream_t *Stream); +#endif diff --git a/precmd.c b/precmd.c new file mode 100644 index 0000000..8d1fc96 --- /dev/null +++ b/precmd.c @@ -0,0 +1,48 @@ +/* Copyright 1997,1999,2001-2004,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Do filename expansion with the shell. + */ + +#define EXPAND_BUF 2048 + +#include "sysincludes.h" +#include "mtools.h" + +void precmd(struct device *dev) +{ +#ifndef OS_mingw32msvc + int status; + pid_t pid; + + if(!dev || !dev->precmd) + return; + + switch((pid=fork())){ + case -1: + perror("Could not fork"); + exit(1); + break; + case 0: /* the son */ + execl("/bin/sh", "sh", "-c", dev->precmd, (char *)NULL); + break; + default: + wait(&status); + break; + } +#endif +} + diff --git a/privileges.c b/privileges.c new file mode 100644 index 0000000..c2f5c74 --- /dev/null +++ b/privileges.c @@ -0,0 +1,211 @@ +/* Copyright 1997,1999,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +int noPrivileges=0; + +#ifdef OS_mingw32msvc +void reclaim_privs(void) +{ +} + +void drop_privs(void) +{ +} + +void destroy_privs(void) +{ +} + +uid_t get_real_uid(void) +{ + return 0; +} + +void init_privs(void) +{ +} + +void closeExec(int fd) +{ +} + +#else +/*#define PRIV_DEBUG*/ + +#if 0 +#undef HAVE_SETEUID +#define HAVE_SETRESUID +#include +int setresuid(int a, int b, int c) +{ + syscall(164, a, b, c); + +} +#endif + +static __inline__ void print_privs(const char *message) +{ +#ifdef PRIV_DEBUG + /* for debugging purposes only */ + fprintf(stderr,"%s egid=%d rgid=%d\n", message, getegid(), getgid()); + fprintf(stderr,"%s euid=%d ruid=%d\n", message, geteuid(), getuid()); +#endif +} + + +static gid_t rgid, egid; +static uid_t ruid, euid; + +/* privilege management routines for SunOS and Solaris. These are + * needed in order to issue raw SCSI read/write ioctls. Mtools drops + * its privileges at the beginning, and reclaims them just for the + * above-mentioned ioctl's. Before popen(), exec() or system, it + * drops its privileges completely, and issues a warning. + */ + + +/* group id handling is lots easyer, as long as we don't use group 0. + * If you want to use group id's, create a *new* group mtools or + * floppy. Chgrp any devices that you only want to be accessible to + * mtools to this group, and give them the appropriate privs. Make + * sure this group doesn't own any other files: be aware that any user + * with access to mtools may mformat these files! + */ + + +static __inline__ void Setuid(uid_t uid) +{ +#if defined HAVE_SETEUID || defined HAVE_SETRESUID + if(euid == 0) { +#ifdef HAVE_SETEUID + seteuid(uid); +#else + setresuid(ruid, uid, euid); +#endif + } else +#endif + setuid(uid); +} + +/* In reclaim_privs and drop privs, we have to manipulate group privileges + * when having no root privileges, else we might lose them */ + +void reclaim_privs(void) +{ + if(noPrivileges) + return; + setgid(egid); + Setuid(euid); + print_privs("after reclaim privs, both uids should be 0 "); +} + +void drop_privs(void) +{ + Setuid(ruid); + setgid(rgid); + print_privs("after drop_privs, real should be 0, effective should not "); +} + +void destroy_privs(void) +{ + +#if defined HAVE_SETEUID || defined HAVE_SETRESUID + if(euid == 0) { +#ifdef HAVE_SETEUID + setuid(0); /* get the necessary privs to drop real root id */ + setuid(ruid); /* this should be enough to get rid of the three + * ids */ + seteuid(ruid); /* for good measure... just in case we came + * accross a system which implemented sane + * semantics instead of POSIXly broken + * semantics for setuid */ +#else + setresuid(ruid, ruid, ruid); +#endif + } +#endif + + /* we also destroy group privileges */ + drop_privs(); + + /* saved set [ug]id will go away by itself on exec */ + + print_privs("destroy_privs, no uid should be zero "); +} + + +uid_t get_real_uid(void) +{ + return ruid; +} + +void init_privs(void) +{ + euid = geteuid(); + ruid = getuid(); + egid = getegid(); + rgid = getgid(); + +#ifndef F_SETFD + if(euid != ruid) { + fprintf(stderr, + "Setuid installation not supported on this platform\n"); + fprintf(stderr, + "Missing F_SETFD"); + exit(1); + } +#endif + + if(euid == 0 && ruid != 0) { +#ifdef HAVE_SETEUID + setuid(0); /* set real uid to 0 */ +#else +#ifndef HAVE_SETRESUID + /* on this machine, it is not possible to reversibly drop + * root privileges. We print an error and quit */ + + /* BEOS is no longer a special case, as both euid and ruid + * return 0, and thus we do not get any longer into this + * branch */ + fprintf(stderr, + "Seteuid call not supported on this architecture.\n"); + fprintf(stderr, + "Mtools cannot be installed setuid root.\n"); + fprintf(stderr, + "However, it can be installed setuid to a non root"); + fprintf(stderr, + "user or setgid to any id.\n"); + exit(1); +#endif +#endif + } + + drop_privs(); + print_privs("after init, real should be 0, effective should not "); +} + +void closeExec(int fd) +{ +#ifdef F_SETFD + fcntl(fd, F_SETFD, 1); +#endif +} +#endif diff --git a/privtest.c b/privtest.c new file mode 100644 index 0000000..e4c60f7 --- /dev/null +++ b/privtest.c @@ -0,0 +1,26 @@ +/* Copyright 1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include +/* this program is used to test whether mtools drops its privileges correctly */ + +main(int argc, char **argv) +{ + setuid(strtoul(argv[1], 0,0)); + system("id"); + +} diff --git a/read_dword.h b/read_dword.h new file mode 100644 index 0000000..fc5dd63 --- /dev/null +++ b/read_dword.h @@ -0,0 +1,30 @@ +#ifndef READ_DWORD +#define READ_DWORD + +/* Copyright 2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +static Dword read_dword(int handle) +{ + Byte val[4]; + + if(read(handle, (char *)val, 4) < 4) + return -1; + + return byte2dword(val); +} +#endif diff --git a/scripts/add-disk b/scripts/add-disk new file mode 100755 index 0000000..3e14e58 --- /dev/null +++ b/scripts/add-disk @@ -0,0 +1,47 @@ +#!/bin/sh + +# Copyright 1997 Tim Hoogasian (hoogs@usa.net) +# Copyright 1997,1998,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +# +# add-disk +# Contributed by Tim Hoogasian (hoogs@usa.net) +# +# Runs the commands to make Solaris locate a new disk that +# has been plugged in after the system was booted. +# + +# This script can be used on a Solaris system to add a SCSI disk +# without needing to reboot/reconfigure the system. It's short and +# simple, but it's quite handy -- and it saves you from having to +# remember the individual commands.... :-) + +# You might also want to use the format.dat file if you don't have one +# yet. It is in this same mtools/scripts directory, and should be +# stored in /etc, or appended to the existing format.dat file + +# All you have to do is attach the Jaz drive, check to make sure there +# isn't SCSI address conflict (Zip and Jaz media tend to default to ID +# number 5) power it up, run "add-disk", insert the media, and GO! + + +/usr/sbin/drvconfig +/usr/sbin/devlinks +/usr/sbin/disks # or /usr/sbin/tapes for tapes +/usr/ucb/ucblinks # Compatibility links + +exit 0 diff --git a/scripts/amuFormat.sh b/scripts/amuFormat.sh new file mode 100755 index 0000000..c9ff469 --- /dev/null +++ b/scripts/amuFormat.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Copyright 2004 Feuz Stefan. +# Copyright 2007 Adam Tkac. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# +# amuFormat.sh Formats various types and sizes of PC-Cards, according to the +# AMU-specification +# +# parameters: $1: Card Type: The Card Type is written as disk/volume-label +# to the boot-record +# The string should have a length of max. 11 characters. +# +# $2: Drive character (b:, c:) +# +# 10-12-2003 lct created +# +vers=1.4 + +#echo "debug: $0,$1,$2,$3,$4" + +# +# main() +# +if [ $# -ne 2 ] ; then + echo "Usage: amuFormat.sh " >&2 + echo " has to be defined in amuFormat.sh itself" >&2 + echo " has to be defined in mtools.conf" >&2 + exit 1 +fi + +echo "amuFormat $vers started..." + +drive="$2" + +case "$1" in +8MBCARD-FW) + ## using the f: or g: drive for fat12 formatting... + ## see mtools.conf file... + case "$2" in + [bB]:) drive="f:" ;; + [cC]:) drive="g:" ;; + *) echo "Drive $2 not supported."; exit 1 ;; + esac + cylinders=245 heads=2 cluster_size=8 + ;; +32MBCARD-FW) + #from amu_toolkit_0_6: + #mformat -t489 -h4 -c4 -n32 -H32 -r32 -vPC-CARD -M512 -N0000 c: + cylinders=489 heads=4 cluster_size=4 + ;; +64MBCARD-FW) + echo "***** WARNING: untested on AvHMU, exiting *****" + exit 1 + cylinders=245 heads=2 cluster_size=8 + ;; +1GBCARD-FW) + # from amu_toolkit_0_6: + #mformat -t2327 -h16 -c64 -n63 -H63 -r32 -v AMU-CARD -M512 -N 0000 c: + echo "***** WARNING: untested on AvHMU *****" + cylinders=2327 heads=16 cluster_size=64 + ;; +64MBCARDSAN) + # from amu_toolkit_0_6: + #mformat -t489 -h8 -c4 -n32 -H32 -r32 -v AMU-CARD -M512 -N 0000 c: + cylinders=489 heads=8 cluster_size=4 + ;; +# +# insert new cards here... +# +*) + echo "Card not supported." + exit 1 + ;; +esac + +echo "Formatting card in slot $2 as $1" + +## initialise partition table +mpartition -I "$drive" + +# write a partition table +mpartition -c -t$cylinders -h$heads -s32 -b32 "$drive" + +## write boot-record, two FATs and a root-directory +mformat -c$cluster_size -v "$1" "$drive" + +minfo "$2" +mdir "$2" + +echo "done." diff --git a/scripts/download b/scripts/download new file mode 100755 index 0000000..142eb99 --- /dev/null +++ b/scripts/download @@ -0,0 +1,81 @@ +#!/bin/sh - + +# Copyright 1996 Carlos Duarte +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + + +## (c) Carlos Duarte ## Created: 18-Dec-96 ## Updated: 18-Dec-96 ## + +# main + +FAKE= +DRIVE=a +TOGGLE=0 +MDEL=: +while [ "$1" ] +do + case `echo z$1|cut -c2-` in + -n) FAKE=echo ;; + -d) DRIVE=`echo $1|cut -c3-` + [ "$DRIVE" = "" ] && { + shift + DRIVE=$1 + [ "$DRIVE" = "" ] && break + } ;; + -t) TOGGLE=1 ;; + -rm) MDEL=mdel ;; + *) break ;; + esac + shift +done + +if [ $# -ne 1 ] ; then + echo "usage: $0 [-n] [-d drive] [-rm] [-t] " + exit 1 +fi + +ndisks=$1 +n=0 +dir=1 + +while test $n -lt $ndisks +do + + while [ -d $dir ] + do + dir=`expr $dir + 1` + done + + $FAKE mkdir $dir + $FAKE mcopy $DRIVE:\* $dir && $FAKE $MDEL $DRIVE:\* + + if [ "$TOGGLE" = "1" ] ; then + if [ "$DRIVE" = "a" ] ; then + DRIVE=b + else + DRIVE=a + fi + else + echo Replace disk and press return + read ans + fi + + n=`expr $n + 1` + dir=`expr $dir + 1` +done + +exit 0 diff --git a/scripts/format.dat b/scripts/format.dat new file mode 100644 index 0000000..7fd31c1 --- /dev/null +++ b/scripts/format.dat @@ -0,0 +1,41 @@ +# Copyright 1997 Tim Hoogasian (hoogs@usa.net) +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# +# /etc/format.dat file for Accessing ZIP and Jaz disks from Solaris +# +# Contributed by Tim Hoogasian (thoogasi@us.oracle.com) +# + +disk_type = "Iomega ZIP 100" \ + : ctlr = SCSI \ + : ncyl = 2406 : acyl = 2 : pcyl = 2408 : nhead = 2 \ + : nsect = 40 : rpm = 3600 : bpt = 20480 + +# Default Zip floppy part'n map : block 0-192480 (entire disk) +# +partition = "Iomega ZIP 100" \ + : disk = "Iomega ZIP 100" : ctlr = SCSI \ + : 2 = 0, 192480 +## +disk_type = "Jaz 1GB" \ + : ctlr = SCSI \ + : ncyl = 1018 : acyl = 2 : pcyl = 1020 : nhead = 64 \ + : nsect = 32 : rpm = 3600 : bpt = 16384 + +partition = "Jaz 1GB" \ + : disk = "Jaz 1GB" : ctlr = SCSI \ + : 2 = 0,2084864 diff --git a/scripts/mcheck b/scripts/mcheck new file mode 100755 index 0000000..f2c917f --- /dev/null +++ b/scripts/mcheck @@ -0,0 +1,61 @@ +#!/bin/sh +# Copyright 1994 David C. Niemi +# Copyright 1994,1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# +# mcheck [ ] +# +# Read every file on an MS-DOS formatted disk to make sure they're good. +# +# Requires: mdir and mread utilities from mtools in user's path. +# +# 1994/02/19 DCN Created +# 1994/??/?? ALK Added case statement for results of mdir +# 1994/09/24 DCN Cleanup (5 minutes on top of the 30 seconds creating it) +# 1994/12/01 DCN Better comments, notices to stderr +# +# Copyright (C) 1994 David C. Niemi (niemi@tuxers.net) +# The author requires that any copies or derived works include this +# copyright notice; no other restrictions are placed on its use. +# + +set -e +set -u + +DRIVE=${1:-'A:'} +mdir ${DRIVE}'*' +case $? in +2) + echo "No files on disk." >&2 + exit 0 + ;; +1) + exit 1 + ;; +0) + ;; +esac + +echo >&2; echo "Verifying files on drive ${DRIVE}..." >&2 +if mtype -/ ${DRIVE}\* > /dev/null; then + echo "Disk in drive ${DRIVE} is OK." >&2 + exit 0 +else + echo "Disk in drive ${DRIVE} has errors." >&2 + exit 1 +fi + +## NOTREACHED ## diff --git a/scripts/mcomp b/scripts/mcomp new file mode 100755 index 0000000..9b12212 --- /dev/null +++ b/scripts/mcomp @@ -0,0 +1,28 @@ +#!/bin/sh + +# Copyright 1996,1997,2001,2002,2006 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +if [ $# -lt 2 ]; then + echo "usage: $0 dosfile [cmpoptions] unixfile" + exit 1 +fi + +dosfile=$1 +shift + +mcopy $dosfile - | cmp $@ + diff --git a/scripts/mxtar b/scripts/mxtar new file mode 100755 index 0000000..0f874bc --- /dev/null +++ b/scripts/mxtar @@ -0,0 +1,25 @@ +#!/bin/sh + +# Copyright 1996,1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . + +taropt=$1 +dosfile=$2 +shift +shift + +mcopy $dosfile - | tar $taropt - $@ + diff --git a/scripts/tgz b/scripts/tgz new file mode 100755 index 0000000..8769ea6 --- /dev/null +++ b/scripts/tgz @@ -0,0 +1,86 @@ +#!/bin/sh +# Copyright 1994 David C. Niemi. +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# +# tgz [destination [source...] ] +# +# Make a gzip'd tar archive $1 (or stdout) out of specified files +# (or, if not specified, from everything in the current directory) +# +# Requires gzip in the user's path. +# +# Requires gnu tar (or something close) in the user's path +# due to use of --exclude, --totals and -S. +# +# 1994/02/19 DCN Created +# 1994/12/01 DCN Cleanup and major improvements +# +# Copyright (C) 1994 David C. Niemi (niemi@tuxers.net) +# The author requires that any copies or derived works include this +# copyright notice; no other restrictions are placed on its use. +# + +set -e +set -u + +Error () +{ echo "Error: $0: ${@-}." >&2 + exit 1 +} + +if [ $# = 0 ]; then + dest= + src=. + tar cvf - . | gzip -9v + exit 0 +elif [ $# = 1 ]; then + dest=$1 + src=. +else + dest=$1 + shift + src="${@-}" +fi + +case $dest in +"" | . | .. | */ | */. | */.. ) + echo "Usage: $0: [destination [source...] ]" >&2 + exit 1 + ;; +*.t?z | *.?z | *.z | *.Z | *.tz | *.tz? ) + ;; +*) + dest=${dest}.tgz ## Add on .tgz as default suffix +esac + +if [ -h "$dest" ]; then + Error "Destination file \"$dest\" already exists as a symbolic link" +elif [ -f "$dest" ]; then + Error "Destination \"$dest\" already exists as a file" +elif [ -d "$dest" ]; then + Error "Destination \"$dest\" already exists as a directory" +fi +if [ -z "$dest" -o "X$dest" = 'X-' ]; then + echo "Writing gzipp'd tar archive to standard output." >&2 + tar cvfS - -- $src | gzip -9v +else + echo "Writing gzip'd tar archive to \"$dest\"." >&2 + tar -cvS --totals --exclude "$dest" -f - -- $src | gzip -9v > "$dest" + ls -l "$dest" >&2 +fi + +exit 0 diff --git a/scripts/uz b/scripts/uz new file mode 100755 index 0000000..ba1cc28 --- /dev/null +++ b/scripts/uz @@ -0,0 +1,88 @@ +#!/bin/sh +# Copyright 1994,2002 David C. Niemi. +# Copyright 1996,1997,2001-2003 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +# uz [file...] +# lz [file...] +# +# If called "uz", gunzips and extracts a gzip'd tar'd archive. +# If called "lz", gunzips and shows a listing of a gzip'd tar'd archive. +# +# Requires: gzip and tar in the user's path. Should work with most tars. +# "-" is now used for backwards compatibility with antique tars, e.g. SCO. +# +# 1994/02/19 DCN Created (as a trivial, but useful script) +# 1994/12/01 DCN Combined uz and lz, added suffix handling +# 2002/09/11 DCN Added bzip2 support +# +# Copyright (C) 1994, 2002 David C. Niemi (niemi at tuxers dot net) +# The author requires that any copies or derived works include this +# copyright notice; no other restrictions are placed on its use. +# + +set -e +set -u + +## Default unzipping command +uzcmd='gzip -cd' + +case $0 in +*uz) + tarparam="-pxvf" + action="Extracting from " + ;; +*lz) + tarparam="-tvf" + action="Reading directory of " + ;; +*) + echo "$0: expect to be named either \"uz\" or \"lz\"." >&2 + exit 1 + ;; +esac + +if [ $# = 0 ]; then + echo "$action standard input." >&2 + $uzcmd - | tar "$tarparam" - + exit 0 +fi + +while [ $# -ge 1 ]; do + echo >&2 + found= + + for suffix in "" .gz .tgz .tar.gz .z .tar.z .taz .tpz .Z .tar.Z .tar.bz2; do + if [ -r "${1}$suffix" ]; then + found=$1$suffix + break + fi + done + + case $found in + *.tar.bz2 | *.tb2) + uzcmd='bzip2 -cd' + ;; + esac + if [ -z "$found" ]; then + echo "$0: could not read \"$1\"." >&2 + else + echo "$action \"$found\"." >&2 + $uzcmd -- "$found" | tar "$tarparam" - + fi + shift +done + +exit 0 diff --git a/scsi.c b/scsi.c new file mode 100644 index 0000000..6cf6537 --- /dev/null +++ b/scsi.c @@ -0,0 +1,330 @@ +/* Copyright 1996 Grant R. Guenther, based on work of Itai Nahshon + * http://www.torque.net/ziptool.html + * Copyright 1997-1999,2001,2002,2005,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * scsi.c + * Iomega Zip/Jaz drive tool + * change protection mode and eject disk + */ + +/* scis.c by Markus Gyger */ +/* This code is based on ftp://gear.torque.net/pub/ziptool.c */ +/* by Grant R. Guenther with the following copyright notice: */ + +/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */ +/* http://www.torque.net/ziptool.html */ + + +/* A.K. Moved this from mzip.c to a separate file in order to share with + * plain_io.c */ + +#include "sysincludes.h" +#include "mtools.h" +#include "scsi.h" + +#if defined OS_hpux +#include +#endif + +#ifdef OS_solaris +#include +#endif /* solaris */ + +#ifdef OS_sunos +#include +#include +#endif /* sunos */ + +#ifdef sgi +#include +#endif + +#ifdef OS_linux +#define SCSI_IOCTL_SEND_COMMAND 1 +struct scsi_ioctl_command { + int inlen; + int outlen; + char cmd[5008]; +}; +#endif + +#ifdef _SCO_DS +#include +#endif + +#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2) +#include +#endif + +#if defined(OS_netbsd) || defined(OS_netbsdelf) +#include +#endif + +int scsi_max_length(void) +{ +#ifdef OS_linux + return 8; +#else + return 255; +#endif +} + +int scsi_open(const char *name, int flag, int mode, void **extra_data) +{ +#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2) + struct cam_device *cam_dev; + cam_dev = cam_open_device(name, O_RDWR); + *extra_data = (void *) cam_dev; + if (cam_dev) + return cam_dev->fd; + else + return -1; +#else + return open(name, O_RDONLY | O_LARGEFILE | O_BINARY +#ifdef O_NDELAY + | O_NDELAY +#endif + /* O_RDONLY | dev->mode*/); +#endif +} + +int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode, + void *data, size_t len, void *extra_data) +{ +#if defined OS_hpux + struct sctl_io sctl_io; + + memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */ + memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */ + sctl_io.cdb_length = cmdlen; /* command length */ + sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */ + + switch (mode) { + case SCSI_IO_READ: + sctl_io.flags = SCTL_READ; + sctl_io.data_length = len; + sctl_io.data = data; + break; + case SCSI_IO_WRITE: + sctl_io.flags = 0; + sctl_io.data_length = data ? len : 0; + sctl_io.data = len ? data : 0; + break; + } + + if (ioctl(fd, SIOC_IO, &sctl_io) == -1) { + perror("scsi_io"); + return -1; + } + + return sctl_io.cdb_status; + +#elif defined OS_sunos || defined OS_solaris + struct uscsi_cmd uscsi_cmd; + memset(&uscsi_cmd, 0, sizeof uscsi_cmd); + uscsi_cmd.uscsi_cdb = (char *)cdb; + uscsi_cmd.uscsi_cdblen = cmdlen; +#ifdef OS_solaris + uscsi_cmd.uscsi_timeout = 20; /* msec? */ +#endif /* solaris */ + + uscsi_cmd.uscsi_buflen = (u_int)len; + uscsi_cmd.uscsi_bufaddr = data; + + switch (mode) { + case SCSI_IO_READ: + uscsi_cmd.uscsi_flags = USCSI_READ; + break; + case SCSI_IO_WRITE: + uscsi_cmd.uscsi_flags = USCSI_WRITE; + break; + } + + if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) { + perror("scsi_io"); + return -1; + } + + if(uscsi_cmd.uscsi_status) { + errno = 0; + fprintf(stderr,"scsi status=%x\n", + (unsigned short)uscsi_cmd.uscsi_status); + return -1; + } + + return 0; + +#elif defined OS_linux + struct scsi_ioctl_command my_scsi_cmd; + + + memcpy(my_scsi_cmd.cmd, cdb, cmdlen); /* copy command */ + + switch (mode) { + case SCSI_IO_READ: + my_scsi_cmd.inlen = 0; + my_scsi_cmd.outlen = len; + break; + case SCSI_IO_WRITE: + my_scsi_cmd.inlen = len; + my_scsi_cmd.outlen = 0; + memcpy(my_scsi_cmd.cmd + cmdlen,data,len); + break; + } + + if (ioctl(fd, SCSI_IOCTL_SEND_COMMAND, &my_scsi_cmd) < 0) { + perror("scsi_io"); + return -1; + } + + switch (mode) { + case SCSI_IO_READ: + memcpy(data, &my_scsi_cmd.cmd[0], len); + break; + case SCSI_IO_WRITE: + break; + } + + return 0; /* where to get scsi status? */ + +#elif (defined _SCO_DS) && (defined SCSIUSERCMD) + struct scsicmd my_scsi_cmd; + + memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */ + memcpy(my_scsi_cmd.cdb, cdb, cmdlen); + my_scsi_cmd.cdb_len = cmdlen; + my_scsi_cmd.data_len = len; + my_scsi_cmd.data_ptr = data; + my_scsi_cmd.is_write = mode == SCSI_IO_WRITE; + if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) { + perror("scsi_io: SCSIUSERCMD"); + return -1; + } + if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) { + fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n", + (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts); + return -1; + } + return 0; +#elif defined sgi + struct dsreq my_scsi_cmd; + + my_scsi_cmd.ds_cmdbuf = (char *)cdb; + my_scsi_cmd.ds_cmdlen = cmdlen; + my_scsi_cmd.ds_databuf = data; + my_scsi_cmd.ds_datalen = len; + switch (mode) { + case SCSI_IO_READ: + my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE; + break; + case SCSI_IO_WRITE: + my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE; + break; + } + my_scsi_cmd.ds_time = 10000; + my_scsi_cmd.ds_link = 0; + my_scsi_cmd.ds_synch =0; + my_scsi_cmd.ds_ret =0; + if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) { + perror("scsi_io"); + return -1; + } + + if(my_scsi_cmd.ds_status) { + errno = 0; + fprintf(stderr,"scsi status=%x\n", + (unsigned short)my_scsi_cmd.ds_status); + return -1; + } + + return 0; +#elif (defined OS_freebsd) && (__FreeBSD__ >= 2) +#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ + union ccb *ccb; + int flags; + int r; + struct cam_device *cam_dev = (struct cam_device *) extra_data; + + + if (cam_dev==NULL || cam_dev->fd!=fd) + { + fprintf(stderr,"invalid file descriptor\n"); + return -1; + } + ccb = cam_getccb(cam_dev); + + bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen); + + if (mode == SCSI_IO_READ) + flags = CAM_DIR_IN; + else if (data && len) + flags = CAM_DIR_OUT; + else + flags = CAM_DIR_NONE; + cam_fill_csio(&ccb->csio, + /* retry */ 1, + /* cbfcnp */ NULL, + flags, + /* tag_action */ MSG_SIMPLE_Q_TAG, + /*data_ptr*/ len ? data : 0, + /*data_len */ data ? len : 0, + 96, + cmdlen, + 5000); + + if (cam_send_ccb(cam_dev, ccb) < 0 || + (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + return -1; + } + return 0; +#elif defined(OS_netbsd) || defined(OS_netbsdelf) + struct scsireq sc; + + memset(&sc, 0, sizeof(sc)); + memcpy(sc.cmd, cdb, cmdlen); + sc.cmdlen = cmdlen; + sc.databuf = data; + sc.datalen = len; + sc.senselen = 0; + sc.timeout = 10000; + switch (mode) { + case SCSI_IO_READ: + sc.flags = SCCMD_READ; + break; + case SCSI_IO_WRITE: + sc.flags = SCCMD_WRITE; + break; + } + + if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) { + perror("SCIOCCOMMAND ioctl"); + return -1; + } + + if (sc.retsts) { + errno = EIO; + fprintf(stderr, "SCSI command failed, retsts %d\n", +sc.retsts); + return -1; + } + + return 0; +#else + fprintf(stderr, "scsi_io not implemented\n"); + return -1; +#endif +} diff --git a/scsi.h b/scsi.h new file mode 100644 index 0000000..8803989 --- /dev/null +++ b/scsi.h @@ -0,0 +1,37 @@ +#ifndef __mtools_scsi_h +#define __mtools_scsi_h +/* Copyright 1997-1999,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#define SCSI_READ 0x8 +#define SCSI_WRITE 0xA +#define SCSI_IOMEGA 0xC +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SENSE 0x1a +#define SCSI_START_STOP 0x1b +#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e +#define SCSI_GROUP1 0x20 +#define SCSI_READ_CAPACITY 0x25 + + +typedef enum { SCSI_IO_READ, SCSI_IO_WRITE } scsi_io_mode_t; +int scsi_max_length(void); +int scsi_cmd(int fd, unsigned char cdb[6], int clen, scsi_io_mode_t mode, + void *data, size_t len, void *extra_data); +int scsi_open(const char *name, int flags, int mode, void **extra_data); + +#endif /* __mtools_scsi_h */ diff --git a/signal.c b/signal.c new file mode 100644 index 0000000..e6a4326 --- /dev/null +++ b/signal.c @@ -0,0 +1,60 @@ +/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "mtools.h" + +#undef got_signal + +int got_signal = 0; + +static void signal_handler(int dummy) +{ + got_signal = 1; +#if 0 + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGQUIT, SIG_IGN); +#endif +} + +#if 0 +int do_gotsignal(char *f, int n) +{ + if(got_signal) + fprintf(stderr, "file=%s line=%d\n", f, n); + return got_signal; +} +#endif + +void setup_signal(void) +{ + /* catch signals */ +#ifdef SIGHUP + signal(SIGHUP, signal_handler); +#endif +#ifdef SIGINT + signal(SIGINT, signal_handler); +#endif +#ifdef SIGTERM + signal(SIGTERM, signal_handler); +#endif +#ifdef SIGQUIT + signal(SIGQUIT, signal_handler); +#endif +} diff --git a/stream.c b/stream.c new file mode 100644 index 0000000..2055f12 --- /dev/null +++ b/stream.c @@ -0,0 +1,87 @@ +/* Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" + +int batchmode = 0; + +int flush_stream(Stream_t *Stream) +{ + int ret=0; + if(!batchmode) { + if(Stream->Class->flush) + ret |= Stream->Class->flush(Stream); + if(Stream->Next) + ret |= flush_stream(Stream->Next); + } + return ret; +} + +Stream_t *copy_stream(Stream_t *Stream) +{ + if(Stream) + Stream->refs++; + return Stream; +} + +int free_stream(Stream_t **Stream) +{ + int ret=0; + + if(!*Stream) + return -1; + if(! --(*Stream)->refs){ + if((*Stream)->Class->flush) + ret |= (*Stream)->Class->flush(*Stream); + if((*Stream)->Class->freeFunc) + ret |= (*Stream)->Class->freeFunc(*Stream); + if((*Stream)->Next) + ret |= free_stream(&(*Stream)->Next); + Free(*Stream); + } else if ( (*Stream)->Next ) + ret |= flush_stream((*Stream)->Next); + *Stream = NULL; + return ret; +} + + +#define GET_DATA(stream, date, size, type, address) \ +(stream)->Class->get_data( (stream), (date), (size), (type), (address) ) + + +int get_data_pass_through(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + return GET_DATA(Stream->Next, date, size, type, address); +} + +int read_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + return READS(Stream->Next, buf, start, len); +} + +int write_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + return WRITES(Stream->Next, buf, start, len); +} + +doscp_t *get_dosConvert_pass_through(Stream_t *Stream) +{ + return GET_DOSCONVERT(Stream->Next); +} diff --git a/stream.h b/stream.h new file mode 100644 index 0000000..5bbba52 --- /dev/null +++ b/stream.h @@ -0,0 +1,93 @@ +#ifndef MTOOLS_STREAM_H +#define MTOOLS_STREAM_H + +/* Copyright 1996-1999,2001,2002,2005,2006,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +typedef struct Stream_t { + struct Class_t *Class; + int refs; + struct Stream_t *Next; + struct Stream_t *Buffer; +} Stream_t; + +#include "mtools.h" +#include "msdos.h" + +#include "llong.h" + +doscp_t *get_dosConvert_pass_through(Stream_t *Stream); + +typedef struct Class_t { + int (*read)(Stream_t *, char *, mt_off_t, size_t); + int (*write)(Stream_t *, char *, mt_off_t, size_t); + int (*flush)(Stream_t *); + int (*freeFunc)(Stream_t *); + int (*set_geom)(Stream_t *, device_t *, device_t *, int media, + union bootsector *); + int (*get_data)(Stream_t *, time_t *, mt_size_t *, int *, int *); + int (*pre_allocate)(Stream_t *, mt_size_t); + + doscp_t *(*get_dosConvert)(Stream_t *); +} Class_t; + +#define READS(stream, buf, address, size) \ +((stream)->Class->read)( (stream), (char *) (buf), (address), (size) ) + +#define WRITES(stream, buf, address, size) \ +((stream)->Class->write)( (stream), (char *) (buf), (address), (size) ) + +#define SET_GEOM(stream, dev, orig_dev, media, boot) \ +(stream)->Class->set_geom( (stream), (dev), (orig_dev), (media), (boot) ) + +#define GET_DATA(stream, date, size, type, address) \ +(stream)->Class->get_data( (stream), (date), (size), (type), (address) ) + +#define PRE_ALLOCATE(stream, size) \ +(stream)->Class->pre_allocate((stream), (size)) + +#define GET_DOSCONVERT(stream) \ + (stream)->Class->get_dosConvert((stream)) + +int flush_stream(Stream_t *Stream); +Stream_t *copy_stream(Stream_t *Stream); +int free_stream(Stream_t **Stream); + +#define FLUSH(stream) \ +flush_stream( (stream) ) + +#define FREE(stream) \ +free_stream( (stream) ) + +#define COPY(stream) \ +copy_stream( (stream) ) + + +#define DeclareThis(x) x *This = (x *) Stream + +int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len); +int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len); + +int get_data_pass_through(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address); + +int read_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len); +int write_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len); + + +#endif + diff --git a/streamcache.c b/streamcache.c new file mode 100644 index 0000000..4277ef0 --- /dev/null +++ b/streamcache.c @@ -0,0 +1,79 @@ +/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * streamcache.c + * Managing a cache of open disks + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "fs.h" +#include "mainloop.h" +#include "plain_io.h" +#include "file.h" + +static int is_initialized = 0; +static Stream_t *fss[256]; /* open drives */ + +static void finish_sc(void) +{ + int i; + + for(i=0; i<256; i++){ + if(fss[i] && fss[i]->refs != 1 ) + fprintf(stderr,"Streamcache allocation problem:%c %d\n", + i, fss[i]->refs); + FREE(&(fss[i])); + } +} + +static void init_streamcache(void) +{ + int i; + + if(is_initialized) + return; + is_initialized = 1; + for(i=0; i<256; i++) + fss[i]=0; + atexit(finish_sc); +} + +Stream_t *open_root_dir(unsigned char drive, int flags, int *isRop) +{ + Stream_t *Fs; + + init_streamcache(); + + drive = toupper(drive); + + /* open the drive */ + if(fss[drive]) + Fs = fss[drive]; + else { + Fs = fs_init(drive, flags, isRop); + if (!Fs){ + fprintf(stderr, "Cannot initialize '%c:'\n", drive); + return NULL; + } + + fss[drive] = Fs; + } + + return OpenRoot(Fs); +} diff --git a/strip-pp.sed b/strip-pp.sed new file mode 100644 index 0000000..8e89ad1 --- /dev/null +++ b/strip-pp.sed @@ -0,0 +1,19 @@ +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools 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. +# +# Mtools 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 Mtools. If not, see . +:1 +/^\.[IP]P$/N +s/^\.[IP]P\n\(\.[ITP]P\)$/\1/ +/^\.PP$/b1 diff --git a/subdir.c b/subdir.c new file mode 100644 index 0000000..164fc0e --- /dev/null +++ b/subdir.c @@ -0,0 +1,44 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "file.h" +#include "buffer.h" + +/* + * Find the directory and load a new dir_chain[]. A null directory + * is OK. Returns a 1 on error. + */ + + +void bufferize(Stream_t **Dir) +{ + Stream_t *BDir; + + if(!*Dir) + return; + BDir = buf_init(*Dir, 64*16384, 512, MDIR_SIZE); + if(!BDir){ + FREE(Dir); + *Dir = NULL; + } else + *Dir = BDir; +} diff --git a/sysincludes.h b/sysincludes.h new file mode 100644 index 0000000..2e7577c --- /dev/null +++ b/sysincludes.h @@ -0,0 +1,604 @@ +/* Copyright 1996-1999,2001,2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * System includes for mtools + */ + +#ifndef SYSINCLUDES_H +#define SYSINCLUDES_H + +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include "config.h" + + +/* OS/2 needs __inline__, but for some reason is not autodetected */ +#ifdef __EMX__ +# ifndef inline +# define inline __inline__ +# endif +#endif + +/***********************************************************************/ +/* */ +/* OS dependancies which cannot be covered by the autoconfigure script */ +/* */ +/***********************************************************************/ + + +#ifdef OS_aux +/* A/UX needs POSIX_SOURCE, just as AIX does. Unlike SCO and AIX, it seems + * to prefer TERMIO over TERMIOS */ +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif +#ifndef POSIX_SOURCE +# define POSIX_SOURCE +#endif + +#endif + + +/* On AIX, we have to prefer strings.h, as string.h lacks a prototype + * for strcasecmp. On most other architectures, it's string.h which seems + * to be more complete */ +#if (defined OS_aix && defined HAVE_STRINGS_H) +# undef HAVE_STRING_H +#endif + + +#ifdef OS_ultrix +/* on ultrix, if termios present, prefer it instead of termio */ +# ifdef HAVE_TERMIOS_H +# undef HAVE_TERMIO_H +# endif +#endif + +#ifdef OS_linux_gnu +/* RMS strikes again */ +# ifndef OS_linux +# define OS_linux +# endif +#endif + +/* For compiling with MingW, use the following configure line + +ac_cv_func_setpgrp_void=yes ../mtools/configure --build=i386-linux-gnu --host=i386-mingw32 --disable-floppyd --without-x --disable-raw-term --srcdir ../mtools + + */ +#ifdef OS_mingw32 +#ifndef OS_mingw32msvc +#define OS_mingw32msvc +#endif +#endif + +#ifdef OS_mingw32msvc +typedef void *caddr_t; +#endif + + +/***********************************************************************/ +/* */ +/* Compiler dependancies */ +/* */ +/***********************************************************************/ + + +#if defined __GNUC__ && defined __STDC__ +/* gcc -traditional doesn't have PACKED, UNUSED and NORETURN */ +# define PACKED __attribute__ ((packed)) +# if __GNUC__ == 2 && __GNUC_MINOR__ > 6 || __GNUC__ >= 3 +/* gcc 2.6.3 doesn't have "unused" */ /* mool */ +# define UNUSED(x) x __attribute__ ((unused));x +# else +# define UNUSED(x) x +# endif +# define NORETURN __attribute__ ((noreturn)) +#else +# define UNUSED(x) x +# define PACKED /* */ +# define NORETURN /* */ +#endif + + +/***********************************************************************/ +/* */ +/* Include files */ +/* */ +/***********************************************************************/ + +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + + +#ifdef HAVE_FEATURES_H +# include +#endif + + +#include + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_LINUX_UNISTD_H +# include +#endif + +#ifdef HAVE_LIBC_H +# include +#endif + +#ifdef HAVE_GETOPT_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_LIMITS_H +# include +#endif + +#ifdef HAVE_SYS_FILE_H +# include +#endif + +#ifdef HAVE_SYS_IOCTL_H +# ifndef sunos +# include +#endif +#endif +/* if we don't have sys/ioctl.h, we rely on unistd to supply a prototype + * for it. If it doesn't, we'll only get a (harmless) warning. The idea + * is to get mtools compile on as many platforms as possible, but to not + * suppress warnings if the platform is broken, as long as these warnings do + * not prevent compilation */ + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifndef NO_TERMIO +# ifdef HAVE_TERMIO_H +# include +# elif defined HAVE_SYS_TERMIO_H +# include +# endif +# if !defined OS_ultrix || !(defined HAVE_TERMIO_H || defined HAVE_TERMIO_H) +/* on Ultrix, avoid double inclusion of both termio and termios */ +# ifdef HAVE_TERMIOS_H +# include +# elif defined HAVE_SYS_TERMIOS_H +# include +# endif +# endif +# ifdef HAVE_STTY_H +# include +# endif +#endif + + +#if defined(OS_aux) && !defined(_SYSV_SOURCE) +/* compiled in POSIX mode, this is left out unless SYSV */ +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input modes */ + unsigned short c_oflag; /* output modes */ + unsigned short c_cflag; /* control modes */ + unsigned short c_lflag; /* line discipline modes */ + char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control chars */ +}; +extern int ioctl(int fildes, int request, void *arg); +#endif + + +#ifdef HAVE_MNTENT_H +# include +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +/* Can only be done here, as BSD is defined in sys/param.h :-( */ +#if defined BSD || defined __BEOS__ +/* on BSD and on BEOS, we prefer gettimeofday, ... */ +# ifdef HAVE_GETTIMEOFDAY +# undef HAVE_TZSET +# endif +#else /* BSD */ +/* ... elsewhere we prefer tzset */ +# ifdef HAVE_TZSET +# undef HAVE_GETTIMEOFDAY +# endif +#endif + + +#include + +#include +#ifndef errno +extern int errno; +#endif + +#ifndef OS_mingw32msvc +#include +#else +typedef unsigned int uid_t; +#endif + + +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif + +#ifdef HAVE_MEMORY_H +# include +#endif + +#ifdef HAVE_MALLOC_H +# include +#endif + +#ifdef HAVE_SIGNAL_H +# include +#else +# ifdef HAVE_SYS_SIGNAL_H +# include +# endif +#endif + +#ifdef HAVE_UTIME_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# ifndef DONT_NEED_WAIT +# include +# endif +#endif + +#ifdef HAVE_WCHAR_H +# include +# ifndef HAVE_PUTWC +# define putwc(c,f) fprintf((f),"%lc",(c)) +# endif +#else +# define wcscmp strcmp +# define wcscasecmp strcasecmp +# define wcsdup strdup +# define wcslen strlen +# define wcschr strchr +# define wcspbrk strpbrk +# define wchar_t char +# define putwc putc +#endif + +#ifdef HAVE_WCTYPE_H +# include +#else +# define towupper(x) toupper(x) +# define towlower(x) tolower(x) +# define iswupper(x) isupper(x) +# define iswlower(x) islower(x) +# define iswcntrl(x) iscntrl(x) +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef USE_FLOPPYD + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_X11_XAUTH_H +#include +#endif + +#ifdef HAVE_X11_XLIB_H +#include +#endif + +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE (-1) +#endif + + +#ifdef sgi +#define MSGIHACK __EXTENSIONS__ +#undef __EXTENSIONS__ +#endif +#include +#ifdef sgi +#define __EXTENSIONS__ MSGIHACK +#undef MSGIHACK +#endif + +/* missing functions */ +#ifndef HAVE_SRANDOM +# ifdef OS_mingw32msvc +# define srandom srand +# else +# define srandom srand48 +# endif +#endif + +#ifndef HAVE_RANDOM +# ifdef OS_mingw32msvc +# define random (long)rand +# else +# define random (long)lrand48 +# endif +#endif + +#ifndef HAVE_STRCHR +# define strchr index +#endif + +#ifndef HAVE_STRRCHR +# define strrchr rindex +#endif + + +#ifndef HAVE_STRDUP +extern char *strdup(const char *str); +#endif /* HAVE_STRDUP */ + + +#ifndef HAVE_MEMCPY +extern char *memcpy(char *s1, const char *s2, size_t n); +#endif + +#ifndef HAVE_MEMSET +extern char *memset(char *s, char c, size_t n); +#endif /* HAVE_MEMSET */ + + +#ifndef HAVE_STRPBRK +extern char *strpbrk(const char *string, const char *brkset); +#endif /* HAVE_STRPBRK */ + + +#ifndef HAVE_STRTOUL +unsigned long strtoul(const char *string, char **eptr, int base); +#endif /* HAVE_STRTOUL */ + +#ifndef HAVE_STRSPN +size_t strspn(const char *s, const char *accept); +#endif /* HAVE_STRSPN */ + +#ifndef HAVE_STRCSPN +size_t strcspn(const char *s, const char *reject); +#endif /* HAVE_STRCSPN */ + +#ifndef HAVE_STRERROR +char *strerror(int errno); +#endif + +#ifndef HAVE_ATEXIT +int atexit(void (*function)(void)); + +#ifndef HAVE_ON_EXIT +void myexit(int code) NORETURN; +#define exit myexit +#endif + +#endif + + +#ifndef HAVE_MEMMOVE +# define memmove(DST, SRC, N) bcopy(SRC, DST, N) +#endif + +#ifndef HAVE_STRCASECMP +int strcasecmp(const char *s1, const char *s2); +#endif + +#ifndef HAVE_STRNCASECMP +int strncasecmp(const char *s1, const char *s2, size_t n); +#endif + +#ifndef HAVE_GETPASS +char *getpass(const char *prompt); +#endif + +#ifdef HAVE_WCHAR_H + +# ifndef HAVE_WCSDUP +wchar_t *wcsdup(const wchar_t *wcs); +# endif + +# ifndef HAVE_WCSCASECMP +int wcscasecmp(const wchar_t *s1, const wchar_t *s2); +# endif + +# ifndef HAVE_WCSNLEN +size_t wcsnlen(const wchar_t *wcs, size_t l); +# endif + +#endif + +#if 0 +#ifndef HAVE_BASENAME +const char *basename(const char *filename); +#endif +#endif + +const char *_basename(const char *filename); + +void _stripexe(char *filename); + +#ifndef __STDC__ +# ifndef signed +# define signed /**/ +# endif +#endif /* !__STDC__ */ + + + +/***************************************************************************/ +/* */ +/* Prototypes for systems where the functions exist but not the prototypes */ +/* */ +/***************************************************************************/ + + + +/* prototypes which might be missing on some platforms, even if the functions + * are present. Do not declare argument types, in order to avoid conflict + * on platforms where the prototypes _are_ correct. Indeed, for most of + * these, there are _several_ "correct" parameter definitions, and not all + * platforms use the same. For instance, some use the const attribute for + * strings not modified by the function, and others do not. By using just + * the return type, which rarely changes, we avoid these problems. + */ + +/* Correction: Now it seems that even return values are not standardized :-( + For instance DEC-ALPHA, OSF/1 3.2d uses ssize_t as a return type for read + and write. NextStep uses a non-void return value for exit, etc. With the + advent of 64 bit system, we'll expect more of these problems in the future. + Better uncomment the lot, except on SunOS, which is known to have bad + incomplete files. Add other OS'es with incomplete include files as needed + */ +#if (defined OS_sunos || defined OS_ultrix) +int read(); +int write(); +int fflush(); +char *strdup(); +int strcasecmp(); +int strncasecmp(); +char *getenv(); +unsigned long strtoul(); +int pclose(); +void exit(); +char *getpass(); +int atoi(); +FILE *fdopen(); +FILE *popen(); +#endif + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# else +# define MAXPATHLEN 1024 +# endif +#endif + + +#ifndef OS_linux +# undef USE_XDF +#endif + +#ifdef NO_XDF +# undef USE_XDF +#endif + +#ifdef __EMX__ +#define INCL_BASE +#define INCL_DOSDEVIOCTL +#include +#endif + +#ifdef OS_nextstep +/* nextstep doesn't have this. Unfortunately, we cannot test its presence + using AC_EGREP_HEADER, as we don't know _which_ header to test, and in + the general case utime.h might be non-existent */ +struct utimbuf +{ + time_t actime,modtime; +}; +#endif + +/* NeXTStep doesn't have these */ +#if !defined(S_ISREG) && defined (_S_IFMT) && defined (_S_IFREG) +#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) +#endif + +#if !defined(S_ISDIR) && defined (_S_IFMT) && defined (_S_IFDIR) +#define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) +#endif + + +#ifdef OS_aix +/* AIX has an offset_t time, but somehow it is not scalar ==> forget about it + */ +# undef HAVE_OFFSET_T +#endif + + +#ifdef HAVE_STAT64 +#define MT_STAT stat64 +#define MT_LSTAT lstat64 +#define MT_FSTAT fstat64 +#else +#define MT_STAT stat +#define MT_LSTAT lstat +#define MT_FSTAT fstat +#endif + + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +#ifndef __GNUC__ +#ifndef __inline__ +#define __inline__ inline +#endif +#endif + +#endif diff --git a/texinfo.tex b/texinfo.tex new file mode 100644 index 0000000..9140826 --- /dev/null +++ b/texinfo.tex @@ -0,0 +1,9291 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{2009-08-14.15} +% +% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995, +% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, +% 2007, 2008, 2009 Free Software Foundation, Inc. +% +% This texinfo.tex file 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 texinfo.tex file 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 . +% +% As a special exception, when this file is read by TeX when processing +% a Texinfo source document, you may use the result without +% restriction. (This has been our intent since Texinfo was invented.) +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% http://www.gnu.org/software/texinfo/ (the Texinfo home page), or +% ftp://tug.org/tex/texinfo.tex +% (and all CTAN mirrors, see http://www.ctan.org). +% The texinfo.tex in any given distribution could well be out +% of date, so if that's what you're using, please check. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever; this makes foo.ps. +% The extra TeX runs get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages, to some +% extent. You can get the existing language-specific files from the +% full Texinfo distribution. +% +% The GNU Texinfo home page is http://www.gnu.org/software/texinfo. + + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + + +\chardef\other=12 + +% We never want plain's \outer definition of \+ in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +% Save some plain tex macros whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexfootnote=\footnote +\let\ptexgtr=> +\let\ptexhat=^ +\let\ptexi=\i +\let\ptexindent=\indent +\let\ptexinsert=\insert +\let\ptexlbrace=\{ +\let\ptexless=< +\let\ptexnewwrite\newwrite +\let\ptexnoindent=\noindent +\let\ptexplus=+ +\let\ptexrbrace=\} +\let\ptexslash=\/ +\let\ptexstar=\* +\let\ptext=\t +\let\ptextop=\top +{\catcode`\'=\active +\global\let\ptexquoteright'}% Math-mode def from plain.tex. +\let\ptexraggedright=\raggedright + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Pre-3.0. +\else + \def\linenumber{l.\the\inputlineno:\space} +\fi + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi + +% Since the category of space is not known, we have to be careful. +\chardef\spacecat = 10 +\def\spaceisspace{\catcode`\ =\spacecat} + +% sometimes characters are active, so we need control sequences. +\chardef\colonChar = `\: +\chardef\commaChar = `\, +\chardef\dashChar = `\- +\chardef\dotChar = `\. +\chardef\exclamChar= `\! +\chardef\lquoteChar= `\` +\chardef\questChar = `\? +\chardef\rquoteChar= `\' +\chardef\semiChar = `\; +\chardef\underChar = `\_ + +% Ignore a token. +% +\def\gobble#1{} + +% The following is used inside several \edef's. +\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname} + +% Hyphenation fixes. +\hyphenation{ + Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script + ap-pen-dix bit-map bit-maps + data-base data-bases eshell fall-ing half-way long-est man-u-script + man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm + par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces + spell-ing spell-ings + stand-alone strong-est time-stamp time-stamps which-ever white-space + wide-spread wrap-around +} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen\bindingoffset +\newdimen\normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. We also make +% some effort to order the tracing commands to reduce output in the log +% file; cf. trace.sty in LaTeX. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{% + \tracingstats2 + \tracingpages1 + \tracinglostchars2 % 2 gives us more in etex + \tracingparagraphs1 + \tracingoutput1 + \tracingmacros2 + \tracingrestores1 + \showboxbreadth\maxdimen \showboxdepth\maxdimen + \ifx\eTeXversion\undefined\else % etex gives us more logging + \tracingscantokens1 + \tracingifs1 + \tracinggroups1 + \tracingnesting2 + \tracingassigns1 + \fi + \tracingcommands3 % 3 gives us more in etex + \errorcontextlines16 +}% + +% add check for \lastpenalty to plain's definitions. If the last thing +% we did was a \nobreak, we don't want to insert more space. +% +\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount + \removelastskip\penalty-50\smallskip\fi\fi} +\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount + \removelastskip\penalty-100\medskip\fi\fi} +\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount + \removelastskip\penalty-200\bigskip\fi\fi} + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Output a mark which sets \thischapter, \thissection and \thiscolor. +% We dump everything together because we only have one kind of mark. +% This works because we only use \botmark / \topmark, not \firstmark. +% +% A mark contains a subexpression of the \ifcase ... \fi construct. +% \get*marks macros below extract the needed part using \ifcase. +% +% Another complication is to let the user choose whether \thischapter +% (\thissection) refers to the chapter (section) in effect at the top +% of a page, or that at the bottom of a page. The solution is +% described on page 260 of The TeXbook. It involves outputting two +% marks for the sectioning macros, one before the section break, and +% one after. I won't pretend I can describe this better than DEK... +\def\domark{% + \toks0=\expandafter{\lastchapterdefs}% + \toks2=\expandafter{\lastsectiondefs}% + \toks4=\expandafter{\prevchapterdefs}% + \toks6=\expandafter{\prevsectiondefs}% + \toks8=\expandafter{\lastcolordefs}% + \mark{% + \the\toks0 \the\toks2 + \noexpand\or \the\toks4 \the\toks6 + \noexpand\else \the\toks8 + }% +} +% \topmark doesn't work for the very first chapter (after the title +% page or the contents), so we use \firstmark there -- this gets us +% the mark with the chapter defs, unless the user sneaks in, e.g., +% @setcolor (or @url, or @link, etc.) between @contents and the very +% first @chapter. +\def\gettopheadingmarks{% + \ifcase0\topmark\fi + \ifx\thischapter\empty \ifcase0\firstmark\fi \fi +} +\def\getbottomheadingmarks{\ifcase1\botmark\fi} +\def\getcolormarks{\ifcase2\topmark\fi} + +% Avoid "undefined control sequence" errors. +\def\lastchapterdefs{} +\def\lastsectiondefs{} +\def\prevchapterdefs{} +\def\prevsectiondefs{} +\def\lastcolordefs{} + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + % We don't want .vr (or whatever) entries like this: + % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}} + % "\acronym" won't work when it's read back in; + % it needs to be + % {\code {{\tt \backslashcurfont }acronym} + \shipout\vbox{% + % Do this early so pdf references go to the beginning of the page. + \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi + % + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingyyy.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 24pt + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \indexdummies + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1\relax \unvbox#1\relax +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg{\parseargusing{}} +\def\parseargusing#1#2{% + \def\argtorun{#2}% + \begingroup + \obeylines + \spaceisspace + #1% + \parseargline\empty% Insert the \empty token, see \finishparsearg below. +} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + \argremovecomment #1\comment\ArgTerm% + }% +} + +% First remove any @comment, then any @c comment. +\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm} +\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm} + +% Each occurrence of `\^^M' or `\^^M' is replaced by a single space. +% +% \argremovec might leave us with trailing space, e.g., +% @end itemize @c foo +% This space token undergoes the same procedure and is eventually removed +% by \finishparsearg. +% +\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M} +\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M} +\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{% + \def\temp{#3}% + \ifx\temp\empty + % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp: + \let\temp\finishparsearg + \else + \let\temp\argcheckspaces + \fi + % Put the space token in: + \temp#1 #3\ArgTerm +} + +% If a _delimited_ argument is enclosed in braces, they get stripped; so +% to get _exactly_ the rest of the line, we had to prevent such situation. +% We prepended an \empty token at the very beginning and we expand it now, +% just before passing the control to \argtorun. +% (Similarly, we have to think about #3 of \argcheckspacesY above: it is +% either the null string, or it ends with \^^M---thus there is no danger +% that a pair of braces would be stripped. +% +% But first, we have to remove the trailing space token. +% +\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}} + +% \parseargdef\foo{...} +% is roughly equivalent to +% \def\foo{\parsearg\Xfoo} +% \def\Xfoo#1{...} +% +% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my +% favourite TeX trick. --kasal, 16nov03 + +\def\parseargdef#1{% + \expandafter \doparseargdef \csname\string#1\endcsname #1% +} +\def\doparseargdef#1#2{% + \def#2{\parsearg#1}% + \def#1##1% +} + +% Several utility definitions with active space: +{ + \obeyspaces + \gdef\obeyedspace{ } + + % Make each space character in the input produce a normal interword + % space in the output. Don't allow a line break at this space, as this + % is used only in environments like @example, where each line of input + % should produce a line of output anyway. + % + \gdef\sepspaces{\obeyspaces\let =\tie} + + % If an index command is used in an @example environment, any spaces + % therein should become regular spaces in the raw index file, not the + % expansion of \tie (\leavevmode \penalty \@M \ ). + \gdef\unsepspaces{\let =\space} +} + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +% Define the framework for environments in texinfo.tex. It's used like this: +% +% \envdef\foo{...} +% \def\Efoo{...} +% +% It's the responsibility of \envdef to insert \begingroup before the +% actual body; @end closes the group after calling \Efoo. \envdef also +% defines \thisenv, so the current environment is known; @end checks +% whether the environment name matches. The \checkenv macro can also be +% used to check whether the current environment is the one expected. +% +% Non-false conditionals (@iftex, @ifset) don't fit into this, so they +% are not treated as environments; they don't open a group. (The +% implementation of @end takes care not to call \endgroup in this +% special case.) + + +% At run-time, environments start with this: +\def\startenvironment#1{\begingroup\def\thisenv{#1}} +% initialize +\let\thisenv\empty + +% ... but they get defined via ``\envdef\foo{...}'': +\long\def\envdef#1#2{\def#1{\startenvironment#1#2}} +\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}} + +% Check whether we're in the right environment: +\def\checkenv#1{% + \def\temp{#1}% + \ifx\thisenv\temp + \else + \badenverr + \fi +} + +% Environment mismatch, #1 expected: +\def\badenverr{% + \errhelp = \EMsimple + \errmessage{This command can appear only \inenvironment\temp, + not \inenvironment\thisenv}% +} +\def\inenvironment#1{% + \ifx#1\empty + out of any environment% + \else + in environment \expandafter\string#1% + \fi +} + +% @end foo executes the definition of \Efoo. +% But first, it executes a specialized version of \checkenv +% +\parseargdef\end{% + \if 1\csname iscond.#1\endcsname + \else + % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03 + \expandafter\checkenv\csname#1\endcsname + \csname E#1\endcsname + \endgroup + \fi +} + +\newhelp\EMsimple{Press RETURN to continue.} + + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce \{ and \} commands for indices, + % and @{ and @} for the aux/toc files. + \catcode`\{ = \other \catcode`\} = \other + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\! = 0 \catcode`\\ = \other + !gdef!lbracecmd[\{]% + !gdef!rbracecmd[\}]% + !gdef!lbraceatcmd[@{]% + !gdef!rbraceatcmd[@}]% +!endgroup + +% @comma{} to avoid , parsing problems. +\let\comma = , + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown @ordf @ordm +% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} +\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}} +\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi + \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% The \TeX{} logo, as in plain, but resetting the spacing so that a +% period following counts as ending a sentence. (Idea found in latex.) +% +\edef\TeX{\TeX \spacefactor=1000 } + +% @LaTeX{} logo. Not quite the same results as the definition in +% latex.ltx, since we use a different font for the raised A; it's most +% convenient for us to use an explicitly smaller font, rather than using +% the \scriptstyle font (since we don't reset \scriptstyle and +% \scriptscriptstyle). +% +\def\LaTeX{% + L\kern-.36em + {\setbox0=\hbox{T}% + \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}% + \kern-.15em + \TeX +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @/ allows a line break. +\let\/=\allowbreak + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=\endofsentencespacefactor\space} + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=\endofsentencespacefactor\space} + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=\endofsentencespacefactor\space} + +% @frenchspacing on|off says whether to put extra space after punctuation. +% +\def\onword{on} +\def\offword{off} +% +\parseargdef\frenchspacing{% + \def\temp{#1}% + \ifx\temp\onword \plainfrenchspacing + \else\ifx\temp\offword \plainnonfrenchspacing + \else + \errhelp = \EMsimple + \errmessage{Unknown @frenchspacing option `\temp', must be on/off}% + \fi\fi +} + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +% Another complication is that the group might be very large. This can +% cause the glue on the previous page to be unduly stretched, because it +% does not have much material. In this case, it's better to add an +% explicit \vfill so that the extra space is at the bottom. The +% threshold for doing this is if the group is more than \vfilllimit +% percent of a page (\vfilllimit can be changed inside of @tex). +% +\newbox\groupbox +\def\vfilllimit{0.7} +% +\envdef\group{% + \ifnum\catcode`\^^M=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + \startsavinginserts + % + \setbox\groupbox = \vtop\bgroup + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% The \vtop produces a box with normal height and large depth; thus, TeX puts +% \baselineskip glue before it, and (when the next line of text is done) +% \lineskip glue after it. Thus, space below is not quite equal to space +% above. But it's pretty close. +\def\Egroup{% + % To get correct interline space between the last line of the group + % and the first line afterwards, we have to propagate \prevdepth. + \endgraf % Not \par, as it may have been set to \lisppar. + \global\dimen1 = \prevdepth + \egroup % End the \vtop. + % \dimen0 is the vertical size of the group's box. + \dimen0 = \ht\groupbox \advance\dimen0 by \dp\groupbox + % \dimen2 is how much space is left on the page (more or less). + \dimen2 = \pageheight \advance\dimen2 by -\pagetotal + % if the group doesn't fit on the current page, and it's a big big + % group, force a page break. + \ifdim \dimen0 > \dimen2 + \ifdim \pagetotal < \vfilllimit\pageheight + \page + \fi + \fi + \box\groupbox + \prevdepth = \dimen1 + \checkinserts +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +% Old definition--didn't work. +%\parseargdef\need{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\parseargdef\need{% + % Ensure vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % If the @need value is less than one line space, it's useless. + \dimen0 = #1\mil + \dimen2 = \ht\strutbox + \advance\dimen2 by \dp\strutbox + \ifdim\dimen0 > \dimen2 + % + % Do a \strut just to make the height of this box be normal, so the + % normal leading is inserted relative to the preceding line. + % And a page break here is fine. + \vtop to #1\mil{\strut\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak + \fi +} + +% @br forces paragraph break (and is undocumented). + +\let\br = \par + +% @page forces the start of a new page. +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break} + +% This defn is used inside nofill environments such as @example. +\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount + \leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current +% paragraph. For more general purposes, use the \margin insertion +% class. WHICH is `l' or `r'. +% +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} +% +\def\doinmargin#1#2{\strut\vadjust{% + \nobreak + \kern-\strutdepth + \vtop to \strutdepth{% + \baselineskip=\strutdepth + \vss + % if you have multiple lines of stuff to put here, you'll need to + % make the vbox yourself of the appropriate size. + \ifx#1l% + \llap{\ignorespaces #2\hskip\inmarginspacing}% + \else + \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}% + \fi + \null + }% +}} +\def\inleftmargin{\doinmargin l} +\def\inrightmargin{\doinmargin r} +% +% @inmargin{TEXT [, RIGHT-TEXT]} +% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right; +% else use TEXT for both). +% +\def\inmargin#1{\parseinmargin #1,,\finish} +\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing. + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \def\lefttext{#1}% have both texts + \def\righttext{#2}% + \else + \def\lefttext{#1}% have only one text + \def\righttext{#1}% + \fi + % + \ifodd\pageno + \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin + \else + \def\temp{\inleftmargin\lefttext}% + \fi + \temp +} + +% @include FILE -- \input text of FILE. +% +\def\include{\parseargusing\filenamecatcodes\includezzz} +\def\includezzz#1{% + \pushthisfilestack + \def\thisfile{#1}% + {% + \makevalueexpandable % we want to expand any @value in FILE. + \turnoffactive % and allow special characters in the expansion + \indexnofonts % Allow `@@' and other weird things in file names. + \edef\temp{\noexpand\input #1 }% + % + % This trickery is to read FILE outside of a group, in case it makes + % definitions, etc. + \expandafter + }\temp + \popthisfilestack +} +\def\filenamecatcodes{% + \catcode`\\=\other + \catcode`~=\other + \catcode`^=\other + \catcode`_=\other + \catcode`|=\other + \catcode`<=\other + \catcode`>=\other + \catcode`+=\other + \catcode`-=\other + \catcode`\`=\other + \catcode`\'=\other +} + +\def\pushthisfilestack{% + \expandafter\pushthisfilestackX\popthisfilestack\StackTerm +} +\def\pushthisfilestackX{% + \expandafter\pushthisfilestackY\thisfile\StackTerm +} +\def\pushthisfilestackY #1\StackTerm #2\StackTerm {% + \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}% +} + +\def\popthisfilestack{\errthisfilestackempty} +\def\errthisfilestackempty{\errmessage{Internal error: + the stack of filenames is empty.}} + +\def\thisfile{} + +% @center line +% outputs that line, centered. +% +\parseargdef\center{% + \ifhmode + \let\next\centerH + \else + \let\next\centerV + \fi + \next{\hfil \ignorespaces#1\unskip \hfil}% +} +\def\centerH#1{% + {% + \hfil\break + \advance\hsize by -\leftskip + \advance\hsize by -\rightskip + \line{#1}% + \break + }% +} +\def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}} + +% @sp n outputs n lines of vertical space + +\parseargdef\sp{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% NCHARS can also be the word `asis' or `none'. +% We cannot feasibly implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\parseargdef\paragraphindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\parseargdef\exampleindent{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @firstparagraphindent WORD +% If WORD is `none', then suppress indentation of the first paragraph +% after a section heading. If WORD is `insert', then do indent at such +% paragraphs. +% +% The paragraph indentation is suppressed or not by calling +% \suppressfirstparagraphindent, which the sectioning commands do. +% We switch the definition of this back and forth according to WORD. +% By default, we suppress indentation. +% +\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent} +\def\insertword{insert} +% +\parseargdef\firstparagraphindent{% + \def\temp{#1}% + \ifx\temp\noneword + \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent + \else\ifx\temp\insertword + \let\suppressfirstparagraphindent = \relax + \else + \errhelp = \EMsimple + \errmessage{Unknown @firstparagraphindent option `\temp'}% + \fi\fi +} + +% Here is how we actually suppress indentation. Redefine \everypar to +% \kern backwards by \parindent, and then reset itself to empty. +% +% We also make \indent itself not actually do anything until the next +% paragraph. +% +\gdef\dosuppressfirstparagraphindent{% + \gdef\indent{% + \restorefirstparagraphindent + \indent + }% + \gdef\noindent{% + \restorefirstparagraphindent + \noindent + }% + \global\everypar = {% + \kern -\parindent + \restorefirstparagraphindent + }% +} + +\gdef\restorefirstparagraphindent{% + \global \let \indent = \ptexindent + \global \let \noindent = \ptexnoindent + \global \everypar = {}% +} + + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math outputs its argument in math mode. +% +% One complication: _ usually means subscripts, but it could also mean +% an actual _ character, as in @math{@var{some_variable} + 1}. So make +% _ active, and distinguish by seeing if the current family is \slfam, +% which is what @var uses. +{ + \catcode`\_ = \active + \gdef\mathunderscore{% + \catcode`\_=\active + \def_{\ifnum\fam=\slfam \_\else\sb\fi}% + } +} +% Another complication: we want \\ (and @\) to output a \ character. +% FYI, plain.tex uses \\ as a temporary control sequence (why?), but +% this is not advertised and we don't care. Texinfo does not +% otherwise define @\. +% +% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\. +\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi} +% +\def\math{% + \tex + \mathunderscore + \let\\ = \mathbackslash + \mathactive + % make the texinfo accent commands work in math mode + \let\"=\ddot + \let\'=\acute + \let\==\bar + \let\^=\hat + \let\`=\grave + \let\u=\breve + \let\v=\check + \let\~=\tilde + \let\dotaccent=\dot + $\finishmath +} +\def\finishmath#1{#1$\endgroup} % Close the group opened by \tex. + +% Some active characters (such as <) are spaced differently in math. +% We have to reset their definitions in case the @math was an argument +% to a command which sets the catcodes (such as @item or @section). +% +{ + \catcode`^ = \active + \catcode`< = \active + \catcode`> = \active + \catcode`+ = \active + \catcode`' = \active + \gdef\mathactive{% + \let^ = \ptexhat + \let< = \ptexless + \let> = \ptexgtr + \let+ = \ptexplus + \let' = \ptexquoteright + } +} + +% Some math mode symbols. +\def\bullet{$\ptexbullet$} +\def\geq{\ifmmode \ge\else $\ge$\fi} +\def\leq{\ifmmode \le\else $\le$\fi} +\def\minus{\ifmmode -\else $-$\fi} + +% @dots{} outputs an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in the cm +% typewriter fonts as three actual period characters; on the other hand, +% in other typewriter fonts three periods are wider than 1.5em. So do +% whichever is larger. +% +\def\dots{% + \leavevmode + \setbox0=\hbox{...}% get width of three periods + \ifdim\wd0 > 1.5em + \dimen0 = \wd0 + \else + \dimen0 = 1.5em + \fi + \hbox to \dimen0{% + \hskip 0pt plus.25fil + .\hskip 0pt plus1fil + .\hskip 0pt plus1fil + .\hskip 0pt plus.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \dots + \spacefactor=\endofsentencespacefactor +} + +% @comma{} is so commas can be inserted into text without messing up +% Texinfo's parsing. +% +\let\comma = , + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \iflinks + \tryauxfile + % Open the new aux file. TeX will close it automatically at exit. + \immediate\openout\auxfile=\jobname.aux + \fi % \openindices needs to do some work in any case. + \openindices + \let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + \openin 1 texinfo.cnf + \ifeof 1 \else \input texinfo.cnf \fi + \closein 1 + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1 +% can be set). So we test for \relax and 0 as well as \undefined, +% borrowed from ifpdf.sty. +\ifx\pdfoutput\undefined +\else + \ifx\pdfoutput\relax + \else + \ifcase\pdfoutput + \else + \pdftrue + \fi + \fi +\fi + +% PDF uses PostScript string constants for the names of xref targets, +% for display in the outlines, and in other places. Thus, we have to +% double any backslashes. Otherwise, a name like "\node" will be +% interpreted as a newline (\n), followed by o, d, e. Not good. +% http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html +% (and related messages, the final outcome is that it is up to the TeX +% user to double the backslashes and otherwise make the string valid, so +% that's what we do). + +% double active backslashes. +% +{\catcode`\@=0 \catcode`\\=\active + @gdef@activebackslashdouble{% + @catcode`@\=@active + @let\=@doublebackslash} +} + +% To handle parens, we must adopt a different approach, since parens are +% not active characters. hyperref.dtx (which has the same problem as +% us) handles it with this amazing macro to replace tokens, with minor +% changes for Texinfo. It is included here under the GPL by permission +% from the author, Heiko Oberdiek. +% +% #1 is the tokens to replace. +% #2 is the replacement. +% #3 is the control sequence with the string. +% +\def\HyPsdSubst#1#2#3{% + \def\HyPsdReplace##1#1##2\END{% + ##1% + \ifx\\##2\\% + \else + #2% + \HyReturnAfterFi{% + \HyPsdReplace##2\END + }% + \fi + }% + \xdef#3{\expandafter\HyPsdReplace#3#1\END}% +} +\long\def\HyReturnAfterFi#1\fi{\fi#1} + +% #1 is a control sequence in which to do the replacements. +\def\backslashparens#1{% + \xdef#1{#1}% redefine it as its expansion; the definition is simply + % \lastnode when called from \setref -> \pdfmkdest. + \HyPsdSubst{(}{\realbackslash(}{#1}% + \HyPsdSubst{)}{\realbackslash)}{#1}% +} + +\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images +with PDF output, and none of those formats could be found. (.eps cannot +be supported due to the design of the PDF format; use regular TeX (DVI +output) for that.)} + +\ifpdf + % + % Color manipulation macros based on pdfcolor.tex, + % except using rgb instead of cmyk; the latter is said to render as a + % very dark gray on-screen and a very dark halftone in print, instead + % of actual black. + \def\rgbDarkRed{0.50 0.09 0.12} + \def\rgbBlack{0 0 0} + % + % k sets the color for filling (usual text, etc.); + % K sets the color for stroking (thin rules, e.g., normal _'s). + \def\pdfsetcolor#1{\pdfliteral{#1 rg #1 RG}} + % + % Set color, and create a mark which defines \thiscolor accordingly, + % so that \makeheadline knows which color to restore. + \def\setcolor#1{% + \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}% + \domark + \pdfsetcolor{#1}% + } + % + \def\maincolor{\rgbBlack} + \pdfsetcolor{\maincolor} + \edef\thiscolor{\maincolor} + \def\lastcolordefs{} + % + \def\makefootline{% + \baselineskip24pt + \line{\pdfsetcolor{\maincolor}\the\footline}% + } + % + \def\makeheadline{% + \vbox to 0pt{% + \vskip-22.5pt + \line{% + \vbox to8.5pt{}% + % Extract \thiscolor definition from the marks. + \getcolormarks + % Typeset the headline with \maincolor, then restore the color. + \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}% + }% + \vss + }% + \nointerlineskip + } + % + % + \pdfcatalog{/PageMode /UseOutlines} + % + % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto). + \def\dopdfimage#1#2#3{% + \def\imagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}% + \def\imageheight{#3}\setbox2 = \hbox{\ignorespaces #3}% + % + % pdftex (and the PDF format) support .png, .jpg, .pdf (among + % others). Let's try in that order. + \let\pdfimgext=\empty + \begingroup + \openin 1 #1.png \ifeof 1 + \openin 1 #1.jpg \ifeof 1 + \openin 1 #1.jpeg \ifeof 1 + \openin 1 #1.JPG \ifeof 1 + \openin 1 #1.pdf \ifeof 1 + \openin 1 #1.PDF \ifeof 1 + \errhelp = \nopdfimagehelp + \errmessage{Could not find image file #1 for pdf}% + \else \gdef\pdfimgext{PDF}% + \fi + \else \gdef\pdfimgext{pdf}% + \fi + \else \gdef\pdfimgext{JPG}% + \fi + \else \gdef\pdfimgext{jpeg}% + \fi + \else \gdef\pdfimgext{jpg}% + \fi + \else \gdef\pdfimgext{png}% + \fi + \closein 1 + \endgroup + % + % without \immediate, ancient pdftex seg faults when the same image is + % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.) + \ifnum\pdftexversion < 14 + \immediate\pdfimage + \else + \immediate\pdfximage + \fi + \ifdim \wd0 >0pt width \imagewidth \fi + \ifdim \wd2 >0pt height \imageheight \fi + \ifnum\pdftexversion<13 + #1.\pdfimgext + \else + {#1.\pdfimgext}% + \fi + \ifnum\pdftexversion < 14 \else + \pdfrefximage \pdflastximage + \fi} + % + \def\pdfmkdest#1{{% + % We have to set dummies so commands such as @code, and characters + % such as \, aren't expanded when present in a section title. + \indexnofonts + \turnoffactive + \activebackslashdouble + \makevalueexpandable + \def\pdfdestname{#1}% + \backslashparens\pdfdestname + \safewhatsit{\pdfdest name{\pdfdestname} xyz}% + }} + % + % used to mark target names; must be expandable. + \def\pdfmkpgn#1{#1} + % + % by default, use a color that is dark enough to print on paper as + % nearly black, but still distinguishable for online viewing. + \def\urlcolor{\rgbDarkRed} + \def\linkcolor{\rgbDarkRed} + \def\endlink{\setcolor{\maincolor}\pdfendlink} + % + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by 1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + % + % #1 is the section text, which is what will be displayed in the + % outline by the pdf viewer. #2 is the pdf expression for the number + % of subentries (or empty, for subsubsections). #3 is the node text, + % which might be empty if this toc entry had no corresponding node. + % #4 is the page number + % + \def\dopdfoutline#1#2#3#4{% + % Generate a link to the node text if that exists; else, use the + % page number. We could generate a destination for the section + % text in the case where a section has no node, but it doesn't + % seem worth the trouble, since most documents are normally structured. + \def\pdfoutlinedest{#3}% + \ifx\pdfoutlinedest\empty + \def\pdfoutlinedest{#4}% + \else + % Doubled backslashes in the name. + {\activebackslashdouble \xdef\pdfoutlinedest{#3}% + \backslashparens\pdfoutlinedest}% + \fi + % + % Also double the backslashes in the display string. + {\activebackslashdouble \xdef\pdfoutlinetext{#1}% + \backslashparens\pdfoutlinetext}% + % + \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}% + } + % + \def\pdfmakeoutlines{% + \begingroup + % Thanh's hack / proper braces in bookmarks + \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace + \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace + % + % Read toc silently, to get counts of subentries for \pdfoutline. + \def\numchapentry##1##2##3##4{% + \def\thischapnum{##2}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + }% + \def\numsecentry##1##2##3##4{% + \advancenumber{chap\thischapnum}% + \def\thissecnum{##2}% + \def\thissubsecnum{0}% + }% + \def\numsubsecentry##1##2##3##4{% + \advancenumber{sec\thissecnum}% + \def\thissubsecnum{##2}% + }% + \def\numsubsubsecentry##1##2##3##4{% + \advancenumber{subsec\thissubsecnum}% + }% + \def\thischapnum{0}% + \def\thissecnum{0}% + \def\thissubsecnum{0}% + % + % use \def rather than \let here because we redefine \chapentry et + % al. a second time, below. + \def\appentry{\numchapentry}% + \def\appsecentry{\numsecentry}% + \def\appsubsecentry{\numsubsecentry}% + \def\appsubsubsecentry{\numsubsubsecentry}% + \def\unnchapentry{\numchapentry}% + \def\unnsecentry{\numsecentry}% + \def\unnsubsecentry{\numsubsecentry}% + \def\unnsubsubsecentry{\numsubsubsecentry}% + \readdatafile{toc}% + % + % Read toc second time, this time actually producing the outlines. + % The `-' means take the \expnumber as the absolute number of + % subentries, which we calculated on our first read of the .toc above. + % + % We use the node names as the destinations. + \def\numchapentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}% + \def\numsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}% + \def\numsubsecentry##1##2##3##4{% + \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}% + \def\numsubsubsecentry##1##2##3##4{% count is always zero + \dopdfoutline{##1}{}{##3}{##4}}% + % + % PDF outlines are displayed using system fonts, instead of + % document fonts. Therefore we cannot use special characters, + % since the encoding is unknown. For example, the eogonek from + % Latin 2 (0xea) gets translated to a | character. Info from + % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100. + % + % xx to do this right, we have to translate 8-bit characters to + % their "best" equivalent, based on the @documentencoding. Right + % now, I guess we'll just let the pdf reader have its way. + \indexnofonts + \setupdatafile + \catcode`\\=\active \otherbackslash + \input \tocreadfilename + \endgroup + } + % + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \ifx\p\space\else\addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \fi + \nextsp} + \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + % make a live url in pdf output. + \def\pdfurl#1{% + \begingroup + % it seems we really need yet another set of dummies; have not + % tried to figure out what each command should do in the context + % of @url. for now, just make @/ a no-op, that's the only one + % people have actually reported a problem with. + % + \normalturnoffactive + \def\@{@}% + \let\/=\empty + \makevalueexpandable + % do we want to go so far as to use \indexnofonts instead of just + % special-casing \var here? + \def\var##1{##1}% + % + \leavevmode\setcolor{\urlcolor}% + \startlink attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS|\relax + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}} + \setcolor{\linkcolor}#1\endlink} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\else + % non-pdf mode + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\setcolor = \gobble + \let\pdfsetcolor = \gobble + \let\pdfmakeoutlines = \relax +\fi % \ifx\pdfoutput + + +\message{fonts,} + +% Change the current font style to #1, remembering it in \curfontstyle. +% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in +% italics, not bold italics. +% +\def\setfontstyle#1{% + \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd. + \csname ten#1\endcsname % change the current font +} + +% Select #1 fonts with the current style. +% +\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname} + +\def\rm{\fam=0 \setfontstyle{rm}} +\def\it{\fam=\itfam \setfontstyle{it}} +\def\sl{\fam=\slfam \setfontstyle{sl}} +\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf} +\def\tt{\fam=\ttfam \setfontstyle{tt}} + +% Unfortunately, we have to override this for titles and the like, since +% in those cases "rm" is bold. Sigh. +\def\rmisbold{\rm\def\curfontstyle{bf}} + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf. +\newfam\sffam +\def\sf{\fam=\sffam \setfontstyle{sf}} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this font style. +\def\ttsl{\setfontstyle{ttsl}} + + +% Default leading. +\newdimen\textleading \textleading = 13.2pt + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +% can get a sort of poor man's double spacing by redefining this. +\def\baselinefactor{1} +% +\def\setleading#1{% + \dimen0 = #1\relax + \normalbaselineskip = \baselinefactor\dimen0 + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% PDF CMaps. See also LaTeX's t1.cmap. +% +% do nothing with this by default. +\expandafter\let\csname cmapOT1\endcsname\gobble +\expandafter\let\csname cmapOT1IT\endcsname\gobble +\expandafter\let\csname cmapOT1TT\endcsname\gobble + +% if we are producing pdf, and we have \pdffontattr, then define cmaps. +% (\pdffontattr was introduced many years ago, but people still run +% older pdftex's; it's easy to conditionalize, so we do.) +\ifpdf \ifx\pdffontattr\undefined \else + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1-0) +%%Title: (TeX-OT1-0 TeX OT1 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1) +/Supplement 0 +>> def +/CMapName /TeX-OT1-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<23> <26> <0023> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +40 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1IT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1IT-0) +%%Title: (TeX-OT1IT-0 TeX OT1IT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1IT) +/Supplement 0 +>> def +/CMapName /TeX-OT1IT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +8 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<25> <26> <0025> +<28> <3B> <0028> +<3F> <5B> <003F> +<5D> <5E> <005D> +<61> <7A> <0061> +<7B> <7C> <2013> +endbfrange +42 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <00660066> +<0C> <00660069> +<0D> <0066006C> +<0E> <006600660069> +<0F> <00660066006C> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<21> <0021> +<22> <201D> +<23> <0023> +<24> <00A3> +<27> <2019> +<3C> <00A1> +<3D> <003D> +<3E> <00BF> +<5C> <201C> +<5F> <02D9> +<60> <2018> +<7D> <02DD> +<7E> <007E> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1IT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +% +% \cmapOT1TT + \begingroup + \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char. + \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap +%%DocumentNeededResources: ProcSet (CIDInit) +%%IncludeResource: ProcSet (CIDInit) +%%BeginResource: CMap (TeX-OT1TT-0) +%%Title: (TeX-OT1TT-0 TeX OT1TT 0) +%%Version: 1.000 +%%EndComments +/CIDInit /ProcSet findresource begin +12 dict begin +begincmap +/CIDSystemInfo +<< /Registry (TeX) +/Ordering (OT1TT) +/Supplement 0 +>> def +/CMapName /TeX-OT1TT-0 def +/CMapType 2 def +1 begincodespacerange +<00> <7F> +endcodespacerange +5 beginbfrange +<00> <01> <0393> +<09> <0A> <03A8> +<21> <26> <0021> +<28> <5F> <0028> +<61> <7E> <0061> +endbfrange +32 beginbfchar +<02> <0398> +<03> <039B> +<04> <039E> +<05> <03A0> +<06> <03A3> +<07> <03D2> +<08> <03A6> +<0B> <2191> +<0C> <2193> +<0D> <0027> +<0E> <00A1> +<0F> <00BF> +<10> <0131> +<11> <0237> +<12> <0060> +<13> <00B4> +<14> <02C7> +<15> <02D8> +<16> <00AF> +<17> <02DA> +<18> <00B8> +<19> <00DF> +<1A> <00E6> +<1B> <0153> +<1C> <00F8> +<1D> <00C6> +<1E> <0152> +<1F> <00D8> +<20> <2423> +<27> <2019> +<60> <2018> +<7F> <00A8> +endbfchar +endcmap +CMapName currentdict /CMap defineresource pop +end +end +%%EndResource +%%EOF + }\endgroup + \expandafter\edef\csname cmapOT1TT\endcsname#1{% + \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}% + }% +\fi\fi + + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor, #5 is the CMap +% encoding (currently only OT1, OT1IT and OT1TT are allowed, pass +% empty to omit). +\def\setfont#1#2#3#4#5{% + \font#1=\fontprefix#2#3 scaled #4 + \csname cmap#5\endcsname#1% +} +% This is what gets called when #5 of \setfont is empty. +\let\cmap\gobble +% emacs-page end of cmaps + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +% Definitions for a main text size of 11pt. This is the default in +% Texinfo. +% +\def\definetextfontsizexi{% +% Text fonts (11.2pt, magstep1). +\def\textnominalsize{11pt} +\edef\mainmagstep{\magstephalf} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep +\def\textecsize{1095} + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstep1}{OT1} +\setfont\deftt\ttshape{10}{\magstep1}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 +\def\smallecsize{0900} + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 +\def\smallerecsize{0800} + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\titleecsize{2074} + +% Chapter (and unnumbered) fonts (17.28pt). +\def\chapnominalsize{17pt} +\setfont\chaprm\rmbshape{12}{\magstep2}{OT1} +\setfont\chapit\itbshape{10}{\magstep3}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep3}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT} +\setfont\chapsf\sfbshape{17}{1000}{OT1} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3}{OT1} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 +\def\chapecsize{1728} + +% Section fonts (14.4pt). +\def\secnominalsize{14pt} +\setfont\secrm\rmbshape{12}{\magstep1}{OT1} +\setfont\secit\itbshape{10}{\magstep2}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep2}{OT1} +\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\secsf\sfbshape{12}{\magstep1}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2}{OT1} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 +\def\sececsize{1440} + +% Subsection fonts (13.15pt). +\def\ssecnominalsize{13pt} +\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1} +\setfont\ssecit\itbshape{10}{1315}{OT1IT} +\setfont\ssecsl\slbshape{10}{1315}{OT1} +\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT} +\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1315}{OT1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +\def\ssececsize{1200} + +% Reduced fonts for @acro in text (10pt). +\def\reducednominalsize{10pt} +\setfont\reducedrm\rmshape{10}{1000}{OT1} +\setfont\reducedtt\ttshape{10}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{1000}{OT1} +\setfont\reducedit\itshape{10}{1000}{OT1IT} +\setfont\reducedsl\slshape{10}{1000}{OT1} +\setfont\reducedsf\sfshape{10}{1000}{OT1} +\setfont\reducedsc\scshape{10}{1000}{OT1} +\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT} +\font\reducedi=cmmi10 +\font\reducedsy=cmsy10 +\def\reducedecsize{1000} + +% reset the current fonts +\textfonts +\rm +} % end of 11pt text font size definitions + + +% Definitions to make the main text be 10pt Computer Modern, with +% section, chapter, etc., sizes following suit. This is for the GNU +% Press printing of the Emacs 22 manual. Maybe other manuals in the +% future. Used with @smallbook, which sets the leading to 12pt. +% +\def\definetextfontsizex{% +% Text fonts (10pt). +\def\textnominalsize{10pt} +\edef\mainmagstep{1000} +\setfont\textrm\rmshape{10}{\mainmagstep}{OT1} +\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT} +\setfont\textbf\bfshape{10}{\mainmagstep}{OT1} +\setfont\textit\itshape{10}{\mainmagstep}{OT1IT} +\setfont\textsl\slshape{10}{\mainmagstep}{OT1} +\setfont\textsf\sfshape{10}{\mainmagstep}{OT1} +\setfont\textsc\scshape{10}{\mainmagstep}{OT1} +\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep +\def\textecsize{1000} + +% A few fonts for @defun names and args. +\setfont\defbf\bfshape{10}{\magstephalf}{OT1} +\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT} +\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf} + +% Fonts for indices, footnotes, small examples (9pt). +\def\smallnominalsize{9pt} +\setfont\smallrm\rmshape{9}{1000}{OT1} +\setfont\smalltt\ttshape{9}{1000}{OT1TT} +\setfont\smallbf\bfshape{10}{900}{OT1} +\setfont\smallit\itshape{9}{1000}{OT1IT} +\setfont\smallsl\slshape{9}{1000}{OT1} +\setfont\smallsf\sfshape{9}{1000}{OT1} +\setfont\smallsc\scshape{10}{900}{OT1} +\setfont\smallttsl\ttslshape{10}{900}{OT1TT} +\font\smalli=cmmi9 +\font\smallsy=cmsy9 +\def\smallecsize{0900} + +% Fonts for small examples (8pt). +\def\smallernominalsize{8pt} +\setfont\smallerrm\rmshape{8}{1000}{OT1} +\setfont\smallertt\ttshape{8}{1000}{OT1TT} +\setfont\smallerbf\bfshape{10}{800}{OT1} +\setfont\smallerit\itshape{8}{1000}{OT1IT} +\setfont\smallersl\slshape{8}{1000}{OT1} +\setfont\smallersf\sfshape{8}{1000}{OT1} +\setfont\smallersc\scshape{10}{800}{OT1} +\setfont\smallerttsl\ttslshape{10}{800}{OT1TT} +\font\smalleri=cmmi8 +\font\smallersy=cmsy8 +\def\smallerecsize{0800} + +% Fonts for title page (20.4pt): +\def\titlenominalsize{20pt} +\setfont\titlerm\rmbshape{12}{\magstep3}{OT1} +\setfont\titleit\itbshape{10}{\magstep4}{OT1IT} +\setfont\titlesl\slbshape{10}{\magstep4}{OT1} +\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT} +\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT} +\setfont\titlesf\sfbshape{17}{\magstep1}{OT1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4}{OT1} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\titleecsize{2074} + +% Chapter fonts (14.4pt). +\def\chapnominalsize{14pt} +\setfont\chaprm\rmbshape{12}{\magstep1}{OT1} +\setfont\chapit\itbshape{10}{\magstep2}{OT1IT} +\setfont\chapsl\slbshape{10}{\magstep2}{OT1} +\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT} +\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT} +\setfont\chapsf\sfbshape{12}{\magstep1}{OT1} +\let\chapbf\chaprm +\setfont\chapsc\scbshape{10}{\magstep2}{OT1} +\font\chapi=cmmi12 scaled \magstep1 +\font\chapsy=cmsy10 scaled \magstep2 +\def\chapecsize{1440} + +% Section fonts (12pt). +\def\secnominalsize{12pt} +\setfont\secrm\rmbshape{12}{1000}{OT1} +\setfont\secit\itbshape{10}{\magstep1}{OT1IT} +\setfont\secsl\slbshape{10}{\magstep1}{OT1} +\setfont\sectt\ttbshape{12}{1000}{OT1TT} +\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT} +\setfont\secsf\sfbshape{12}{1000}{OT1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep1}{OT1} +\font\seci=cmmi12 +\font\secsy=cmsy10 scaled \magstep1 +\def\sececsize{1200} + +% Subsection fonts (10pt). +\def\ssecnominalsize{10pt} +\setfont\ssecrm\rmbshape{10}{1000}{OT1} +\setfont\ssecit\itbshape{10}{1000}{OT1IT} +\setfont\ssecsl\slbshape{10}{1000}{OT1} +\setfont\ssectt\ttbshape{10}{1000}{OT1TT} +\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT} +\setfont\ssecsf\sfbshape{10}{1000}{OT1} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{1000}{OT1} +\font\sseci=cmmi10 +\font\ssecsy=cmsy10 +\def\ssececsize{1000} + +% Reduced fonts for @acro in text (9pt). +\def\reducednominalsize{9pt} +\setfont\reducedrm\rmshape{9}{1000}{OT1} +\setfont\reducedtt\ttshape{9}{1000}{OT1TT} +\setfont\reducedbf\bfshape{10}{900}{OT1} +\setfont\reducedit\itshape{9}{1000}{OT1IT} +\setfont\reducedsl\slshape{9}{1000}{OT1} +\setfont\reducedsf\sfshape{9}{1000}{OT1} +\setfont\reducedsc\scshape{10}{900}{OT1} +\setfont\reducedttsl\ttslshape{10}{900}{OT1TT} +\font\reducedi=cmmi9 +\font\reducedsy=cmsy9 +\def\reducedecsize{0900} + +% reduce space between paragraphs +\divide\parskip by 2 + +% reset the current fonts +\textfonts +\rm +} % end of 10pt text font size definitions + + +% We provide the user-level command +% @fonttextsize 10 +% (or 11) to redefine the text font size. pt is assumed. +% +\def\xword{10} +\def\xiword{11} +% +\parseargdef\fonttextsize{% + \def\textsizearg{#1}% + \wlog{doing @fonttextsize \textsizearg}% + % + % Set \globaldefs so that documents can use this inside @tex, since + % makeinfo 4.8 does not support it, but we need it nonetheless. + % + \begingroup \globaldefs=1 + \ifx\textsizearg\xword \definetextfontsizex + \else \ifx\textsizearg\xiword \definetextfontsizexi + \else + \errhelp=\EMsimple + \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'} + \fi\fi + \endgroup +} + + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts except +% in the main text, we don't bother to reset \scriptfont and +% \scriptscriptfont (which would also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy + \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf + \textfont\ttfam=\tentt \textfont\sffam=\tensf +} + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this because \STYLE needs to also set the +% current \fam for math mode. Our \STYLE (e.g., \rm) commands hardwire +% \tenSTYLE to set the current font. +% +% Each font-changing command also sets the names \lsize (one size lower) +% and \lllsize (three sizes lower). These relative commands are used in +% the LaTeX logo and acronyms. +% +% This all needs generalizing, badly. +% +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy + \let\tenttsl=\textttsl + \def\curfontsize{text}% + \def\lsize{reduced}\def\lllsize{smaller}% + \resetmathfonts \setleading{\textleading}} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \def\curfontsize{title}% + \def\lsize{chap}\def\lllsize{subsec}% + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rmisbold #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy + \let\tenttsl=\chapttsl + \def\curfontsize{chap}% + \def\lsize{sec}\def\lllsize{text}% + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy + \let\tenttsl=\secttsl + \def\curfontsize{sec}% + \def\lsize{subsec}\def\lllsize{reduced}% + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy + \let\tenttsl=\ssecttsl + \def\curfontsize{ssec}% + \def\lsize{text}\def\lllsize{small}% + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts +\def\reducedfonts{% + \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl + \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc + \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy + \let\tenttsl=\reducedttsl + \def\curfontsize{reduced}% + \def\lsize{small}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallfonts{% + \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl + \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc + \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy + \let\tenttsl=\smallttsl + \def\curfontsize{small}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{10.5pt}} +\def\smallerfonts{% + \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl + \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc + \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy + \let\tenttsl=\smallerttsl + \def\curfontsize{smaller}% + \def\lsize{smaller}\def\lllsize{smaller}% + \resetmathfonts \setleading{9.5pt}} + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000}{OT1} +\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1} % no cmb12 +\setfont\shortcontsl\slshape{12}{1000}{OT1} +\setfont\shortconttt\ttshape{12}{1000}{OT1TT} + +% Define these just so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Set the fonts to use with the @small... environments. +\let\smallexamplefonts = \smallfonts + +% About \smallexamplefonts. If we use \smallfonts (9pt), @smallexample +% can fit this many characters: +% 8.5x11=86 smallbook=72 a4=90 a5=69 +% If we use \scriptfonts (8pt), then we can fit this many characters: +% 8.5x11=90+ smallbook=80 a4=90+ a5=77 +% For me, subjectively, the few extra characters that fit aren't worth +% the additional smallness of 8pt. So I'm making the default 9pt. +% +% By the way, for comparison, here's what fits with @example (10pt): +% 8.5x11=71 smallbook=60 a4=75 a5=58 +% --karl, 24jan03. + +% Set up the default fonts, so we can use them for creating boxes. +% +\definetextfontsizexi + + +\message{markup,} + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Markup style infrastructure. \defmarkupstylesetup\INITMACRO will +% define and register \INITMACRO to be called on markup style changes. +% \INITMACRO can check \currentmarkupstyle for the innermost +% style and the set of \ifmarkupSTYLE switches for all styles +% currently in effect. +\newif\ifmarkupvar +\newif\ifmarkupsamp +\newif\ifmarkupkey +%\newif\ifmarkupfile % @file == @samp. +%\newif\ifmarkupoption % @option == @samp. +\newif\ifmarkupcode +\newif\ifmarkupkbd +%\newif\ifmarkupenv % @env == @code. +%\newif\ifmarkupcommand % @command == @code. +\newif\ifmarkuptex % @tex (and part of @math, for now). +\newif\ifmarkupexample +\newif\ifmarkupverb +\newif\ifmarkupverbatim + +\let\currentmarkupstyle\empty + +\def\setupmarkupstyle#1{% + \csname markup#1true\endcsname + \def\currentmarkupstyle{#1}% + \markupstylesetup +} + +\let\markupstylesetup\empty + +\def\defmarkupstylesetup#1{% + \expandafter\def\expandafter\markupstylesetup + \expandafter{\markupstylesetup #1}% + \def#1% +} + +% Markup style setup for left and right quotes. +\defmarkupstylesetup\markupsetuplq{% + \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname + \ifx\temp\relax \markupsetuplqdefault \else \temp \fi +} + +\defmarkupstylesetup\markupsetuprq{% + \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname + \ifx\temp\relax \markupsetuprqdefault \else \temp \fi +} + +{ +\catcode`\'=\active +\catcode`\`=\active + +\gdef\markupsetuplqdefault{\let`\lq} +\gdef\markupsetuprqdefault{\let'\rq} + +\gdef\markupsetcodequoteleft{\let`\codequoteleft} +\gdef\markupsetcodequoteright{\let'\codequoteright} + +\gdef\markupsetnoligaturesquoteleft{\let`\noligaturesquoteleft} +} + +\let\markupsetuplqcode \markupsetcodequoteleft +\let\markupsetuprqcode \markupsetcodequoteright +\let\markupsetuplqexample \markupsetcodequoteleft +\let\markupsetuprqexample \markupsetcodequoteright +\let\markupsetuplqverb \markupsetcodequoteleft +\let\markupsetuprqverb \markupsetcodequoteright +\let\markupsetuplqverbatim \markupsetcodequoteleft +\let\markupsetuprqverbatim \markupsetcodequoteright + +\let\markupsetuplqsamp \markupsetnoligaturesquoteleft +\let\markupsetuplqkbd \markupsetnoligaturesquoteleft + +% Allow an option to not replace quotes with a regular directed right +% quote/apostrophe (char 0x27), but instead use the undirected quote +% from cmtt (char 0x0d). The undirected quote is ugly, so don't make it +% the default, but it works for pasting with more pdf viewers (at least +% evince), the lilypond developers report. xpdf does work with the +% regular 0x27. +% +\def\codequoteright{% + \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax + \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax + '% + \else \char'15 \fi + \else \char'15 \fi +} +% +% and a similar option for the left quote char vs. a grave accent. +% Modern fonts display ASCII 0x60 as a grave accent, so some people like +% the code environments to do likewise. +% +\def\codequoteleft{% + \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax + \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax + % [Knuth] pp. 380,381,391 + % \relax disables Spanish ligatures ?` and !` of \tt font. + \relax`% + \else \char'22 \fi + \else \char'22 \fi +} + +% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font. +\def\noligaturesquoteleft{\relax\lq} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else + \ptexslash\fi\fi\fi} +\def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx} + +% like \smartslanted except unconditionally uses \ttsl. +% @var is set to this for defun arguments. +\def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx} + +% @cite is like \smartslanted except unconditionally use \sl. We never want +% ttsl for book titles, do we? +\def\cite#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\slanted=\smartslanted +\def\var#1{{\setupmarkupstyle{var}\smartslanted{#1}}} +\let\dfn=\smartslanted +\let\emph=\smartitalic + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @b, explicit bold. Also @strong. +\def\b#1{{\bf #1}} +\let\strong=\b + +% @sansserif, explicit sans. +\def\sansserif#1{{\sf #1}} + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +% Set sfcode to normal for the chars that usually have another value. +% Can't use plain's \frenchspacing because it uses the `\x notation, and +% sometimes \x has an active definition that messes things up. +% +\catcode`@=11 + \def\plainfrenchspacing{% + \sfcode\dotChar =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m + \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m + \def\endofsentencespacefactor{1000}% for @. and friends + } + \def\plainnonfrenchspacing{% + \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000 + \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250 + \def\endofsentencespacefactor{3000}% for @. and friends + } +\catcode`@=\other +\def\endofsentencespacefactor{3000}% default + +% @t, explicit typewriter. +\def\t#1{% + {\tt \rawbackslash \plainfrenchspacing #1}% + \null +} + +% @samp. +\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}} + +% definition of @key that produces a lozenge. Doesn't adjust to text size. +%\setfont\keyrm\rmshape{8}{1000}{OT1} +%\font\keysy=cmsy9 +%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{% +% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% +% \vbox{\hrule\kern-0.4pt +% \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% +% \kern-0.4pt\hrule}% +% \kern-.06em\raise0.4pt\hbox{\angleright}}}} + +% definition of @key with no lozenge. If the current font is already +% monospace, don't change it; that way, we respect @kbdinputstyle. But +% if it isn't monospace, then use \tt. +% +\def\key#1{{\setupmarkupstyle{key}% + \nohyphenation + \ifmonospace\else\tt\fi + #1}\null} + +% ctrl is no longer a Texinfo command. +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \plainfrenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in @code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active \catcode`\_=\active + \catcode`\'=\active \catcode`\`=\active + \global\let'=\rq \global\let`=\lq % default definitions + % + \global\def\code{\begingroup + \setupmarkupstyle{code}% + % The following should really be moved into \setupmarkupstyle handlers. + \catcode\dashChar=\active \catcode\underChar=\active + \ifallowcodebreaks + \let-\codedash + \let_\codeunder + \else + \let-\realdash + \let_\realunder + \fi + \codex + } +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{% + % this is all so @math{@code{var_name}+1} can work. In math mode, _ + % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.) + % will therefore expand the active definition of _, which is us + % (inside @code that is), therefore an endless loop. + \ifusingtt{\ifmmode + \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_. + \else\normalunderscore \fi + \discretionary{}{}{}}% + {\_}% +} +\def\codex #1{\tclose{#1}\endgroup} + +% An additional complication: the above will allow breaks after, e.g., +% each of the four underscores in __typeof__. This is undesirable in +% some manuals, especially if they don't have long identifiers in +% general. @allowcodebreaks provides a way to control this. +% +\newif\ifallowcodebreaks \allowcodebreakstrue + +\def\keywordtrue{true} +\def\keywordfalse{false} + +\parseargdef\allowcodebreaks{% + \def\txiarg{#1}% + \ifx\txiarg\keywordtrue + \allowcodebreakstrue + \else\ifx\txiarg\keywordfalse + \allowcodebreaksfalse + \else + \errhelp = \EMsimple + \errmessage{Unknown @allowcodebreaks option `\txiarg'}% + \fi\fi +} + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. +\def\kbd#1{{\setupmarkupstyle{kbd}\def\look{#1}\expandafter\kbdfoo\look??\par}} + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\parseargdef\kbdinputstyle{% + \def\txiarg{#1}% + \ifx\txiarg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\txiarg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\txiarg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \else + \errhelp = \EMsimple + \errmessage{Unknown @kbdinputstyle option `\txiarg'}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is `distinct'. +\kbdinputstyle distinct + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi +\else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi} + +% For @indicateurl, @env, @command quotes seem unnecessary, so use \code. +\let\indicateurl=\code +\let\env=\code +\let\command=\code + +% @clicksequence{File @click{} Open ...} +\def\clicksequence#1{\begingroup #1\endgroup} + +% @clickstyle @arrow (by default) +\parseargdef\clickstyle{\def\click{#1}} +\def\click{\arrow} + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{\begingroup + \unsepspaces + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \ifpdf + \unhbox0 % PDF: 2nd arg given, show only it + \else + \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url + \fi + \else + \code{#1}% only url given, so show it + \fi + \fi + \endlink +\endgroup} + +% @url synonym for @uref, since that's how everyone uses it. +% +\let\url=\uref + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{\begingroup + \unsepspaces + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + \endgroup} +\else + \let\email=\uref +\fi + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% @acronym for "FBI", "NATO", and the like. +% We print this one point size smaller, since it's intended for +% all-uppercase. +% +\def\acronym#1{\doacronym #1,,\finish} +\def\doacronym#1,#2,#3\finish{% + {\selectfonts\lsize #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + +% @abbr for "Comput. J." and the like. +% No font change, but don't do end-of-sentence spacing. +% +\def\abbr#1{\doabbr #1,,\finish} +\def\doabbr#1,#2,#3\finish{% + {\plainfrenchspacing #1}% + \def\temp{#2}% + \ifx\temp\empty \else + \space ({\unsepspaces \ignorespaces \temp \unskip})% + \fi +} + + +\message{glyphs,} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +% +% Since these characters are used in examples, they should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% +\def\point{$\star$} +\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}} +\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% The @error{} command. +% Adapted from the TeXbook's \boxit. +% +\newbox\errorbox +% +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \reducedsf error\kern-1.5pt} +% +\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{% + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} +% +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @pounds{} is a sterling sign, which Knuth put in the CM italic font. +% +\def\pounds{{\it\$}} + +% @euro{} comes from a separate font, depending on the current style. +% We use the free feym* fonts from the eurosym package by Henrik +% Theiling, which support regular, slanted, bold and bold slanted (and +% "outlined" (blackboard board, sort of) versions, which we don't need). +% It is available from http://www.ctan.org/tex-archive/fonts/eurosym. +% +% Although only regular is the truly official Euro symbol, we ignore +% that. The Euro is designed to be slightly taller than the regular +% font height. +% +% feymr - regular +% feymo - slanted +% feybr - bold +% feybo - bold slanted +% +% There is no good (free) typewriter version, to my knowledge. +% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide. +% Hmm. +% +% Also doesn't work in math. Do we need to do math with euro symbols? +% Hope not. +% +% +\def\euro{{\eurofont e}} +\def\eurofont{% + % We set the font at each command, rather than predefining it in + % \textfonts and the other font-switching commands, so that + % installations which never need the symbol don't have to have the + % font installed. + % + % There is only one designed size (nominal 10pt), so we always scale + % that to the current nominal size. + % + % By the way, simply using "at 1em" works for cmr10 and the like, but + % does not work for cmbx10 and other extended/shrunken fonts. + % + \def\eurosize{\csname\curfontsize nominalsize\endcsname}% + % + \ifx\curfontstyle\bfstylename + % bold: + \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize + \else + % regular: + \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize + \fi + \thiseurofont +} + +% Glyphs from the EC fonts. We don't use \let for the aliases, because +% sometimes we redefine the original macro, and the alias should reflect +% the redefinition. +% +% Use LaTeX names for the Icelandic letters. +\def\DH{{\ecfont \char"D0}} % Eth +\def\dh{{\ecfont \char"F0}} % eth +\def\TH{{\ecfont \char"DE}} % Thorn +\def\th{{\ecfont \char"FE}} % thorn +% +\def\guillemetleft{{\ecfont \char"13}} +\def\guillemotleft{\guillemetleft} +\def\guillemetright{{\ecfont \char"14}} +\def\guillemotright{\guillemetright} +\def\guilsinglleft{{\ecfont \char"0E}} +\def\guilsinglright{{\ecfont \char"0F}} +\def\quotedblbase{{\ecfont \char"12}} +\def\quotesinglbase{{\ecfont \char"0D}} +% +% This positioning is not perfect (see the ogonek LaTeX package), but +% we have the precomposed glyphs for the most common cases. We put the +% tests to use those glyphs in the single \ogonek macro so we have fewer +% dummy definitions to worry about for index entries, etc. +% +% ogonek is also used with other letters in Lithuanian (IOU), but using +% the precomposed glyphs for those is not so easy since they aren't in +% the same EC font. +\def\ogonek#1{{% + \def\temp{#1}% + \ifx\temp\macrocharA\Aogonek + \else\ifx\temp\macrochara\aogonek + \else\ifx\temp\macrocharE\Eogonek + \else\ifx\temp\macrochare\eogonek + \else + \ecfont \setbox0=\hbox{#1}% + \ifdim\ht0=1ex\accent"0C #1% + \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}% + \fi + \fi\fi\fi\fi + }% +} +\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A} +\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a} +\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E} +\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e} +% +% Use the ec* fonts (cm-super in outline format) for non-CM glyphs. +\def\ecfont{% + % We can't distinguish serif/sans and italic/slanted, but this + % is used for crude hacks anyway (like adding French and German + % quotes to documents typeset with CM, where we lose kerning), so + % hopefully nobody will notice/care. + \edef\ecsize{\csname\curfontsize ecsize\endcsname}% + \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}% + \ifx\curfontstyle\bfstylename + % bold: + \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize + \else + % regular: + \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize + \fi + \thisecfont +} + +% @registeredsymbol - R in a circle. The font for the R should really +% be smaller yet, but lllsize is the best we can do for now. +% Adapted from the plain.tex definition of \copyright. +% +\def\registeredsymbol{% + $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}% + \hfil\crcr\Orb}}% + }$% +} + +% @textdegree - the normal degrees sign. +% +\def\textdegree{$^\circ$} + +% Laurent Siebenmann reports \Orb undefined with: +% Textures 1.7.7 (preloaded format=plain 93.10.14) (68K) 16 APR 2004 02:38 +% so we'll define it if necessary. +% +\ifx\Orb\undefined +\def\Orb{\mathhexbox20D} +\fi + +% Quotes. +\chardef\quotedblleft="5C +\chardef\quotedblright=`\" +\chardef\quoteleft=`\` +\chardef\quoteright=`\' + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\envdef\titlepage{% + % Open one extra group, as we want to close it in the middle of \Etitlepage. + \begingroup + \parindent=0pt \textfonts + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \let\page = \oldpage + \page + \null + }% +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % Need this before the \...aftertitlepage checks so that if they are + % in effect the toc pages will come out with page numbers. + \HEADINGSon + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Macros to be used within @titlepage: + +\let\subtitlerm=\tenrm +\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines} + +\parseargdef\title{% + \checkenv\titlepage + \leftline{\titlefonts\rmisbold #1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt +} + +\parseargdef\subtitle{% + \checkenv\titlepage + {\subtitlefont \rightline{#1}}% +} + +% @author should come last, but may come many times. +% It can also be used inside @quotation. +% +\parseargdef\author{% + \def\temp{\quotation}% + \ifx\thisenv\temp + \def\quotationauthor{#1}% printed in \Equotation. + \else + \checkenv\titlepage + \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi + {\secfonts\rmisbold \leftline{#1}}% + \fi +} + + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make TeX use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + + +\def\evenheading{\parsearg\evenheadingxxx} +\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish} +\def\evenheadingyyy #1\|#2\|#3\|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddheading{\parsearg\oddheadingxxx} +\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish} +\def\oddheadingyyy #1\|#2\|#3\|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish} +\def\evenfootingyyy #1\|#2\|#3\|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\def\oddfooting{\parsearg\oddfootingxxx} +\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish} +\def\oddfootingyyy #1\|#2\|#3\|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -12pt + \global\advance\vsize by -12pt +} + +\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}} + +% @evenheadingmarks top \thischapter <- chapter at the top of a page +% @evenheadingmarks bottom \thischapter <- chapter at the bottom of a page +% +% The same set of arguments for: +% +% @oddheadingmarks +% @evenfootingmarks +% @oddfootingmarks +% @everyheadingmarks +% @everyfootingmarks + +\def\evenheadingmarks{\headingmarks{even}{heading}} +\def\oddheadingmarks{\headingmarks{odd}{heading}} +\def\evenfootingmarks{\headingmarks{even}{footing}} +\def\oddfootingmarks{\headingmarks{odd}{footing}} +\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1} + \headingmarks{odd}{heading}{#1} } +\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1} + \headingmarks{odd}{footing}{#1} } +% #1 = even/odd, #2 = heading/footing, #3 = top/bottom. +\def\headingmarks#1#2#3 {% + \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname + \global\expandafter\let\csname get#1#2marks\endcsname \temp +} + +\everyheadingmarks bottom +\everyfootingmarks bottom + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{% +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{% +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% This produces Day Month Year style of output. +% Only define if not already defined, in case a txi-??.tex file has set +% up a different format (e.g., txi-cs.tex does this). +\ifx\today\undefined +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} +\fi + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg{\gdef\thistitle}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @ftable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemindicate{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. However, if + % what follows is an environment such as @example, there will be no + % \parskip glue; then the negative vskip we just inserted would + % cause the example and the item to crash together. So we use this + % bizarre value of 10001 as a signal to \aboveenvbreak to insert + % \parskip glue after all. Section titles are handled this way also. + % + \penalty 10001 + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a list environment}} +\def\itemx{\errmessage{@itemx while not in a list environment}} + +% @table, @ftable, @vtable. +\envdef\table{% + \let\itemindex\gobble + \tablecheck{table}% +} +\envdef\ftable{% + \def\itemindex ##1{\doind {fn}{\code{##1}}}% + \tablecheck{ftable}% +} +\envdef\vtable{% + \def\itemindex ##1{\doind {vr}{\code{##1}}}% + \tablecheck{vtable}% +} +\def\tablecheck#1{% + \ifnum \the\catcode`\^^M=\active + \endgroup + \errmessage{This command won't work in this context; perhaps the problem is + that we are \inenvironment\thisenv}% + \def\next{\doignore{#1}}% + \else + \let\next\tablex + \fi + \next +} +\def\tablex#1{% + \def\itemindicate{#1}% + \parsearg\tabley +} +\def\tabley#1{% + {% + \makevalueexpandable + \edef\temp{\noexpand\tablez #1\space\space\space}% + \expandafter + }\temp \endtablez +} +\def\tablez #1 #2 #3 #4\endtablez{% + \aboveenvbreak + \ifnum 0#1>0 \advance \leftskip by #1\mil \fi + \ifnum 0#2>0 \tableindent=#2\mil \fi + \ifnum 0#3>0 \advance \rightskip by #3\mil \fi + \itemmax=\tableindent + \advance \itemmax by -\itemmargin + \advance \leftskip by \tableindent + \exdentamount=\tableindent + \parindent = 0pt + \parskip = \smallskipamount + \ifdim \parskip=0pt \parskip=2pt \fi + \let\item = \internalBitem + \let\itemx = \internalBitemx +} +\def\Etable{\endgraf\afterenvbreak} +\let\Eftable\Etable +\let\Evtable\Etable +\let\Eitemize\Etable +\let\Eenumerate\Etable + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\envdef\itemize{\parsearg\doitemize} + +\def\doitemize#1{% + \aboveenvbreak + \itemmax=\itemindent + \advance\itemmax by -\itemmargin + \advance\leftskip by \itemindent + \exdentamount=\itemindent + \parindent=0pt + \parskip=\smallskipamount + \ifdim\parskip=0pt \parskip=2pt \fi + % + % Try typesetting the item mark that if the document erroneously says + % something like @itemize @samp (intending @table), there's an error + % right away at the @itemize. It's not the best error message in the + % world, but it's better than leaving it to the @item. This means if + % the user wants an empty mark, they have to say @w{} not just @w. + \def\itemcontents{#1}% + \setbox0 = \hbox{\itemcontents}% + % + % @itemize with no arg is equivalent to @itemize @bullet. + \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi + % + \let\item=\itemizeitem +} + +% Definition of @item while inside @itemize and @enumerate. +% +\def\itemizeitem{% + \advance\itemno by 1 % for enumerations + {\let\par=\endgraf \smallbreak}% reasonable place to break + {% + % If the document has an @itemize directly after a section title, a + % \nobreak will be last on the list, and \sectionheading will have + % done a \vskip-\parskip. In that case, we don't want to zero + % parskip, or the item text will crash with the heading. On the + % other hand, when there is normal text preceding the item (as there + % usually is), we do want to zero parskip, or there would be too much + % space. In that case, we won't have a \nobreak before. At least + % that's the theory. + \ifnum\lastpenalty<10000 \parskip=0in \fi + \noindent + \hbox to 0pt{\hss \itemcontents \kern\itemmargin}% + % + \vadjust{\penalty 1200}}% not good to break after first line of item. + \flushcr +} + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\envparseargdef\enumerate{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call \doitemize, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \doitemize{#1.}\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab do not need to be on their own lines, but it will not hurt +% if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the @columnfraction, usually a decimal number like .5, but might +% be just 1. We just use it, whatever it is. +% +\def\pickupwholefraction#1 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a + % separator; typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% multitable-only commands. +% +% @headitem starts a heading row, which we typeset in bold. +% Assignments have to be global since we are inside the implicit group +% of an alignment entry. \everycr resets \everytab so we don't have to +% undo it ourselves. +\def\headitemfont{\b}% for people to use in the template row; not changeable +\def\headitem{% + \checkenv\multitable + \crcr + \global\everytab={\bf}% can't use \headitemfont since the parsing differs + \the\everytab % for the first item +}% +% +% A \tab used to include \hskip1sp. But then the space in a template +% line is not enough. That is bad. So let's go back to just `&' until +% we again encounter the problem the 1sp was intended to solve. +% --karl, nathan@acm.org, 20apr99. +\def\tab{\checkenv\multitable &\the\everytab}% + +% @multitable ... @end multitable definitions: +% +\newtoks\everytab % insert after every tab. +% +\envdef\multitable{% + \vskip\parskip + \startsavinginserts + % + % @item within a multitable starts a normal row. + % We use \def instead of \let so that if one of the multitable entries + % contains an @itemize, we don't choke on the \item (seen as \crcr aka + % \endtemplate) expanding \doitemize. + \def\item{\crcr}% + % + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + % + \everycr = {% + \noalign{% + \global\everytab={}% + \global\colcount=0 % Reset the column counter. + % Check for saved footnotes, etc. + \checkinserts + % Keeps underfull box messages off when table breaks over pages. + %\filbreak + % Maybe so, but it also creates really weird page breaks when the + % table breaks over pages. Wouldn't \vfil be better? Wait until the + % problem manifests itself, so it can be fixed for real --karl. + }% + }% + % + \parsearg\domultitable +} +\def\domultitable#1{% + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup &% + \global\advance\colcount by 1 + \multistrut + \vtop{% + % Use the current \colcount to find the correct column width: + \hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively + % marking characters. + \noindent\ignorespaces##\unskip\multistrut + }\cr +} +\def\Emultitable{% + \crcr + \egroup % end the \halign + \global\setpercentfalse +} + +\def\setmultitablespacing{% + \def\multistrut{\strut}% just use the standard line spacing + % + % Compute \multitablelinespace (if not defined by user) for use in + % \multitableparskip calculation. We used define \multistrut based on + % this, but (ironically) that caused the spacing to be off. + % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100. +\ifdim\multitablelinespace=0pt +\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip +\global\advance\multitablelinespace by-\ht0 +\fi +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} + +% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext, +% @ifnotxml always succeed. They currently do nothing; we don't +% attempt to check whether the conditionals are properly nested. But we +% have to remember that they are conditionals, so that @end doesn't +% attempt to close an environment group. +% +\def\makecond#1{% + \expandafter\let\csname #1\endcsname = \relax + \expandafter\let\csname iscond.#1\endcsname = 1 +} +\makecond{iftex} +\makecond{ifnotdocbook} +\makecond{ifnothtml} +\makecond{ifnotinfo} +\makecond{ifnotplaintext} +\makecond{ifnotxml} + +% Ignore @ignore, @ifhtml, @ifinfo, and the like. +% +\def\direntry{\doignore{direntry}} +\def\documentdescription{\doignore{documentdescription}} +\def\docbook{\doignore{docbook}} +\def\html{\doignore{html}} +\def\ifdocbook{\doignore{ifdocbook}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifinfo{\doignore{ifinfo}} +\def\ifnottex{\doignore{ifnottex}} +\def\ifplaintext{\doignore{ifplaintext}} +\def\ifxml{\doignore{ifxml}} +\def\ignore{\doignore{ignore}} +\def\menu{\doignore{menu}} +\def\xml{\doignore{xml}} + +% Ignore text until a line `@end #1', keeping track of nested conditionals. +% +% A count to remember the depth of nesting. +\newcount\doignorecount + +\def\doignore#1{\begingroup + % Scan in ``verbatim'' mode: + \obeylines + \catcode`\@ = \other + \catcode`\{ = \other + \catcode`\} = \other + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \spaceisspace + % + % Count number of #1's that we've seen. + \doignorecount = 0 + % + % Swallow text until we reach the matching `@end #1'. + \dodoignore{#1}% +} + +{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source. + \obeylines % + % + \gdef\dodoignore#1{% + % #1 contains the command name as a string, e.g., `ifinfo'. + % + % Define a command to find the next `@end #1'. + \long\def\doignoretext##1^^M@end #1{% + \doignoretextyyy##1^^M@#1\_STOP_}% + % + % And this command to find another #1 command, at the beginning of a + % line. (Otherwise, we would consider a line `@c @ifset', for + % example, to count as an @ifset for nesting.) + \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}% + % + % And now expand that command. + \doignoretext ^^M% + }% +} + +\def\doignoreyyy#1{% + \def\temp{#1}% + \ifx\temp\empty % Nothing found. + \let\next\doignoretextzzz + \else % Found a nested condition, ... + \advance\doignorecount by 1 + \let\next\doignoretextyyy % ..., look for another. + % If we're here, #1 ends with ^^M\ifinfo (for example). + \fi + \next #1% the token \_STOP_ is present just after this macro. +} + +% We have to swallow the remaining "\_STOP_". +% +\def\doignoretextzzz#1{% + \ifnum\doignorecount = 0 % We have just found the outermost @end. + \let\next\enddoignore + \else % Still inside a nested condition. + \advance\doignorecount by -1 + \let\next\doignoretext % Look for the next @end. + \fi + \next +} + +% Finish off ignored text. +{ \obeylines% + % Ignore anything after the last `@end #1'; this matters in verbatim + % environments, where otherwise the newline after an ignored conditional + % would result in a blank line in the output. + \gdef\enddoignore#1^^M{\endgroup\ignorespaces}% +} + + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% We rely on the fact that \parsearg sets \catcode`\ =10. +% +\parseargdef\set{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + {% + \makevalueexpandable + \def\temp{#2}% + \edef\next{\gdef\makecsname{SET#1}}% + \ifx\temp\empty + \next{}% + \else + \setzzz#2\endsetzzz + \fi + }% +} +% Remove the trailing space \setxxx inserted. +\def\setzzz#1 \endsetzzz{\next{#1}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\parseargdef\clear{% + {% + \makevalueexpandable + \global\expandafter\let\csname SET#1\endcsname=\relax + }% +} + +% @value{foo} gets the text saved in variable foo. +\def\value{\begingroup\makevalueexpandable\valuexxx} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} +{ + \catcode`\- = \active \catcode`\_ = \active + % + \gdef\makevalueexpandable{% + \let\value = \expandablevalue + % We don't want these characters active, ... + \catcode`\-=\other \catcode`\_=\other + % ..., but we might end up with active ones in the argument if + % we're called from @code, as @code{@value{foo-bar_}}, though. + % So \let them to their normal equivalents. + \let-\realdash \let_\normalunderscore + } +} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we call \makevalueexpandable in \indexdummies). +% The command has to be fully expandable (if the variable is set), since +% the result winds up in the index file. This means that if the +% variable's value contains other Texinfo commands, it's almost certain +% it will fail (although perhaps we could fix that with sufficient work +% to do a one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \message{Variable `#1', used in @value, is not set.}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +% To get special treatment of `@end ifset,' call \makeond and the redefine. +% +\makecond{ifset} +\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}} +\def\doifset#1#2{% + {% + \makevalueexpandable + \let\next=\empty + \expandafter\ifx\csname SET#2\endcsname\relax + #1% If not set, redefine \next. + \fi + \expandafter + }\next +} +\def\ifsetfail{\doignore{ifset}} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +% The `\else' inside the `\doifset' parameter is a trick to reuse the +% above code: if the variable is not set, do nothing, if it is set, +% then redefine \next to \ifclearfail. +% +\makecond{ifclear} +\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}} +\def\ifclearfail{\doignore{ifclear}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory=\comment + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within macros and \if's. +\edef\newwrite{\makecsname{ptexnewwrite}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} +% +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. +% +\def\defcodeindex{\parsearg\newcodeindex} +% +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}}% +} + + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +% +\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}} +\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}} + +% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo), +% #3 the target index (bar). +\def\dosynindex#1#2#3{% + % Only do \closeout if we haven't already done it, else we'll end up + % closing the target index. + \expandafter \ifx\csname donesynindex#2\endcsname \relax + % The \closeout helps reduce unnecessary open files; the limit on the + % Acorn RISC OS is a mere 16 files. + \expandafter\closeout\csname#2indfile\endcsname + \expandafter\let\csname donesynindex#2\endcsname = 1 + \fi + % redefine \fooindfile: + \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname + \expandafter\let\csname#2indfile\endcsname=\temp + % redefine \fooindex: + \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +% Take care of Texinfo commands that can appear in an index entry. +% Since there are some commands we want to expand, and others we don't, +% we have to laboriously prevent expansion for those that we don't. +% +\def\indexdummies{% + \escapechar = `\\ % use backslash in output files. + \def\@{@}% change to @@ when we switch to @ as escape char in index files. + \def\ {\realbackslash\space }% + % + % Need these in case \tex is in effect and \{ is a \delimiter again. + % But can't use \lbracecmd and \rbracecmd because texindex assumes + % braces and backslashes are used only as delimiters. + \let\{ = \mylbrace + \let\} = \myrbrace + % + % I don't entirely understand this, but when an index entry is + % generated from a macro call, the \endinput which \scanmacro inserts + % causes processing to be prematurely terminated. This is, + % apparently, because \indexsorttmp is fully expanded, and \endinput + % is an expandable command. The redefinition below makes \endinput + % disappear altogether for that purpose -- although logging shows that + % processing continues to some further point. On the other hand, it + % seems \endinput does not hurt in the printed index arg, since that + % is still getting written without apparent harm. + % + % Sample source (mac-idx3.tex, reported by Graham Percival to + % help-texinfo, 22may06): + % @macro funindex {WORD} + % @findex xyz + % @end macro + % ... + % @funindex commtest + % + % The above is not enough to reproduce the bug, but it gives the flavor. + % + % Sample whatsit resulting: + % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}} + % + % So: + \let\endinput = \empty + % + % Do the redefinitions. + \commondummies +} + +% For the aux and toc files, @ is the escape character. So we want to +% redefine everything using @ as the escape character (instead of +% \realbackslash, still used for index files). When everything uses @, +% this will be simpler. +% +\def\atdummies{% + \def\@{@@}% + \def\ {@ }% + \let\{ = \lbraceatcmd + \let\} = \rbraceatcmd + % + % Do the redefinitions. + \commondummies + \otherbackslash +} + +% Called from \indexdummies and \atdummies. +% +\def\commondummies{% + % + % \definedummyword defines \#1 as \string\#1\space, thus effectively + % preventing its expansion. This is used only for control% words, + % not control letters, because the \space would be incorrect for + % control characters, but is needed to separate the control word + % from whatever follows. + % + % For control letters, we have \definedummyletter, which omits the + % space. + % + % These can be used both for control words that take an argument and + % those that do not. If it is followed by {arg} in the input, then + % that will dutifully get written to the index (or wherever). + % + \def\definedummyword ##1{\def##1{\string##1\space}}% + \def\definedummyletter##1{\def##1{\string##1}}% + \let\definedummyaccent\definedummyletter + % + \commondummiesnofonts + % + \definedummyletter\_% + % + % Non-English letters. + \definedummyword\AA + \definedummyword\AE + \definedummyword\DH + \definedummyword\L + \definedummyword\O + \definedummyword\OE + \definedummyword\TH + \definedummyword\aa + \definedummyword\ae + \definedummyword\dh + \definedummyword\exclamdown + \definedummyword\l + \definedummyword\o + \definedummyword\oe + \definedummyword\ordf + \definedummyword\ordm + \definedummyword\questiondown + \definedummyword\ss + \definedummyword\th + % + % Although these internal commands shouldn't show up, sometimes they do. + \definedummyword\bf + \definedummyword\gtr + \definedummyword\hat + \definedummyword\less + \definedummyword\sf + \definedummyword\sl + \definedummyword\tclose + \definedummyword\tt + % + \definedummyword\LaTeX + \definedummyword\TeX + % + % Assorted special characters. + \definedummyword\bullet + \definedummyword\comma + \definedummyword\copyright + \definedummyword\registeredsymbol + \definedummyword\dots + \definedummyword\enddots + \definedummyword\equiv + \definedummyword\error + \definedummyword\euro + \definedummyword\guillemetleft + \definedummyword\guillemetright + \definedummyword\guilsinglleft + \definedummyword\guilsinglright + \definedummyword\expansion + \definedummyword\minus + \definedummyword\ogonek + \definedummyword\pounds + \definedummyword\point + \definedummyword\print + \definedummyword\quotedblbase + \definedummyword\quotedblleft + \definedummyword\quotedblright + \definedummyword\quoteleft + \definedummyword\quoteright + \definedummyword\quotesinglbase + \definedummyword\result + \definedummyword\textdegree + % + % We want to disable all macros so that they are not expanded by \write. + \macrolist + % + \normalturnoffactive + % + % Handle some cases of @value -- where it does not contain any + % (non-fully-expandable) commands. + \makevalueexpandable +} + +% \commondummiesnofonts: common to \commondummies and \indexnofonts. +% +\def\commondummiesnofonts{% + % Control letters and accents. + \definedummyletter\!% + \definedummyaccent\"% + \definedummyaccent\'% + \definedummyletter\*% + \definedummyaccent\,% + \definedummyletter\.% + \definedummyletter\/% + \definedummyletter\:% + \definedummyaccent\=% + \definedummyletter\?% + \definedummyaccent\^% + \definedummyaccent\`% + \definedummyaccent\~% + \definedummyword\u + \definedummyword\v + \definedummyword\H + \definedummyword\dotaccent + \definedummyword\ogonek + \definedummyword\ringaccent + \definedummyword\tieaccent + \definedummyword\ubaraccent + \definedummyword\udotaccent + \definedummyword\dotless + % + % Texinfo font commands. + \definedummyword\b + \definedummyword\i + \definedummyword\r + \definedummyword\sc + \definedummyword\t + % + % Commands that take arguments. + \definedummyword\acronym + \definedummyword\cite + \definedummyword\code + \definedummyword\command + \definedummyword\dfn + \definedummyword\email + \definedummyword\emph + \definedummyword\env + \definedummyword\file + \definedummyword\kbd + \definedummyword\key + \definedummyword\math + \definedummyword\option + \definedummyword\pxref + \definedummyword\ref + \definedummyword\samp + \definedummyword\strong + \definedummyword\tie + \definedummyword\uref + \definedummyword\url + \definedummyword\var + \definedummyword\verb + \definedummyword\w + \definedummyword\xref +} + +% \indexnofonts is used when outputting the strings to sort the index +% by, and when constructing control sequence names. It eliminates all +% control sequences and just writes whatever the best ASCII sort string +% would be for a given command (usually its argument). +% +\def\indexnofonts{% + % Accent commands should become @asis. + \def\definedummyaccent##1{\let##1\asis}% + % We can just ignore other control letters. + \def\definedummyletter##1{\let##1\empty}% + % Hopefully, all control words can become @asis. + \let\definedummyword\definedummyaccent + % + \commondummiesnofonts + % + % Don't no-op \tt, since it isn't a user-level command + % and is used in the definitions of the active chars like <, >, |, etc. + % Likewise with the other plain tex font commands. + %\let\tt=\asis + % + \def\ { }% + \def\@{@}% + % how to handle braces? + \def\_{\normalunderscore}% + % + % Non-English letters. + \def\AA{AA}% + \def\AE{AE}% + \def\DH{DZZ}% + \def\L{L}% + \def\OE{OE}% + \def\O{O}% + \def\TH{ZZZ}% + \def\aa{aa}% + \def\ae{ae}% + \def\dh{dzz}% + \def\exclamdown{!}% + \def\l{l}% + \def\oe{oe}% + \def\ordf{a}% + \def\ordm{o}% + \def\o{o}% + \def\questiondown{?}% + \def\ss{ss}% + \def\th{zzz}% + % + \def\LaTeX{LaTeX}% + \def\TeX{TeX}% + % + % Assorted special characters. + % (The following {} will end up in the sort string, but that's ok.) + \def\bullet{bullet}% + \def\comma{,}% + \def\copyright{copyright}% + \def\dots{...}% + \def\enddots{...}% + \def\equiv{==}% + \def\error{error}% + \def\euro{euro}% + \def\expansion{==>}% + \def\guillemetleft{<<}% + \def\guillemetright{>>}% + \def\guilsinglleft{<}% + \def\guilsinglright{>}% + \def\minus{-}% + \def\point{.}% + \def\pounds{pounds}% + \def\print{-|}% + \def\quotedblbase{"}% + \def\quotedblleft{"}% + \def\quotedblright{"}% + \def\quoteleft{`}% + \def\quoteright{'}% + \def\quotesinglbase{,}% + \def\registeredsymbol{R}% + \def\result{=>}% + \def\textdegree{o}% + % + % We need to get rid of all macros, leaving only the arguments (if present). + % Of course this is not nearly correct, but it is the best we can do for now. + % makeinfo does not expand macros in the argument to @deffn, which ends up + % writing an index entry, and texindex isn't prepared for an index sort entry + % that starts with \. + % + % Since macro invocations are followed by braces, we can just redefine them + % to take a single TeX argument. The case of a macro invocation that + % goes to end-of-line is not handled. + % + \macrolist +} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% Most index entries go through here, but \dosubind is the general case. +% #1 is the index name, #2 is the entry text. +\def\doind#1#2{\dosubind{#1}{#2}{}} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% empty if called from \doind, as we usually are (the main exception +% is with most defuns, which call us directly). +% +\def\dosubind#1#2#3{% + \iflinks + {% + % Store the main index entry text (including the third arg). + \toks0 = {#2}% + % If third arg is present, precede it with a space. + \def\thirdarg{#3}% + \ifx\thirdarg\empty \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + \edef\writeto{\csname#1indfile\endcsname}% + % + \safewhatsit\dosubindwrite + }% + \fi +} + +% Write the entry in \toks0 to the index file: +% +\def\dosubindwrite{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}% + \fi + % + % Remember, we are within a group. + \indexdummies % Must do this here, since \bf, etc expand at this stage + \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % Process the index entry with all font commands turned off, to + % get the string to sort by. + {\indexnofonts + \edef\temp{\the\toks0}% need full expansion + \xdef\indexsorttmp{\temp}% + }% + % + % Set up the complete index entry, with both the sort key and + % the original text, including any font commands. We write + % three arguments to \entry to the .?? file (four in the + % subentry case), texindex reduces to two when writing the .??s + % sorted result. + \edef\temp{% + \write\writeto{% + \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}% + }% + \temp +} + +% Take care of unwanted page breaks/skips around a whatsit: +% +% If a skip is the last thing on the list now, preserve it +% by backing up by \lastskip, doing the \write, then inserting +% the skip again. Otherwise, the whatsit generated by the +% \write or \pdfdest will make \lastskip zero. The result is that +% sequences like this: +% @end defun +% @tindex whatever +% @defun ... +% will have extra space inserted, because the \medbreak in the +% start of the @defun won't see the skip inserted by the @end of +% the previous defun. +% +% But don't do any of this if we're not in vertical mode. We +% don't want to do a \vskip and prematurely end a paragraph. +% +% Avoid page breaks due to these extra skips, too. +% +% But wait, there is a catch there: +% We'll have to check whether \lastskip is zero skip. \ifdim is not +% sufficient for this purpose, as it ignores stretch and shrink parts +% of the skip. The only way seems to be to check the textual +% representation of the skip. +% +% The following is almost like \def\zeroskipmacro{0.0pt} except that +% the ``p'' and ``t'' characters have catcode \other, not 11 (letter). +% +\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname} +% +\newskip\whatsitskip +\newcount\whatsitpenalty +% +% ..., ready, GO: +% +\def\safewhatsit#1{% +\ifhmode + #1% +\else + % \lastskip and \lastpenalty cannot both be nonzero simultaneously. + \whatsitskip = \lastskip + \edef\lastskipmacro{\the\lastskip}% + \whatsitpenalty = \lastpenalty + % + % If \lastskip is nonzero, that means the last item was a + % skip. And since a skip is discardable, that means this + % -\whatsitskip glue we're inserting is preceded by a + % non-discardable item, therefore it is not a potential + % breakpoint, therefore no \nobreak needed. + \ifx\lastskipmacro\zeroskipmacro + \else + \vskip-\whatsitskip + \fi + % + #1% + % + \ifx\lastskipmacro\zeroskipmacro + % If \lastskip was zero, perhaps the last item was a penalty, and + % perhaps it was >=10000, e.g., a \nobreak. In that case, we want + % to re-insert the same penalty (values >10000 are used for various + % signals); since we just inserted a non-discardable item, any + % following glue (such as a \parskip) would be a breakpoint. For example: + % + % @deffn deffn-whatever + % @vindex index-whatever + % Description. + % would allow a break between the index-whatever whatsit + % and the "Description." paragraph. + \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi + \else + % On the other hand, if we had a nonzero \lastskip, + % this make-up glue would be preceded by a non-discardable item + % (the whatsit from the \write), so we must insert a \nobreak. + \nobreak\vskip\whatsitskip + \fi +\fi +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\parseargdef\printindex{\begingroup + \dobreak \chapheadingskip{10000}% + % + \smallfonts \rm + \tolerance = 9500 + \plainfrenchspacing + \everypar = {}% don't want the \kern\-parindent from indentation suppression. + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\backslashcurfont}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \nobreak + \vskip 0pt plus 3\baselineskip + \penalty 0 + \vskip 0pt plus -3\baselineskip + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + % Do our best not to break after the initial. + \nobreak + \vskip .33\baselineskip plus .1\baselineskip +}} + +% \entry typesets a paragraph consisting of the text (#1), dot leaders, and +% then page number (#2) flushed to the right margin. It is used for index +% and table of contents entries. The paragraph is indented by \leftskip. +% +% A straightforward implementation would start like this: +% \def\entry#1#2{... +% But this freezes the catcodes in the argument, and can cause problems to +% @code, which sets - active. This problem was fixed by a kludge--- +% ``-'' was active throughout whole index, but this isn't really right. +% +% The right solution is to prevent \entry from swallowing the whole text. +% --kasal, 21nov03 +\def\entry{% + \begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing + % columns. + \vskip 0pt plus1pt + % + % Swallow the left brace of the text (first parameter): + \afterassignment\doentry + \let\temp = +} +\def\doentry{% + \bgroup % Instead of the swallowed brace. + \noindent + \aftergroup\finishentry + % And now comes the text of the entry. +} +\def\finishentry#1{% + % #1 is the page number. + % + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \setbox\boxA = \hbox{#1}% + \ifdim\wd\boxA = 0pt + \ % + \else + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ifpdf + \pdfgettoks#1.% + \ \the\toksA + \else + \ #1% + \fi + \fi + \par + \endgroup +} + +% Like plain.tex's \dotfill, except uses up at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm +\def\secondary#1#2{{% + \parfillskip=0in + \parskip=0in + \hangindent=1in + \hangafter=1 + \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + #2 + \fi + \par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + \advance\dimen@ by -\ht\partialpage + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +% +% Re-output the contents of the output page -- any previous material, +% followed by the two boxes we just split, in box0 and box2. +\def\pagesofar{% + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +% +% All done with double columns. +\def\enddoublecolumns{% + % The following penalty ensures that the page builder is exercised + % _before_ we change the output routine. This is necessary in the + % following situation: + % + % The last section of the index consists only of a single entry. + % Before this section, \pagetotal is less than \pagegoal, so no + % break occurs before the last section starts. However, the last + % section, consisting of \initial and the single \entry, does not + % fit on the page and has to be broken off. Without the following + % penalty the page builder will not be exercised until \eject + % below, and by that time we'll already have changed the output + % routine to the \balancecolumns version, so the next-to-last + % double-column page will be processed with \balancecolumns, which + % is wrong: The two columns will go to the main vertical list, with + % the broken-off section in the recent contributions. As soon as + % the output routine finishes, TeX starts reconsidering the page + % break. The two columns and the broken-off section both fit on the + % page, because the two columns now take up only half of the page + % goal. When TeX sees \eject from below which follows the final + % section, it invokes the new output routine that we've set after + % \balancecolumns below; \onepageout will try to fit the two columns + % and the final section into the vbox of \pageheight (see + % \pagebody), causing an overfull box. + % + % Note that glue won't work here, because glue does not exercise the + % page builder, unlike penalties (see The TeXbook, pp. 280-281). + \penalty0 + % + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +% +% Called at the end of the double column material. +\def\balancecolumns{% + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +% \unnumberedno is an oxymoron, of course. But we count the unnumbered +% sections so that we can refer to them unambiguously in the pdf +% outlines by their "section number". We avoid collisions with chapter +% numbers by starting them at 10000. (If a document ever has 10000 +% chapters, we're in trouble anyway, I'm sure.) +\newcount\unnumberedno \unnumberedno = 10000 +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +% +% \def\appendixletter{\char\the\appendixno} +% We do the following ugly conditional instead of the above simple +% construct for the sake of pdftex, which needs the actual +% letter in the expansion, not just typeset. +% +\def\appendixletter{% + \ifnum\appendixno=`A A% + \else\ifnum\appendixno=`B B% + \else\ifnum\appendixno=`C C% + \else\ifnum\appendixno=`D D% + \else\ifnum\appendixno=`E E% + \else\ifnum\appendixno=`F F% + \else\ifnum\appendixno=`G G% + \else\ifnum\appendixno=`H H% + \else\ifnum\appendixno=`I I% + \else\ifnum\appendixno=`J J% + \else\ifnum\appendixno=`K K% + \else\ifnum\appendixno=`L L% + \else\ifnum\appendixno=`M M% + \else\ifnum\appendixno=`N N% + \else\ifnum\appendixno=`O O% + \else\ifnum\appendixno=`P P% + \else\ifnum\appendixno=`Q Q% + \else\ifnum\appendixno=`R R% + \else\ifnum\appendixno=`S S% + \else\ifnum\appendixno=`T T% + \else\ifnum\appendixno=`U U% + \else\ifnum\appendixno=`V V% + \else\ifnum\appendixno=`W W% + \else\ifnum\appendixno=`X X% + \else\ifnum\appendixno=`Y Y% + \else\ifnum\appendixno=`Z Z% + % The \the is necessary, despite appearances, because \appendixletter is + % expanded while writing the .toc file. \char\appendixno is not + % expandable, thus it is written literally, thus all appendixes come out + % with the same letter (or @) in the toc without it. + \else\char\the\appendixno + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + +% Each @chapter defines these (using marks) as the number+name, number +% and name of the chapter. Page headings and footings can use +% these. @section does likewise. +\def\thischapter{} +\def\thischapternum{} +\def\thischaptername{} +\def\thissection{} +\def\thissectionnum{} +\def\thissectionname{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% we only have subsub. +\chardef\maxseclevel = 3 +% +% A numbered section within an unnumbered changes to unnumbered too. +% To achive this, remember the "biggest" unnum. sec. we are currently in: +\chardef\unmlevel = \maxseclevel +% +% Trace whether the current chapter is an appendix or not: +% \chapheadtype is "N" or "A", unnumbered chapters are ignored. +\def\chapheadtype{N} + +% Choose a heading macro +% #1 is heading type +% #2 is heading level +% #3 is text for heading +\def\genhead#1#2#3{% + % Compute the abs. sec. level: + \absseclevel=#2 + \advance\absseclevel by \secbase + % Make sure \absseclevel doesn't fall outside the range: + \ifnum \absseclevel < 0 + \absseclevel = 0 + \else + \ifnum \absseclevel > 3 + \absseclevel = 3 + \fi + \fi + % The heading type: + \def\headtype{#1}% + \if \headtype U% + \ifnum \absseclevel < \unmlevel + \chardef\unmlevel = \absseclevel + \fi + \else + % Check for appendix sections: + \ifnum \absseclevel = 0 + \edef\chapheadtype{\headtype}% + \else + \if \headtype A\if \chapheadtype N% + \errmessage{@appendix... within a non-appendix chapter}% + \fi\fi + \fi + % Check for numbered within unnumbered: + \ifnum \absseclevel > \unmlevel + \def\headtype{U}% + \else + \chardef\unmlevel = 3 + \fi + \fi + % Now print the heading: + \if \headtype U% + \ifcase\absseclevel + \unnumberedzzz{#3}% + \or \unnumberedseczzz{#3}% + \or \unnumberedsubseczzz{#3}% + \or \unnumberedsubsubseczzz{#3}% + \fi + \else + \if \headtype A% + \ifcase\absseclevel + \appendixzzz{#3}% + \or \appendixsectionzzz{#3}% + \or \appendixsubseczzz{#3}% + \or \appendixsubsubseczzz{#3}% + \fi + \else + \ifcase\absseclevel + \chapterzzz{#3}% + \or \seczzz{#3}% + \or \numberedsubseczzz{#3}% + \or \numberedsubsubseczzz{#3}% + \fi + \fi + \fi + \suppressfirstparagraphindent +} + +% an interface: +\def\numhead{\genhead N} +\def\apphead{\genhead A} +\def\unnmhead{\genhead U} + +% @chapter, @appendix, @unnumbered. Increment top-level counter, reset +% all lower-level sectioning counters to zero. +% +% Also set \chaplevelprefix, which we prepend to @float sequence numbers +% (e.g., figures), q.v. By default (before any chapter), that is empty. +\let\chaplevelprefix = \empty +% +\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz#1{% + % section resetting is \global in case the chapter is in a group, such + % as an @include file. + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\chapno by 1 + % + % Used for \float. + \gdef\chaplevelprefix{\the\chapno.}% + \resetallfloatnos + % + % \putwordChapter can contain complex things in translations. + \toks0=\expandafter{\putwordChapter}% + \message{\the\toks0 \space \the\chapno}% + % + % Write the actual heading. + \chapmacro{#1}{Ynumbered}{\the\chapno}% + % + % So @section and the like are numbered underneath this chapter. + \global\let\section = \numberedsec + \global\let\subsection = \numberedsubsec + \global\let\subsubsection = \numberedsubsubsec +} + +\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz +% +\def\appendixzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\appendixno by 1 + \gdef\chaplevelprefix{\appendixletter.}% + \resetallfloatnos + % + % \putwordAppendix can contain complex things in translations. + \toks0=\expandafter{\putwordAppendix}% + \message{\the\toks0 \space \appendixletter}% + % + \chapmacro{#1}{Yappendix}{\appendixletter}% + % + \global\let\section = \appendixsec + \global\let\subsection = \appendixsubsec + \global\let\subsubsection = \appendixsubsubsec +} + +\outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz#1{% + \global\secno=0 \global\subsecno=0 \global\subsubsecno=0 + \global\advance\unnumberedno by 1 + % + % Since an unnumbered has no number, no prefix for figures. + \global\let\chaplevelprefix = \empty + \resetallfloatnos + % + % This used to be simply \message{#1}, but TeX fully expands the + % argument to \message. Therefore, if #1 contained @-commands, TeX + % expanded them. For example, in `@unnumbered The @cite{Book}', TeX + % expanded @cite (which turns out to cause errors because \cite is meant + % to be executed, not expanded). + % + % Anyway, we don't want the fully-expanded definition of @cite to appear + % as a result of the \message, we just want `@cite' itself. We use + % \the to achieve this: TeX expands \the only once, + % simply yielding the contents of . (We also do this for + % the toc entries.) + \toks0 = {#1}% + \message{(\the\toks0)}% + % + \chapmacro{#1}{Ynothing}{\the\unnumberedno}% + % + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\parseargdef\centerchap{% + % Well, we could do the following in a group, but that would break + % an assumption that \chapmacro is called at the outermost level. + % Thus we are safer this way: --kasal, 24feb04 + \let\centerparametersmaybe = \centerparameters + \unnmhead0{#1}% + \let\centerparametersmaybe = \relax +} + +% @top is like @unnumbered. +\let\top\unnumbered + +% Sections. +\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz +\def\seczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% +} + +\outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}% +} +\let\appendixsec\appendixsection + +\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}% +} + +% Subsections. +\outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno}% +} + +\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz#1{% + \global\subsubsecno=0 \global\advance\subsecno by 1 + \sectionheading{#1}{subsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno}% +} + +% Subsubsections. +\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynumbered}% + {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Yappendix}% + {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz#1{% + \global\advance\subsubsecno by 1 + \sectionheading{#1}{subsubsec}{Ynothing}% + {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}% +} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\let\section = \numberedsec +\let\subsection = \numberedsubsec +\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + +\def\majorheading{% + {\advance\chapheadingskip by 10pt \chapbreak }% + \parsearg\chapheadingzzz +} + +\def\chapheading{\chapbreak \parsearg\chapheadingzzz} +\def\chapheadingzzz#1{% + {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\ptexraggedright + \rmisbold #1\hfill}}% + \bigskip \par\penalty 200\relax + \suppressfirstparagraphindent +} + +% @heading, @subheading, @subsubheading. +\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} +\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{} + \suppressfirstparagraphindent} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +% Because \domark is called before \chapoddpage, the filler page will +% get the headings for the next chapter, which is wrong. But we don't +% care -- we just disable all headings on the filler page. +\def\chapoddpage{% + \chappager + \ifodd\pageno \else + \begingroup + \evenheadline={\hfil}\evenfootline={\hfil}% + \oddheadline={\hfil}\oddfootline={\hfil}% + \hbox to 0pt{}% + \chappager + \endgroup + \fi +} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{% +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +% Chapter opening. +% +% #1 is the text, #2 is the section type (Ynumbered, Ynothing, +% Yappendix, Yomitfromtoc), #3 the chapter number. +% +% To test against our argument. +\def\Ynothingkeyword{Ynothing} +\def\Yomitfromtockeyword{Yomitfromtoc} +\def\Yappendixkeyword{Yappendix} +% +\def\chapmacro#1#2#3{% + % Insert the first mark before the heading break (see notes for \domark). + \let\prevchapterdefs=\lastchapterdefs + \let\prevsectiondefs=\lastsectiondefs + \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}% + \gdef\thissection{}}% + % + \def\temptype{#2}% + \ifx\temptype\Ynothingkeyword + \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% + \gdef\thischapter{\thischaptername}}% + \else\ifx\temptype\Yomitfromtockeyword + \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}% + \gdef\thischapter{}}% + \else\ifx\temptype\Yappendixkeyword + \toks0={#1}% + \xdef\lastchapterdefs{% + \gdef\noexpand\thischaptername{\the\toks0}% + \gdef\noexpand\thischapternum{\appendixletter}% + % \noexpand\putwordAppendix avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thischapter{\noexpand\putwordAppendix{} + \noexpand\thischapternum: + \noexpand\thischaptername}% + }% + \else + \toks0={#1}% + \xdef\lastchapterdefs{% + \gdef\noexpand\thischaptername{\the\toks0}% + \gdef\noexpand\thischapternum{\the\chapno}% + % \noexpand\putwordChapter avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thischapter{\noexpand\putwordChapter{} + \noexpand\thischapternum: + \noexpand\thischaptername}% + }% + \fi\fi\fi + % + % Output the mark. Pass it through \safewhatsit, to take care of + % the preceding space. + \safewhatsit\domark + % + % Insert the chapter heading break. + \pchapsepmacro + % + % Now the second mark, after the heading break. No break points + % between here and the heading. + \let\prevchapterdefs=\lastchapterdefs + \let\prevsectiondefs=\lastsectiondefs + \domark + % + {% + \chapfonts \rmisbold + % + % Have to define \lastsection before calling \donoderef, because the + % xref code eventually uses it. On the other hand, it has to be called + % after \pchapsepmacro, or the headline will change too soon. + \gdef\lastsection{#1}% + % + % Only insert the separating space if we have a chapter/appendix + % number, and don't print the unnumbered ``number''. + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unnchap}% + \else\ifx\temptype\Yomitfromtockeyword + \setbox0 = \hbox{}% contents like unnumbered, but no toc entry + \def\toctype{omit}% + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{\putwordAppendix{} #3\enspace}% + \def\toctype{app}% + \else + \setbox0 = \hbox{#3\enspace}% + \def\toctype{numchap}% + \fi\fi\fi + % + % Write the toc entry for this chapter. Must come before the + % \donoderef, because we include the current node name in the toc + % entry, and \donoderef resets it to empty. + \writetocentry{\toctype}{#1}{#3}% + % + % For pdftex, we have to write out the node definition (aka, make + % the pdfdest) after any page break, but before the actual text has + % been typeset. If the destination for the pdf outline is after the + % text, then jumping from the outline may wind up with the text not + % being visible, for instance under high magnification. + \donoderef{#2}% + % + % Typeset the actual heading. + \nobreak % Avoid page breaks at the interline glue. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright + \hangindent=\wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerparameters{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt +} + + +% I don't think this chapter style is supported any more, so I'm not +% updating it with the new noderef stuff. We'll see. --karl, 11aug03. +% +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} +% +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\ptexraggedright + \rmisbold #1\hfill}}\bigskip \par\nobreak +} +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rmisbold #1}\hfill}}\bigskip \par\nobreak +} +\def\CHAPFopen{% + \global\let\chapmacro=\chfopen + \global\let\centerchapmacro=\centerchfopen} + + +% Section titles. These macros combine the section number parts and +% call the generic \sectionheading to do the printing. +% +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip{-1000}} + +% Subsection titles. +\newskip\subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}} + +% Subsubsection titles. +\def\subsubsecheadingskip{\subsecheadingskip} +\def\subsubsecheadingbreak{\subsecheadingbreak} + + +% Print any size, any type, section title. +% +% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is +% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the +% section number. +% +\def\seckeyword{sec} +% +\def\sectionheading#1#2#3#4{% + {% + % Switch to the right set of fonts. + \csname #2fonts\endcsname \rmisbold + % + \def\sectionlevel{#2}% + \def\temptype{#3}% + % + % Insert first mark before the heading break (see notes for \domark). + \let\prevsectiondefs=\lastsectiondefs + \ifx\temptype\Ynothingkeyword + \ifx\sectionlevel\seckeyword + \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}% + \gdef\thissection{\thissectionname}}% + \fi + \else\ifx\temptype\Yomitfromtockeyword + % Don't redefine \thissection. + \else\ifx\temptype\Yappendixkeyword + \ifx\sectionlevel\seckeyword + \toks0={#1}% + \xdef\lastsectiondefs{% + \gdef\noexpand\thissectionname{\the\toks0}% + \gdef\noexpand\thissectionnum{#4}% + % \noexpand\putwordSection avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thissection{\noexpand\putwordSection{} + \noexpand\thissectionnum: + \noexpand\thissectionname}% + }% + \fi + \else + \ifx\sectionlevel\seckeyword + \toks0={#1}% + \xdef\lastsectiondefs{% + \gdef\noexpand\thissectionname{\the\toks0}% + \gdef\noexpand\thissectionnum{#4}% + % \noexpand\putwordSection avoids expanding indigestible + % commands in some of the translations. + \gdef\noexpand\thissection{\noexpand\putwordSection{} + \noexpand\thissectionnum: + \noexpand\thissectionname}% + }% + \fi + \fi\fi\fi + % + % Go into vertical mode. Usually we'll already be there, but we + % don't want the following whatsit to end up in a preceding paragraph + % if the document didn't happen to have a blank line. + \par + % + % Output the mark. Pass it through \safewhatsit, to take care of + % the preceding space. + \safewhatsit\domark + % + % Insert space above the heading. + \csname #2headingbreak\endcsname + % + % Now the second mark, after the heading break. No break points + % between here and the heading. + \let\prevsectiondefs=\lastsectiondefs + \domark + % + % Only insert the space after the number if we have a section number. + \ifx\temptype\Ynothingkeyword + \setbox0 = \hbox{}% + \def\toctype{unn}% + \gdef\lastsection{#1}% + \else\ifx\temptype\Yomitfromtockeyword + % for @headings -- no section number, don't include in toc, + % and don't redefine \lastsection. + \setbox0 = \hbox{}% + \def\toctype{omit}% + \let\sectionlevel=\empty + \else\ifx\temptype\Yappendixkeyword + \setbox0 = \hbox{#4\enspace}% + \def\toctype{app}% + \gdef\lastsection{#1}% + \else + \setbox0 = \hbox{#4\enspace}% + \def\toctype{num}% + \gdef\lastsection{#1}% + \fi\fi\fi + % + % Write the toc entry (before \donoderef). See comments in \chapmacro. + \writetocentry{\toctype\sectionlevel}{#1}{#4}% + % + % Write the node reference (= pdf destination for pdftex). + % Again, see comments in \chapmacro. + \donoderef{#3}% + % + % Interline glue will be inserted when the vbox is completed. + % That glue will be a valid breakpoint for the page, since it'll be + % preceded by a whatsit (usually from the \donoderef, or from the + % \writetocentry if there was no node). We don't want to allow that + % break, since then the whatsits could end up on page n while the + % section is on page n+1, thus toc/etc. are wrong. Debian bug 276000. + \nobreak + % + % Output the actual section heading. + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright + \hangindent=\wd0 % zero if no section number + \unhbox0 #1}% + }% + % Add extra space after the heading -- half of whatever came above it. + % Don't allow stretch, though. + \kern .5 \csname #2headingskip\endcsname + % + % Do not let the kern be a potential breakpoint, as it would be if it + % was followed by glue. + \nobreak + % + % We'll almost certainly start a paragraph next, so don't let that + % glue accumulate. (Not a breakpoint because it's preceded by a + % discardable item.) + \vskip-\parskip + % + % This is purely so the last item on the list is a known \penalty > + % 10000. This is so \startdefun can avoid allowing breakpoints after + % section headings. Otherwise, it would insert a valid breakpoint between: + % + % @section sec-whatever + % @deffn def-whatever + \penalty 10001 +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. +% +% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno} +% We append the current node name (if any) and page number as additional +% arguments for the \{chap,sec,...}entry macros which will eventually +% read this. The node name is used in the pdf outlines as the +% destination to jump to. +% +% We open the .toc file for writing here instead of at @setfilename (or +% any other fixed time) so that @contents can be anywhere in the document. +% But if #1 is `omit', then we don't do anything. This is used for the +% table of contents chapter openings themselves. +% +\newif\iftocfileopened +\def\omitkeyword{omit}% +% +\def\writetocentry#1#2#3{% + \edef\writetoctype{#1}% + \ifx\writetoctype\omitkeyword \else + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + % + \iflinks + {\atdummies + \edef\temp{% + \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}% + \temp + }% + \fi + \fi + % + % Tell \shipout to create a pdf destination on each page, if we're + % writing pdf. These are used in the table of contents. We can't + % just write one on every page because the title pages are numbered + % 1 and 2 (the page numbers aren't printed), and so are the first + % two pages of the document. Thus, we'd have two destinations named + % `1', and two named `2'. + \ifpdf \global\pdfmakepagedesttrue \fi +} + + +% These characters do not print properly in the Computer Modern roman +% fonts, so we must take special care. This is more or less redundant +% with the Texinfo input format setup at the end of this file. +% +\def\activecatcodes{% + \catcode`\"=\active + \catcode`\$=\active + \catcode`\<=\active + \catcode`\>=\active + \catcode`\\=\active + \catcode`\^=\active + \catcode`\_=\active + \catcode`\|=\active + \catcode`\~=\active +} + + +% Read the toc file, which is essentially Texinfo input. +\def\readtocfile{% + \setupdatafile + \activecatcodes + \input \tocreadfilename +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Prepare to read what we've written to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \chapmacro{#1}{Yomitfromtoc}{}% + % + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi +} + +% redefined for the two-volume lispref. We always output on +% \jobname.toc even if this is redefined. +% +\def\tocreadfilename{\jobname.toc} + +% Normal (long) toc. +% +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \tocreadfilename\space + \ifeof 1 \else + \readtocfile + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \ifeof 1 \else + \pdfmakeoutlines + \fi + \closein 1 + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\numchapentry = \shortchapentry + \let\appentry = \shortchapentry + \let\unnchapentry = \shortunnchapentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf + \let\sl=\shortcontsl \let\tt=\shortconttt + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\numsecentry##1##2##3##4{} + \let\appsecentry = \numsecentry + \let\unnsecentry = \numsecentry + \let\numsubsecentry = \numsecentry + \let\appsubsecentry = \numsecentry + \let\unnsubsecentry = \numsecentry + \let\numsubsubsecentry = \numsecentry + \let\appsubsubsecentry = \numsecentry + \let\unnsubsubsecentry = \numsecentry + \openin 1 \tocreadfilename\space + \ifeof 1 \else + \readtocfile + \fi + \closein 1 + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \global\pageno = \savepageno +} +\let\shortcontents = \summarycontents + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g., `A' for an appendix, or `3' for a chapter. +% +\def\shortchaplabel#1{% + % This space should be enough, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % But use \hss just in case. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + % + % We'd like to right-justify chapter numbers, but that looks strange + % with appendix letters. And right-justifying numbers and + % left-justifying letters looks strange when there is less than 10 + % chapters. Have to read the whole toc once to know how many chapters + % there are before deciding ... + \hbox to 1em{#1\hss}% +} + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapters, in the main contents. +\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}} +% +% Chapters, in the short toc. +% See comments in \dochapentry re vbox and related settings. +\def\shortchapentry#1#2#3#4{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}% +} + +% Appendices, in the main contents. +% Need the word Appendix, and a fixed-size box. +% +\def\appendixbox#1{% + % We use M since it's probably the widest letter. + \setbox0 = \hbox{\putwordAppendix{} M}% + \hbox to \wd0{\putwordAppendix{} #1\hss}} +% +\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}} + +% Unnumbered chapters. +\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}} +\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}} + +% Sections. +\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}} +\let\appsecentry=\numsecentry +\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}} + +% Subsections. +\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}} +\let\appsubsecentry=\numsubsecentry +\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}} + +% And subsubsections. +\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}} +\let\appsubsubsecentry=\numsubsubsecentry +\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}} + +% This parameter controls the indentation of the various levels. +% Same as \defaultparindent. +\newdimen\tocindent \tocindent = 15pt + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% We use the same \entry macro as for the index entries. +\let\tocentry = \entry + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\def\subsecentryfonts{\textfonts} +\def\subsubsecentryfonts{\textfonts} + + +\message{environments,} +% @foo ... @end foo. + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\envdef\tex{% + \setupmarkupstyle{tex}% + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie + \catcode `\%=14 + \catcode `\+=\other + \catcode `\"=\other + \catcode `\|=\other + \catcode `\<=\other + \catcode `\>=\other + \catcode`\`=\other + \catcode`\'=\other + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\/=\ptexslash + \let\*=\ptexstar + \let\t=\ptext + \expandafter \let\csname top\endcsname=\ptextop % outer + \let\frenchspacing=\plainfrenchspacing + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +} +% There is no need to define \Etex. + +% Define @lisp ... @end lisp. +% @lisp environment forms a group so it can rebind things, +% including the definition of @end lisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip. +% +\def\aboveenvbreak{{% + % =10000 instead of <10000 because of a special case in \itemzzz and + % \sectionheading, q.v. + \ifnum \lastpenalty=10000 \else + \advance\envskipamount by \parskip + \endgraf + \ifdim\lastskip<\envskipamount + \removelastskip + % it's not a good place to break if the last penalty was \nobreak + % or better ... + \ifnum\lastpenalty<10000 \penalty-50 \fi + \vskip\envskipamount + \fi + \fi +}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins; it will +% also clear it, so that its embedded environments do the narrowing again. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\envdef\cartouche{% + \ifhmode\par\fi % can't be in the midst of a paragraph. + \startsavinginserts + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt % we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either + % side, and for 6pt waste from + % each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing = t% + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \kern3pt + \hsize=\cartinner + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip + \comment % For explanation, see the end of \def\group. +} +\def\Ecartouche{% + \ifhmode\par\fi + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup + \checkinserts +} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\newdimen\nonfillparindent +\def\nonfillstart{% + \aboveenvbreak + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + % Turn off paragraph indentation but redefine \indent to emulate + % the normal \indent. + \nonfillparindent=\parindent + \parindent = 0pt + \let\indent\nonfillindent + % + \emergencystretch = 0pt % don't try to avoid overfull boxes + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \let\exdent=\nofillexdent +} + +\begingroup +\obeyspaces +% We want to swallow spaces (but not other tokens) after the fake +% @indent in our nonfill-environments, where spaces are normally +% active and set to @tie, resulting in them not being ignored after +% @indent. +\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}% +\gdef\nonfillindentcheck{% +\ifx\temp % +\expandafter\nonfillindentgobble% +\else% +\leavevmode\nonfillindentbox% +\fi% +}% +\endgroup +\def\nonfillindentgobble#1{\nonfillindent} +\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}} + +% If you want all examples etc. small: @set dispenvsize small. +% If you want even small examples the full size: @set dispenvsize nosmall. +% This affects the following displayed environments: +% @example, @display, @format, @lisp +% +\def\smallword{small} +\def\nosmallword{nosmall} +\let\SETdispenvsize\relax +\def\setnormaldispenv{% + \ifx\SETdispenvsize\smallword + % end paragraph for sake of leading, in case document has no blank + % line. This is redundant with what happens in \aboveenvbreak, but + % we need to do it before changing the fonts, and it's inconvenient + % to change the fonts afterward. + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} +\def\setsmalldispenv{% + \ifx\SETdispenvsize\nosmallword + \else + \ifnum \lastpenalty=10000 \else \endgraf \fi + \smallexamplefonts \rm + \fi +} + +% We often define two environments, @foo and @smallfoo. +% Let's do it by one command: +\def\makedispenv #1#2{ + \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2} + \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2} + \expandafter\let\csname E#1\endcsname \afterenvbreak + \expandafter\let\csname Esmall#1\endcsname \afterenvbreak +} + +% Define two synonyms: +\def\maketwodispenvs #1#2#3{ + \makedispenv{#1}{#3} + \makedispenv{#2}{#3} +} + +% @lisp: indented, narrowed, typewriter font; @example: same as @lisp. +% +% @smallexample and @smalllisp: use smaller fonts. +% Originally contributed by Pavel@xerox. +% +\maketwodispenvs {lisp}{example}{% + \nonfillstart + \tt\setupmarkupstyle{example}% + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} +% @display/@smalldisplay: same as @lisp except keep current font. +% +\makedispenv {display}{% + \nonfillstart + \gobble +} + +% @format/@smallformat: same as @display except don't narrow margins. +% +\makedispenv{format}{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} + +% @flushleft: same as @format, but doesn't obey \SETdispenvsize. +\envdef\flushleft{% + \let\nonarrowing = t% + \nonfillstart + \gobble +} +\let\Eflushleft = \afterenvbreak + +% @flushright. +% +\envdef\flushright{% + \let\nonarrowing = t% + \nonfillstart + \advance\leftskip by 0pt plus 1fill + \gobble +} +\let\Eflushright = \afterenvbreak + + +% @raggedright does more-or-less normal line breaking but no right +% justification. From plain.tex. +\envdef\raggedright{% + \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax +} +\let\Eraggedright\par + +\envdef\raggedleft{% + \parindent=0pt \leftskip0pt plus2em + \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt + \hbadness=10000 % Last line will usually be underfull, so turn off + % badness reporting. +} +\let\Eraggedleft\par + +\envdef\raggedcenter{% + \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em + \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt + \hbadness=10000 % Last line will usually be underfull, so turn off + % badness reporting. +} +\let\Eraggedcenter\par + + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. We keep \parskip nonzero in general, since +% we're doing normal filling. So, when using \aboveenvbreak and +% \afterenvbreak, temporarily make \parskip 0. +% +\def\quotationstart{% + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \parindent=0pt + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \else + \let\nonarrowing = \relax + \fi + \parsearg\quotationlabel +} + +\envdef\quotation{% + \setnormaldispenv + \quotationstart +} + +\envdef\smallquotation{% + \setsmalldispenv + \quotationstart +} +\let\Esmallquotation = \Equotation + +% We have retained a nonzero parskip for the environment, since we're +% doing normal filling. +% +\def\Equotation{% + \par + \ifx\quotationauthor\undefined\else + % indent a bit. + \leftline{\kern 2\leftskip \sl ---\quotationauthor}% + \fi + {\parskip=0pt \afterenvbreak}% +} + +% If we're given an argument, typeset it in bold with a colon after. +\def\quotationlabel#1{% + \def\temp{#1}% + \ifx\temp\empty \else + {\bf #1: }% + \fi +} + + +% LaTeX-like @verbatim...@end verbatim and @verb{...} +% If we want to allow any as delimiter, +% we need the curly braces so that makeinfo sees the @verb command, eg: +% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org +% +% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. +% +% [Knuth] p.344; only we need to do the other characters Texinfo sets +% active too. Otherwise, they get lost as the first character on a +% verbatim line. +\def\dospecials{% + \do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% + \do\<\do\>\do\|\do\@\do+\do\"% + % Don't do the quotes -- if we do, @set txicodequoteundirected and + % @set txicodequotebacktick will not have effect on @verb and + % @verbatim, and ?` and !` ligatures won't get disabled. + %\do\`\do\'% +} +% +% [Knuth] p. 380 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1=\other}\dospecials} +% +% Setup for the @verb command. +% +% Eight spaces for a tab +\begingroup + \catcode`\^^I=\active + \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} +\endgroup +% +\def\setupverb{% + \tt % easiest (and conventionally used) font for verbatim + \def\par{\leavevmode\endgraf}% + \setupmarkupstyle{verb}% + \tabeightspaces + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces +} + +% Setup for the @verbatim environment +% +% Real tab expansion +\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount +% +\def\starttabbox{\setbox0=\hbox\bgroup} +% +\begingroup + \catcode`\^^I=\active + \gdef\tabexpand{% + \catcode`\^^I=\active + \def^^I{\leavevmode\egroup + \dimen0=\wd0 % the width so far, or since the previous tab + \divide\dimen0 by\tabw + \multiply\dimen0 by\tabw % compute previous multiple of \tabw + \advance\dimen0 by\tabw % advance to next multiple of \tabw + \wd0=\dimen0 \box0 \starttabbox + }% + } +\endgroup + +% start the verbatim environment. +\def\setupverbatim{% + \let\nonarrowing = t% + \nonfillstart + % Easiest (and conventionally used) font for verbatim + \tt + \def\par{\leavevmode\egroup\box0\endgraf}% + \tabexpand + \setupmarkupstyle{verbatim}% + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces + \everypar{\starttabbox}% +} + +% Do the @verb magic: verbatim text is quoted by unique +% delimiter characters. Before first delimiter expect a +% right brace, after last delimiter expect closing brace: +% +% \def\doverb'{'#1'}'{#1} +% +% [Knuth] p. 382; only eat outer {} +\begingroup + \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other + \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] +\endgroup +% +\def\verb{\begingroup\setupverb\doverb} +% +% +% Do the @verbatim magic: define the macro \doverbatim so that +% the (first) argument ends when '@end verbatim' is reached, ie: +% +% \def\doverbatim#1@end verbatim{#1} +% +% For Texinfo it's a lot easier than for LaTeX, +% because texinfo's \verbatim doesn't stop at '\end{verbatim}': +% we need not redefine '\', '{' and '}'. +% +% Inspired by LaTeX's verbatim command set [latex.ltx] +% +\begingroup + \catcode`\ =\active + \obeylines % + % ignore everything up to the first ^^M, that's the newline at the end + % of the @verbatim input line itself. Otherwise we get an extra blank + % line in the output. + \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% + % We really want {...\end verbatim} in the body of the macro, but + % without the active space; thus we have to use \xdef and \gobble. +\endgroup +% +\envdef\verbatim{% + \setupverbatim\doverbatim +} +\let\Everbatim = \afterenvbreak + + +% @verbatiminclude FILE - insert text of file in verbatim environment. +% +\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} +% +\def\doverbatiminclude#1{% + {% + \makevalueexpandable + \setupverbatim + \indexnofonts % Allow `@@' and other weird things in file names. + \input #1 + \afterenvbreak + }% +} + +% @copying ... @end copying. +% Save the text away for @insertcopying later. +% +% We save the uninterpreted tokens, rather than creating a box. +% Saving the text in a box would be much easier, but then all the +% typesetting commands (@smallbook, font changes, etc.) have to be done +% beforehand -- and a) we want @copying to be done first in the source +% file; b) letting users define the frontmatter in as flexible order as +% possible is very desirable. +% +\def\copying{\checkenv{}\begingroup\scanargctxt\docopying} +\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}} +% +\def\insertcopying{% + \begingroup + \parindent = 0pt % paragraph indentation looks wrong on title page + \scanexp\copyingtext + \endgroup +} + + +\message{defuns,} +% @defun etc. + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deflastargmargin \deflastargmargin=18pt +\newcount\defunpenalty + +% Start the processing of @deffn: +\def\startdefun{% + \ifnum\lastpenalty<10000 + \medbreak + \defunpenalty=10003 % Will keep this @deffn together with the + % following @def command, see below. + \else + % If there are two @def commands in a row, we'll have a \nobreak, + % which is there to keep the function description together with its + % header. But if there's nothing but headers, we need to allow a + % break somewhere. Check specifically for penalty 10002, inserted + % by \printdefunline, instead of 10000, since the sectioning + % commands also insert a nobreak penalty, and we don't want to allow + % a break between a section heading and a defun. + % + % As a minor refinement, we avoid "club" headers by signalling + % with penalty of 10003 after the very first @deffn in the + % sequence (see above), and penalty of 10002 after any following + % @def command. + \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi + % + % Similarly, after a section heading, do not allow a break. + % But do insert the glue. + \medskip % preceded by discardable penalty, so not a breakpoint + \fi + % + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent +} + +\def\dodefunx#1{% + % First, check whether we are in the right environment: + \checkenv#1% + % + % As above, allow line break if we have multiple x headers in a row. + % It's not a great place, though. + \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi + % + % And now, it's time to reuse the body of the original defun: + \expandafter\gobbledefun#1% +} +\def\gobbledefun#1\startdefun{} + +% \printdefunline \deffnheader{text} +% +\def\printdefunline#1#2{% + \begingroup + % call \deffnheader: + #1#2 \endheader + % common ending: + \interlinepenalty = 10000 + \advance\rightskip by 0pt plus 1fil + \endgraf + \nobreak\vskip -\parskip + \penalty\defunpenalty % signal to \startdefun and \dodefunx + % Some of the @defun-type tags do not enable magic parentheses, + % rendering the following check redundant. But we don't optimize. + \checkparencounts + \endgroup +} + +\def\Edefun{\endgraf\medbreak} + +% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn; +% the only thing remaining is to define \deffnheader. +% +\def\makedefun#1{% + \expandafter\let\csname E#1\endcsname = \Edefun + \edef\temp{\noexpand\domakedefun + \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}% + \temp +} + +% \domakedefun \deffn \deffnx \deffnheader +% +% Define \deffn and \deffnx, without parameters. +% \deffnheader has to be defined explicitly. +% +\def\domakedefun#1#2#3{% + \envdef#1{% + \startdefun + \parseargusing\activeparens{\printdefunline#3}% + }% + \def#2{\dodefunx#1}% + \def#3% +} + +%%% Untyped functions: + +% @deffn category name args +\makedefun{deffn}{\deffngeneral{}} + +% @deffn category class name args +\makedefun{defop}#1 {\defopon{#1\ \putwordon}} + +% \defopon {category on}class name args +\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deffngeneral {subind}category name args +% +\def\deffngeneral#1#2 #3 #4\endheader{% + % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}. + \dosubind{fn}{\code{#3}}{#1}% + \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}% +} + +%%% Typed functions: + +% @deftypefn category type name args +\makedefun{deftypefn}{\deftypefngeneral{}} + +% @deftypeop category class type name args +\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}} + +% \deftypeopon {category on}class type name args +\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} } + +% \deftypefngeneral {subind}category type name args +% +\def\deftypefngeneral#1#2 #3 #4 #5\endheader{% + \dosubind{fn}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Typed variables: + +% @deftypevr category type var args +\makedefun{deftypevr}{\deftypecvgeneral{}} + +% @deftypecv category class type var args +\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}} + +% \deftypecvof {category of}class type var args +\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} } + +% \deftypecvgeneral {subind}category type var args +% +\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{% + \dosubind{vr}{\code{#4}}{#1}% + \defname{#2}{#3}{#4}\defunargs{#5\unskip}% +} + +%%% Untyped variables: + +% @defvr category var args +\makedefun{defvr}#1 {\deftypevrheader{#1} {} } + +% @defcv category class var args +\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}} + +% \defcvof {category of}class var args +\def\defcvof#1#2 {\deftypecvof{#1}#2 {} } + +%%% Type: +% @deftp category name args +\makedefun{deftp}#1 #2 #3\endheader{% + \doind{tp}{\code{#2}}% + \defname{#1}{}{#2}\defunargs{#3\unskip}% +} + +% Remaining @defun-like shortcuts: +\makedefun{defun}{\deffnheader{\putwordDeffunc} } +\makedefun{defmac}{\deffnheader{\putwordDefmac} } +\makedefun{defspec}{\deffnheader{\putwordDefspec} } +\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} } +\makedefun{defvar}{\defvrheader{\putwordDefvar} } +\makedefun{defopt}{\defvrheader{\putwordDefopt} } +\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} } +\makedefun{defmethod}{\defopon\putwordMethodon} +\makedefun{deftypemethod}{\deftypeopon\putwordMethodon} +\makedefun{defivar}{\defcvof\putwordInstanceVariableof} +\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof} + +% \defname, which formats the name of the @def (not the args). +% #1 is the category, such as "Function". +% #2 is the return type, if any. +% #3 is the function name. +% +% We are followed by (but not passed) the arguments, if any. +% +\def\defname#1#2#3{% + % Get the values of \leftskip and \rightskip as they were outside the @def... + \advance\leftskip by -\defbodyindent + % + % How we'll format the type name. Putting it in brackets helps + % distinguish it from the body text that may end up on the next line + % just below it. + \def\temp{#1}% + \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi} + % + % Figure out line sizes for the paragraph shape. + % The first line needs space for \box0; but if \rightskip is nonzero, + % we need only space for the part of \box0 which exceeds it: + \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip + % The continuations: + \dimen2=\hsize \advance\dimen2 by -\defargsindent + % (plain.tex says that \dimen1 should be used only as global.) + \parshape 2 0in \dimen0 \defargsindent \dimen2 + % + % Put the type name to the right margin. + \noindent + \hbox to 0pt{% + \hfil\box0 \kern-\hsize + % \hsize has to be shortened this way: + \kern\leftskip + % Intentionally do not respect \rightskip, since we need the space. + }% + % + % Allow all lines to be underfull without complaint: + \tolerance=10000 \hbadness=10000 + \exdentamount=\defbodyindent + {% + % defun fonts. We use typewriter by default (used to be bold) because: + % . we're printing identifiers, they should be in tt in principle. + % . in languages with many accents, such as Czech or French, it's + % common to leave accents off identifiers. The result looks ok in + % tt, but exceedingly strange in rm. + % . we don't want -- and --- to be treated as ligatures. + % . this still does not fix the ?` and !` ligatures, but so far no + % one has made identifiers using them :). + \df \tt + \def\temp{#2}% return value type + \ifx\temp\empty\else \tclose{\temp} \fi + #3% output function name + }% + {\rm\enskip}% hskip 0.5 em of \tenrm + % + \boldbrax + % arguments will be output next, if any. +} + +% Print arguments in slanted roman (not ttsl), inconsistently with using +% tt for the name. This is because literal text is sometimes needed in +% the argument list (groff manual), and ttsl and tt are not very +% distinguishable. Prevent hyphenation at `-' chars. +% +\def\defunargs#1{% + % use sl by default (not ttsl), + % tt for the names. + \df \sl \hyphenchar\font=0 + % + % On the other hand, if an argument has two dashes (for instance), we + % want a way to get ttsl. Let's try @var for that. + \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}% + #1% + \sl\hyphenchar\font=45 +} + +% We want ()&[] to print specially on the defun line. +% +\def\activeparens{% + \catcode`\(=\active \catcode`\)=\active + \catcode`\[=\active \catcode`\]=\active + \catcode`\&=\active +} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +{ + \activeparens + \global\let(=\lparen \global\let)=\rparen + \global\let[=\lbrack \global\let]=\rbrack + \global\let& = \& + + \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} + \gdef\magicamp{\let&=\amprm} +} + +\newcount\parencount + +% If we encounter &foo, then turn on ()-hacking afterwards +\newif\ifampseen +\def\amprm#1 {\ampseentrue{\bf\ }} + +\def\parenfont{% + \ifampseen + % At the first level, print parens in roman, + % otherwise use the default font. + \ifnum \parencount=1 \rm \fi + \else + % The \sf parens (in \boldbrax) actually are a little bolder than + % the contained text. This is especially needed for [ and ] . + \sf + \fi +} +\def\infirstlevel#1{% + \ifampseen + \ifnum\parencount=1 + #1% + \fi + \fi +} +\def\bfafterword#1 {#1 \bf} + +\def\opnr{% + \global\advance\parencount by 1 + {\parenfont(}% + \infirstlevel \bfafterword +} +\def\clnr{% + {\parenfont)}% + \infirstlevel \sl + \global\advance\parencount by -1 +} + +\newcount\brackcount +\def\lbrb{% + \global\advance\brackcount by 1 + {\bf[}% +} +\def\rbrb{% + {\bf]}% + \global\advance\brackcount by -1 +} + +\def\checkparencounts{% + \ifnum\parencount=0 \else \badparencount \fi + \ifnum\brackcount=0 \else \badbrackcount \fi +} +% these should not use \errmessage; the glibc manual, at least, actually +% has such constructs (when documenting function pointers). +\def\badparencount{% + \message{Warning: unbalanced parentheses in @def...}% + \global\parencount=0 +} +\def\badbrackcount{% + \message{Warning: unbalanced square brackets in @def...}% + \global\brackcount=0 +} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scantokens#1{% + \toks0={#1}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \input \jobname.tmp + } +\fi + +\def\scanmacro#1{% + \begingroup + \newlinechar`\^^M + \let\xeatspaces\eatspaces + % Undo catcode changes of \startcontents and \doprintindex + % When called from @insertcopying or (short)caption, we need active + % backslash to get it printed correctly. Previously, we had + % \catcode`\\=\other instead. We'll see whether a problem appears + % with macro expansion. --kasal, 19aug04 + \catcode`\@=0 \catcode`\\=\active \escapechar=`\@ + % ... and \example + \spaceisspace + % + % Append \endinput to make sure that TeX does not see the ending newline. + % I've verified that it is necessary both for e-TeX and for ordinary TeX + % --kasal, 29nov03 + \scantokens{#1\endinput}% + \endgroup +} + +\def\scanexp#1{% + \edef\temp{\noexpand\scanmacro{#1}}% + \temp +} + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? + +% List of all defined macros in the form +% \definedummyword\macro1\definedummyword\macro2... +% Currently is also contains all @aliases; the list can be split +% if there is a need. +\def\macrolist{} + +% Add the macro to \macrolist +\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname} +\def\addtomacrolistxxx#1{% + \toks0 = \expandafter{\macrolist\definedummyword#1}% + \xdef\macrolist{\the\toks0}% +} + +% Utility routines. +% This does \let #1 = #2, with \csnames; that is, +% \let \csname#1\endcsname = \csname#2\endcsname +% (except of course we have to play expansion games). +% +\def\cslet#1#2{% + \expandafter\let + \csname#1\expandafter\endcsname + \csname#2\endcsname +} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=\other \catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% Non-ASCII encodings make 8-bit characters active, so un-activate +% them to avoid their expansion. Must do this non-globally, to +% confine the change to the current group. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\scanctxt{% + \catcode`\"=\other + \catcode`\+=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\@=\other + \catcode`\^=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\~=\other + \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi +} + +\def\scanargctxt{% + \scanctxt + \catcode`\\=\other + \catcode`\^^M=\other +} + +\def\macrobodyctxt{% + \scanctxt + \catcode`\{=\other + \catcode`\}=\other + \catcode`\^^M=\other + \usembodybackslash +} + +\def\macroargctxt{% + \scanctxt + \catcode`\\=\other +} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{Macro name \the\macname\space already defined}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + \addtomacrolist{\the\macname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\parseargdef\unmacro{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist: + \begingroup + \expandafter\let\csname#1\endcsname \relax + \let\definedummyword\unmacrodo + \xdef\macrolist{\macrolist}% + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% Called by \do from \dounmacro on each macro. The idea is to omit any +% macro definitions that have been changed to \relax. +% +\def\unmacrodo#1{% + \ifx #1\relax + % remove this + \else + \noexpand\definedummyword \noexpand#1% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \macnamexxx} + + +% @alias. +% We need some trickery to remove the optional spaces around the equal +% sign. Just make them active and then expand them all to nothing. +\def\alias{\parseargusing\obeyspaces\aliasxxx} +\def\aliasxxx #1{\aliasyyy#1\relax} +\def\aliasyyy #1=#2\relax{% + {% + \expandafter\let\obeyedspace=\empty + \addtomacrolist{#1}% + \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}% + }% + \next +} + + +\message{cross references,} + +\newwrite\auxfile +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's only job in TeX is to define \lastnode, which is used in +% cross-references. The @node line might or might not have commas, and +% might or might not have spaces before the first comma, like: +% @node foo , bar , ... +% We don't want such trailing spaces in the node name. +% +\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse} +% +% also remove a trailing comma, in case of something like this: +% @node Help-Cross, , , Cross-refs +\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse} +\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}} + +\let\nwnode=\node +\let\lastnode=\empty + +% Write a cross-reference definition for the current node. #1 is the +% type (Ynumbered, Yappendix, Ynothing). +% +\def\donoderef#1{% + \ifx\lastnode\empty\else + \setref{\lastnode}{#1}% + \global\let\lastnode=\empty + \fi +} + +% @anchor{NAME} -- define xref target at arbitrary point. +% +\newcount\savesfregister +% +\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi} +\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi} +\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces} + +% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an +% anchor), which consists of three parts: +% 1) NAME-title - the current sectioning name taken from \lastsection, +% or the anchor name. +% 2) NAME-snt - section number and type, passed as the SNT arg, or +% empty for anchors. +% 3) NAME-pg - the page number. +% +% This is called from \donoderef, \anchor, and \dofloat. In the case of +% floats, there is an additional part, which is not written here: +% 4) NAME-lof - the text as it should appear in a @listoffloats. +% +\def\setref#1#2{% + \pdfmkdest{#1}% + \iflinks + {% + \atdummies % preserve commands, but don't expand them + \edef\writexrdef##1##2{% + \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef + ##1}{##2}}% these are parameters of \writexrdef + }% + \toks0 = \expandafter{\lastsection}% + \immediate \writexrdef{title}{\the\toks0 }% + \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc. + \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, during \shipout + }% + \fi +} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \unsepspaces + \def\printedmanual{\ignorespaces #5}% + \def\printedrefname{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual\unskip}% + \setbox0=\hbox{\printedrefname\unskip}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printedrefname{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printedrefname{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printedrefname{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printedrefname{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % Make link in pdf output. + \ifpdf + {\indexnofonts + \turnoffactive + % This expands tokens, so do it after making catcode changes, so _ + % etc. don't get their TeX definitions. + \getfilename{#4}% + % + % See comments at \activebackslashdouble. + {\activebackslashdouble \xdef\pdfxrefdest{#1}% + \backslashparens\pdfxrefdest}% + % + \leavevmode + \startlink attr{/Border [0 0 0]}% + \ifnum\filenamelength>0 + goto file{\the\filename.pdf} name{\pdfxrefdest}% + \else + goto name{\pdfmkpgn{\pdfxrefdest}}% + \fi + }% + \setcolor{\linkcolor}% + \fi + % + % Float references are printed completely differently: "Figure 1.2" + % instead of "[somenode], p.3". We distinguish them by the + % LABEL-title being set to a magic string. + {% + % Have to otherify everything special to allow the \csname to + % include an _ in the xref name, etc. + \indexnofonts + \turnoffactive + \expandafter\global\expandafter\let\expandafter\Xthisreftitle + \csname XR#1-title\endcsname + }% + \iffloat\Xthisreftitle + % If the user specified the print name (third arg) to the ref, + % print it instead of our usual "Figure 1.2". + \ifdim\wd0 = 0pt + \refx{#1-snt}{}% + \else + \printedrefname + \fi + % + % if the user also gave the printed manual name (fifth arg), append + % "in MANUALNAME". + \ifdim \wd1 > 0pt + \space \putwordin{} \cite{\printedmanual}% + \fi + \else + % node/anchor (non-float) references. + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordSection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % output the `[mynode]' via a macro so it can be overridden. + \xrefprintnodename\printedrefname + % + % But we always want a comma and a space: + ,\space + % + % output the `page 3'. + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \fi + \endlink +\endgroup} + +% This macro is called from \xrefX for the `[nodename]' part of xref +% output. It's a separate macro only so it can be changed more easily, +% since square brackets don't work well in some documents. Particularly +% one that Bob is working on :). +% +\def\xrefprintnodename#1{[#1]} + +% Things referred to by \setref. +% +\def\Ynothing{} +\def\Yomitfromtoc{} +\def\Ynumbered{% + \ifnum\secno=0 + \putwordChapter@tie \the\chapno + \else \ifnum\subsecno=0 + \putwordSection@tie \the\chapno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno + \else + \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} +\def\Yappendix{% + \ifnum\secno=0 + \putwordAppendix@tie @char\the\appendixno{}% + \else \ifnum\subsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno + \else \ifnum\subsubsecno=0 + \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno + \else + \putwordSection@tie + @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno + \fi\fi\fi +} + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. +% +\def\refx#1#2{% + {% + \indexnofonts + \otherbackslash + \expandafter\global\expandafter\let\expandafter\thisrefX + \csname XR#1\endcsname + }% + \ifx\thisrefX\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \thisrefX + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. Usually it's +% just a \def (we prepend XR to the control sequence name to avoid +% collisions). But if this is a float type, we have more work to do. +% +\def\xrdef#1#2{% + {% The node name might contain 8-bit characters, which in our current + % implementation are changed to commands like @'e. Don't let these + % mess up the control sequence name. + \indexnofonts + \turnoffactive + \xdef\safexrefname{#1}% + }% + % + \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref + % + % Was that xref control sequence that we just defined for a float? + \expandafter\iffloat\csname XR\safexrefname\endcsname + % it was a float, and we have the (safe) float type in \iffloattype. + \expandafter\let\expandafter\floatlist + \csname floatlist\iffloattype\endcsname + % + % Is this the first time we've seen this float type? + \expandafter\ifx\floatlist\relax + \toks0 = {\do}% yes, so just \do + \else + % had it before, so preserve previous elements in list. + \toks0 = \expandafter{\floatlist\do}% + \fi + % + % Remember this xref in the control sequence \floatlistFLOATTYPE, + % for later use in \listoffloats. + \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0 + {\safexrefname}}% + \fi +} + +% Read the last existing aux file, if any. No error if none exists. +% +\def\tryauxfile{% + \openin 1 \jobname.aux + \ifeof 1 \else + \readdatafile{aux}% + \global\havexrefstrue + \fi + \closein 1 +} + +\def\setupdatafile{% + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\^=\other + % + % Special characters. Should be turned off anyway, but... + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`\%=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % + % This is to support \ in node names and titles, since the \ + % characters end up in a \csname. It's easier than + % leaving it active and making its active definition an actual \ + % character. What I don't understand is why it works in the *value* + % of the xrdef. Seems like it should be a catcode12 \, and that + % should not typeset properly. But it works, so I'm moving on for + % now. --karl, 15jan04. + \catcode`\\=\other + % + % Make the characters 128-255 be printing characters. + {% + \count1=128 + \def\loop{% + \catcode\count1=\other + \advance\count1 by 1 + \ifnum \count1<256 \loop \fi + }% + }% + % + % @ is our escape character in .aux files, and we need braces. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\@=0 +} + +\def\readdatafile#1{% +\begingroup + \setupdatafile + \input\jobname.#1 +\endgroup} + + +\message{insertions,} +% including footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \let\indent=\ptexindent + \let\noindent=\ptexnoindent + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \dofootnote +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset (and anything else that uses +% \parseargline) fails inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\gdef\dofootnote{% + \insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \hsize=\pagewidth + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + \smallfonts \rm + % + % Because we use hanging indentation in footnotes, a @noindent appears + % to exdent this text, so make it be a no-op. makeinfo does not use + % hanging indentation so @noindent can still be needed within footnote + % text after an @example or the like (not that this is good style). + \let\noindent = \relax + % + % Hang the footnote text off the number. Use \everypar in case the + % footnote extends for more than one paragraph. + \everypar = {\hang}% + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +}%end \catcode `\@=11 + +% In case a @footnote appears in a vbox, save the footnote text and create +% the real \insert just after the vbox finished. Otherwise, the insertion +% would be lost. +% Similarly, if a @footnote appears inside an alignment, save the footnote +% text to a box and make the \insert when a row of the table is finished. +% And the same can be done for other insert classes. --kasal, 16nov03. + +% Replace the \insert primitive by a cheating macro. +% Deeper inside, just make sure that the saved insertions are not spilled +% out prematurely. +% +\def\startsavinginserts{% + \ifx \insert\ptexinsert + \let\insert\saveinsert + \else + \let\checkinserts\relax + \fi +} + +% This \insert replacement works for both \insert\footins{foo} and +% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}. +% +\def\saveinsert#1{% + \edef\next{\noexpand\savetobox \makeSAVEname#1}% + \afterassignment\next + % swallow the left brace + \let\temp = +} +\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}} +\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1} + +\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi} + +\def\placesaveins#1{% + \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname + {\box#1}% +} + +% eat @SAVE -- beware, all of them have catcode \other: +{ + \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials % ;-) + \gdef\gobblesave @SAVE{} +} + +% initialization: +\def\newsaveins #1{% + \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}% + \next +} +\def\newsaveinsX #1{% + \csname newbox\endcsname #1% + \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts + \checksaveins #1}% +} + +% initialize: +\let\checkinserts\empty +\newsaveins\footins +\newsaveins\margin + + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + % Do not bother showing banner with epsf.tex v2.7k (available in + % doc/epsf.tex and on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +\closein 1 +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is (ignored optional) html alt text. +% #5 is (ignored optional) extension. +% #6 is just the usual extra ignored arg for parsing this stuff. +\newif\ifimagevmode +\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup + \catcode`\^^M = 5 % in case we're inside an example + \normalturnoffactive % allow _ et al. in names + % If the image is by itself, center it. + \ifvmode + \imagevmodetrue + \nobreak\medskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \fi + % + % Leave vertical mode so that indentation from an enclosing + % environment such as @quotation is respected. On the other hand, if + % it's at the top level, we don't want the normal paragraph indentation. + \noindent + % + % Output the image. + \ifpdf + \dopdfimage{#1}{#2}{#3}% + \else + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% + \fi + % + \ifimagevmode \medskip \fi % space after the standalone image +\endgroup} + + +% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables, +% etc. We don't actually implement floating yet, we always include the +% float "here". But it seemed the best name for the future. +% +\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish} + +% There may be a space before second and/or third parameter; delete it. +\def\eatcommaspace#1, {#1,} + +% #1 is the optional FLOATTYPE, the text label for this float, typically +% "Figure", "Table", "Example", etc. Can't contain commas. If omitted, +% this float will not be numbered and cannot be referred to. +% +% #2 is the optional xref label. Also must be present for the float to +% be referable. +% +% #3 is the optional positioning argument; for now, it is ignored. It +% will somehow specify the positions allowed to float to (here, top, bottom). +% +% We keep a separate counter for each FLOATTYPE, which we reset at each +% chapter-level command. +\let\resetallfloatnos=\empty +% +\def\dofloat#1,#2,#3,#4\finish{% + \let\thiscaption=\empty + \let\thisshortcaption=\empty + % + % don't lose footnotes inside @float. + % + % BEWARE: when the floats start float, we have to issue warning whenever an + % insert appears inside a float which could possibly float. --kasal, 26may04 + % + \startsavinginserts + % + % We can't be used inside a paragraph. + \par + % + \vtop\bgroup + \def\floattype{#1}% + \def\floatlabel{#2}% + \def\floatloc{#3}% we do nothing with this yet. + % + \ifx\floattype\empty + \let\safefloattype=\empty + \else + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + \fi + % + % If label is given but no type, we handle that as the empty type. + \ifx\floatlabel\empty \else + % We want each FLOATTYPE to be numbered separately (Figure 1, + % Table 1, Figure 2, ...). (And if no label, no number.) + % + \expandafter\getfloatno\csname\safefloattype floatno\endcsname + \global\advance\floatno by 1 + % + {% + % This magic value for \lastsection is output by \setref as the + % XREFLABEL-title value. \xrefX uses it to distinguish float + % labels (which have a completely different output format) from + % node and anchor labels. And \xrdef uses it to construct the + % lists of floats. + % + \edef\lastsection{\floatmagic=\safefloattype}% + \setref{\floatlabel}{Yfloat}% + }% + \fi + % + % start with \parskip glue, I guess. + \vskip\parskip + % + % Don't suppress indentation if a float happens to start a section. + \restorefirstparagraphindent +} + +% we have these possibilities: +% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap +% @float Foo,lbl & no caption: Foo 1.1 +% @float Foo & @caption{Cap}: Foo: Cap +% @float Foo & no caption: Foo +% @float ,lbl & Caption{Cap}: 1.1: Cap +% @float ,lbl & no caption: 1.1 +% @float & @caption{Cap}: Cap +% @float & no caption: +% +\def\Efloat{% + \let\floatident = \empty + % + % In all cases, if we have a float type, it comes first. + \ifx\floattype\empty \else \def\floatident{\floattype}\fi + % + % If we have an xref label, the number comes next. + \ifx\floatlabel\empty \else + \ifx\floattype\empty \else % if also had float type, need tie first. + \appendtomacro\floatident{\tie}% + \fi + % the number. + \appendtomacro\floatident{\chaplevelprefix\the\floatno}% + \fi + % + % Start the printed caption with what we've constructed in + % \floatident, but keep it separate; we need \floatident again. + \let\captionline = \floatident + % + \ifx\thiscaption\empty \else + \ifx\floatident\empty \else + \appendtomacro\captionline{: }% had ident, so need a colon between + \fi + % + % caption text. + \appendtomacro\captionline{\scanexp\thiscaption}% + \fi + % + % If we have anything to print, print it, with space before. + % Eventually this needs to become an \insert. + \ifx\captionline\empty \else + \vskip.5\parskip + \captionline + % + % Space below caption. + \vskip\parskip + \fi + % + % If have an xref label, write the list of floats info. Do this + % after the caption, to avoid chance of it being a breakpoint. + \ifx\floatlabel\empty \else + % Write the text that goes in the lof to the aux file as + % \floatlabel-lof. Besides \floatident, we include the short + % caption if specified, else the full caption if specified, else nothing. + {% + \atdummies + % + % since we read the caption text in the macro world, where ^^M + % is turned into a normal character, we have to scan it back, so + % we don't write the literal three characters "^^M" into the aux file. + \scanexp{% + \xdef\noexpand\gtemp{% + \ifx\thisshortcaption\empty + \thiscaption + \else + \thisshortcaption + \fi + }% + }% + \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident + \ifx\gtemp\empty \else : \gtemp \fi}}% + }% + \fi + \egroup % end of \vtop + % + % place the captured inserts + % + % BEWARE: when the floats start floating, we have to issue warning + % whenever an insert appears inside a float which could possibly + % float. --kasal, 26may04 + % + \checkinserts +} + +% Append the tokens #2 to the definition of macro #1, not expanding either. +% +\def\appendtomacro#1#2{% + \expandafter\def\expandafter#1\expandafter{#1#2}% +} + +% @caption, @shortcaption +% +\def\caption{\docaption\thiscaption} +\def\shortcaption{\docaption\thisshortcaption} +\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption} +\def\defcaption#1#2{\egroup \def#1{#2}} + +% The parameter is the control sequence identifying the counter we are +% going to use. Create it if it doesn't exist and assign it to \floatno. +\def\getfloatno#1{% + \ifx#1\relax + % Haven't seen this figure type before. + \csname newcount\endcsname #1% + % + % Remember to reset this floatno at the next chap. + \expandafter\gdef\expandafter\resetallfloatnos + \expandafter{\resetallfloatnos #1=0 }% + \fi + \let\floatno#1% +} + +% \setref calls this to get the XREFLABEL-snt value. We want an @xref +% to the FLOATLABEL to expand to "Figure 3.1". We call \setref when we +% first read the @float command. +% +\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}% + +% Magic string used for the XREFLABEL-title value, so \xrefX can +% distinguish floats from other xref types. +\def\floatmagic{!!float!!} + +% #1 is the control sequence we are passed; we expand into a conditional +% which is true if #1 represents a float ref. That is, the magic +% \lastsection value which we \setref above. +% +\def\iffloat#1{\expandafter\doiffloat#1==\finish} +% +% #1 is (maybe) the \floatmagic string. If so, #2 will be the +% (safe) float type for this float. We set \iffloattype to #2. +% +\def\doiffloat#1=#2=#3\finish{% + \def\temp{#1}% + \def\iffloattype{#2}% + \ifx\temp\floatmagic +} + +% @listoffloats FLOATTYPE - print a list of floats like a table of contents. +% +\parseargdef\listoffloats{% + \def\floattype{#1}% floattype + {% + % the floattype might have accents or other special characters, + % but we need to use it in a control sequence name. + \indexnofonts + \turnoffactive + \xdef\safefloattype{\floattype}% + }% + % + % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE. + \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax + \ifhavexrefs + % if the user said @listoffloats foo but never @float foo. + \message{\linenumber No `\safefloattype' floats to list.}% + \fi + \else + \begingroup + \leftskip=\tocindent % indent these entries like a toc + \let\do=\listoffloatsdo + \csname floatlist\safefloattype\endcsname + \endgroup + \fi +} + +% This is called on each entry in a list of floats. We're passed the +% xref label, in the form LABEL-title, which is how we save it in the +% aux file. We strip off the -title and look up \XRLABEL-lof, which +% has the text we're supposed to typeset here. +% +% Figures without xref labels will not be included in the list (since +% they won't appear in the aux file). +% +\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish} +\def\listoffloatsdoentry#1-title\finish{{% + % Can't fully expand XR#1-lof because it can contain anything. Just + % pass the control sequence. On the other hand, XR#1-pg is just the + % page number, and we want to fully expand that so we can get a link + % in pdf output. + \toksA = \expandafter{\csname XR#1-lof\endcsname}% + % + % use the same \entry macro we use to generate the TOC and index. + \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}% + \writeentry +}} + + +\message{localization,} + +% For single-language documents, @documentlanguage is usually given very +% early, just after @documentencoding. Single argument is the language +% (de) or locale (de_DE) abbreviation. +% +{ + \catcode`\_ = \active + \globaldefs=1 +\parseargdef\documentlanguage{\begingroup + \let_=\normalunderscore % normal _ character for filenames + \tex % read txi-??.tex file in plain TeX. + % Read the file by the name they passed if it exists. + \openin 1 txi-#1.tex + \ifeof 1 + \documentlanguagetrywithoutunderscore{#1_\finish}% + \else + \globaldefs = 1 % everything in the txi-LL files needs to persist + \input txi-#1.tex + \fi + \closein 1 + \endgroup % end raw TeX +\endgroup} +% +% If they passed de_DE, and txi-de_DE.tex doesn't exist, +% try txi-de.tex. +% +\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{% + \openin 1 txi-#1.tex + \ifeof 1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \else + \globaldefs = 1 % everything in the txi-LL files needs to persist + \input txi-#1.tex + \fi + \closein 1 +} +}% end of special _ catcode +% +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? Putting it in the current +directory should work if nowhere else does.} + +% This macro is called from txi-??.tex files; the first argument is the +% \language name to set (without the "\lang@" prefix), the second and +% third args are \{left,right}hyphenmin. +% +% The language names to pass are determined when the format is built. +% See the etex.log file created at that time, e.g., +% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log. +% +% With TeX Live 2008, etex now includes hyphenation patterns for all +% available languages. This means we can support hyphenation in +% Texinfo, at least to some extent. (This still doesn't solve the +% accented characters problem.) +% +\catcode`@=11 +\def\txisetlanguage#1#2#3{% + % do not set the language if the name is undefined in the current TeX. + \expandafter\ifx\csname lang@#1\endcsname \relax + \message{no patterns for #1}% + \else + \global\language = \csname lang@#1\endcsname + \fi + % but there is no harm in adjusting the hyphenmin values regardless. + \global\lefthyphenmin = #2\relax + \global\righthyphenmin = #3\relax +} + +% Helpers for encodings. +% Set the catcode of characters 128 through 255 to the specified number. +% +\def\setnonasciicharscatcode#1{% + \count255=128 + \loop\ifnum\count255<256 + \global\catcode\count255=#1\relax + \advance\count255 by 1 + \repeat +} + +\def\setnonasciicharscatcodenonglobal#1{% + \count255=128 + \loop\ifnum\count255<256 + \catcode\count255=#1\relax + \advance\count255 by 1 + \repeat +} + +% @documentencoding sets the definition of non-ASCII characters +% according to the specified encoding. +% +\parseargdef\documentencoding{% + % Encoding being declared for the document. + \def\declaredencoding{\csname #1.enc\endcsname}% + % + % Supported encodings: names converted to tokens in order to be able + % to compare them with \ifx. + \def\ascii{\csname US-ASCII.enc\endcsname}% + \def\latnine{\csname ISO-8859-15.enc\endcsname}% + \def\latone{\csname ISO-8859-1.enc\endcsname}% + \def\lattwo{\csname ISO-8859-2.enc\endcsname}% + \def\utfeight{\csname UTF-8.enc\endcsname}% + % + \ifx \declaredencoding \ascii + \asciichardefs + % + \else \ifx \declaredencoding \lattwo + \setnonasciicharscatcode\active + \lattwochardefs + % + \else \ifx \declaredencoding \latone + \setnonasciicharscatcode\active + \latonechardefs + % + \else \ifx \declaredencoding \latnine + \setnonasciicharscatcode\active + \latninechardefs + % + \else \ifx \declaredencoding \utfeight + \setnonasciicharscatcode\active + \utfeightchardefs + % + \else + \message{Unknown document encoding #1, ignoring.}% + % + \fi % utfeight + \fi % latnine + \fi % latone + \fi % lattwo + \fi % ascii +} + +% A message to be logged when using a character that isn't available +% the default font encoding (OT1). +% +\def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}} + +% Take account of \c (plain) vs. \, (Texinfo) difference. +\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi} + +% First, make active non-ASCII characters in order for them to be +% correctly categorized when TeX reads the replacement text of +% macros containing the character definitions. +\setnonasciicharscatcode\active +% +% Latin1 (ISO-8859-1) character definitions. +\def\latonechardefs{% + \gdef^^a0{~} + \gdef^^a1{\exclamdown} + \gdef^^a2{\missingcharmsg{CENT SIGN}} + \gdef^^a3{{\pounds}} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\missingcharmsg{YEN SIGN}} + \gdef^^a6{\missingcharmsg{BROKEN BAR}} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\copyright} + \gdef^^aa{\ordf} + \gdef^^ab{\guillemetleft} + \gdef^^ac{$\lnot$} + \gdef^^ad{\-} + \gdef^^ae{\registeredsymbol} + \gdef^^af{\={}} + % + \gdef^^b0{\textdegree} + \gdef^^b1{$\pm$} + \gdef^^b2{$^2$} + \gdef^^b3{$^3$} + \gdef^^b4{\'{}} + \gdef^^b5{$\mu$} + \gdef^^b6{\P} + % + \gdef^^b7{$^.$} + \gdef^^b8{\cedilla\ } + \gdef^^b9{$^1$} + \gdef^^ba{\ordm} + % + \gdef^^bb{\guilletright} + \gdef^^bc{$1\over4$} + \gdef^^bd{$1\over2$} + \gdef^^be{$3\over4$} + \gdef^^bf{\questiondown} + % + \gdef^^c0{\`A} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\~A} + \gdef^^c4{\"A} + \gdef^^c5{\ringaccent A} + \gdef^^c6{\AE} + \gdef^^c7{\cedilla C} + \gdef^^c8{\`E} + \gdef^^c9{\'E} + \gdef^^ca{\^E} + \gdef^^cb{\"E} + \gdef^^cc{\`I} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\"I} + % + \gdef^^d0{\DH} + \gdef^^d1{\~N} + \gdef^^d2{\`O} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\~O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\O} + \gdef^^d9{\`U} + \gdef^^da{\'U} + \gdef^^db{\^U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\TH} + \gdef^^df{\ss} + % + \gdef^^e0{\`a} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\~a} + \gdef^^e4{\"a} + \gdef^^e5{\ringaccent a} + \gdef^^e6{\ae} + \gdef^^e7{\cedilla c} + \gdef^^e8{\`e} + \gdef^^e9{\'e} + \gdef^^ea{\^e} + \gdef^^eb{\"e} + \gdef^^ec{\`{\dotless i}} + \gdef^^ed{\'{\dotless i}} + \gdef^^ee{\^{\dotless i}} + \gdef^^ef{\"{\dotless i}} + % + \gdef^^f0{\dh} + \gdef^^f1{\~n} + \gdef^^f2{\`o} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\~o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\o} + \gdef^^f9{\`u} + \gdef^^fa{\'u} + \gdef^^fb{\^u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\th} + \gdef^^ff{\"y} +} + +% Latin9 (ISO-8859-15) encoding character definitions. +\def\latninechardefs{% + % Encoding is almost identical to Latin1. + \latonechardefs + % + \gdef^^a4{\euro} + \gdef^^a6{\v S} + \gdef^^a8{\v s} + \gdef^^b4{\v Z} + \gdef^^b8{\v z} + \gdef^^bc{\OE} + \gdef^^bd{\oe} + \gdef^^be{\"Y} +} + +% Latin2 (ISO-8859-2) character definitions. +\def\lattwochardefs{% + \gdef^^a0{~} + \gdef^^a1{\ogonek{A}} + \gdef^^a2{\u{}} + \gdef^^a3{\L} + \gdef^^a4{\missingcharmsg{CURRENCY SIGN}} + \gdef^^a5{\v L} + \gdef^^a6{\'S} + \gdef^^a7{\S} + \gdef^^a8{\"{}} + \gdef^^a9{\v S} + \gdef^^aa{\cedilla S} + \gdef^^ab{\v T} + \gdef^^ac{\'Z} + \gdef^^ad{\-} + \gdef^^ae{\v Z} + \gdef^^af{\dotaccent Z} + % + \gdef^^b0{\textdegree} + \gdef^^b1{\ogonek{a}} + \gdef^^b2{\ogonek{ }} + \gdef^^b3{\l} + \gdef^^b4{\'{}} + \gdef^^b5{\v l} + \gdef^^b6{\'s} + \gdef^^b7{\v{}} + \gdef^^b8{\cedilla\ } + \gdef^^b9{\v s} + \gdef^^ba{\cedilla s} + \gdef^^bb{\v t} + \gdef^^bc{\'z} + \gdef^^bd{\H{}} + \gdef^^be{\v z} + \gdef^^bf{\dotaccent z} + % + \gdef^^c0{\'R} + \gdef^^c1{\'A} + \gdef^^c2{\^A} + \gdef^^c3{\u A} + \gdef^^c4{\"A} + \gdef^^c5{\'L} + \gdef^^c6{\'C} + \gdef^^c7{\cedilla C} + \gdef^^c8{\v C} + \gdef^^c9{\'E} + \gdef^^ca{\ogonek{E}} + \gdef^^cb{\"E} + \gdef^^cc{\v E} + \gdef^^cd{\'I} + \gdef^^ce{\^I} + \gdef^^cf{\v D} + % + \gdef^^d0{\DH} + \gdef^^d1{\'N} + \gdef^^d2{\v N} + \gdef^^d3{\'O} + \gdef^^d4{\^O} + \gdef^^d5{\H O} + \gdef^^d6{\"O} + \gdef^^d7{$\times$} + \gdef^^d8{\v R} + \gdef^^d9{\ringaccent U} + \gdef^^da{\'U} + \gdef^^db{\H U} + \gdef^^dc{\"U} + \gdef^^dd{\'Y} + \gdef^^de{\cedilla T} + \gdef^^df{\ss} + % + \gdef^^e0{\'r} + \gdef^^e1{\'a} + \gdef^^e2{\^a} + \gdef^^e3{\u a} + \gdef^^e4{\"a} + \gdef^^e5{\'l} + \gdef^^e6{\'c} + \gdef^^e7{\cedilla c} + \gdef^^e8{\v c} + \gdef^^e9{\'e} + \gdef^^ea{\ogonek{e}} + \gdef^^eb{\"e} + \gdef^^ec{\v e} + \gdef^^ed{\'\i} + \gdef^^ee{\^\i} + \gdef^^ef{\v d} + % + \gdef^^f0{\dh} + \gdef^^f1{\'n} + \gdef^^f2{\v n} + \gdef^^f3{\'o} + \gdef^^f4{\^o} + \gdef^^f5{\H o} + \gdef^^f6{\"o} + \gdef^^f7{$\div$} + \gdef^^f8{\v r} + \gdef^^f9{\ringaccent u} + \gdef^^fa{\'u} + \gdef^^fb{\H u} + \gdef^^fc{\"u} + \gdef^^fd{\'y} + \gdef^^fe{\cedilla t} + \gdef^^ff{\dotaccent{}} +} + +% UTF-8 character definitions. +% +% This code to support UTF-8 is based on LaTeX's utf8.def, with some +% changes for Texinfo conventions. It is included here under the GPL by +% permission from Frank Mittelbach and the LaTeX team. +% +\newcount\countUTFx +\newcount\countUTFy +\newcount\countUTFz + +\gdef\UTFviiiTwoOctets#1#2{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\endcsname} +% +\gdef\UTFviiiThreeOctets#1#2#3{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname} +% +\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter + \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname} + +\gdef\UTFviiiDefined#1{% + \ifx #1\relax + \message{\linenumber Unicode char \string #1 not defined for Texinfo}% + \else + \expandafter #1% + \fi +} + +\begingroup + \catcode`\~13 + \catcode`\"12 + + \def\UTFviiiLoop{% + \global\catcode\countUTFx\active + \uccode`\~\countUTFx + \uppercase\expandafter{\UTFviiiTmp}% + \advance\countUTFx by 1 + \ifnum\countUTFx < \countUTFy + \expandafter\UTFviiiLoop + \fi} + + \countUTFx = "C2 + \countUTFy = "E0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiTwoOctets\string~}} + \UTFviiiLoop + + \countUTFx = "E0 + \countUTFy = "F0 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiThreeOctets\string~}} + \UTFviiiLoop + + \countUTFx = "F0 + \countUTFy = "F4 + \def\UTFviiiTmp{% + \xdef~{\noexpand\UTFviiiFourOctets\string~}} + \UTFviiiLoop +\endgroup + +\begingroup + \catcode`\"=12 + \catcode`\<=12 + \catcode`\.=12 + \catcode`\,=12 + \catcode`\;=12 + \catcode`\!=12 + \catcode`\~=13 + + \gdef\DeclareUnicodeCharacter#1#2{% + \countUTFz = "#1\relax + \wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}% + \begingroup + \parseXMLCharref + \def\UTFviiiTwoOctets##1##2{% + \csname u8:##1\string ##2\endcsname}% + \def\UTFviiiThreeOctets##1##2##3{% + \csname u8:##1\string ##2\string ##3\endcsname}% + \def\UTFviiiFourOctets##1##2##3##4{% + \csname u8:##1\string ##2\string ##3\string ##4\endcsname}% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter + \gdef\UTFviiiTmp{#2}% + \endgroup} + + \gdef\parseXMLCharref{% + \ifnum\countUTFz < "A0\relax + \errhelp = \EMsimple + \errmessage{Cannot define Unicode char value < 00A0}% + \else\ifnum\countUTFz < "800\relax + \parseUTFviiiA,% + \parseUTFviiiB C\UTFviiiTwoOctets.,% + \else\ifnum\countUTFz < "10000\relax + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiB E\UTFviiiThreeOctets.{,;}% + \else + \parseUTFviiiA;% + \parseUTFviiiA,% + \parseUTFviiiA!% + \parseUTFviiiB F\UTFviiiFourOctets.{!,;}% + \fi\fi\fi + } + + \gdef\parseUTFviiiA#1{% + \countUTFx = \countUTFz + \divide\countUTFz by 64 + \countUTFy = \countUTFz + \multiply\countUTFz by 64 + \advance\countUTFx by -\countUTFz + \advance\countUTFx by 128 + \uccode `#1\countUTFx + \countUTFz = \countUTFy} + + \gdef\parseUTFviiiB#1#2#3#4{% + \advance\countUTFz by "#10\relax + \uccode `#3\countUTFz + \uppercase{\gdef\UTFviiiTmp{#2#3#4}}} +\endgroup + +\def\utfeightchardefs{% + \DeclareUnicodeCharacter{00A0}{\tie} + \DeclareUnicodeCharacter{00A1}{\exclamdown} + \DeclareUnicodeCharacter{00A3}{\pounds} + \DeclareUnicodeCharacter{00A8}{\"{ }} + \DeclareUnicodeCharacter{00A9}{\copyright} + \DeclareUnicodeCharacter{00AA}{\ordf} + \DeclareUnicodeCharacter{00AB}{\guillemetleft} + \DeclareUnicodeCharacter{00AD}{\-} + \DeclareUnicodeCharacter{00AE}{\registeredsymbol} + \DeclareUnicodeCharacter{00AF}{\={ }} + + \DeclareUnicodeCharacter{00B0}{\ringaccent{ }} + \DeclareUnicodeCharacter{00B4}{\'{ }} + \DeclareUnicodeCharacter{00B8}{\cedilla{ }} + \DeclareUnicodeCharacter{00BA}{\ordm} + \DeclareUnicodeCharacter{00BB}{\guillemetright} + \DeclareUnicodeCharacter{00BF}{\questiondown} + + \DeclareUnicodeCharacter{00C0}{\`A} + \DeclareUnicodeCharacter{00C1}{\'A} + \DeclareUnicodeCharacter{00C2}{\^A} + \DeclareUnicodeCharacter{00C3}{\~A} + \DeclareUnicodeCharacter{00C4}{\"A} + \DeclareUnicodeCharacter{00C5}{\AA} + \DeclareUnicodeCharacter{00C6}{\AE} + \DeclareUnicodeCharacter{00C7}{\cedilla{C}} + \DeclareUnicodeCharacter{00C8}{\`E} + \DeclareUnicodeCharacter{00C9}{\'E} + \DeclareUnicodeCharacter{00CA}{\^E} + \DeclareUnicodeCharacter{00CB}{\"E} + \DeclareUnicodeCharacter{00CC}{\`I} + \DeclareUnicodeCharacter{00CD}{\'I} + \DeclareUnicodeCharacter{00CE}{\^I} + \DeclareUnicodeCharacter{00CF}{\"I} + + \DeclareUnicodeCharacter{00D0}{\DH} + \DeclareUnicodeCharacter{00D1}{\~N} + \DeclareUnicodeCharacter{00D2}{\`O} + \DeclareUnicodeCharacter{00D3}{\'O} + \DeclareUnicodeCharacter{00D4}{\^O} + \DeclareUnicodeCharacter{00D5}{\~O} + \DeclareUnicodeCharacter{00D6}{\"O} + \DeclareUnicodeCharacter{00D8}{\O} + \DeclareUnicodeCharacter{00D9}{\`U} + \DeclareUnicodeCharacter{00DA}{\'U} + \DeclareUnicodeCharacter{00DB}{\^U} + \DeclareUnicodeCharacter{00DC}{\"U} + \DeclareUnicodeCharacter{00DD}{\'Y} + \DeclareUnicodeCharacter{00DE}{\TH} + \DeclareUnicodeCharacter{00DF}{\ss} + + \DeclareUnicodeCharacter{00E0}{\`a} + \DeclareUnicodeCharacter{00E1}{\'a} + \DeclareUnicodeCharacter{00E2}{\^a} + \DeclareUnicodeCharacter{00E3}{\~a} + \DeclareUnicodeCharacter{00E4}{\"a} + \DeclareUnicodeCharacter{00E5}{\aa} + \DeclareUnicodeCharacter{00E6}{\ae} + \DeclareUnicodeCharacter{00E7}{\cedilla{c}} + \DeclareUnicodeCharacter{00E8}{\`e} + \DeclareUnicodeCharacter{00E9}{\'e} + \DeclareUnicodeCharacter{00EA}{\^e} + \DeclareUnicodeCharacter{00EB}{\"e} + \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}} + \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}} + \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}} + \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}} + + \DeclareUnicodeCharacter{00F0}{\dh} + \DeclareUnicodeCharacter{00F1}{\~n} + \DeclareUnicodeCharacter{00F2}{\`o} + \DeclareUnicodeCharacter{00F3}{\'o} + \DeclareUnicodeCharacter{00F4}{\^o} + \DeclareUnicodeCharacter{00F5}{\~o} + \DeclareUnicodeCharacter{00F6}{\"o} + \DeclareUnicodeCharacter{00F8}{\o} + \DeclareUnicodeCharacter{00F9}{\`u} + \DeclareUnicodeCharacter{00FA}{\'u} + \DeclareUnicodeCharacter{00FB}{\^u} + \DeclareUnicodeCharacter{00FC}{\"u} + \DeclareUnicodeCharacter{00FD}{\'y} + \DeclareUnicodeCharacter{00FE}{\th} + \DeclareUnicodeCharacter{00FF}{\"y} + + \DeclareUnicodeCharacter{0100}{\=A} + \DeclareUnicodeCharacter{0101}{\=a} + \DeclareUnicodeCharacter{0102}{\u{A}} + \DeclareUnicodeCharacter{0103}{\u{a}} + \DeclareUnicodeCharacter{0104}{\ogonek{A}} + \DeclareUnicodeCharacter{0105}{\ogonek{a}} + \DeclareUnicodeCharacter{0106}{\'C} + \DeclareUnicodeCharacter{0107}{\'c} + \DeclareUnicodeCharacter{0108}{\^C} + \DeclareUnicodeCharacter{0109}{\^c} + \DeclareUnicodeCharacter{0118}{\ogonek{E}} + \DeclareUnicodeCharacter{0119}{\ogonek{e}} + \DeclareUnicodeCharacter{010A}{\dotaccent{C}} + \DeclareUnicodeCharacter{010B}{\dotaccent{c}} + \DeclareUnicodeCharacter{010C}{\v{C}} + \DeclareUnicodeCharacter{010D}{\v{c}} + \DeclareUnicodeCharacter{010E}{\v{D}} + + \DeclareUnicodeCharacter{0112}{\=E} + \DeclareUnicodeCharacter{0113}{\=e} + \DeclareUnicodeCharacter{0114}{\u{E}} + \DeclareUnicodeCharacter{0115}{\u{e}} + \DeclareUnicodeCharacter{0116}{\dotaccent{E}} + \DeclareUnicodeCharacter{0117}{\dotaccent{e}} + \DeclareUnicodeCharacter{011A}{\v{E}} + \DeclareUnicodeCharacter{011B}{\v{e}} + \DeclareUnicodeCharacter{011C}{\^G} + \DeclareUnicodeCharacter{011D}{\^g} + \DeclareUnicodeCharacter{011E}{\u{G}} + \DeclareUnicodeCharacter{011F}{\u{g}} + + \DeclareUnicodeCharacter{0120}{\dotaccent{G}} + \DeclareUnicodeCharacter{0121}{\dotaccent{g}} + \DeclareUnicodeCharacter{0124}{\^H} + \DeclareUnicodeCharacter{0125}{\^h} + \DeclareUnicodeCharacter{0128}{\~I} + \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}} + \DeclareUnicodeCharacter{012A}{\=I} + \DeclareUnicodeCharacter{012B}{\={\dotless{i}}} + \DeclareUnicodeCharacter{012C}{\u{I}} + \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}} + + \DeclareUnicodeCharacter{0130}{\dotaccent{I}} + \DeclareUnicodeCharacter{0131}{\dotless{i}} + \DeclareUnicodeCharacter{0132}{IJ} + \DeclareUnicodeCharacter{0133}{ij} + \DeclareUnicodeCharacter{0134}{\^J} + \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}} + \DeclareUnicodeCharacter{0139}{\'L} + \DeclareUnicodeCharacter{013A}{\'l} + + \DeclareUnicodeCharacter{0141}{\L} + \DeclareUnicodeCharacter{0142}{\l} + \DeclareUnicodeCharacter{0143}{\'N} + \DeclareUnicodeCharacter{0144}{\'n} + \DeclareUnicodeCharacter{0147}{\v{N}} + \DeclareUnicodeCharacter{0148}{\v{n}} + \DeclareUnicodeCharacter{014C}{\=O} + \DeclareUnicodeCharacter{014D}{\=o} + \DeclareUnicodeCharacter{014E}{\u{O}} + \DeclareUnicodeCharacter{014F}{\u{o}} + + \DeclareUnicodeCharacter{0150}{\H{O}} + \DeclareUnicodeCharacter{0151}{\H{o}} + \DeclareUnicodeCharacter{0152}{\OE} + \DeclareUnicodeCharacter{0153}{\oe} + \DeclareUnicodeCharacter{0154}{\'R} + \DeclareUnicodeCharacter{0155}{\'r} + \DeclareUnicodeCharacter{0158}{\v{R}} + \DeclareUnicodeCharacter{0159}{\v{r}} + \DeclareUnicodeCharacter{015A}{\'S} + \DeclareUnicodeCharacter{015B}{\'s} + \DeclareUnicodeCharacter{015C}{\^S} + \DeclareUnicodeCharacter{015D}{\^s} + \DeclareUnicodeCharacter{015E}{\cedilla{S}} + \DeclareUnicodeCharacter{015F}{\cedilla{s}} + + \DeclareUnicodeCharacter{0160}{\v{S}} + \DeclareUnicodeCharacter{0161}{\v{s}} + \DeclareUnicodeCharacter{0162}{\cedilla{t}} + \DeclareUnicodeCharacter{0163}{\cedilla{T}} + \DeclareUnicodeCharacter{0164}{\v{T}} + + \DeclareUnicodeCharacter{0168}{\~U} + \DeclareUnicodeCharacter{0169}{\~u} + \DeclareUnicodeCharacter{016A}{\=U} + \DeclareUnicodeCharacter{016B}{\=u} + \DeclareUnicodeCharacter{016C}{\u{U}} + \DeclareUnicodeCharacter{016D}{\u{u}} + \DeclareUnicodeCharacter{016E}{\ringaccent{U}} + \DeclareUnicodeCharacter{016F}{\ringaccent{u}} + + \DeclareUnicodeCharacter{0170}{\H{U}} + \DeclareUnicodeCharacter{0171}{\H{u}} + \DeclareUnicodeCharacter{0174}{\^W} + \DeclareUnicodeCharacter{0175}{\^w} + \DeclareUnicodeCharacter{0176}{\^Y} + \DeclareUnicodeCharacter{0177}{\^y} + \DeclareUnicodeCharacter{0178}{\"Y} + \DeclareUnicodeCharacter{0179}{\'Z} + \DeclareUnicodeCharacter{017A}{\'z} + \DeclareUnicodeCharacter{017B}{\dotaccent{Z}} + \DeclareUnicodeCharacter{017C}{\dotaccent{z}} + \DeclareUnicodeCharacter{017D}{\v{Z}} + \DeclareUnicodeCharacter{017E}{\v{z}} + + \DeclareUnicodeCharacter{01C4}{D\v{Z}} + \DeclareUnicodeCharacter{01C5}{D\v{z}} + \DeclareUnicodeCharacter{01C6}{d\v{z}} + \DeclareUnicodeCharacter{01C7}{LJ} + \DeclareUnicodeCharacter{01C8}{Lj} + \DeclareUnicodeCharacter{01C9}{lj} + \DeclareUnicodeCharacter{01CA}{NJ} + \DeclareUnicodeCharacter{01CB}{Nj} + \DeclareUnicodeCharacter{01CC}{nj} + \DeclareUnicodeCharacter{01CD}{\v{A}} + \DeclareUnicodeCharacter{01CE}{\v{a}} + \DeclareUnicodeCharacter{01CF}{\v{I}} + + \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}} + \DeclareUnicodeCharacter{01D1}{\v{O}} + \DeclareUnicodeCharacter{01D2}{\v{o}} + \DeclareUnicodeCharacter{01D3}{\v{U}} + \DeclareUnicodeCharacter{01D4}{\v{u}} + + \DeclareUnicodeCharacter{01E2}{\={\AE}} + \DeclareUnicodeCharacter{01E3}{\={\ae}} + \DeclareUnicodeCharacter{01E6}{\v{G}} + \DeclareUnicodeCharacter{01E7}{\v{g}} + \DeclareUnicodeCharacter{01E8}{\v{K}} + \DeclareUnicodeCharacter{01E9}{\v{k}} + + \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}} + \DeclareUnicodeCharacter{01F1}{DZ} + \DeclareUnicodeCharacter{01F2}{Dz} + \DeclareUnicodeCharacter{01F3}{dz} + \DeclareUnicodeCharacter{01F4}{\'G} + \DeclareUnicodeCharacter{01F5}{\'g} + \DeclareUnicodeCharacter{01F8}{\`N} + \DeclareUnicodeCharacter{01F9}{\`n} + \DeclareUnicodeCharacter{01FC}{\'{\AE}} + \DeclareUnicodeCharacter{01FD}{\'{\ae}} + \DeclareUnicodeCharacter{01FE}{\'{\O}} + \DeclareUnicodeCharacter{01FF}{\'{\o}} + + \DeclareUnicodeCharacter{021E}{\v{H}} + \DeclareUnicodeCharacter{021F}{\v{h}} + + \DeclareUnicodeCharacter{0226}{\dotaccent{A}} + \DeclareUnicodeCharacter{0227}{\dotaccent{a}} + \DeclareUnicodeCharacter{0228}{\cedilla{E}} + \DeclareUnicodeCharacter{0229}{\cedilla{e}} + \DeclareUnicodeCharacter{022E}{\dotaccent{O}} + \DeclareUnicodeCharacter{022F}{\dotaccent{o}} + + \DeclareUnicodeCharacter{0232}{\=Y} + \DeclareUnicodeCharacter{0233}{\=y} + \DeclareUnicodeCharacter{0237}{\dotless{j}} + + \DeclareUnicodeCharacter{02DB}{\ogonek{ }} + + \DeclareUnicodeCharacter{1E02}{\dotaccent{B}} + \DeclareUnicodeCharacter{1E03}{\dotaccent{b}} + \DeclareUnicodeCharacter{1E04}{\udotaccent{B}} + \DeclareUnicodeCharacter{1E05}{\udotaccent{b}} + \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}} + \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}} + \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}} + \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}} + \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}} + \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}} + \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}} + \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}} + + \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}} + \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}} + + \DeclareUnicodeCharacter{1E20}{\=G} + \DeclareUnicodeCharacter{1E21}{\=g} + \DeclareUnicodeCharacter{1E22}{\dotaccent{H}} + \DeclareUnicodeCharacter{1E23}{\dotaccent{h}} + \DeclareUnicodeCharacter{1E24}{\udotaccent{H}} + \DeclareUnicodeCharacter{1E25}{\udotaccent{h}} + \DeclareUnicodeCharacter{1E26}{\"H} + \DeclareUnicodeCharacter{1E27}{\"h} + + \DeclareUnicodeCharacter{1E30}{\'K} + \DeclareUnicodeCharacter{1E31}{\'k} + \DeclareUnicodeCharacter{1E32}{\udotaccent{K}} + \DeclareUnicodeCharacter{1E33}{\udotaccent{k}} + \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}} + \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}} + \DeclareUnicodeCharacter{1E36}{\udotaccent{L}} + \DeclareUnicodeCharacter{1E37}{\udotaccent{l}} + \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}} + \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}} + \DeclareUnicodeCharacter{1E3E}{\'M} + \DeclareUnicodeCharacter{1E3F}{\'m} + + \DeclareUnicodeCharacter{1E40}{\dotaccent{M}} + \DeclareUnicodeCharacter{1E41}{\dotaccent{m}} + \DeclareUnicodeCharacter{1E42}{\udotaccent{M}} + \DeclareUnicodeCharacter{1E43}{\udotaccent{m}} + \DeclareUnicodeCharacter{1E44}{\dotaccent{N}} + \DeclareUnicodeCharacter{1E45}{\dotaccent{n}} + \DeclareUnicodeCharacter{1E46}{\udotaccent{N}} + \DeclareUnicodeCharacter{1E47}{\udotaccent{n}} + \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}} + \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}} + + \DeclareUnicodeCharacter{1E54}{\'P} + \DeclareUnicodeCharacter{1E55}{\'p} + \DeclareUnicodeCharacter{1E56}{\dotaccent{P}} + \DeclareUnicodeCharacter{1E57}{\dotaccent{p}} + \DeclareUnicodeCharacter{1E58}{\dotaccent{R}} + \DeclareUnicodeCharacter{1E59}{\dotaccent{r}} + \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}} + \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}} + \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}} + \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}} + + \DeclareUnicodeCharacter{1E60}{\dotaccent{S}} + \DeclareUnicodeCharacter{1E61}{\dotaccent{s}} + \DeclareUnicodeCharacter{1E62}{\udotaccent{S}} + \DeclareUnicodeCharacter{1E63}{\udotaccent{s}} + \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}} + \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}} + \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}} + \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}} + \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}} + \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}} + + \DeclareUnicodeCharacter{1E7C}{\~V} + \DeclareUnicodeCharacter{1E7D}{\~v} + \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}} + \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}} + + \DeclareUnicodeCharacter{1E80}{\`W} + \DeclareUnicodeCharacter{1E81}{\`w} + \DeclareUnicodeCharacter{1E82}{\'W} + \DeclareUnicodeCharacter{1E83}{\'w} + \DeclareUnicodeCharacter{1E84}{\"W} + \DeclareUnicodeCharacter{1E85}{\"w} + \DeclareUnicodeCharacter{1E86}{\dotaccent{W}} + \DeclareUnicodeCharacter{1E87}{\dotaccent{w}} + \DeclareUnicodeCharacter{1E88}{\udotaccent{W}} + \DeclareUnicodeCharacter{1E89}{\udotaccent{w}} + \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}} + \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}} + \DeclareUnicodeCharacter{1E8C}{\"X} + \DeclareUnicodeCharacter{1E8D}{\"x} + \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}} + \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}} + + \DeclareUnicodeCharacter{1E90}{\^Z} + \DeclareUnicodeCharacter{1E91}{\^z} + \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}} + \DeclareUnicodeCharacter{1E93}{\udotaccent{z}} + \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}} + \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}} + \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}} + \DeclareUnicodeCharacter{1E97}{\"t} + \DeclareUnicodeCharacter{1E98}{\ringaccent{w}} + \DeclareUnicodeCharacter{1E99}{\ringaccent{y}} + + \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}} + \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}} + + \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}} + \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}} + \DeclareUnicodeCharacter{1EBC}{\~E} + \DeclareUnicodeCharacter{1EBD}{\~e} + + \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}} + \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}} + \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}} + \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}} + + \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}} + \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}} + + \DeclareUnicodeCharacter{1EF2}{\`Y} + \DeclareUnicodeCharacter{1EF3}{\`y} + \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}} + + \DeclareUnicodeCharacter{1EF8}{\~Y} + \DeclareUnicodeCharacter{1EF9}{\~y} + + \DeclareUnicodeCharacter{2013}{--} + \DeclareUnicodeCharacter{2014}{---} + \DeclareUnicodeCharacter{2018}{\quoteleft} + \DeclareUnicodeCharacter{2019}{\quoteright} + \DeclareUnicodeCharacter{201A}{\quotesinglbase} + \DeclareUnicodeCharacter{201C}{\quotedblleft} + \DeclareUnicodeCharacter{201D}{\quotedblright} + \DeclareUnicodeCharacter{201E}{\quotedblbase} + \DeclareUnicodeCharacter{2022}{\bullet} + \DeclareUnicodeCharacter{2026}{\dots} + \DeclareUnicodeCharacter{2039}{\guilsinglleft} + \DeclareUnicodeCharacter{203A}{\guilsinglright} + \DeclareUnicodeCharacter{20AC}{\euro} + + \DeclareUnicodeCharacter{2192}{\expansion} + \DeclareUnicodeCharacter{21D2}{\result} + + \DeclareUnicodeCharacter{2212}{\minus} + \DeclareUnicodeCharacter{2217}{\point} + \DeclareUnicodeCharacter{2261}{\equiv} +}% end of \utfeightchardefs + + +% US-ASCII character definitions. +\def\asciichardefs{% nothing need be done + \relax +} + +% Make non-ASCII characters printable again for compatibility with +% existing Texinfo documents that may use them, even without declaring a +% document encoding. +% +\setnonasciicharscatcode \other + + +\message{formatting,} + +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; +% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip; +% 7) physical page height; 8) physical page width. +% +% We also call \setleading{\textleading}, so the caller should define +% \textleading. The caller should also set \parskip. +% +\def\internalpagesizes#1#2#3#4#5#6#7#8{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \ifpdf + \pdfpageheight #7\relax + \pdfpagewidth #8\relax + % if we don't reset these, they will remain at "1 true in" of + % whatever layout pdftex was dumped with. + \pdfhorigin = 1 true in + \pdfvorigin = 1 true in + \fi + % + \setleading{\textleading} + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % If page is nothing but text, make it come out even. + \internalpagesizes{607.2pt}{6in}% that's 46 lines + {\voffset}{.25in}% + {\bindingoffset}{36pt}% + {11in}{8.5in}% +}} + +% Use @smallbook to reset parameters for 7x9.25 trim size. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.5in}{5in}% + {-.2in}{0in}% + {\bindingoffset}{16pt}% + {9.25in}{7in}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .5cm +}} + +% Use @smallerbook to reset parameters for 6x9 trim size. +% (Just testing, parameters still in flux.) +\def\smallerbook{{\globaldefs = 1 + \parskip = 1.5pt plus 1pt + \textleading = 12pt + % + \internalpagesizes{7.4in}{4.8in}% + {-.2in}{-.4in}% + {0pt}{14pt}% + {9in}{6in}% + % + \lispnarrowing = 0.25in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = .4cm +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \textleading = 13.2pt + % + % Double-side printing via postscript on Laserjet 4050 + % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm. + % To change the settings for a different printer or situation, adjust + % \normaloffset until the front-side and back-side texts align. Then + % do the same for \bindingoffset. You can set these for testing in + % your texinfo source file like this: + % @tex + % \global\normaloffset = -6mm + % \global\bindingoffset = 10mm + % @end tex + \internalpagesizes{673.2pt}{160mm}% that's 51 lines + {\voffset}{\hoffset}% + {\bindingoffset}{44pt}% + {297mm}{210mm}% + % + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \defbodyindent = 5mm +}} + +% Use @afivepaper to print on European A5 paper. +% From romildo@urano.iceb.ufop.br, 2 July 2000. +% He also recommends making @example and @lisp be small. +\def\afivepaper{{\globaldefs = 1 + \parskip = 2pt plus 1pt minus 0.1pt + \textleading = 12.5pt + % + \internalpagesizes{160mm}{120mm}% + {\voffset}{\hoffset}% + {\bindingoffset}{8pt}% + {210mm}{148mm}% + % + \lispnarrowing = 0.2in + \tolerance = 800 + \hfuzz = 1.2pt + \contentsrightmargin = 0pt + \defbodyindent = 2mm + \tableindent = 12mm +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. +\def\afourlatex{{\globaldefs = 1 + \afourpaper + \internalpagesizes{237mm}{150mm}% + {\voffset}{4.6mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + % + % Must explicitly reset to 0 because we call \afourpaper. + \globaldefs = 0 +}} + +% Use @afourwide to print on A4 paper in landscape format. +\def\afourwide{{\globaldefs = 1 + \afourpaper + \internalpagesizes{241mm}{165mm}% + {\voffset}{-2.95mm}% + {\bindingoffset}{7mm}% + {297mm}{210mm}% + \globaldefs = 0 +}} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\parseargdef\pagesizes{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{\textleading}% + % + \dimen0 = #1\relax + \advance\dimen0 by \voffset + % + \dimen2 = \hsize + \advance\dimen2 by \normaloffset + % + \internalpagesizes{#1}{\hsize}% + {\voffset}{\normaloffset}% + {\bindingoffset}{44pt}% + {\dimen0}{\dimen2}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +% DEL is a comment character, in case @c does not suffice. +\catcode`\^^? = 14 + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\catcode`\$=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} +\def\normaldollar{$}%$ font-lock fix + +% This macro is used to make a character print one way in \tt +% (where it can probably be output as-is), and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +\let\realunder=_ +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em } + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +\catcode`\$=\active +\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +% Used sometimes to turn off (effectively) the active characters even after +% parsing them. +\def\turnoffactive{% + \normalturnoffactive + \otherbackslash +} + +\catcode`\@=0 + +% \backslashcurfont outputs one backslash character in current font, +% as in \char`\\. +\global\chardef\backslashcurfont=`\\ +\global\let\rawbackslashxx=\backslashcurfont % let existing .??s files work + +% \realbackslash is an actual character `\' with catcode other, and +% \doublebackslash is two of them (for the pdf outlines). +{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}} + +% In texinfo, backslash is an active character; it prints the backslash +% in fixed width font. +\catcode`\\=\active +@def@normalbackslash{{@tt@backslashcurfont}} +% On startup, @fixbackslash assigns: +% @let \ = @normalbackslash + +% \rawbackslash defines an active \ to do \backslashcurfont. +% \otherbackslash defines an active \ to be a literal `\' character with +% catcode other. +@gdef@rawbackslash{@let\=@backslashcurfont} +@gdef@otherbackslash{@let\=@realbackslash} + +% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of +% the literal character `\'. +% +@def@normalturnoffactive{% + @let\=@normalbackslash + @let"=@normaldoublequote + @let~=@normaltilde + @let^=@normalcaret + @let_=@normalunderscore + @let|=@normalverticalbar + @let<=@normalless + @let>=@normalgreater + @let+=@normalplus + @let$=@normaldollar %$ font-lock fix + @markupsetuplqdefault + @markupsetuprqdefault + @unsepspaces +} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\' in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also turn back on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active + @catcode`@_=@active +} + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These look ok in all fonts, so just make them not special. +@catcode`@& = @other +@catcode`@# = @other +@catcode`@% = @other + +@c Finally, make ` and ' active, so that txicodequoteundirected and +@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we +@c don't make ` and ' active, @code will not get them as active chars. +@c Do this last of all since we use ` in the previous @catcode assignments. +@catcode`@'=@active +@catcode`@`=@active +@markupsetuplqdefault +@markupsetuprqdefault + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: + +@c vim:sw=2: + +@ignore + arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115 +@end ignore diff --git a/tty.c b/tty.c new file mode 100644 index 0000000..25950f2 --- /dev/null +++ b/tty.c @@ -0,0 +1,222 @@ +/* Copyright 1997,2001,2002,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include +#include "sysincludes.h" +#include "mtools.h" + +static FILE *tty=NULL; +static int notty=0; +static int ttyfd=-1; +#ifdef USE_RAWTERM +int mtools_raw_tty = 1; +#else +int mtools_raw_tty = 0; +#endif + +#ifdef USE_RAWTERM +# if defined TCSANOW && defined HAVE_TCSETATTR +/* we have tcsetattr & tcgetattr. Good */ +typedef struct termios Terminal; +# define stty(a,b) (void)tcsetattr(a,TCSANOW,b) +# define gtty(a,b) (void)tcgetattr(a,b) +# define USE_TCIFLUSH + +# elif defined TCSETS && defined TCGETS +typedef struct termios Terminal; +# define stty(a,b) (void)ioctl(a,TCSETS,(char *)b) +# define gtty(a,b) (void)ioctl(a,TCGETS,(char *)b) +# define USE_TCIFLUSH + +# elif defined TCSETA && defined TCGETA +typedef struct termio Terminal; +# define stty(a,b) (void)ioctl(a,TCSETA,(char *)b) +# define gtty(a,b) (void)ioctl(a,TCGETA,(char *)b) +# define USE_TCIFLUSH + +# elif defined(HAVE_SGTTY_H) && defined(TIOCSETP) && defined(TIOCGETP) +typedef struct sgttyb Terminal; +# define stty(a,b) (void)ioctl(a,TIOCSETP,(char *)b) +# define gtty(a,b) (void)ioctl(a,TIOCGETP,(char *)b) +# define USE_SGTTY +# define discard_input(a) /**/ + +# else +/* no way to use raw terminal */ +# warning Cannot use raw terminal code (disabled) +# undef USE_RAWTERM +# endif + +#endif + +#ifdef USE_TCIFLUSH +# if defined TCIFLUSH && defined HAVE_TCFLUSH +# define discard_input(a) tcflush(a,TCIFLUSH) +# else +# define discard_input(a) /**/ +# endif +#endif + +#ifdef USE_RAWTERM + +static int tty_mode = -1; /* 1 for raw, 0 for cooked, -1 for initial */ +static int need_tty_reset = 0; +static int handlerIsSet = 0; + +#define restore_tty(a) stty(STDIN,a) + + +#define STDIN ttyfd +#define FAIL (-1) +#define DONE 0 +static Terminal in_orig; + +/*--------------- Signal Handler routines -------------*/ + +static void tty_time_out(int dummy) +{ + int exit_code; + signal(SIGALRM, SIG_IGN); + if(tty && need_tty_reset) + restore_tty (&in_orig); +#ifdef future + if (fail_on_timeout) + exit_code=SHFAIL; + else { + if (default_choice && mode_defined) { + if (yes_no) { + if ('Y' == default_choice) + exit_code=0; + else + exit_code=1; + } else + exit_code=default_choice-minc+1; + } else + exit_code=DONE; + } +#else + exit_code = DONE; +#endif + exit(exit_code); +} + +static void cleanup_tty(void) +{ + if(tty && need_tty_reset) { + restore_tty (&in_orig); + setup_signal(); + } +} + +static void set_raw_tty(int mode) +{ + Terminal in_raw; + + if(mode != tty_mode && mode != -1) { + if(!handlerIsSet) { + /* Determine existing TTY settings */ + gtty (STDIN, &in_orig); + need_tty_reset = 1; + + /* Restore original TTY settings on exit */ + atexit(cleanup_tty); + handlerIsSet = 1; + } + + + setup_signal(); + signal (SIGALRM, tty_time_out); + + /* Change STDIN settings to raw */ + + gtty (STDIN, &in_raw); + if(mode) { +#ifdef USE_SGTTY + in_raw.sg_flags |= CBREAK; +#else + in_raw.c_lflag &= ~ICANON; + in_raw.c_cc[VMIN]=1; + in_raw.c_cc[VTIME]=0; +#endif + stty (STDIN, &in_raw); + } else { +#ifdef USE_SGTTY + in_raw.sg_flags &= ~CBREAK; +#else + in_raw.c_lflag |= ICANON; +#endif + stty (STDIN, &in_raw); + } + tty_mode = mode; + discard_input(STDIN); + } +} +#endif + +FILE *opentty(int mode) +{ + if(notty) + return NULL; + if (tty == NULL) { + ttyfd = open("/dev/tty", O_RDONLY); + if(ttyfd >= 0) { + tty = fdopen(ttyfd, "r"); + } + } + if (tty == NULL){ + if ( !isatty(0) ){ + notty = 1; + return NULL; + } + ttyfd = 0; + tty = stdin; + } +#ifdef USE_RAWTERM + if(mtools_raw_tty) + set_raw_tty(mode); +#endif + return tty; +} + +int ask_confirmation(const char *format, ...) +{ + char ans[10]; + va_list ap; + + if(!opentty(-1)) + return 0; + + while (1) { + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fflush(stderr); + fflush(opentty(-1)); + if (mtools_raw_tty) { + ans[0] = fgetc(opentty(1)); + fputs("\n", stderr); + } else { + if(fgets(ans,9, opentty(0)) == NULL) + /* Treat end-of-file as no */ + ans[0] = 'n'; + } + if (ans[0] == 'y' || ans[0] == 'Y') + return 0; + if (ans[0] == 'n' || ans[0] == 'N') + return -1; + } +} diff --git a/unixdir.c b/unixdir.c new file mode 100644 index 0000000..ea16caa --- /dev/null +++ b/unixdir.c @@ -0,0 +1,166 @@ +/* Copyright 1998-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "file.h" +#include "htable.h" +#include "mainloop.h" +#include + +typedef struct Dir_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + struct MT_STAT statbuf; + char *pathname; + DIR *dir; +#ifdef HAVE_FCHDIR + int fd; +#endif +} Dir_t; + +/*#define FCHDIR_MODE*/ + +static int get_dir_data(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + DeclareThis(Dir_t); + + if(date) + *date = This->statbuf.st_mtime; + if(size) + *size = (mt_size_t) This->statbuf.st_size; + if(type) + *type = 1; + if(address) + *address = 0; + return 0; +} + +static int dir_free(Stream_t *Stream) +{ + DeclareThis(Dir_t); + + Free(This->pathname); + closedir(This->dir); + return 0; +} + +static Class_t DirClass = { + 0, /* read */ + 0, /* write */ + 0, /* flush */ + dir_free, /* free */ + 0, /* get_geom */ + get_dir_data , + 0 /* pre-allocate */ +}; + +#ifdef HAVE_FCHDIR +#define FCHDIR_MODE +#endif + +int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); +int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, + int follow_dir_link); + +int unix_dir_loop(Stream_t *Stream, MainParam_t *mp) +{ + DeclareThis(Dir_t); + struct dirent *entry; + char *newName; + int ret=0; + +#ifdef FCHDIR_MODE + int fd; + + fd = open(".", O_RDONLY); + if(chdir(This->pathname) < 0) { + fprintf(stderr, "Could not chdir into %s (%s)\n", + This->pathname, strerror(errno)); + return -1; + } +#endif + while((entry=readdir(This->dir)) != NULL) { + if(got_signal) + break; + if(isSpecial(entry->d_name)) + continue; +#ifndef FCHDIR_MODE + newName = malloc(strlen(This->pathname) + 1 + + strlen(entry->d_name) + 1); + if(!newName) { + ret = ERROR_ONE; + break; + } + strcpy(newName, This->pathname); + strcat(newName, "/"); + strcat(newName, entry->d_name); +#else + newName = entry->d_name; +#endif + ret |= unix_loop(Stream, mp, newName, 0); +#ifndef FCHDIR_MODE + free(newName); +#endif + } +#ifdef FCHDIR_MODE + if(fchdir(fd) < 0) + perror("Could not chdir back to .."); + close(fd); +#endif + return ret; +} + +Stream_t *OpenDir(Stream_t *Stream, const char *filename) +{ + Dir_t *This; + + This = New(Dir_t); + + This->Class = &DirClass; + This->Next = 0; + This->refs = 1; + This->Buffer = 0; + This->pathname = malloc(strlen(filename)+1); + if(This->pathname == NULL) { + Free(This); + return NULL; + } + strcpy(This->pathname, filename); + + if(MT_STAT(filename, &This->statbuf) < 0) { + Free(This->pathname); + Free(This); + return NULL; + } + + This->dir = opendir(filename); + if(!This->dir) { + Free(This->pathname); + Free(This); + return NULL; + } + + return (Stream_t *) This; +} diff --git a/version.texi b/version.texi new file mode 100644 index 0000000..395eb53 --- /dev/null +++ b/version.texi @@ -0,0 +1,3 @@ +@set EDITION 4.0.12 +@set VERSION 4.0.12 +@set UPDATED November 2009 diff --git a/vfat.c b/vfat.c new file mode 100644 index 0000000..05a26a1 --- /dev/null +++ b/vfat.c @@ -0,0 +1,826 @@ +/* Copyright 1995 David C. Niemi + * Copyright 1996-2003,2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * vfat.c + * + * Miscellaneous VFAT-related functions + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "file.h" +#include "dirCache.h" +#include "file_name.h" + +/* #define DEBUG */ + +const char *short_illegals=";+=[]',\"*\\<>/?:|"; +const char *long_illegals = "\"*\\<>/?:|\005"; + +/* Automatically derive a new name */ +static void autorename(char *name, + char tilda, char dot, const char *illegals, + int limit, int bump) +{ + int tildapos, dotpos; + unsigned int seqnum=0, maxseq=0; + char tmp; + char *p; + +#ifdef DEBUG + printf("In autorename for name=%s.\n", name); +#endif + tildapos = -1; + + for(p=name; *p ; p++) + if (strchr(illegals, *p)) { + *p = '_'; + bump = 0; + } + + for(dotpos=0; + name[dotpos] && dotpos < limit && name[dotpos] != dot ; + dotpos++) { + if(name[dotpos] == tilda) { + tildapos = dotpos; + seqnum = 0; + maxseq = 1; + } else if (name[dotpos] >= '0' && name[dotpos] <= '9') { + seqnum = seqnum * 10 + name[dotpos] - '0'; + maxseq = maxseq * 10; + } else + tildapos = -1; /* sequence number interrupted */ + } + if(tildapos == -1) { + /* no sequence number yet */ + if(dotpos > limit - 2) { + tildapos = limit - 2; + dotpos = limit; + } else { + tildapos = dotpos; + dotpos += 2; + } + seqnum = 1; + } else { + if(bump) + seqnum++; + if(seqnum > 999999) { + seqnum = 1; + tildapos = dotpos - 2; + /* this matches Win95's behavior, and also guarantees + * us that the sequence numbers never get shorter */ + } + if (seqnum == maxseq) { + if(dotpos >= limit) + tildapos--; + else + dotpos++; + } + } + + tmp = name[dotpos]; + if((bump && seqnum == 1) || seqnum > 1 || mtools_numeric_tail) + sprintf(name+tildapos,"%c%d",tilda, seqnum); + if(dot) + name[dotpos]=tmp; + /* replace the character if it wasn't a space */ +#ifdef DEBUG + printf("Out autorename for name=%s.\n", name); +#endif +} + + +void autorename_short(dos_name_t *name, int bump) +{ + autorename(name->base, '~', ' ', short_illegals, 8, bump); +} + +void autorename_long(char *name, int bump) +{ + autorename(name, '-', '\0', long_illegals, 255, bump); +} + + +static __inline__ int unicode_read(struct unicode_char *in, + wchar_t *out, int num) +{ + wchar_t *end_out = out+num; + + while(out < end_out) { +#ifdef HAVE_WCHAR_H + *out = in->lchar | ((in->uchar) << 8); +#else + if (in->uchar) + *out = '_'; + else + *out = in->lchar; +#endif + ++out; + ++in; + } + return num; +} + + +void clear_vfat(struct vfat_state *v) +{ + v->subentries = 0; + v->status = 0; + v->present = 0; +} + + +/* sum_shortname + * + * Calculate the checksum that results from the short name in *dir. + * + * The sum is formed by circularly right-shifting the previous sum + * and adding in each character, from left to right, padding both + * the name and extension to maximum length with spaces and skipping + * the "." (hence always summing exactly 11 characters). + * + * This exact algorithm is required in order to remain compatible + * with Microsoft Windows-95 and Microsoft Windows NT 3.5. + * Thanks to Jeffrey Richter of Microsoft Systems Journal for + * pointing me to the correct algorithm. + * + * David C. Niemi (niemi@tuxers.net) 95.01.19 + */ +static __inline__ unsigned char sum_shortname(const dos_name_t *dn) +{ + unsigned char sum; + const char *name=dn->base; + const char *end = name+11; + + for (sum=0; name> 1) + + *name; + return(sum); +} + +/* check_vfat + * + * Inspect a directory and any associated VSEs. + * Return 1 if the VSEs comprise a valid long file name, + * 0 if not. + */ +static __inline__ void check_vfat(struct vfat_state *v, struct directory *dir) +{ + dos_name_t dn;; + + if (! v->subentries) { +#ifdef DEBUG + fprintf(stderr, "check_vfat: no VSEs.\n"); +#endif + return; + } + + memcpy(dn.base, (char *)dir->name, 8); + memcpy(dn.ext, (char *)dir->ext, 3); + + if (v->sum != sum_shortname(&dn)) + return; + + if( (v->status & ((1<subentries) - 1)) != (1<subentries) - 1) + return; /* missing entries */ + + /* zero out byte following last entry, for good measure */ + v->name[VSE_NAMELEN * v->subentries] = 0; + v->present = 1; +} + + +int clear_vses(Stream_t *Dir, int entrySlot, size_t last) +{ + direntry_t entry; + dirCache_t *cache; + int error; + + entry.Dir = Dir; + entry.entry = entrySlot; + + /*maximize(last, entry.entry + MAX_VFAT_SUBENTRIES);*/ + cache = allocDirCache(Dir, last); + if(!cache) { + fprintf(stderr, "Out of memory error in clear_vses\n"); + exit(1); + } + addFreeEntry(cache, entry.entry, last); + for (; entry.entry < (signed int) last; ++entry.entry) { +#ifdef DEBUG + fprintf(stderr,"Clearing entry %d.\n", entry.entry); +#endif + dir_read(&entry, &error); + if(error) + return error; + if(!entry.dir.name[0] || entry.dir.name[0] == DELMARK) + break; + entry.dir.name[0] = DELMARK; + if (entry.dir.attr == 0xf) + entry.dir.attr = '\0'; + low_level_dir_write(&entry); + } + return 0; +} + +int write_vfat(Stream_t *Dir, dos_name_t *shortname, char *longname, int start, + direntry_t *mainEntry) +{ + struct vfat_subentry *vse; + int vse_id, num_vses; + wchar_t *c; + direntry_t entry; + dirCache_t *cache; + wchar_t unixyName[13]; + doscp_t *cp = GET_DOSCONVERT(Dir); + + wchar_t wlongname[MAX_VNAMELEN+1]; + int wlen; + + if(longname) { +#ifdef DEBUG + printf("Entering write_vfat with longname=\"%s\", start=%d.\n", + longname,start); +#endif + entry.Dir = Dir; + vse = (struct vfat_subentry *) &entry.dir; + /* Fill in invariant part of vse */ + vse->attribute = 0x0f; + vse->hash1 = vse->sector_l = vse->sector_u = 0; + vse->sum = sum_shortname(shortname); +#ifdef DEBUG + printf("Wrote checksum=%d for shortname %s.%s\n", + vse->sum,shortname->base,shortname->ext); +#endif + + wlen = native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, + 0, 0); + num_vses = (wlen + VSE_NAMELEN - 1)/VSE_NAMELEN; + for (vse_id = num_vses; vse_id; --vse_id) { + int end = 0; + + c = wlongname + (vse_id - 1) * VSE_NAMELEN; + + c += unicode_write(c, vse->text1, VSE1SIZE, &end); + c += unicode_write(c, vse->text2, VSE2SIZE, &end); + c += unicode_write(c, vse->text3, VSE3SIZE, &end); + + vse->id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id; +#ifdef DEBUG + printf("Writing longname=(%s), VSE %d (%13s) at %d, end = %d.\n", + longname, vse_id, longname + (vse_id-1) * VSE_NAMELEN, + start + num_vses - vse_id, start + num_vses); +#endif + + entry.entry = start + num_vses - vse_id; + low_level_dir_write(&entry); + } + } else { + num_vses = 0; + wlongname[0]='\0'; + } + cache = allocDirCache(Dir, start + num_vses + 1); + if(!cache) { + fprintf(stderr, "Out of memory error\n"); + exit(1); + } + unix_name(cp, shortname->base, shortname->ext, 0, unixyName); + addUsedEntry(cache, start, start + num_vses + 1, wlongname, unixyName, + &mainEntry->dir); + low_level_dir_write(mainEntry); + return start + num_vses; +} + +void dir_write(direntry_t *entry) +{ + dirCacheEntry_t *dce; + dirCache_t *cache; + + if(entry->entry == -3) { + fprintf(stderr, "Attempt to write root directory pointer\n"); + exit(1); + } + + cache = allocDirCache(entry->Dir, entry->entry + 1); + if(!cache) { + fprintf(stderr, "Out of memory error in dir_write\n"); + exit(1); + } + dce = cache->entries[entry->entry]; + if(dce) { + if(entry->dir.name[0] == DELMARK) { + addFreeEntry(cache, dce->beginSlot, dce->endSlot); + } else { + dce->dir = entry->dir; + } + } + low_level_dir_write(entry); +} + + +/* + * The following function translates a series of vfat_subentries into + * data suitable for a dircache entry + */ +static __inline__ void parse_vses(direntry_t *entry, + struct vfat_state *v) +{ + struct vfat_subentry *vse; + unsigned char id, last_flag; + wchar_t *c; + + vse = (struct vfat_subentry *) &entry->dir; + + id = vse->id & VSE_MASK; + last_flag = (vse->id & VSE_LAST); + if (id > MAX_VFAT_SUBENTRIES) { + fprintf(stderr, "parse_vses: invalid VSE ID %d at %d.\n", + id, entry->entry); + return; + } + +/* 950819: This code enforced finding the VSEs in order. Well, Win95 + * likes to write them in *reverse* order for some bizarre reason! So + * we pretty much have to tolerate them coming in any possible order. + * So skip this check, we'll do without it (What does this do, Alain?). + * + * 950820: Totally rearranged code to tolerate any order but to warn if + * they are not in reverse order like Win95 uses. + * + * 950909: Tolerate any order. We recognize new chains by mismatching + * checksums. In the event that the checksums match, new entries silently + * overwrite old entries of the same id. This should accept all valid + * entries, but may fail to reject invalid entries in some rare cases. + */ + + /* bad checksum, begin new chain */ + if(v->sum != vse->sum) { + clear_vfat(v); + v->sum = vse->sum; + } + +#ifdef DEBUG + if(v->status & (1 << (id-1))) + fprintf(stderr, + "parse_vses: duplicate VSE %d\n", vse->id); +#endif + + v->status |= 1 << (id-1); + if(last_flag) + v->subentries = id; + +#ifdef DEBUG + if (id > v->subentries) + /* simple test to detect entries preceding + * the "last" entry (really the first) */ + fprintf(stderr, + "parse_vses: new VSE %d sans LAST flag\n", + vse->id); +#endif + + c = &(v->name[VSE_NAMELEN * (id-1)]); + c += unicode_read(vse->text1, c, VSE1SIZE); + c += unicode_read(vse->text2, c, VSE2SIZE); + c += unicode_read(vse->text3, c, VSE3SIZE); +#ifdef DEBUG + printf("Read VSE %d at %d, subentries=%d, = (%13ls).\n", + id,entry->entry,v->subentries,&(v->name[VSE_NAMELEN * (id-1)])); +#endif + if (last_flag) + *c = '\0'; /* Null terminate long name */ +} + + +static dirCacheEntry_t *vfat_lookup_loop_common(doscp_t *cp, + direntry_t *direntry, + dirCache_t *cache, + int lookForFreeSpace, + int *io_error) +{ + wchar_t newfile[13]; + int initpos = direntry->entry + 1; + struct vfat_state vfat; + wchar_t *longname; + int error; + + /* not yet cached */ + *io_error = 0; + clear_vfat(&vfat); + while(1) { + ++direntry->entry; + if(!dir_read(direntry, &error)){ + if(error) { + *io_error = error; + return NULL; + } + addFreeEntry(cache, initpos, direntry->entry); + return addEndEntry(cache, direntry->entry); + } + + if (direntry->dir.name[0] == '\0'){ + /* the end of the directory */ + if(lookForFreeSpace) + continue; + return addEndEntry(cache, direntry->entry); + } + if(direntry->dir.name[0] != DELMARK && + direntry->dir.attr == 0x0f) + parse_vses(direntry, &vfat); + else + /* the main entry */ + break; + } + + /* If we get here, it's a short name FAT entry, maybe erased. + * thus we should make sure that the vfat structure will be + * cleared before the next loop run */ + + /* deleted file */ + if (direntry->dir.name[0] == DELMARK) { + return addFreeEntry(cache, initpos, + direntry->entry + 1); + } + + check_vfat(&vfat, &direntry->dir); + if(!vfat.present) + vfat.subentries = 0; + + /* mark space between last entry and this one as free */ + addFreeEntry(cache, initpos, + direntry->entry - vfat.subentries); + + if (direntry->dir.attr & 0x8){ + /* Read entry as a label */ + wchar_t *ptr = newfile; + ptr += dos_to_wchar(cp, direntry->dir.name, ptr, 8); + ptr += dos_to_wchar(cp, direntry->dir.ext, ptr, 3); + *ptr = '\0'; + } else + unix_name(cp, + direntry->dir.name, + direntry->dir.ext, + direntry->dir.Case, + newfile); + + if(vfat.present) + longname = vfat.name; + else + longname = 0; + + return addUsedEntry(cache, direntry->entry - vfat.subentries, + direntry->entry + 1, longname, + newfile, &direntry->dir); +} + +static __inline__ dirCacheEntry_t *vfat_lookup_loop_for_read(doscp_t *cp, + direntry_t *direntry, + dirCache_t *cache, + int *io_error) +{ + int initpos = direntry->entry + 1; + dirCacheEntry_t *dce; + + *io_error = 0; + dce = cache->entries[initpos]; + if(dce) { + direntry->entry = dce->endSlot - 1; + return dce; + } else { + return vfat_lookup_loop_common(cp, + direntry, cache, 0, io_error); + } +} + + +typedef enum result_t { + RES_NOMATCH, + RES_MATCH, + RES_END, + RES_ERROR +} result_t; + + +/* + * 0 does not match + * 1 matches + * 2 end + */ +static result_t checkNameForMatch(struct direntry_t *direntry, + dirCacheEntry_t *dce, + const wchar_t *filename, + int length, + int flags) +{ + switch(dce->type) { + case DCET_FREE: + return RES_NOMATCH; + case DCET_END: + return RES_END; + case DCET_USED: + break; + default: + fprintf(stderr, "Unexpected entry type %d\n", + dce->type); + return RES_ERROR; + } + + direntry->dir = dce->dir; + + /* make sure the entry is of an accepted type */ + if((direntry->dir.attr & 0x8) && !(flags & ACCEPT_LABEL)) + return RES_NOMATCH; + + + /*---------- multiple files ----------*/ + if(!((flags & MATCH_ANY) || + (dce->longName && + match(dce->longName, filename, direntry->name, 0, length)) || + match(dce->shortName, filename, direntry->name, 1, length))) { + + return RES_NOMATCH; + } + + /* entry of non-requested type, has to come after name + * checking because of clash handling */ + if(IS_DIR(direntry) && !(flags & ACCEPT_DIR)) { + if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) { + char tmp[4*13+1]; + wchar_to_native(dce->shortName,tmp,13); + fprintf(stderr, "Skipping \"%s\", is a directory\n", + tmp); + } + return RES_NOMATCH; + } + + if(!(direntry->dir.attr & (ATTR_LABEL | ATTR_DIR)) && + !(flags & ACCEPT_PLAIN)) { + if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) { + char tmp[4*13+1]; + wchar_to_native(dce->shortName,tmp,13); + fprintf(stderr, + "Skipping \"%s\", is not a directory\n", + tmp); + } + return RES_NOMATCH; + } + + return RES_MATCH; +} + + +/* + * vfat_lookup looks for filenames in directory dir. + * if a name if found, it is returned in outname + * if applicable, the file is opened and its stream is returned in File + */ + +int vfat_lookup(direntry_t *direntry, const char *filename, int length, + int flags, char *shortname, char *longname) +{ + dirCacheEntry_t *dce; + result_t result; + dirCache_t *cache; + int io_error; + wchar_t wfilename[MAX_VNAMELEN+1]; + wchar_t *wfilenamep = wfilename; + doscp_t *cp = GET_DOSCONVERT(direntry->Dir); + + if(length == -1 && filename) + length = strlen(filename); + + if(filename != NULL) + length = native_to_wchar(filename, wfilename, MAX_VNAMELEN, + filename+length, 0); + else { + wfilenamep = NULL; + length = 0; + } + + if (direntry->entry == -2) + return -1; + + cache = allocDirCache(direntry->Dir, direntry->entry+1); + if(!cache) { + fprintf(stderr, "Out of memory error in vfat_lookup [0]\n"); + exit(1); + } + + do { + dce = vfat_lookup_loop_for_read(cp, direntry, cache, &io_error); + if(!dce) { + if (io_error) + return -2; + fprintf(stderr, "Out of memory error in vfat_lookup\n"); + exit(1); + } + result = checkNameForMatch(direntry, dce, + wfilename, + length, flags); + } while(result == RES_NOMATCH); + + if(result == RES_MATCH){ + if(longname){ + if(dce->longName) + wchar_to_native(dce->longName, + longname, MAX_VNAMELEN); + else + *longname ='\0'; + } + if(shortname) + wchar_to_native(dce->shortName, shortname, 12); + direntry->beginSlot = dce->beginSlot; + direntry->endSlot = dce->endSlot-1; + return 0; /* file found */ + } else { + direntry->entry = -2; + return -1; /* no file found */ + } +} + +static __inline__ dirCacheEntry_t *vfat_lookup_loop_for_insert(doscp_t *cp, + direntry_t *direntry, + int initpos, + dirCache_t *cache) +{ + dirCacheEntry_t *dce; + int io_error; + + dce = cache->entries[initpos]; + if(dce && dce->type != DCET_END) { + return dce; + } else { + direntry->entry = initpos - 1; + dce = vfat_lookup_loop_common(cp, + direntry, cache, 1, &io_error); + if(!dce) { + if (io_error) { + return NULL; + } + fprintf(stderr, + "Out of memory error in vfat_lookup_loop\n"); + exit(1); + } + return cache->entries[initpos]; + } +} + +static void accountFreeSlots(struct scan_state *ssp, dirCacheEntry_t *dce) +{ + if(ssp->got_slots) + return; + + if(ssp->free_end != dce->beginSlot) { + ssp->free_start = dce->beginSlot; + } + ssp->free_end = dce->endSlot; + + if(ssp->free_end - ssp->free_start >= ssp->size_needed) { + ssp->got_slots = 1; + ssp->slot = ssp->free_start + ssp->size_needed - 1; + } +} + +static void clear_scan(wchar_t *longname, int use_longname, + struct scan_state *s) +{ + s->shortmatch = s->longmatch = s->slot = -1; + s->free_end = s->got_slots = s->free_start = 0; + + if (use_longname) + s->size_needed = 1 + + (wcslen(longname) + VSE_NAMELEN - 1)/VSE_NAMELEN; + else + s->size_needed = 1; +} + +/* lookup_for_insert replaces the old scandir function. It directly + * calls into vfat_lookup_loop, thus eliminating the overhead of the + * normal vfat_lookup + */ +int lookupForInsert(Stream_t *Dir, + struct direntry_t *direntry, + dos_name_t *dosname, + char *longname, + struct scan_state *ssp, + int ignore_entry, + int source_entry, + int pessimisticShortRename, + int use_longname) +{ + direntry_t entry; + int ignore_match; + dirCacheEntry_t *dce; + dirCache_t *cache; + int pos; /* position _before_ the next answered entry */ + wchar_t shortName[13]; + wchar_t wlongname[MAX_VNAMELEN+1]; + doscp_t *cp = GET_DOSCONVERT(Dir); + + native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, 0, 0); + clear_scan(wlongname, use_longname, ssp); + + ignore_match = (ignore_entry == -2 ); + + initializeDirentry(&entry, Dir); + ssp->match_free = 0; + + /* hash bitmap of already encountered names. Speeds up batch appends + * to huge directories, because in the best case, we only need to scan + * the new entries rather than the whole directory */ + cache = allocDirCache(Dir, 1); + if(!cache) { + fprintf(stderr, "Out of memory error in lookupForInsert\n"); + exit(1); + } + + if(!ignore_match) + unix_name(cp, dosname->base, dosname->ext, 0, shortName); + + pos = cache->nrHashed; + if(source_entry >= 0 || + (pos && isHashed(cache, wlongname))) { + pos = 0; + } else if(pos && !ignore_match && isHashed(cache, shortName)) { + if(pessimisticShortRename) { + ssp->shortmatch = -2; + return 1; + } + pos = 0; + } else if(growDirCache(cache, pos) < 0) { + fprintf(stderr, "Out of memory error in vfat_looup [0]\n"); + exit(1); + } + do { + dce = vfat_lookup_loop_for_insert(cp, &entry, pos, cache); + switch(dce->type) { + case DCET_FREE: + accountFreeSlots(ssp, dce); + break; + case DCET_USED: + if(!(dce->dir.attr & 0x8) && + (signed int)dce->endSlot-1 == source_entry) + accountFreeSlots(ssp, dce); + + /* labels never match, neither does the + * ignored entry */ + if( (dce->dir.attr & 0x8) || + ((signed int)dce->endSlot-1==ignore_entry)) + break; + + /* check long name */ + if((dce->longName && + !wcscasecmp(dce->longName, wlongname)) || + (dce->shortName && + !wcscasecmp(dce->shortName, wlongname))) { + ssp->longmatch = dce->endSlot - 1; + /* long match is a reason for + * immediate stop */ + direntry->beginSlot = dce->beginSlot; + direntry->endSlot = dce->endSlot-1; + return 1; + } + + /* Long name or not, always check for + * short name match */ + if (!ignore_match && + !wcscasecmp(shortName, dce->shortName)) + ssp->shortmatch = dce->endSlot - 1; + break; + case DCET_END: + break; + } + pos = dce->endSlot; + } while(dce->type != DCET_END); + if (ssp->shortmatch > -1) + return 1; + ssp->max_entry = dce->beginSlot; + if (ssp->got_slots) + return 6; /* Success */ + + /* Need more room. Can we grow the directory? */ + if(!isRootDir(Dir)) + return 5; /* OK, try to grow the directory */ + + fprintf(stderr, "No directory slots\n"); + return -1; +} + + + +/* End vfat.c */ diff --git a/vfat.h b/vfat.h new file mode 100644 index 0000000..ca3f8e8 --- /dev/null +++ b/vfat.h @@ -0,0 +1,110 @@ +#ifndef MTOOLS_VFAT_H +#define MTOOLS_VFAT_H + +/* Copyright 1995 David C. Niemi + * Copyright 1996-1998,2000-2003,2005,2007-2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "msdos.h" + +/* + * VFAT-related common header file + */ +#define VFAT_SUPPORT + +struct unicode_char { + unsigned char lchar; + unsigned char uchar; +} PACKED; + + +/* #define MAX_VFAT_SUBENTRIES 32 */ /* Theoretical max # of VSEs */ +#define MAX_VFAT_SUBENTRIES 20 /* Max useful # of VSEs */ +#define VSE_NAMELEN 13 + +#define VSE1SIZE 5 +#define VSE2SIZE 6 +#define VSE3SIZE 2 + +#include "stream.h" + +struct vfat_subentry { + unsigned char id; /* 0x40 = last; & 0x1f = VSE ID */ + struct unicode_char text1[VSE1SIZE]; + unsigned char attribute; /* 0x0f for VFAT */ + unsigned char hash1; /* Always 0? */ + unsigned char sum; /* Checksum of short name */ + struct unicode_char text2[VSE2SIZE]; + unsigned char sector_l; /* 0 for VFAT */ + unsigned char sector_u; /* 0 for VFAT */ + struct unicode_char text3[VSE3SIZE]; +}; + +/* Enough size for a worst case number of full VSEs plus a null */ +#define VBUFSIZE ((MAX_VFAT_SUBENTRIES*VSE_NAMELEN) + 1) + +/* Max legal length of a VFAT long name */ +#define MAX_VNAMELEN (255) + +#define VSE_PRESENT 0x01 +#define VSE_LAST 0x40 +#define VSE_MASK 0x1f + +struct vfat_state { + wchar_t name[VBUFSIZE]; + int status; /* is now a bit map of 32 bits */ + int subentries; + unsigned char sum; /* no need to remember the sum for each entry, + * it is the same anyways */ + int present; +}; + + +struct scan_state { + int match_free; + int shortmatch; + int longmatch; + unsigned int free_start; + unsigned int free_end; + int slot; + int got_slots; + unsigned int size_needed; + int max_entry; +}; + +#include "mtoolsDirentry.h" + +void clear_vfat(struct vfat_state *); +int unicode_write(wchar_t *, struct unicode_char *, int num, int *end); + +int clear_vses(Stream_t *, int, size_t); +void autorename_short(struct dos_name_t *, int); +void autorename_long(char *, int); + +#define DO_OPEN 1 /* open all files that are found */ +#define ACCEPT_LABEL 0x08 +#define ACCEPT_DIR 0x10 +#define ACCEPT_PLAIN 0x20 +#define MATCH_ANY 0x40 +#define NO_MSG 0x80 +#define NO_DOTS 0x100 /* accept no dots if matched by wildcard */ +#define DO_OPEN_DIRS 0x400 /* open all directories that are found */ +#define OPEN_PARENT 0x1000 /* in target lookup, open parent + * instead of file itself */ +#define NO_UNIX 0x2000 /* in target lookup, consider all files to reside on + * the DOS fs */ +#endif diff --git a/xdf_io.c b/xdf_io.c new file mode 100644 index 0000000..f0db3b3 --- /dev/null +++ b/xdf_io.c @@ -0,0 +1,710 @@ +/* Copyright 1994,1996-2003,2005,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + * + * Io to an xdf disk + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + + +#include "sysincludes.h" +#ifdef OS_linux +#include "msdos.h" +#include "mtools.h" +#include "devices.h" +#include "xdf_io.h" + +/* Algorithms can't be patented */ + +typedef struct sector_map { + unsigned int head:1; + unsigned int size:7; +} sector_map_t; + + +struct { + unsigned char track_size; + unsigned int track0_size:7; + unsigned int rootskip:1; + unsigned char rate; + sector_map_t map[9]; +} xdf_table[]= { + { + 19, 16, 0, 0, + { {0,3}, {0,6}, {1,2}, {0,2}, {1,6}, {1,3}, {0,0} } + }, + { + 23, 19, 0, 0, + { {0,3}, {0,4}, {1,6}, {0,2}, {1,2}, {0,6}, {1,4}, {1,3}, {0,0} } + }, + { + 46, 37, 1, 0x43, + { {0,3}, {0,4}, {0,5}, {0,7}, {1,3}, {1,4}, {1,5}, {1,7}, {0,0} } + }, + { + 24, 20, 1, 0, + { {0,5}, {1,6}, {0,6}, {1, 5} } + }, + { + 48, 41, 1, 0, + { {0,6}, {1,7}, {0,7}, {1, 6} } + } +}; + +#define NUMBER(x) (sizeof(x)/sizeof(x[0])) + +typedef struct { + unsigned char begin; /* where it begins */ + unsigned char end; + unsigned char sector; + unsigned char sizecode; + + unsigned int dirty:1; + unsigned int phantom:2; + unsigned int valid:1; + unsigned int head:1; +} TrackMap_t; + + + +typedef struct Xdf_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + int fd; + char *buffer; + + int current_track; + + sector_map_t *map; + + int track_size; + int track0_size; + int sector_size; + int FatSize; + int RootDirSize; + TrackMap_t *track_map; + + unsigned char last_sector; + unsigned char rate; + + unsigned int stretch:1; + unsigned int rootskip:1; + signed int drive:4; +} Xdf_t; + +typedef struct { + unsigned char head; + unsigned char sector; + unsigned char ptr; +} Compactify_t; + + +static int analyze_reply(RawRequest_t *raw_cmd, int do_print) +{ + int ret, bytes, newbytes; + + bytes = 0; + while(1) { + ret = analyze_one_reply(raw_cmd, &newbytes, do_print); + bytes += newbytes; + switch(ret) { + case 0: + return bytes; + case 1: + raw_cmd++; + break; + case -1: + if(bytes) + return bytes; + else + return 0; + } + } +} + + + +static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr, + const char *message, int retries) +{ + int j; + int ret=-1; + + if(!nr) + return 0; + for (j=0; j< retries; j++){ + switch(send_one_cmd(fd, raw_cmd, message)) { + case -1: + return -1; + case 1: + j++; + continue; + case 0: + break; + } + if((ret=analyze_reply(raw_cmd, j)) > 0) + return ret; /* ok */ + } + if(j > 1 && j == retries) { + fprintf(stderr,"Too many errors, giving up\n"); + return 0; + } + return -1; +} + + + +#define REC (This->track_map[ptr]) +#define END(x) (This->track_map[(x)].end) +#define BEGIN(x) (This->track_map[(x)].begin) + +static int add_to_request(Xdf_t *This, int ptr, + RawRequest_t *request, int *nr, + int direction, Compactify_t *compactify) +{ +#if 0 + if(direction == MT_WRITE) { + printf("writing %d: %d %d %d %d [%02x]\n", + ptr, This->current_track, + REC.head, REC.sector, REC.sizecode, + *(This->buffer + ptr * This->sector_size)); + } else + printf(" load %d.%d\n", This->current_track, ptr); +#endif + if(REC.phantom) { + if(direction== MT_READ) + memset(This->buffer + ptr * This->sector_size, 0, + 128 << REC.sizecode); + return 0; + } + + if(*nr && + RR_SIZECODE(request+(*nr)-1) == REC.sizecode && + compactify->head == REC.head && + compactify->ptr + 1 == ptr && + compactify->sector +1 == REC.sector) { + RR_SETSIZECODE(request+(*nr)-1, REC.sizecode); + } else { + if(*nr) + RR_SETCONT(request+(*nr)-1); + RR_INIT(request+(*nr)); + RR_SETDRIVE(request+(*nr), This->drive); + RR_SETRATE(request+(*nr), This->rate); + RR_SETTRACK(request+(*nr), This->current_track); + RR_SETPTRACK(request+(*nr), + This->current_track << This->stretch); + RR_SETHEAD(request+(*nr), REC.head); + RR_SETSECTOR(request+(*nr), REC.sector); + RR_SETSIZECODE(request+(*nr), REC.sizecode); + RR_SETDIRECTION(request+(*nr), direction); + RR_SETDATA(request+(*nr), + (caddr_t) This->buffer + ptr * This->sector_size); + (*nr)++; + } + compactify->ptr = ptr; + compactify->head = REC.head; + compactify->sector = REC.sector; + return 0; +} + + +static void add_to_request_if_invalid(Xdf_t *This, int ptr, + RawRequest_t *request, int *nr, + Compactify_t *compactify) +{ + if(!REC.valid) + add_to_request(This, ptr, request, nr, MT_READ, compactify); + +} + + +static void adjust_bounds(Xdf_t *This, off_t *begin, off_t *end) +{ + /* translates begin and end from byte to sectors */ + *begin = *begin / This->sector_size; + *end = (*end + This->sector_size - 1) / This->sector_size; +} + + +static __inline__ int try_flush_dirty(Xdf_t *This) +{ + int ptr, nr, bytes; + RawRequest_t requests[100]; + Compactify_t compactify; + + if(This->current_track < 0) + return 0; + + nr = 0; + for(ptr=0; ptr < This->last_sector; ptr=REC.end) + if(REC.dirty) + add_to_request(This, ptr, + requests, &nr, + MT_WRITE, &compactify); +#if 1 + bytes = send_cmd(This->fd,requests, nr, "writing", 4); + if(bytes < 0) + return bytes; +#else + bytes = 0xffffff; +#endif + for(ptr=0; ptr < This->last_sector; ptr=REC.end) + if(REC.dirty) { + if(bytes >= REC.end - REC.begin) { + bytes -= REC.end - REC.begin; + REC.dirty = 0; + } else + return 1; + } + return 0; +} + + + +static int flush_dirty(Xdf_t *This) +{ + int ret; + + while((ret = try_flush_dirty(This))) { + if(ret < 0) + return ret; + } + return 0; +} + + +static int load_data(Xdf_t *This, off_t begin, off_t end, int retries) +{ + int ptr, nr, bytes; + RawRequest_t requests[100]; + Compactify_t compactify; + + adjust_bounds(This, &begin, &end); + + ptr = begin; + nr = 0; + for(ptr=REC.begin; ptr < end ; ptr = REC.end) + add_to_request_if_invalid(This, ptr, requests, &nr, + &compactify); + bytes = send_cmd(This->fd,requests, nr, "reading", retries); + if(bytes < 0) + return bytes; + ptr = begin; + for(ptr=REC.begin; ptr < end ; ptr = REC.end) { + if(!REC.valid) { + if(bytes >= REC.end - REC.begin) { + bytes -= REC.end - REC.begin; + REC.valid = 1; + } else if(ptr > begin) + return ptr * This->sector_size; + else + return -1; + } + } + return end * This->sector_size; +} + +static void mark_dirty(Xdf_t *This, off_t begin, off_t end) +{ + int ptr; + + adjust_bounds(This, &begin, &end); + + ptr = begin; + for(ptr=REC.begin; ptr < end ; ptr = REC.end) { + REC.valid = 1; + if(!REC.phantom) + REC.dirty = 1; + } +} + + +static int load_bounds(Xdf_t *This, off_t begin, off_t end) +{ + off_t lbegin, lend; + int endp1, endp2; + + lbegin = begin; + lend = end; + + adjust_bounds(This, &lbegin, &lend); + + if(begin != BEGIN(lbegin) * This->sector_size && + end != BEGIN(lend) * This->sector_size && + lend < END(END(lbegin))) + /* contiguous end & begin, load them in one go */ + return load_data(This, begin, end, 4); + + if(begin != BEGIN(lbegin) * This->sector_size) { + endp1 = load_data(This, begin, begin, 4); + if(endp1 < 0) + return endp1; + } + + if(end != BEGIN(lend) * This->sector_size) { + endp2 = load_data(This, end, end, 4); + if(endp2 < 0) + return BEGIN(lend) * This->sector_size; + } + return lend * This->sector_size; +} + + +static int fill_t0(Xdf_t *This, int ptr, int size, int *sector, int *head) +{ + int n; + + for(n = 0; n < size; ptr++,n++) { + REC.head = *head; + REC.sector = *sector + 129; + REC.phantom = 0; + (*sector)++; + if(!*head && *sector >= This->track0_size - 8) { + *sector = 0; + *head = 1; + } + } + return ptr; +} + + +static int fill_phantoms(Xdf_t *This, int ptr, int size) +{ + int n; + + for(n = 0; n < size; ptr++,n++) + REC.phantom = 1; + return ptr; +} + +static void decompose(Xdf_t *This, int where, int len, off_t *begin, + off_t *end, int boot) +{ + int ptr, track; + sector_map_t *map; + int lbegin, lend; + + track = where / This->track_size / 1024; + + *begin = where - track * This->track_size * 1024; + *end = where + len - track * This->track_size * 1024; + maximize(*end, This->track_size * 1024); + + if(This->current_track == track && !boot) + /* already OK, return immediately */ + return; + if(!boot) + flush_dirty(This); + This->current_track = track; + + if(track) { + for(ptr=0, map=This->map; map->size; map++) { + /* iterate through all sectors */ + lbegin = ptr; + lend = ptr + (128 << map->size) / This->sector_size; + for( ; ptr < lend ; ptr++) { + REC.begin = lbegin; + REC.end = lend; + + REC.head = map->head; + REC.sector = map->size + 128; + REC.sizecode = map->size; + + REC.valid = 0; + REC.dirty = 0; + REC.phantom = 0; + } + } + REC.begin = REC.end = ptr; + } else { + int sector, head; + + head = 0; + sector = 0; + + for(ptr=boot; ptr < 2 * This->track_size; ptr++) { + REC.begin = ptr; + REC.end = ptr+1; + + REC.sizecode = 2; + + REC.valid = 0; + REC.dirty = 0; + } + + /* boot & 1st fat */ + ptr=fill_t0(This, 0, 1 + This->FatSize, §or, &head); + + /* second fat */ + ptr=fill_phantoms(This, ptr, This->FatSize); + + /* root dir */ + ptr=fill_t0(This, ptr, This->RootDirSize, §or, &head); + + /* "bad sectors" at the beginning of the fs */ + ptr=fill_phantoms(This, ptr, 5); + + if(This->rootskip) + sector++; + + /* beginning of the file system */ + ptr = fill_t0(This, ptr, + (This->track_size - This->FatSize) * 2 - + This->RootDirSize - 6, + §or, &head); + } + This->last_sector = ptr; +} + + +static int xdf_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + off_t begin, end; + size_t len2; + DeclareThis(Xdf_t); + + decompose(This, truncBytes32(where), len, &begin, &end, 0); + len2 = load_data(This, begin, end, 4); + if(len2 < 0) + return len2; + len2 -= begin; + maximize(len, len2); + memcpy(buf, This->buffer + begin, len); + return end - begin; +} + +static int xdf_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + off_t begin, end; + size_t len2; + DeclareThis(Xdf_t); + + decompose(This, truncBytes32(where), len, &begin, &end, 0); + len2 = load_bounds(This, begin, end); + if(len2 < 0) + return len2; + maximize(end, (off_t)len2); + len2 -= begin; + maximize(len, (off_t)len2); + memcpy(This->buffer + begin, buf, len); + mark_dirty(This, begin, end); + return end - begin; +} + +static int xdf_flush(Stream_t *Stream) +{ + DeclareThis(Xdf_t); + + return flush_dirty(This); +} + +static int xdf_free(Stream_t *Stream) +{ + DeclareThis(Xdf_t); + Free(This->track_map); + Free(This->buffer); + return close(This->fd); +} + + +static int check_geom(struct device *dev, int media, union bootsector *boot) +{ + int sect; + + if(media >= 0xfc && media <= 0xff) + return 1; /* old DOS */ + + if (!IS_MFORMAT_ONLY(dev)) { + if(compare(dev->sectors, 19) && + compare(dev->sectors, 23) && + compare(dev->sectors, 24) && + compare(dev->sectors, 46) && + compare(dev->sectors, 48)) + return 1; + + /* check against contradictory info from configuration file */ + if(compare(dev->heads, 2)) + return 1; + } + + /* check against info from boot */ + if(boot) { + sect = WORD(nsect); + if((sect != 19 && sect != 23 && sect != 24 && + sect != 46 && sect != 48) || + (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)) || + WORD(nheads) !=2) + return 1; + } + return 0; +} + +static void set_geom(union bootsector *boot, struct device *dev) +{ + /* fill in config info to be returned to user */ + dev->heads = 2; + dev->use_2m = 0xff; + if(boot) { + dev->sectors = WORD(nsect); + if(WORD(psect)) + dev->tracks = WORD(psect) / dev->sectors / 2; + } +} + +static int config_geom(Stream_t *Stream, struct device *dev, + struct device *orig_dev, int media, + union bootsector *boot) +{ + if(check_geom(dev, media, boot)) + return 1; + set_geom(boot,dev); + return 0; +} + +static Class_t XdfClass = { + xdf_read, + xdf_write, + xdf_flush, + xdf_free, + config_geom, + 0, /* get_data */ + 0 /* pre-allocate */ +}; + +Stream_t *XdfOpen(struct device *dev, char *name, + int mode, char *errmsg, struct xdf_info *info) +{ + Xdf_t *This; + off_t begin, end; + union bootsector *boot; + unsigned int type; + + if(dev && (!SHOULD_USE_XDF(dev) || check_geom(dev, 0, 0))) + return NULL; + + This = New(Xdf_t); + if (!This) + return NULL; + + This->Class = &XdfClass; + This->sector_size = 512; + This->stretch = 0; + + precmd(dev); + This->fd = open(name, mode | dev->mode | O_EXCL | O_NDELAY); + if(This->fd < 0) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno)); +#else + sprintf(errmsg,"xdf floppy: open: \"%s\"", strerror(errno)); +#endif + goto exit_0; + } + closeExec(This->fd); + + This->drive = GET_DRIVE(This->fd); + if(This->drive < 0) + goto exit_1; + + /* allocate buffer */ + This->buffer = (char *) malloc(96 * 512); + if (!This->buffer) + goto exit_1; + + This->current_track = -1; + This->track_map = (TrackMap_t *) + calloc(96, sizeof(TrackMap_t)); + if(!This->track_map) + goto exit_2; + + /* lock the device on writes */ + if (lock_dev(This->fd, mode == O_RDWR, dev)) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:", + dev->name); +#else + sprintf(errmsg,"xdf floppy: device \"%s\" busy:", + dev->name); +#endif + goto exit_3; + } + + /* Before reading the boot sector, assume dummy values suitable + * for reading at least the boot sector */ + This->track_size = 11; + This->track0_size = 6; + This->rate = 0; + This->FatSize = 9; + This->RootDirSize = 1; + decompose(This, 0, 512, &begin, &end, 0); + if (load_data(This, 0, 1, 1) < 0 ) { + This->rate = 0x43; + if(load_data(This, 0, 1, 1) < 0) + goto exit_3; + } + + boot = (union bootsector *) This->buffer; + This->FatSize = WORD(fatlen); + This->RootDirSize = WORD(dirents)/16; + This->track_size = WORD(nsect); + for(type=0; type < NUMBER(xdf_table); type++) { + if(xdf_table[type].track_size == This->track_size) { + This->map = xdf_table[type].map; + This->track0_size = xdf_table[type].track0_size; + This->rootskip = xdf_table[type].rootskip; + This->rate = xdf_table[type].rate; + break; + } + } + if(type == NUMBER(xdf_table)) + goto exit_3; + + if(info) { + info->RootDirSize = This->RootDirSize; + info->FatSize = This->FatSize; + info->BadSectors = 5; + } + decompose(This, 0, 512, &begin, &end, 1); + + This->refs = 1; + This->Next = 0; + This->Buffer = 0; + if(dev) + set_geom(boot, dev); + return (Stream_t *) This; + +exit_3: + Free(This->track_map); +exit_2: + Free(This->buffer); +exit_1: + close(This->fd); +exit_0: + Free(This); + return NULL; +} + +#endif + +/* Algorithms can't be patented */ + diff --git a/xdf_io.h b/xdf_io.h new file mode 100644 index 0000000..db5d52c --- /dev/null +++ b/xdf_io.h @@ -0,0 +1,33 @@ +#ifndef MTOOLS_XDFIO_H +#define MTOOLS_XDFIO_H + +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools 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. + * + * Mtools 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 Mtools. If not, see . + */ + +#include "msdos.h" +#include "stream.h" + +struct xdf_info { + int FatSize; + int RootDirSize; + int BadSectors; +}; + +Stream_t *XdfOpen(struct device *dev, char *name, + int mode, char *errmsg, struct xdf_info *info); + +#endif