Import mtools 4.0.26

Bug: 175204891
Bug: 180112530
Change-Id: I8a656b5da155f9857afa4f48c6b40fe72f68c052
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..f3740ba
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,90 @@
+// Copyright 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary_host {
+    name: "mtools",
+    srcs: [
+        "buffer.c",
+        "charsetConv.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",
+        "filter.c",
+        "floppyd_io.c",
+        "force_io.c",
+        "hash.c",
+        "init.c",
+        "llong.c",
+        "lockdev.c",
+        "match.c",
+        "mainloop.c",
+        "mattrib.c",
+        "mbadblocks.c",
+        "mcat.c",
+        "mcd.c",
+        "mclasserase.c",
+        "mcopy.c",
+        "mdel.c",
+        "mdir.c",
+        "mdoctorfat.c",
+        "mdu.c",
+        "mformat.c",
+        "minfo.c",
+        "misc.c",
+        "missFuncs.c",
+        "mk_direntry.c",
+        "mlabel.c",
+        "mmd.c",
+        "mmount.c",
+        "mmove.c",
+        "mpartition.c",
+        "mshortname.c",
+        "mshowfat.c",
+        "mzip.c",
+        "mtools.c",
+        "old_dos.c",
+        "patchlevel.c",
+        "plain_io.c",
+        "precmd.c",
+        "privileges.c",
+        "scsi.c",
+        "signal.c",
+        "stream.c",
+        "streamcache.c",
+        "strtonum.c",
+        "subdir.c",
+        "unixdir.c",
+        "tty.c",
+        "vfat.c",
+        "xdf_io.c",
+    ],
+    cflags: [
+        "-DSYSCONFDIR=\"/etc\"",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-parameter",
+        "-Wno-unused-result",
+    ],
+    symlinks: [
+        "mcopy",
+    ],
+}
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. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/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/LICENSE b/LICENSE
new file mode 120000
index 0000000..d24842f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+COPYING
\ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..89ba8a0
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,18 @@
+name: "mtools"
+description:
+    "Mtools is a collection of utilities to access MS-DOS disks from GNU and "
+    "Unix without mounting them."
+
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://www.gnu.org/software/mtools/"
+  }
+  url {
+    type: ARCHIVE
+    value: "https://ftp.gnu.org/gnu/mtools/mtools-4.0.26.tar.lz"
+  }
+  version: "4.0.26"
+  last_upgrade_date { year: 2021 month: 2 day: 3 }
+  license_type: BY_EXCEPTION_ONLY
+}
diff --git a/MODULE_LICENSE_GFDL b/MODULE_LICENSE_GFDL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_GFDL
diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_GPL
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 <http://www.gnu.org/licenses/>.
+#
+#       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..616d59f
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,336 @@
+#  Copyright 1996-2004,2006-2010 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 <http://www.gnu.org/licenses/>.
+#
+#       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@
+
+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 mshortname.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 mshortname.1 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 strtonum.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 lockdev.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 mshortname.o mshowfat.o mzip.o mtools.o old_dos.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 strtonum.o
+
+OBJS2 = missFuncs.o mkmanifest.o misc.o patchlevel.o
+
+OBJS3 = floppyd.o llong.o lockdev.o
+
+OBJS4 = floppyd_installtest.o misc.o expand.o privileges.o strtonum.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 lockdev.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 \
+mshortname.c mshowfat.c mzip.c mtools.c old_dos.c plain_io.c precmd.c \
+privileges.c \
+scsi.c 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 mshortname \
+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) -lXau -lX11 $(LIBS)
+X_CCFLAGS = $(X_CFLAGS) $(CFLAGS)
+
+all:    mtools $(LINKS) mkmanifest @FLOPPYD@ mtools.1 mtools.5
+
+%.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: $(OBJS3)
+	$(LINK) $(OBJS3) -o $@ $(X_LDFLAGS)
+floppyd_installtest: $(OBJS4)
+	$(LINK) $(OBJS4) -o $@ $(ALLLIBS)
+
+
+$(LINKS): mtools
+	rm -f $@ && $(LN_S) mtools $@
+
+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 sysconfdir.texi
+	$(MAKEINFO) -I$(srcdir) $< --no-split --output=$@
+
+dvi: mtools.dvi
+%.dvi: %.texi sysconfdir.texi
+	$(TEXI2DVI) $<
+
+ps: mtools.ps
+%.ps: %.dvi
+	dvips -f < $< > $@
+
+pdf: mtools.pdf
+%.pdf: %.texi sysconfdir.texi
+	$(TEXI2PDF) $<
+
+mtools.1: mtools.tmpl.1 Makefile
+	sed "s%SYSCONFDIR%$(sysconfdir)/%g" $(srcdir)/mtools.tmpl.1 >mtools.1
+
+mtools.5: mtools.tmpl.5 Makefile
+	sed "s%SYSCONFDIR%$(sysconfdir)/%g" $(srcdir)/mtools.tmpl.5 >mtools.5
+
+sysconfdir.texi:
+	echo "@set SYSCONFDIR $(sysconfdir)/" >sysconfdir.texi
+
+html: mtools.html mtools_toc.html
+%.html %_toc.html: %.texi  sysconfdir.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 $(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 easier 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..02f8b5c
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,1156 @@
+v4_0_26
+	- Fix compilation on Macintosh
+	- Ignore image file locking errors if we are performing a
+          read-only access anyways
+	- Minor man-page fixes
+v4_0_25
+	- Preserve non-updated contents of info sector, just in case
+          it contains program code
+	- When parsing config file, always use "C" locale for
+          case-insensitive comparisons
+v4_0_24
+	- Spelling fixes in documentation
+	- Permit calling "make install" with >= -j2
+	- Added AC_SYS_LARGEFILE, needed for compiling on certain ARM procs
+v4_0_23
+	- Address lots of compiler warnings (assignments between different types)
+	- Network speedup fixes for floppyd (TCP_CORK)
+	- Typo fixes
+	- Explicitly pass available target buffer size for character
+	set conversions
+v4_0_22
+	- Fixed -f flag for mformat (size is KBytes, rather than sectors)
+	- Fixed toupper/tolower usage (unsigned char rather than plain signed)
+v4_0_21
+	- Fixed compilation for MingW
+	- After MingW compilation, make sure executable has .exe extension
+	- Addressed compiler warnings
+	- Fixed length handling in character set conversion (Unicode file names)
+	- Fixed matching of character range, when containing Unicode
+	characters (mdir "c:test[α-ω].exe")
+	- Fixed initialization of my_scsi_cmd constructor
+v4_0_20
+	- initialize directory entries to 0
+	- bad message "Too few sectors" replaced with "Too many sectors"
+	- apostrophe in mlabel no longer causes generation of long entry
+	- option to fake system date for file creation using the
+	SOURCE_DATE_EPOCH environment variables
+
+	- can now be compiled with "clang" compiler
+	- fallback function for strndup, for those platforms that don't have it
+	- fixed a number of -Wextra warnings
+
+	- new compressed archive formats for uz/lz
+
+	- allow to specify number of reserved sectors for FAT32.
+	- file/device locking with timeout (rather than immediate failure)
+	- fixed support for BPB-less legacy formats.
+	- removed check that disk must be an integer number of tracks.
+
+	- removed .eh/.oh macros from manual pages
+v4_0_19
+	- Fix for short file names starting with character 0xE5
+	(by remapping it to 0x5)
+	- mpartition: Partition types closer to what Microsoft uses
+	- mformat: figure out LBA geometry as last resort if geometry
+	is neither specified in config and/or commandline, nor can be
+	queried from the device
+	- mformat: use same default cluster size by size as Microsoft
+	for FAT32
+	- additional sanity checks
+	- document how cluster size is picked in mformat.c man page
+	- document how partition types are picked in mpartition.c man page
+v4_0_18	
+	Fix for names of iconv encodings on AIX
+	Fix mt_size_t on NetBSD
+	Fixed compilation on Mingw
+	Fixed doc (especially mformat)
+	Fix mformat'ing of FAT12 filesystems with huge cluster sizes
+	Minfo prints image file name in mformat command line if an image
+	file name was given
+	Always generate gzip-compressed RPMs, in order to remain
+	compatible with older distributions
+	Fixed buffer overflow with drive letter in mclasserase
+v4_0_17
+	mbadblocks now takes a list of bad blocks (either as sectors
+	or as clusters)
+	mbadblocks now is able to do write scanning for bad blocks
+	mshowfat can show cluster of specific offset
+	Enable mtools to deal with very small sector sizes...
+	Fixed encoding of all-lowercase names (no need to mangle
+	these)
+	Consider every directory entry after an ENDMARK (0x00) to be deleted
+	After writing a new entry at end of a directory, be sure to also add
+	an ENDMARK (0x00)
+
+	Deal with possibility of a NULL pointer being returned by
+	localtime during timestamp conversion
+v4_0_16
+	configure.in fixes
+	fixed formatting of fat_size_calculation.tex document
+	compatibility with current autoconfig versions
+	Make it clear that label is limited to 11 characters
+	Fixed typo in initialization of FAT32 info sector
+v4_0_15
+	Added missing -i option to mshortname
+	Split .deb package into mtools and floppyd in order to
+	match Ubuntu
+v4_0_14
+	New mshortname command
+	Fix floppyd for disks bigger than 2 Gig
+	Remove obsolete -z flag
+	Remove now unsupported AC_USE_SYSTEM_EXTENSIONS
+	Fixed output formatting of mdir if MTOOLS_DOTTED_DIR is set
+	Mformat now correctly writes backup boot sector
+	Fixed signedness of serial number in mlabel
+	Fixed buffer size problem in mlabel
+	Make mlabel write backup boot sector if FAT32
+	Catch situation where both clear and new label are given to mlabel
+	Quote filename parameters to scripts
+	Mformat: Close file descriptor for boot sector
+	Added lzip support to scripts/uz
+	Added Tot_sectors option to mformat
+	Fixed hidden sector handling in mformat
+	Minfo generates mformat command lines containing new -T option
+	Mlabel prints error if label too long
+v4_0_13
+	Merged Debian patches
+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-dependent 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 condition 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 making 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 occurred 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 easier 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 privileges 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 accommodate
+	operating systems with file name size limits.
+v19970420
+	Autoextend size for images that are too small.  Moved BSD
+	dependent #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 <mgyger@itr.ch>)
+	Renamed mtest to mtoolstest to please pine.
+v19961210
+	Added warning about running mtools with root privs.
+v19961209
+	Fixed uninitialized 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 address 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 accessible 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
+	Spelling 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.
+	<rant>
+	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".
+	</rant>
+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 <paul@ahwau.ahold.nl>:
+	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 <sys/time.h> 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 <Martin.Kraemer@mch.sni.de>:
+		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..bd979c8
--- /dev/null
+++ b/README
@@ -0,0 +1,73 @@
+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 info-mtools@gnu.org .
+
+You may subscribe to the mtools mailing list at
+https://lists.gnu.org/mailman/listinfo/info-mtools
+
+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 <marcone@xs4all.nl>
+Alain Knaff <alain@knaff.lu>
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 <Martin.Kraemer@mch.sni.de>.
+
+-----------------------------------------------------------------------------
+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 <http://www.gnu.org/licenses/>.
+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 <stdio.h>
+#include <sys/types.h>
+#include <errno.h> ],
+    [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..e129ac4
--- /dev/null
+++ b/buffer.c
@@ -0,0 +1,388 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 alignment,
+				 * 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)
+{
+	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 + (mt_off_t) This->cur_size) {
+		maximize(*len, This->cur_size - OFFSET);
+		return INSIDE;
+	} else if(start == This->current + (mt_off_t) 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;
+	mt_off_t 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+(mt_off_t)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=0;
+
+	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;
+#ifdef DEBUG
+		default:
+			fprintf(stderr, "Should not happen\n");
+			exit(1);
+#endif
+	}
+
+	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 */
+	0, /* discard */
+};
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+
+Stream_t *buf_init(Stream_t *Next, 
+		   int size, 
+		   int cylinderSize,
+		   int sectorSize);
+
+#endif
diff --git a/buildMingw.sh b/buildMingw.sh
new file mode 100755
index 0000000..d3ded53
--- /dev/null
+++ b/buildMingw.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# Build Mingw (Windows) executable
+#
+# For this you meed the mingw cross-compiler to be installed
+#
+# You may download the RPMs from http://mirzam.it.vu.nl/mingw/
+# All 4 RPM's are needed:
+#  mingw-binutils
+#  mingw-gcc-core
+#  mingw-runtime
+#  mingw-w32api
+
+dir=`dirname $0`
+$dir/configure --srcdir $dir  --host i586-mingw32msvc --disable-floppyd
+make
+mv mtools mtools.exe
diff --git a/byte_dword.h b/byte_dword.h
new file mode 100644
index 0000000..c3c3b97
--- /dev/null
+++ b/byte_dword.h
@@ -0,0 +1,63 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+static Dword byte2dword(Byte* val)
+{
+	Dword l;
+	l = (Dword)((val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3]);
+	
+	return l;
+}	
+
+UNUSED(static Qword byte2qword(Byte* val))
+{
+	Qword l;
+	l = val[0];
+	l = (l << 8) | val[1];
+	l = (l << 8) | val[2];
+	l = (l << 8) | val[3];
+	l = (l << 8) | val[4];
+	l = (l << 8) | val[5];
+	l = (l << 8) | val[6];
+	l = (l << 8) | val[7];
+	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;
+}
+
+UNUSED(static void qword2byte(Qword parm, Byte* rval))
+{
+	rval[0] = (parm >> 56) & 0xff;
+	rval[1] = (parm >> 48) & 0xff;
+	rval[2] = (parm >> 40)  & 0xff;
+	rval[3] = (parm >> 32)  & 0xff;
+	rval[4] = (parm >> 24) & 0xff;
+	rval[5] = (parm >> 16) & 0xff;
+	rval[6] = (parm >> 8)  & 0xff;
+	rval[7] = parm         & 0xff;
+}
+
+#endif
diff --git a/charsetConv.c b/charsetConv.c
new file mode 100644
index 0000000..8734be5
--- /dev/null
+++ b/charsetConv.c
@@ -0,0 +1,434 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * Various character set conversions used by mtools
+ */
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "file_name.h"
+
+
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+
+struct doscp_t {
+	iconv_t from;
+	iconv_t to;
+};
+
+static const char *wcharCp=NULL;
+
+static const 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 const char *asciiTries[] = {
+	"ASCII", "ASCII-GR", "ISO8859-1"
+};
+
+static const wchar_t *testString = L"ab";
+
+static int try(const 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 = 0;
+	size_t i;
+	
+	for(i=0; i < sizeof(asciiTries) / sizeof(asciiTries[0]); i++) {
+		test = iconv_open(asciiTries[i], testCp);
+		if(test != (iconv_t) -1)
+			break;
+	}
+	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(void) {
+	unsigned 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, const 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;
+	char *dos2 = (char *) dos; /* Magic to be able to call iconv with its 
+				      buggy prototype */
+	r=iconv(cp->from, &dos2, &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 in_len, size_t out_len, int *mangled)
+{
+	int r;
+	unsigned int i;
+	char *dptr = dest;
+	size_t len;
+
+	in_len=in_len*sizeof(wchar_t);
+
+	while(in_len > 0 && out_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(out_len <= 0)
+			break;
+		if(dptr) 
+			*dptr++ = '_';
+		in_len -= sizeof(wchar_t);
+
+		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; i<len; i++) {
+		if(dest[i] == '?') {
+			dest[i] = '_';
+			*mangled |= 1;
+		}
+	}
+	return len;
+}
+
+void wchar_to_dos(doscp_t *cp,
+		  wchar_t *wchar, char *dos, size_t len, int *mangled)
+{
+	safe_iconv(cp->to, wchar, dos, len, 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, const char *dos, wchar_t *wchar, size_t len)
+{
+	int i;
+
+	for(i=0; i<len && dos[i]; i++) {
+		char c = dos[i];
+		if(c >= ' ' && 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<len && wchar[i]; i++) {
+		char c = wchar[i];
+		if(c >= ' ' && 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 <langinfo.h>
+
+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,
+		    size_t out_len)
+{
+#ifdef HAVE_ICONV_H
+	int mangled;
+	int r;
+	initialize_to_native();
+	len = wcsnlen(wchar,len);
+	r=safe_iconv(to_native, wchar, native, len, out_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<len && wchar[i] != 0; i++) {
+		int r = wcrtomb(dptr, wchar[i], &ps);
+		if(r < 0 && errno == EILSEQ) {
+			r=1;
+			*dptr='_';
+		}
+		if(r < 0)
+			return r;
+		dptr+=r;
+	}
+	*dptr='\0';
+	return dptr-native;
+#endif
+}
+
+/**
+ * Convert native string to wchar string, generating at most len wchar
+ * characters. If end is supplied, stop conversion when source pointer
+ * exceeds end. Returns number of generated wchars
+ */
+int native_to_wchar(const char *native, wchar_t *wchar, size_t len,
+		    const char *end, int *mangled)
+{
+	mbstate_t ps;
+	unsigned int i;
+	memset(&ps, 0, sizeof(ps));
+
+	for(i=0; i<len && (native < end || !end); i++) {
+		int r = mbrtowc(wchar+i, native, len, &ps);
+		if(r < 0) {
+			/* Unconvertible character. Just pretend it's Latin1
+			   encoded (if valid Latin1 character) or substitute
+			   with an underscore if not
+			*/
+			char c = *native;
+			if(c >= '\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) || (!end && *native &&  i == len)))
+		*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 <http://www.gnu.org/licenses/>.
+
+# 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 <http://www.gnu.org/licenses/>.
+ */
+
+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..5c437e0
--- /dev/null
+++ b/codepages.c
@@ -0,0 +1,119 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#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 }
+};
+#else
+/* Should down  ISO C forbids an empty translation unit warning [-Wpedantic]: */
+typedef int make_iso_compilers_happy;
+#endif
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..550bfbf
--- /dev/null
+++ b/config.c
@@ -0,0 +1,925 @@
+/*  Copyright 1996-2005,2007-2009,2011 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#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 unsigned int flag_mask; /* mask of currently set flags */
+
+/* devices */
+static unsigned 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 unsigned 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;
+uint8_t mtools_rate_0=0;
+uint8_t 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_lock_timeout=30;
+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,
+	T_UINT8,
+	T_UINT16
+    } 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_UINT8 },
+    { "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT8 },
+    { "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 },
+    { "MTOOLS_LOCK_TIMEOUT", (caddr_t) &mtools_lock_timeout, T_UINT },
+    { "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT }
+};
+
+typedef struct {
+    const char *name;
+    unsigned 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;
+    unsigned 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_UINT16 },
+    { "SECTORS", OFFS(sectors), T_UINT16 },
+    { "HIDDEN", OFFS(hidden), T_UINT },
+    { "PRECMD", OFFS(precmd), T_STRING },
+    { "BLOCKSIZE", OFFS(blocksize), T_UINT },
+    { "CODEPAGE", OFFS(codepage), T_UINT }
+};
+
+#if (defined  HAVE_TOUPPER_L || defined HAVE_STRNCASECMP_L)
+static locale_t C=NULL;
+
+static void init_canon(void) {
+    if(C == NULL)
+	C = newlocale(LC_CTYPE_MASK, "C", NULL);
+}
+#endif
+
+#ifdef HAVE_TOUPPER_L
+static int canon_drv(int drive) {
+    int ret;
+    init_canon();
+    ret = toupper_l(drive, C);
+    return ret;
+}
+#else
+static int canon_drv(int drive) {
+    return toupper(drive);
+}
+#endif
+
+#ifdef HAVE_STRNCASECMP_L
+static int cmp_tok(const char *a, const char *b, int len) {
+    init_canon();
+    return strncasecmp_l(a, b, len, C);
+}
+#else
+static int cmp_tok(const char *a, const char *b, int len) {
+    return strncasecmp(a, b, len);
+}
+#endif
+
+
+static char ch_canon_drv(char drive) {
+    return (char) canon_drv( (unsigned char) drive);
+}
+
+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) NORETURN;
+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", filename, msg);
+    if(errno != 0)
+	fprintf(stderr, " (%s)", strerror(errno));
+    fprintf(stderr, "\n");
+    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) {
+	    errno = 0;
+	    switch(global_switches[i].type) {
+	    case T_INT:
+		* ((int *)global_switches[i].address) = strtoi(s,0,0);
+		break;
+	    case T_UINT:
+		* ((unsigned int *)global_switches[i].address) = strtoui(s,0,0);
+		break;
+	    case T_UINT8:
+		* ((uint8_t *)global_switches[i].address) = strtou8(s,0,0);
+		break;
+	    case T_UINT16:
+		* ((uint16_t *)global_switches[i].address) = strtou16(s,0,0);
+		break;
+	    case T_STRING:
+		* ((char **)global_switches[i].address) = s;
+		break;
+	    }
+	    if(errno != 0) {
+		fprintf(stderr, "Bad number %s for %s (%s)\n", s,
+			global_switches[i].name,
+			strerror(errno));
+		exit(1);
+	    }
+	}
+    }
+}
+
+static int mtools_getline(void)
+{
+    if(!fp || !fgets(buffer, MAX_LINE_LEN+1, 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 &&
+	    !cmp_tok(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 long get_unumber(unsigned long max)
+{
+    char *last;
+    unsigned long n;
+
+    skip_junk(1);
+    last = pos;
+    n=strtoul(pos, &pos, 0);
+    if(errno)
+	syntax("bad number", 0);
+    if(last == pos)
+	syntax("numeral expected", 0);
+    if(n > max)
+	syntax("number too big", 0);
+    pos++;
+    token_nr++;
+    return n;
+}
+
+static int get_number(void)
+{
+    char *last;
+    int n;
+
+    skip_junk(1);
+    last = pos;
+    n=(int) strtol(pos, &pos, 0);
+    if(errno)
+	syntax("bad number", 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)
+{
+    unsigned int i, j;
+
+    drive = ch_canon_drv(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)
+{
+    unsigned 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)
+{
+    if(cur_dev == -1) {
+	trusted = 0;
+	return;
+    }
+    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",
+		canon_drv(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)
+		* ((unsigned int *)((long)switches[i].address+base_address)) =
+		    (unsigned int) get_unumber(UINT_MAX);
+	    else if(switches[i].type == T_UINT8)
+		* ((uint8_t *)((long)switches[i].address+base_address)) =
+		    (uint8_t) get_unumber(UINT8_MAX);
+	    else if(switches[i].type == T_UINT16)
+		* ((uint16_t *)((long)switches[i].address+base_address)) =
+		    (uint16_t) get_unumber(UINT16_MAX);
+	    else 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 void parse_all(int privilege);
+
+void set_cmd_line_image(char *img) {
+  char *ofsp;
+
+  prepend();
+  devices[cur_dev].drive = ':';
+  default_drive = ':';
+
+  ofsp = strstr(img, "@@");
+  if (ofsp == NULL) {
+    /* no separator => no offset */
+    devices[cur_dev].name = strdup(img);
+    devices[cur_dev].offset = 0;
+  } else {
+    devices[cur_dev].name = strndup(img, ofsp - img);
+    devices[cur_dev].offset = str_to_offset(ofsp+2);
+  }
+
+  devices[cur_dev].fat_bits = 0;
+  devices[cur_dev].tracks = 0;
+  devices[cur_dev].heads = 0;
+  devices[cur_dev].sectors = 0;
+  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;
+    parse_all(0);
+  }
+}
+
+void check_number_parse_errno(char c, const char *oarg, char *endptr) {
+    if(endptr && *endptr) {
+	fprintf(stderr, "Bad number %s\n", oarg);
+	exit(1);
+    }
+    if(errno) {
+	fprintf(stderr, "Bad number %s for -%c (%s)\n", oarg,
+		c, strerror(errno));
+	exit(1);
+    }
+}
+
+static uint16_t tou16(int in, const char *comment) {
+    if(in > UINT16_MAX) {
+	fprintf(stderr, "Number of %s %d too big\n", comment, in);
+	exit(1);
+    }
+    if(in < 0) {
+	fprintf(stderr, "Number of %s %d negative\n", comment, in);
+	exit(1);
+    }
+    return (uint16_t) in;
+       
+}
+
+static void parse_old_device_line(char drive)
+{
+    char name[MAXPATHLEN];
+    int items;
+    long offset;
+
+    int heads, sectors;
+    
+    /* 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,&heads,
+		   &sectors, &offset);
+    devices[cur_dev].heads = tou16(heads, "heads");
+    devices[cur_dev].sectors = tou16(sectors, "sectors");
+    
+    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);
+    }
+    if(!devices[cur_dev].tracks){
+	devices[cur_dev].sectors = 0;
+	devices[cur_dev].heads = 0;
+    }
+	
+    devices[cur_dev].drive = ch_canon_drv(devices[cur_dev].drive);
+    maintain_default_drive(devices[cur_dev].drive);
+    if (!(devices[cur_dev].name = strdup(name))) {
+	printOom();
+	exit(1);
+    }
+    devices[cur_dev].misc_flags |= MFORMAT_ONLY_FLAG;
+    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 = ch_canon_drv(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 void parse_all(int privilege) {
+    errno=0;
+    while (parse_one(privilege));
+}
+
+
+static int parse(const char *name, int privilege)
+{
+    if(fp) {
+	fprintf(stderr, "File descriptor already set!\n");
+	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 */
+
+    parse_all(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  UNUSEDP) NORETURN;
+void mtoolstest(int argc, char **argv, int type  UNUSEDP)
+{
+    /* testing purposes only */
+    struct device *dev;
+    char drive='\0';
+
+    if(argc > 1 && argv[1][0] && argv[1][1] == ':') {
+	drive = ch_canon_drv(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);
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..2e9ad7f
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1462 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-10-02'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# 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.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <config-patches@gnu.org>.
+
+
+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 <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2016 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
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+	;;
+esac
+
+# 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 tuples: *-*-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=`(uname -p 2>/dev/null || \
+	    /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 ;;
+	    earmv*)
+		arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine=${arch}${endian}-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) and ABI.
+	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		os=netbsdelf
+		;;
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		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
+	# Determine ABI tags.
+	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+		;;
+	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/[-_].*//' | cut -d. -f1,2`
+		;;
+	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}${abi}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:LibertyBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${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 ;;
+    *:Sortix:*:*)
+	echo ${UNAME_MACHINE}-unknown-sortix
+	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`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    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 ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    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:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH=i386
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH=x86_64
+	    fi
+	fi
+	echo ${SUN_ARCH}-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 <stdio.h>  /* 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 <sys/systemcfg.h>
+
+		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:*:[4567])
+	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/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
+	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 <stdlib.h>
+		#include <unistd.h>
+
+		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 -q __LP64__
+	    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 <unistd.h>
+	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:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    *:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		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 ;;
+    8664:Windows_NT:*)
+	echo x86_64-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-${LIBC}`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 "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	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 -q ld.so.1
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	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-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    e2k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    k1om:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    mips64el:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${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-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	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.[02]*:*)
+	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' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/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 i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configure will decide that
+	# this is a cross-build.
+	echo i586-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; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	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; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; 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.[02]*:*)
+	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 <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes@openmarket.com>.
+	# 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 ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	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 ;;
+    SX-ACE:SUPER-UX:*:*)
+	echo sxace-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
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
+	fi
+	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 ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	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 ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+    amd64:Isilon\ OneFS:*:*)
+	echo x86_64-unknown-onefs
+	exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to config-patches@gnu.org to
+provide the necessary 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 b/config.h
new file mode 100644
index 0000000..66661fe
--- /dev/null
+++ b/config.h
@@ -0,0 +1,509 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* 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 */
+#define DECL_SYS_ERRLIST 1
+
+/* Define to 1 if you have the `alarm' function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `atexit' function. */
+#define HAVE_ATEXIT 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if the system has the type `caddr_t'. */
+#define HAVE_CADDR_T 1
+
+/* Define to 1 if you have the `fchdir' function. */
+#define HAVE_FCHDIR 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `flock' function. */
+#define HAVE_FLOCK 1
+
+/* Define to 1 if you have the `getgroupid' function. */
+/* #undef HAVE_GETGROUPID */
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H 1
+
+/* Define to 1 if you have the `getpass' function. */
+#define HAVE_GETPASS 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `getuserid' function. */
+/* #undef HAVE_GETUSERID */
+
+/* Define to 1 if you have the `htons' function. */
+#define HAVE_HTONS 1
+
+/* Define to 1 if you have the <iconv.h> header file. */
+#define HAVE_ICONV_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_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 <libc.h> header file. */
+/* #undef HAVE_LIBC_H */
+
+/* Define to 1 if you have the `iconv' library (-liconv). */
+/* #undef HAVE_LIBICONV */
+
+/* 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 <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+#define HAVE_LINUX_FS_H 1
+
+/* Define to 1 if you have the <linux/unistd.h> header file. */
+#define HAVE_LINUX_UNISTD_H 1
+
+/* 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 <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `lockf' function. */
+#define HAVE_LOCKF 1
+
+/* Define when the compiler supports LOFF_T type */
+#define HAVE_LOFF_T 1
+
+/* Define when the compiler supports LONG_LONG type */
+#define HAVE_LONG_LONG 1
+
+/* Define to 1 if you have the `lseek64' function. */
+#define HAVE_LSEEK64 1
+
+/* Define when you have an LSEEK64 prototype */
+#define HAVE_LSEEK64_PROTOTYPE 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the `media_oldaliases' function. */
+/* #undef HAVE_MEDIA_OLDALIASES */
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#define HAVE_MNTENT_H 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define when the compiler supports OFFSET_T type */
+/* #undef HAVE_OFFSET_T */
+
+/* Define when the system has a 64 bit off_t type */
+#define HAVE_OFF_T_64 1
+
+/* Define to 1 if you have the `on_exit' function. */
+#define HAVE_ON_EXIT 1
+
+/* Define to 1 if you have the `putwc' function. */
+#define HAVE_PUTWC 1
+
+/* Define to 1 if you have the `random' function. */
+#define HAVE_RANDOM 1
+
+/* Define to 1 if you have the `setenv' function. */
+#define HAVE_SETENV 1
+
+/* Define to 1 if you have the `seteuid' function. */
+#define HAVE_SETEUID 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setpgrp' function. */
+#define HAVE_SETPGRP 1
+
+/* Define to 1 if you have the `setresuid' function. */
+#define HAVE_SETRESUID 1
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Define to 1 if you have the `srandom' function. */
+#define HAVE_SRANDOM 1
+
+/* Define to 1 if you have the `stat64' function. */
+#define HAVE_STAT64 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strcspn' function. */
+#define HAVE_STRCSPN 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the `strncasecmp_l' function. */
+#define HAVE_STRNCASECMP_L 1
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the `strnlen' function. */
+#define HAVE_STRNLEN 1
+
+/* Define to 1 if you have the `strpbrk' function. */
+#define HAVE_STRPBRK 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if you have the `strspn' function. */
+#define HAVE_STRSPN 1
+
+/* Define to 1 if you have the `strtoi' function. */
+/* #undef HAVE_STRTOI */
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if you have the `strtoui' function. */
+/* #undef HAVE_STRTOUI */
+
+/* Define to 1 if you have the `strtoul' function. */
+#define HAVE_STRTOUL 1
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the <sys/floppy.h> header file. */
+/* #undef HAVE_SYS_FLOPPY_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/signal.h> header file. */
+#define HAVE_SYS_SIGNAL_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysmacros.h> header file. */
+#define HAVE_SYS_SYSMACROS_H 1
+
+/* Define to 1 if you have the <sys/termios.h> header file. */
+/* #undef HAVE_SYS_TERMIOS_H */
+
+/* Define to 1 if you have the <sys/termio.h> header file. */
+/* #undef HAVE_SYS_TERMIO_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the `tcflush' function. */
+#define HAVE_TCFLUSH 1
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#define HAVE_TCSETATTR 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the `toupper_l' function. */
+#define HAVE_TOUPPER_L 1
+
+/* Define to 1 if you have the `tzset' function. */
+#define HAVE_TZSET 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `usleep' function. */
+#define HAVE_USLEEP 1
+
+/* Define to 1 if you have the `utime' function. */
+/* #undef HAVE_UTIME */
+
+/* Define to 1 if you have the `utimes' function. */
+#define HAVE_UTIMES 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcscasecmp' function. */
+#define HAVE_WCSCASECMP 1
+
+/* Define to 1 if you have the `wcsdup' function. */
+#define HAVE_WCSDUP 1
+
+/* Define to 1 if you have the `wcsnlen' function. */
+#define HAVE_WCSNLEN 1
+
+/* Define to 1 if you have the <wctype.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Define to 1 if you have the <xlocale.h> header file. */
+/* #undef HAVE_XLOCALE_H */
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if the `setpgrp' function takes no argument. */
+#define SETPGRP_VOID 1
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+/* #undef TM_IN_SYS_TIME */
+
+/* Define when you want to include floppyd support */
+#define USE_FLOPPYD 1
+
+/* Define on non Unix OS'es which don't have the concept of tty's */
+#define USE_RAWTERM 1
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+
+/* Define this if you want to use Xdf */
+#define USE_XDF 1
+
+/* 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 */
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* 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 for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT32_T */
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+/* #undef _UINT8_T */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* 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 the type of a signed integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int16_t */
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef int32_t */
+
+/* Define to the type of a signed integer type of width exactly 8 bits if such
+   a type exists and the standard includes do not define it. */
+/* #undef int8_t */
+
+/* Define to `long int' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef ssize_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint16_t */
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint32_t */
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+   such a type exists and the standard includes do not define it. */
+/* #undef uint8_t */
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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <signal.h>
+#define SYSCONFDIR "/boot/system"
+#define USE_RAWTERM
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..783ee60
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,508 @@
+/* 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 `alarm' function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <assert.h> 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 the system has the type `caddr_t'. */
+#undef HAVE_CADDR_T
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the <fcntl.h> 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 <getopt.h> 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 <iconv.h> header file. */
+#undef HAVE_ICONV_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_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 <libc.h> header file. */
+#undef HAVE_LIBC_H
+
+/* Define to 1 if you have the `iconv' library (-liconv). */
+#undef HAVE_LIBICONV
+
+/* 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 <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+#undef HAVE_LINUX_FS_H
+
+/* Define to 1 if you have the <linux/unistd.h> 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 <locale.h> 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 <malloc.h> 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 <memory.h> 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 <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_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 <sgtty.h> header file. */
+#undef HAVE_SGTTY_H
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the <signal.h> 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 <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> 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 <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> 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 `strncasecmp_l' function. */
+#undef HAVE_STRNCASECMP_L
+
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
+/* 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 `strtoi' function. */
+#undef HAVE_STRTOI
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define to 1 if you have the `strtoui' function. */
+#undef HAVE_STRTOUI
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/floppy.h> header file. */
+#undef HAVE_SYS_FLOPPY_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/signal.h> header file. */
+#undef HAVE_SYS_SIGNAL_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/sysmacros.h> header file. */
+#undef HAVE_SYS_SYSMACROS_H
+
+/* Define to 1 if you have the <sys/termios.h> header file. */
+#undef HAVE_SYS_TERMIOS_H
+
+/* Define to 1 if you have the <sys/termio.h> header file. */
+#undef HAVE_SYS_TERMIO_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> 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 <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define to 1 if you have the `toupper_l' function. */
+#undef HAVE_TOUPPER_L
+
+/* Define to 1 if you have the `tzset' function. */
+#undef HAVE_TZSET
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `usleep' function. */
+#undef HAVE_USLEEP
+
+/* 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 <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if you have the <wchar.h> 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 <wctype.h> header file. */
+#undef HAVE_WCTYPE_H
+
+/* Define to 1 if you have the <xlocale.h> header file. */
+#undef HAVE_XLOCALE_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 home page for this package. */
+#undef PACKAGE_URL
+
+/* 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
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `time_t', as computed by sizeof. */
+#undef SIZEOF_TIME_T
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> 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
+
+/* Enable large inode numbers on Mac OS X 10.5.  */
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* 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 for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+#undef _UINT32_T
+
+/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
+   <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
+   #define below would cause a syntax error. */
+#undef _UINT8_T
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* 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 the type of a signed integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+#undef int16_t
+
+/* Define to the type of a signed integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+#undef int32_t
+
+/* Define to the type of a signed integer type of width exactly 8 bits if such
+   a type exists and the standard includes do not define it. */
+#undef int8_t
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define to the type of an unsigned integer type of width exactly 16 bits if
+   such a type exists and the standard includes do not define it. */
+#undef uint16_t
+
+/* Define to the type of an unsigned integer type of width exactly 32 bits if
+   such a type exists and the standard includes do not define it. */
+#undef uint32_t
+
+/* Define to the type of an unsigned integer type of width exactly 8 bits if
+   such a type exists and the standard includes do not define it. */
+#undef uint8_t
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..dd2ca93
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1825 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
+
+timestamp='2016-11-04'
+
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# 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.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches to <config-patches@gnu.org>.
+#
+# 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.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
+# 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 or 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 <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2016 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-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | cloudabi*-eabi* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    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 | -microblaze*)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-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*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-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 \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| ba \
+	| be32 | be64 \
+	| bfin \
+	| c4x | c8051 | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| e2k | epiphany \
+	| fido | fr30 | frv | ft32 \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| k1om \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa32r6 | mipsisa32r6el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64r6 | mipsisa64r6el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
+	| ns16k | ns32k \
+	| open8 | or1k | or1knd | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pru \
+	| pyramid \
+	| riscv32 | riscv64 \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| visium \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	leon|leon[3-9])
+		basic_machine=sparc-$basic_machine
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-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-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| ba-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| e2k-* | elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| k1om-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa32r6-* | mipsisa32r6el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64r6-* | mipsisa64r6el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| or1k*-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pru-* \
+	| pyramid-* \
+	| riscv32-* | riscv64-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | 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-* | sv1-* | sx*-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| visium-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# 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
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	asmjs)
+		basic_machine=asmjs-unknown
+		;;
+	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
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	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 | 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
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	e500v[12])
+		basic_machine=powerpc-unknown
+		os=$os"spe"
+		;;
+	e500v[12]-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=$os"spe"
+		;;
+	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*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
+		;;
+	leon-*|leon[3-9]-*)
+		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+		;;
+	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
+		;;
+	microblaze*)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
+	mingw32)
+		basic_machine=i686-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
+		;;
+	moxiebox)
+		basic_machine=moxie-unknown
+		os=-moxiebox
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i686-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	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
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	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 | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle)
+		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)
+		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 | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
+		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
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	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
+		;;
+	tile*)
+		basic_machine=$basic_machine-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
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-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[24]aeb | 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.
+	-auroraux)
+		os=-auroraux
+		;;
+	-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* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* | -cloudabi* | -sortix* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
+	      | -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* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+	      | -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* | -es* \
+	      | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
+	# 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
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-ios)
+		;;
+	-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
+		;;
+	c8051-*)
+		os=-elf
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		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
+		;;
+	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
+				;;
+			-cnk*|-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..bf65254
--- /dev/null
+++ b/configure
@@ -0,0 +1,7903 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 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
+
+
+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
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (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
+
+
+# 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.
+as_myself=
+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
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="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_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    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_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+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
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+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'`
+
+# 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_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # 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; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # 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
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+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 -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+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='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# 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'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/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=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="buffer.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#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
+runstatedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+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
+enable_largefile
+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'
+runstatedir='${localstatedir}/run'
+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= ;;
+  *)    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_fn_error $? "invalid feature name: $ac_useropt"
+    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_fn_error $? "invalid feature name: $ac_useropt"
+    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 ;;
+
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
+  -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_fn_error $? "invalid package name: $ac_useropt"
+    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_fn_error $? "invalid package name: $ac_useropt"
+    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_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    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_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $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 runstatedir
+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_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+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
+  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_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# 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_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	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]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
+  --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         debugging messages
+  --enable-raw-term      raw terminal (readkey behaviour, default)
+  --disable-largefile     omit support for large files
+  --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<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  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.
+
+Report bugs to the package provider.
+_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.69
+
+Copyright (C) 2012 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
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_header_compiler=yes
+else
+  ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { 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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+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
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_find_intX_t LINENO BITS VAR
+# -----------------------------------
+# Finds a signed integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_intX_t ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5
+$as_echo_n "checking for int$2_t... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+     # Order is important - never check a type that is potentially smaller
+     # than half of the expected target width.
+     for ac_type in int$2_t 'int' 'long int' \
+	 'long long int' 'short int' 'signed char'; do
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+	     enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+	        enum { N = $2 / 2 - 1 };
+int
+main ()
+{
+static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1)
+		 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  case $ac_type in #(
+  int$2_t) :
+    eval "$3=yes" ;; #(
+  *) :
+    eval "$3=\$ac_type" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       if eval test \"x\$"$3"\" = x"no"; then :
+
+else
+  break
+fi
+     done
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_find_intX_t
+
+# ac_fn_c_find_uintX_t LINENO BITS VAR
+# ------------------------------------
+# Finds an unsigned integer type with width BITS, setting cache variable VAR
+# accordingly.
+ac_fn_c_find_uintX_t ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5
+$as_echo_n "checking for uint$2_t... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+     # Order is important - never check a type that is potentially smaller
+     # than half of the expected target width.
+     for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \
+	 'unsigned long long int' 'unsigned short int' 'unsigned char'; do
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  case $ac_type in #(
+  uint$2_t) :
+    eval "$3=yes" ;; #(
+  *) :
+    eval "$3=\$ac_type" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+       if eval test \"x\$"$3"\" = x"no"; then :
+
+else
+  break
+fi
+     done
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_find_uintX_t
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  eval "$3=no"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+	 return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+	    return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  eval "$3=yes"
+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
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if test "$cross_compiling" = yes; then
+    # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=0 ac_mid=0
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid; break
+else
+  as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+			if test $ac_lo -le $ac_mid; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=-1 ac_mid=-1
+  while :; do
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_lo=$ac_mid; break
+else
+  as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+			if test $ac_mid -le $ac_hi; then
+			  ac_lo= ac_hi=
+			  break
+			fi
+			as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  done
+else
+  ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+  as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_hi=$ac_mid
+else
+  as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+  else
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+  FILE *f = fopen ("conftest.val", "w");
+  if (! f)
+    return 1;
+  if (($2) < 0)
+    {
+      long int i = longval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%ld", i);
+    }
+  else
+    {
+      unsigned long int i = ulongval ();
+      if (i != ($2))
+	return 1;
+      fprintf (f, "%lu", i);
+    }
+  /* Do not output a trailing newline, as this causes \r\n confusion
+     on some platforms.  */
+  return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+  ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+  fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* 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 $2 ();
+/* 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_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+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.69.  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) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append 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
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset 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
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    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:${as_lineno-$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= ;; #(
+      *) { eval $ac_var=; 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
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    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
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      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
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      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'; as_fn_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
+
+$as_echo "/* confdefs.h */" > 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
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_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
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+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 /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$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" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  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.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$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:${as_lineno-$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:${as_lineno-$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:${as_lineno-$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:${as_lineno-$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:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$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.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$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_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$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:${as_lineno-$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:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$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:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; 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
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; 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:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { 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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; 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:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$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 ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  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:${as_lineno-$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:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; 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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+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:${as_lineno-$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:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* 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"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+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:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+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_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:${as_lineno-$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 ${ac_cv_prog_CPP+:} false; 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 <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> 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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i 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:${as_lineno-$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 <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> 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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+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:${as_lineno-$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 ${ac_cv_path_GREP+:} false; 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"
+      as_fn_executable_p "$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
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    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_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; 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"
+      as_fn_executable_p "$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
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    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_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
+$as_echo_n "checking whether $CC needs -traditional... " >&6; }
+if ${ac_cv_prog_gcc_traditional+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sgtty.h>
+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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <termio.h>
+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:${as_lineno-$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_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+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:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; 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 as_fn_executable_p "$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:${as_lineno-$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:${as_lineno-$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:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_INSTALL_INFO+:} false; 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 as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_INSTALL_INFO="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$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:${as_lineno-$LINENO}: result: $INSTALL_INFO" >&5
+$as_echo "$INSTALL_INFO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#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
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+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`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+  ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+  MINIX=yes
+else
+  MINIX=
+fi
+
+
+  if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+  fi
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#         define __EXTENSIONS__ 1
+          $ac_includes_default
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_safe_to_define___extensions__=yes
+else
+  ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$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 &&
+    $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+  $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+  $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+  $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; 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_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+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:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; 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_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+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:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; 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_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+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:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this sort of thing.  */
+  typedef int charset[2];
+  const charset cs = { 0, 0 };
+  /* 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 sort of thing.  */
+    char tx;
+    char *t = &tx;
+    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 sort of thing, saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; } bx;
+    struct s *b = &bx; 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
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_const=yes
+else
+  ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw
+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:${as_lineno-$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
+
+$as_echo "#define USE_XDF 1" >>confdefs.h
+
+fi
+else
+
+$as_echo "#define USE_XDF 1" >>confdefs.h
+
+fi
+
+
+
+# Check whether --enable-vold was given.
+if test "${enable_vold+set}" = set; then :
+  enableval=$enable_vold; if test x$enableval = xyes; then
+
+$as_echo "#define USING_VOLD 1" >>confdefs.h
+
+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
+
+$as_echo "#define USING_NEW_VOLD 1" >>confdefs.h
+
+fi
+fi
+
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug; if test x$enableval = xyes; then
+
+$as_echo "#define DEBUG 1" >>confdefs.h
+
+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
+
+$as_echo "#define USE_RAWTERM 1" >>confdefs.h
+
+fi
+else
+
+$as_echo "#define USE_RAWTERM 1" >>confdefs.h
+
+fi
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwnam in -lsun" >&5
+$as_echo_n "checking for getpwnam in -lsun... " >&6; }
+if ${ac_cv_lib_sun_getpwnam+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsun  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_sun_getpwnam=yes
+else
+  ac_cv_lib_sun_getpwnam=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sun_getpwnam" >&5
+$as_echo "$ac_cv_lib_sun_getpwnam" >&6; }
+if test "x$ac_cv_lib_sun_getpwnam" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSUN 1
+_ACEOF
+
+  LIBS="-lsun $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cam_open_device in -lcam" >&5
+$as_echo_n "checking for cam_open_device in -lcam... " >&6; }
+if ${ac_cv_lib_cam_cam_open_device+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcam  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_cam_cam_open_device=yes
+else
+  ac_cv_lib_cam_cam_open_device=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$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" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCAM 1
+_ACEOF
+
+  LIBS="-lcam $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv in -liconv" >&5
+$as_echo_n "checking for iconv in -liconv... " >&6; }
+if ${ac_cv_lib_iconv_iconv+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-liconv  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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 iconv ();
+int
+main ()
+{
+return iconv ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_iconv_iconv=yes
+else
+  ac_cv_lib_iconv_iconv=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_iconv_iconv" >&5
+$as_echo "$ac_cv_lib_iconv_iconv" >&6; }
+if test "x$ac_cv_lib_iconv_iconv" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBICONV 1
+_ACEOF
+
+  LIBS="-liconv $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#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
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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 ${ac_cv_header_sys_wait_h+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/wait.h>
+#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
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_sys_wait_h=yes
+else
+  ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+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 io.h signal.h sys/signal.h utime.h sgtty.h \
+sys/floppy.h mntent.h sys/sysmacros.h netinet/in.h netinet/tcp.h assert.h \
+iconv.h wctype.h wchar.h locale.h xlocale.h linux/fs.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = 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`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = 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`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+
+done
+
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+  enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if ${ac_cv_sys_largefile_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_sys_largefile_CC=no
+     if test "$GCC" != yes; then
+       ac_save_CC=$CC
+       while :; do
+	 # IRIX 6.2 and later do not support large files by default,
+	 # so use the C compiler's -n32 option if that helps.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+	 if ac_fn_c_try_compile "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext
+	 CC="$CC -n32"
+	 if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+	 break
+       done
+       CC=$ac_save_CC
+       rm -f conftest.$ac_ext
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+  if test "$ac_cv_sys_largefile_CC" != no; then
+    CC=$CC$ac_cv_sys_largefile_CC
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if ${ac_cv_sys_file_offset_bits+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_file_offset_bits=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  if test $ac_cv_sys_file_offset_bits = unknown; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if ${ac_cv_sys_large_files+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+		       && LARGE_OFF_T % 2147483647 == 1)
+		      ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_large_files=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  fi
+
+
+fi
+
+ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t"
+case $ac_cv_c_int8_t in #(
+  no|yes) ;; #(
+  *)
+
+cat >>confdefs.h <<_ACEOF
+#define int8_t $ac_cv_c_int8_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t"
+case $ac_cv_c_int16_t in #(
+  no|yes) ;; #(
+  *)
+
+cat >>confdefs.h <<_ACEOF
+#define int16_t $ac_cv_c_int16_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t"
+case $ac_cv_c_int32_t in #(
+  no|yes) ;; #(
+  *)
+
+cat >>confdefs.h <<_ACEOF
+#define int32_t $ac_cv_c_int32_t
+_ACEOF
+;;
+esac
+
+ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t"
+case $ac_cv_c_uint8_t in #(
+  no|yes) ;; #(
+  *)
+
+$as_echo "#define _UINT8_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint8_t $ac_cv_c_uint8_t
+_ACEOF
+;;
+  esac
+
+ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t"
+case $ac_cv_c_uint16_t in #(
+  no|yes) ;; #(
+  *)
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint16_t $ac_cv_c_uint16_t
+_ACEOF
+;;
+  esac
+
+ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t"
+case $ac_cv_c_uint32_t in #(
+  no|yes) ;; #(
+  *)
+
+$as_echo "#define _UINT32_T 1" >>confdefs.h
+
+
+cat >>confdefs.h <<_ACEOF
+#define uint32_t $ac_cv_c_uint32_t
+_ACEOF
+;;
+  esac
+
+ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default"
+if test "x$ac_cv_type_ssize_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define ssize_t int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define off_t long int
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if ${ac_cv_type_signal+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_type_signal=int
+else
+  ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$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
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5
+$as_echo_n "checking for uid_t in sys/types.h... " >&6; }
+if ${ac_cv_type_uid_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "uid_t" >/dev/null 2>&1; then :
+  ac_cv_type_uid_t=yes
+else
+  ac_cv_type_uid_t=no
+fi
+rm -f conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5
+$as_echo "$ac_cv_type_uid_t" >&6; }
+if test $ac_cv_type_uid_t = no; then
+
+$as_echo "#define uid_t int" >>confdefs.h
+
+
+$as_echo "#define gid_t int" >>confdefs.h
+
+fi
+
+
+ac_fn_c_check_type "$LINENO" "caddr_t" "ac_cv_type_caddr_t" "$ac_includes_default"
+if test "x$ac_cv_type_caddr_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_CADDR_T 1
+_ACEOF
+
+
+fi
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if ${ac_cv_sizeof_size_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_size_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (size_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_size_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of time_t" >&5
+$as_echo_n "checking size of time_t... " >&6; }
+if ${ac_cv_sizeof_time_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (time_t))" "ac_cv_sizeof_time_t"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_time_t" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (time_t)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_time_t=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_time_t" >&5
+$as_echo "$ac_cv_sizeof_time_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_TIME_T $ac_cv_sizeof_time_t
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if ${ac_cv_sizeof_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
+$as_echo "$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5
+$as_echo_n "checking size of long long... " >&6; }
+if ${ac_cv_sizeof_long_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long"        "$ac_includes_default"; then :
+
+else
+  if test "$ac_cv_type_long_long" = yes; then
+     { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (long long)
+See \`config.log' for more details" "$LINENO" 5; }
+   else
+     ac_cv_sizeof_long_long=0
+   fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5
+$as_echo "$ac_cv_sizeof_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long
+_ACEOF
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether llseek declared in unistd.h" >&5
+$as_echo_n "checking whether llseek declared in unistd.h... " >&6; }
+if ${mtools_cv_have_llseek_prototype+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+extern int llseek(int);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  mtools_cv_have_llseek_prototype=no
+else
+  mtools_cv_have_llseek_prototype=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_LLSEEK_PROTOTYPE 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lseek64 declared in unistd.h" >&5
+$as_echo_n "checking whether lseek64 declared in unistd.h... " >&6; }
+if ${mtools_cv_have_lseek64_prototype+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include "sysincludes.h"
+#include <unistd.h>
+
+int
+main ()
+{
+extern int lseek64(int);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  mtools_cv_have_lseek64_prototype=no
+else
+  mtools_cv_have_lseek64_prototype=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_LSEEK64_PROTOTYPE 1" >>confdefs.h
+
+fi
+
+
+for ac_func in htons
+do :
+  ac_fn_c_check_func "$LINENO" "htons" "ac_cv_func_htons"
+if test "x$ac_cv_func_htons" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_HTONS 1
+_ACEOF
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this sort of thing.  */
+  typedef int charset[2];
+  const charset cs = { 0, 0 };
+  /* 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 sort of thing.  */
+    char tx;
+    char *t = &tx;
+    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 sort of thing, saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; } bx;
+    struct s *b = &bx; 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
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_const=yes
+else
+  ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_inline=$ac_kw
+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:${as_lineno-$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
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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 ${ac_cv_header_time+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_time=yes
+else
+  ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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 ${ac_cv_struct_tm+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+				     int *p = &tm.tm_sec;
+				     return !p;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_struct_tm=time.h
+else
+  ac_cv_struct_tm=sys/time.h
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if ${ac_cv_type_signal+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_type_signal=int
+else
+  ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$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 strndup strcspn strspn strtoul strtol strtoll strtoi strtoui \
+memcpy strpbrk memset setenv seteuid setresuid setpgrp \
+tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \
+snprintf stat64 setlocale toupper_l strncasecmp_l \
+wcsdup wcscasecmp wcsnlen putwc \
+getuserid getgroupid \
+alarm sigaction usleep
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit off_t" >&5
+$as_echo_n "checking for 64-bit off_t... " >&6; }
+if ${sfs_cv_off_t_64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+switch (0) case 0: case (sizeof (off_t) <= 4):;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  sfs_cv_off_t_64=no
+else
+  sfs_cv_off_t_64=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_OFF_T_64 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports loff_t type" >&5
+$as_echo_n "checking whether ${CC} supports loff_t type... " >&6; }
+if ${ice_cv_have_loff_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+int
+main ()
+{
+loff_t a;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ice_cv_have_loff_t=yes
+else
+  ice_cv_have_loff_t=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_LOFF_T 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports offset_t type" >&5
+$as_echo_n "checking whether ${CC} supports offset_t type... " >&6; }
+if ${ice_cv_have_offset_t+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+int
+main ()
+{
+offset_t a;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ice_cv_have_offset_t=yes
+else
+  ice_cv_have_offset_t=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_OFFSET_T 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports long long type" >&5
+$as_echo_n "checking whether ${CC} supports long long type... " >&6; }
+if ${ice_cv_have_long_long+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+long long a;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ice_cv_have_long_long=yes
+else
+  ice_cv_have_long_long=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define HAVE_LONG_LONG 1" >>confdefs.h
+
+fi
+
+
+
+for ac_func in utimes utime
+do :
+  as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = 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`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking declaration of sys_errlist" >&5
+$as_echo_n "checking declaration of sys_errlist... " >&6; }
+if ${cf_cv_dcl_sys_errlist+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+int
+main ()
+{
+char *c = (char *) *sys_errlist
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  cf_cv_dcl_sys_errlist=yes
+else
+  cf_cv_dcl_sys_errlist=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cf_cv_dcl_sys_errlist" >&5
+$as_echo "$cf_cv_dcl_sys_errlist" >&6; }
+test $cf_cv_dcl_sys_errlist = no ||
+$as_echo "#define DECL_SYS_ERRLIST 1" >>confdefs.h
+
+
+
+
+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
+    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_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:${as_lineno-$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_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #(
+    *,NONE | NONE,*) if ${ac_cv_have_x+:} false; 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/X11R7/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R7
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R7/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R7
+/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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <X11/Xlib.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+  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.i 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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <X11/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+  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 -f core conftest.err conftest.$ac_objext \
+    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:${as_lineno-$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:${as_lineno-$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.
+
+$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h
+
+  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:${as_lineno-$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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       X_LIBS="$X_LIBS -R$x_libraries"
+else
+  LIBS="$ac_xsave_LIBS -R $x_libraries"
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	  X_LIBS="$X_LIBS -R $x_libraries"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    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 confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dnet_dnet_ntoa=yes
+else
+  ac_cv_lib_dnet_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$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" = xyes; then :
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+    if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet_stub  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+  ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$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" = xyes; then :
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+    fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    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.
+    ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = xyes; then :
+
+fi
+
+    if test $ac_cv_func_gethostbyname = no; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+      if test $ac_cv_lib_nsl_gethostbyname = no; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_gethostbyname+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_bsd_gethostbyname=yes
+else
+  ac_cv_lib_bsd_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; 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.
+    ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = xyes; then :
+
+fi
+
+    if test $ac_cv_func_connect = no; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_connect+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_socket_connect=yes
+else
+  ac_cv_lib_socket_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = xyes; then :
+  X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+    fi
+
+    # Guillermo Gomez says -lposix is necessary on A/UX.
+    ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove"
+if test "x$ac_cv_func_remove" = xyes; then :
+
+fi
+
+    if test $ac_cv_func_remove = no; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if ${ac_cv_lib_posix_remove+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_posix_remove=yes
+else
+  ac_cv_lib_posix_remove=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = xyes; then :
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+    fi
+
+    # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+    ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat"
+if test "x$ac_cv_func_shmat" = xyes; then :
+
+fi
+
+    if test $ac_cv_func_shmat = no; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if ${ac_cv_lib_ipc_shmat+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lipc  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ipc_shmat=yes
+else
+  ac_cv_lib_ipc_shmat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = xyes; 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:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+  ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; 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:${as_lineno-$LINENO}: checking for main in -lsocket" >&5
+$as_echo_n "checking for main in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_main+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_socket_main=yes
+else
+  ac_cv_lib_socket_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5
+$as_echo "$ac_cv_lib_socket_main" >&6; }
+if test "x$ac_cv_lib_socket_main" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lbsd" >&5
+$as_echo_n "checking for main in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_main+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_bsd_main=yes
+else
+  ac_cv_lib_bsd_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_main" >&5
+$as_echo "$ac_cv_lib_bsd_main" >&6; }
+if test "x$ac_cv_lib_bsd_main" = xyes; 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`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = 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"
+
+$as_echo "#define USE_FLOPPYD 1" >>confdefs.h
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether setpgrp takes no argument" >&5
+$as_echo_n "checking whether setpgrp takes no argument... " >&6; }
+if ${ac_cv_func_setpgrp_void+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  as_fn_error $? "cannot check setpgrp when cross compiling" "$LINENO" 5
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* 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
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_func_setpgrp_void=no
+else
+  ac_cv_func_setpgrp_void=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$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
+
+$as_echo "#define SETPGRP_VOID 1" >>confdefs.h
+
+fi
+
+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:${as_lineno-$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= ;; #(
+      *) { eval $ac_var=; 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
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$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=
+U=
+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.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append 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:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_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}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_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
+
+
+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
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (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
+
+
+# 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.
+as_myself=
+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
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+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
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+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'`
+
+# 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
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+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 -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    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_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# 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
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=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.69.  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 and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, 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 the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 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=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    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 ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; 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"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append 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
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --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_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append 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_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  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= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# 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=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/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 {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+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_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  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_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  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 >>"\$ac_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
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_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 < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries 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[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+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 >"$ac_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_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  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
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$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_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+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_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[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="$ac_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_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append 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:${as_lineno-$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 >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    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"; as_fn_mkdir_p
+  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:${as_lineno-$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 "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$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 "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# 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 || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure-stamp b/configure-stamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/configure-stamp
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..5ff75c1
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,412 @@
+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 <http://www.gnu.org/licenses/>.
+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         debugging 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)
+AC_CHECK_LIB(iconv, iconv)
+
+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 io.h signal.h sys/signal.h utime.h sgtty.h \
+sys/floppy.h mntent.h sys/sysmacros.h netinet/in.h netinet/tcp.h assert.h \
+iconv.h wctype.h wchar.h locale.h xlocale.h linux/fs.h)
+AC_CHECK_HEADERS(termio.h sys/termio.h, [break])
+AC_CHECK_HEADERS(termios.h sys/termios.h, [break])
+
+dnl Check for types
+AC_SYS_LARGEFILE
+AC_TYPE_INT8_T
+AC_TYPE_INT16_T
+AC_TYPE_INT32_T
+AC_TYPE_UINT8_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_SSIZE_T
+AC_TYPE_SIZE_T
+AC_TYPE_OFF_T
+AC_TYPE_SIGNAL
+AC_TYPE_UID_T
+
+AC_CHECK_TYPES(caddr_t)
+AC_CHECK_SIZEOF(size_t)
+AC_CHECK_SIZEOF(time_t)
+AC_CHECK_SIZEOF(long)
+AC_CHECK_SIZEOF(long long)
+
+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 <unistd.h>], [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 <unistd.h>
+], [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 strndup strcspn strspn strtoul strtol strtoll strtoi strtoui \
+memcpy strpbrk memset setenv seteuid setresuid setpgrp \
+tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \
+snprintf stat64 setlocale toupper_l strncasecmp_l \
+wcsdup wcscasecmp wcsnlen putwc \
+getuserid getgroupid \
+alarm sigaction usleep)
+
+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 <unistd.h>
+#include <sys/types.h>
+],[
+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 <sys/types.h>],[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 <sys/types.h>],[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
+    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_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)
+dnl AC_CHECK_LIB(nsl,getpwnam)
+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])
+    AC_FUNC_SETPGRP
+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..ad5b3d0
--- /dev/null
+++ b/copyfile.c
@@ -0,0 +1,75 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+#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;
+	ssize_t 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, (size_t) ret)) != ret){
+			if(retw < 0 )
+				perror("write in copy");
+			else
+				fprintf(stderr,
+					"Short write %lu instead of %d\n",
+					(unsigned long) 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..f98e47c
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,229 @@
+mtools (4.0.26) stable; urgency=low
+  * Fix compilation on Macintosh
+  * Ignore image file locking errors if we are performing a read-only access anyways
+  * Minor man-page fixes
+ -- Alain Knaff <alain@knaff.lu>  Sat, 28 Nov 2020 12:46:04 +0100
+mtools (4.0.25) stable; urgency=low
+  * Preserve non-updated contents of info sector, just in case it contains program code
+  * When parsing config file, always use "C" locale for case-insensitive comparisons
+ -- Alain Knaff <alain@knaff.lu>  Sat, 24 Oct 2020 16:53:52 +0200
+mtools (4.0.24) stable; urgency=low
+  * Spelling fixes in documentation
+  * Permit calling "make install" with >= -j2
+  * Added AC_SYS_LARGEFILE, needed for compiling on certain ARM procs
+
+ -- Alain Knaff <alain@knaff.lu>  Sun, 22 Mar 2020 07:45:19 +0100
+mtools (4.0.23) stable; urgency=low
+  * Address lots of compiler warnings (assignments between different types)
+  * Network speedup fixes for floppyd (TCP_CORK)
+  * Typo fixes
+  * Explicitly pass available target buffer size for character set conversions
+
+ -- Alain Knaff <alain@knaff.lu>  Sun,  9 Dec 2018 23:26:50 +0100
+mtools (4.0.22) stable; urgency=low
+  * Fixed -f flag for mformat (size is KBytes, rather than sectors)
+  * Fixed toupper/tolower usage (unsigned char rather than plain signed)
+ -- Alain Knaff <alain@knaff.lu>  Sun,  2 Dec 2018 18:29:59 +0100
+
+mtools (4.0.21) stable; urgency=low
+  * Fixed compilation for MingW
+  * After MingW compilation, make sure executable has .exe extension
+  * Addressed compiler warnings
+  * Fixed length handling in character set conversion (Unicode file names)
+  * Fixed matching of character range, when containing Unicode characters (mdir "c:test[α-ω].exe")
+  * Fixed initialization of my_scsi_cmd constructor
+ -- Alain Knaff <alain@knaff.lu>  Sat, 24 Nov 2018 09:50:03 +0100
+
+mtools (4.0.20) stable; urgency=low
+  * initialize directory entries to 0
+  * bad message "Too few sectors" replaced with "Too many sectors"
+  * apostrophe in mlabel no longer causes generation of long entry
+  * option to fake system date for file creation using the SOURCE_DATE_EPOCH environment variables
+  * can now be compiled with "clang" compiler
+  * fallback function for strndup, for those platforms that don't have it
+  * fixed a number of -Wextra warnings
+  * new compressed archive formats for uz/lz
+  * allow to specify number of reserved sectors for FAT32.
+  * file/device locking with timeout (rather than immediate failure)
+  * fixed support for BPB-less legacy formats.
+  * removed check that disk must be an integer number of tracks.
+  * removed .eh/.oh macros from manual pages
+ -- Alain Knaff <alain@knaff.lu>  Sun, 11 Nov 2018 14:56:06 +0100
+
+mtools (4.0.19) stable; urgency=low
+  * Fix for short file names starting with character 0xE5
+  (by remapping it to 0x5)
+  * mpartition: Partition types closer to what Microsoft uses
+  * mformat: figure out LBA geometry as last resort if geometry
+  * is neither specified in config and/or commandline, nor can be
+  * queried from the device
+  * mformat: use same default cluster size by size as Microsoft
+  for FAT32
+  * additional sanity checks
+  * document how cluster size is picked in mformat.c man page
+  * document how partition types are picked in mpartition.c man page
+ -- Alain Knaff <alain@knaff.lu>  Thu, 29 Sep 2018 12:00:00 +0200
+mtools (4.0.18) stable; urgency=low
+  * Fix for names of iconv encodings on AIX
+  * Fix mt_size_t on NetBSD
+  * Fixed compilation on Mingw
+  * Fixed doc (especially mformat)
+  * Fix mformat'ing of FAT12 filesystems with huge cluster sizes
+  * Minfo prints image file name in mformat command line if an image
+  * file name was given
+  * Always generate gzip-compressed RPMs, in order to remain
+  * compatible with older distributions
+  * Fixed buffer overflow with drive letter in mclasserase
+ -- Alain Knaff <alain@knaff.lu>  Wed,  9 Jan 2013 00:21:20 +0200
+mtools (4.0.17) stable; urgency=low
+
+  * mbadblocks now takes a list of bad blocks (either as sectors
+    or as clusters)
+  * mbadblocks now is able to do write scanning for bad blocks
+  * mshowfat can show cluster of specific offset
+  * Enable mtools to deal with very small sector sizes...
+  * Fixed encoding of all-lowercase names (no need to mangle
+    these)
+  * Consider every directory entry after an ENDMARK (0x00) to be deleted
+  * After writing a new entry at end of a directory, be sure to also add
+    an ENDMARK (0x00)
+  * Deal with possibility of a NULL pointer being returned by
+    localtime during timestamp conversion
+ -- Alain Knaff <alain@knaff.lu>  Wed, 29 Jun 2011 00:21:20 +0200
+mtools (4.0.16) stable; urgency=low
+
+  * configure.in fixes
+  * fixed formatting of fat_size_calculation.tex document
+  * compatibility with current autoconfig versions
+  * Make it clear that label is limited to 11 characters
+  * Fixed typo in initialization of FAT32 info sector
+
+ -- Alain Knaff <alain@knaff.lu>  Sat, 16 Apr 2011 18:00:30 +0200
+mtools (4.0.15) stable; urgency=low
+
+  * Added missing -i option to mshortname
+  * Split .deb package into mtools and floppyd in order to
+    match Ubuntu
+
+ -- Alain Knaff <alain@knaff.lu>  Sun, 17 Oct 2010 19:42:46 +0200
+mtools (4.0.14) stable; urgency=low
+
+  * New mshortname command
+  * Fix floppyd for disks bigger than 2 Gig
+  * Remove obsolete -z flag
+  * Remove now unsupported AC_USE_SYSTEM_EXTENSIONS
+  * Fixed output formatting of mdir if MTOOLS_DOTTED_DIR is set
+  * Mformat now correctly writes backup boot sector
+  * Fixed signedness of serial number in mlabel
+  * Fixed buffer size problem in mlabel
+  * Make mlabel write backup boot sector if FAT32
+  * Catch situation where both clear and new label are given to mlabel
+  * Quote filename parameters to scripts
+  * Mformat: Close file descriptor for boot sector
+  * Added lzip support to scripts/uz
+  * Added Tot_sectors option to mformat
+  * Fixed hidden sector handling in mformat
+  * Minfo generates mformat command lines containing new -T option
+  * Mlabel prints error if label too long
+
+ -- Alain Knaff <alain@knaff.lu>  Tue, 12 Oct 2010 00:19:48 +0200
+mtools (4.0.13) stable; urgency=low
+
+  * Merged Debian patches
+
+ -- Alain Knaff <alain@knaff.lu>  Sun, 28 Feb 2010 15:33:45 +0100
+mtools (4.0.12) stable; urgency=low
+
+  * Mingw compatibility fixes
+
+ -- Alain Knaff <alain@knaff.lu>  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 <alain@knaff.lu>  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 <alain@knaff.lu>  Tue,  3 Mar 2009 22:14:04 +0100
+mtools (4.0.9) stable; urgency=low
+
+  * More copyright stuff
+
+ -- Alain Knaff <alain@knaff.lu>  Mon,  2 Mar 2009 22:15:54 +0100
+mtools (4.0.8) stable; urgency=low
+
+  * Copyright notices
+
+ -- Alain Knaff <alain@knaff.lu>  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 <alain@knaff.lu>  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 <alain@knaff.lu>  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 <alain@knaff.lu>  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 <alain@knaff.lu>  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 <alain@knaff.lu>  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 <alain@knaff.lu>  Mon, 26 Jan 2009 22:58:06 +0100
+mtools (4.0.1) stable; urgency=low
+
+  * Missing functions on Solaris
+
+ -- Alain Knaff <alain@knaff.lu>  Sun,  7 Dec 2008 21:38:55 +0100
+mtools (4.0.0) stable; urgency=low
+
+  * Offset for -i-specified image files
+
+ -- Alain Knaff <alain@knaff.lu>  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 <alain@knaff.lu>  Tue, 18 Nov 2008 22:42:23 +0100
+mtools (4.0.0-pre1) stable; urgency=low
+
+  * Unicode support
+
+ -- Alain Knaff <alain@knaff.lu>  Sat,  1 Nov 2008 20:52:58 +0100
+mtools (3.9.11-20071226) stable; urgency=low
+
+  * first release of debian package
+
+ -- Alain Knaff <alain@knaff.lu>  Tue, 28 Aug 2007 23:23:37 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..ec00b44
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,31 @@
+Source: mtools
+Build-Depends: debhelper (>= 7), autotools-dev, libxt-dev, texinfo
+Section: otherosfs
+Priority: optional
+Maintainer: Alain Knaff <alain@knaff.lu>
+Homepage: http://www.mtools.linux.lu/
+
+Package: floppyd
+Priority: extra
+Architecture: any
+Replaces: mtools (<< 3.9.7)
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Suggests: mtools
+Description: Daemon for remote access to floppy drives
+ 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.
+
+Package: mtools
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Provides: mtools
+Suggests: floppyd
+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.
diff --git a/debian/floppyd.files b/debian/floppyd.files
new file mode 100644
index 0000000..8383412
--- /dev/null
+++ b/debian/floppyd.files
@@ -0,0 +1 @@
+usr/bin/floppyd*
diff --git a/debian/floppyd.manpages b/debian/floppyd.manpages
new file mode 100644
index 0000000..427671f
--- /dev/null
+++ b/debian/floppyd.manpages
@@ -0,0 +1,2 @@
+floppyd.1
+floppyd_installtest.1
diff --git a/debian/mcheck.1 b/debian/mcheck.1
new file mode 100644
index 0000000..6eece5c
--- /dev/null
+++ b/debian/mcheck.1
@@ -0,0 +1,33 @@
+.\" mcheck (package: mtools) 2003-05-04
+.TH mcheck 1 "May 2003" "mtools"
+.SH NAME
+mcheck \- verify all files on an MS-DOS formatted disk 
+.SH SYNOPSIS
+.PP
+.B mcheck
+[\fImsdosdrive\fR]
+.SH DESCRIPTION
+.\" Putting a newline after each sentence can generate better output.
+mcheck is a script that verifies all files on a MS-DOS formatted disk by
+reading them using 
+.BR mtype (1)
+
+The optional argument specifies the MS-DOS drive letter of the disk 
+to be checked. A: is used by default.
+
+.SH LICENSE
+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.
+
+.SH AUTHOR
+mcheck was written by David C. Niemi <niemi@tuxers.net>
+
+This manual page was written by Rabin Vincent <r.vincent@iu-bremen.de>
+for the Debian GNU/Linux system (but may be used by others).
+ 
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR mdir (1),
+.BR mtype (1)
diff --git a/debian/mtools.conf b/debian/mtools.conf
new file mode 100644
index 0000000..4f6805c
--- /dev/null
+++ b/debian/mtools.conf
@@ -0,0 +1,25 @@
+# Debian default mtools.conf file.
+# "info mtools" or "man mtools.conf" for more detail.
+
+# # 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 hdimage.
+drive m: file="/var/lib/dosemu/hdimage.first" partition=1 offset=128
+
+# # dosemu floppy image
+drive n: file="/var/lib/dosemu/fdimage"
+
+# # SCSI zip disk
+# drive z: file="/dev/sda4"
+
+# # uncomment the following line to display all file names in lower
+# # case by default
+# mtools_lower_case=1
diff --git a/debian/mtools.files b/debian/mtools.files
new file mode 100644
index 0000000..e772481
--- /dev/null
+++ b/debian/mtools.files
@@ -0,0 +1 @@
+usr/bin
diff --git a/debian/mtools.manpages b/debian/mtools.manpages
new file mode 100644
index 0000000..be24a60
--- /dev/null
+++ b/debian/mtools.manpages
@@ -0,0 +1,33 @@
+lz.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
+mshortname.1
+mshowfat.1
+mtools.1
+mtoolstest.1
+mtype.1
+mzip.1
+tgz.1
+uz.1
+mxtar.1
+mcomp.1
+mtools.5
+debian/mcheck.1
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..768e6c9
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,64 @@
+#!/usr/bin/make -f
+# rules for mtools package
+# by Luis Bustamante (luferbu@fluidsignal.com)
+
+export DH_VERBOSE=1
+DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+configure: configure-stamp
+configure-stamp:
+	dh_testdir
+	cp -f /usr/share/misc/config.sub /usr/share/misc/config.guess .
+	./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr \
+	    --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --sysconfdir=/etc
+	touch configure-stamp
+
+build: patch build-stamp
+build-stamp: configure-stamp
+	dh_testdir
+	$(MAKE)
+	touch build-stamp
+
+clean: unpatch
+	dh_testdir
+	dh_testroot
+	rm -rf build-stamp configure-stamp
+	rm -rf config.sub config.guess
+	[ ! -f Makefile ] || $(MAKE) distclean
+	dh_clean config.cache config.log config.status .#patchlevel.c.1.18 .#mtools.spec.1.4 .#mtools.texi.1.11 .#fat_size_calculation.tex.1.1
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_prep
+	dh_installdirs
+	$(MAKE) install prefix=$$( pwd )/debian/tmp/usr
+	[ -d debian/mtools/etc/ ] || mkdir -p debian/mtools/etc
+	install -m 644 debian/mtools.conf debian/mtools/etc/
+	dh_movefiles
+
+binary-indep:
+binary-arch: mtools
+binary: binary-indep binary-arch
+
+mtools: build install
+	dh_testdir
+	dh_testroot
+	dh_installdocs
+	dh_installexamples -pmtools mtools.conf
+	dh_installman
+	dh_installinfo -pmtools mtools.info
+	dh_installchangelogs
+	dh_strip
+	dh_link -pmtools /usr/share/man/man5/mtools.5 /usr/share/man/man5/mtools.conf.5
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+.PHONY: build clean binary-indep binary-arch binary install \
+	mtools patch clean-build unpatch configure
diff --git a/devices.c b/devices.c
new file mode 100644
index 0000000..f9d894e
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * 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),0,0}
+
+
+
+#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
+ * <frank@math.hmc.edu> */
+	{"/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 <simao@iris.ctd.comsat.com> */
+	{"/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
+ * <paolo@to.sem.it>, may cause "Not a typewriter" messages on other
+ * versions according to support@vital.com */
+
+#include <sys/floppy.h>
+#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 <sys/vtoc.h>
+#include <sys/sysmacros.h>
+#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 <chris@rivers.dra.hmg.gb> */
+#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 <ofer@stat.Berkeley.EDU>, May 14, 1997.
+ */
+
+#define INIT_GENERIC
+
+#include <sys/fdio.h>
+#include <sys/mkdev.h>	/* 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 <sys/ioctl.h>
+#include <sun/dkio.h>
+
+#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
+
+static 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, 0, 0},
+	{"/dev/fd1", 'B', 0, 0, 0,0, 0,0, FDEF_ARG, 0, 0},
+	/* we assume that the Zip or Jaz drive is the second on the SCSI bus */
+	{"/dev/sdb4",'J', GENHD, 0, 0 },
+	{"/dev/sdb4",'Z', GENHD, 0, 0 },
+	/*	{"/dev/sda4",'D', GENHD, 0, 0 },*/
+	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 <jmz@FreeBSD.org> 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 <sys/gdioctl.h>
+
+#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 <sys/fcntl.h>
+#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 unsigned 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 unsigned int nr_const_devices = 0;
+#endif
diff --git a/devices.h b/devices.h
new file mode 100644
index 0000000..7ca2feb
--- /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 <http://www.gnu.org/licenses/>.
+ */
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_SYSMACROS_H
+
+#include <sys/sysmacros.h>
+#ifndef MAJOR
+#define MAJOR(dev) major(dev)
+#endif  /* MAJOR not defined */
+#ifndef MINOR
+#define MINOR(dev) minor(dev)
+#endif  /* MINOR not defined */
+
+#else
+ 
+#include <linux/fs.h>        /* get MAJOR/MINOR from Linux kernel */
+#ifndef major
+#define major(x) MAJOR(x)
+#endif
+
+#endif /* HAVE_SYS_SYSMACROS_H */
+
+#include <linux/fd.h>
+#include <linux/fdreg.h>
+#include <linux/major.h>
+
+
+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, uint8_t 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,uint8_t 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, uint8_t 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, 
+					   uint8_t sector))
+{
+	request->cmd[4] = sector;
+	request->cmd[6] = sector-1;
+}
+
+UNUSED(static __inline__ void RR_SETSIZECODE(struct floppy_raw_cmd *request, 
+					     uint8_t 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..006c544
--- /dev/null
+++ b/dirCache.c
@@ -0,0 +1,373 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+#include "sysincludes.h"
+#include "vfat.h"
+#include "dirCache.h"
+#include "dirCacheP.h"
+#include <assert.h>
+
+
+#define BITS_PER_INT (sizeof(unsigned int) * 8)
+
+
+static __inline__ uint32_t rol(uint32_t arg, int shift)
+{
+	arg &= 0xffffffff; /* for 64 bit machines */
+	return (arg << shift) | (arg >> (32 - shift));
+}
+
+
+static uint32_t calcHash(wchar_t *name)
+{
+	uint32_t hash;
+	unsigned int i;
+	wint_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((wint_t)*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 unsigned int addBit(unsigned int *bitmap,
+			   unsigned int hash, int checkOnly)
+{
+	unsigned int bit;
+	int entry;
+
+	bit = 1u << (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, unsigned int slot)
+{
+	if((int) slot < 0) {
+		fprintf(stderr, "Bad slot %d\n", slot);
+		exit(1);
+	}
+
+	if( cache->nr_entries <= slot) {
+		unsigned 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, unsigned int slot)
+{
+	dirCache_t **dcp;
+
+	if((int)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, sizeof((*dcp)->bm0));
+		memset( (*dcp)->bm1, 0, sizeof((*dcp)->bm1));
+		memset( (*dcp)->bm2, 0, sizeof((*dcp)->bm1));
+		(*dcp)->nrHashed = 0;
+	} else
+		if(growDirCache(*dcp, slot) < 0)
+			return 0;
+	return *dcp;
+}
+
+/* Free a range of entries. The range being cleared is always aligned
+ * on the begin of an entry. Entries which are cleared entirely are
+ * free'd. Entries which are cleared half-way (can only happen at end)
+ * are "shortened" by moving its beginSlot
+ * If this was a range representing space after end-mark, return beginning
+ * of range if it had been shortened in its lifetime (which means that end
+ * mark must have moved => may need to be rewritten)
+ */
+static int 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;
+		}
+		
+		/* Due to the way this is called, we _always_ de-allocate
+		 * starting from beginning... */
+		assert(entry->beginSlot == beginSlot);
+
+		clearEnd = entry->endSlot;
+		if(clearEnd > endSlot)
+			clearEnd = endSlot;
+		clearBegin = beginSlot;
+		
+		for(i = clearBegin; i <clearEnd; i++)
+			cache->entries[i] = 0;
+
+		entry->beginSlot = clearEnd;
+
+		if(entry->beginSlot == entry->endSlot) {
+			int needWriteEnd = 0;
+			if(entry->endMarkPos != -1 &&
+			   entry->endMarkPos < (int) beginSlot)
+				needWriteEnd = 1;
+
+			if(entry->longName)
+				free(entry->longName);
+			if(entry->shortName)
+				free(entry->shortName);
+			free(entry);
+			if(needWriteEnd) {
+				return (int) beginSlot;
+			}
+		}
+
+		beginSlot = clearEnd;
+	}
+	return -1;
+}
+
+static dirCacheEntry_t *allocDirCacheEntry(dirCache_t *cache,
+					   unsigned int beginSlot,
+					   unsigned int endSlot,
+					   dirCacheEntryType_t type)
+{
+	dirCacheEntry_t *entry;
+	unsigned 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;
+	entry->endMarkPos = -1;
+
+	freeDirCacheRange(cache, beginSlot, endSlot);
+	for(i=beginSlot; i<endSlot; i++) {
+		cache->entries[i] = entry;
+	}
+	return entry;
+}
+
+dirCacheEntry_t *addUsedEntry(dirCache_t *cache,
+			      unsigned int beginSlot,
+			      unsigned 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;
+}
+
+/* Try to merge free slot at position "slot" with slot at previous position
+ * After successful merge, both will point to a same DCE (the one which used
+ * to be previous)
+ * Only does something if both of these slots are actually free
+ */
+static void mergeFreeSlots(dirCache_t *cache, unsigned 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;
+		previous->endMarkPos = next->endMarkPos;
+		free(next);		
+	}
+}
+
+/* Create a free range extending from beginSlot to endSlot, and try to merge
+ * it with any neighboring free ranges */
+dirCacheEntry_t *addFreeEndEntry(dirCache_t *cache,
+				 unsigned int beginSlot,
+				 unsigned int endSlot,
+				 int isAtEnd)
+{
+	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);
+	if(isAtEnd)
+		entry->endMarkPos = (int) beginSlot;
+	mergeFreeSlots(cache, beginSlot);
+	mergeFreeSlots(cache, endSlot);
+	return cache->entries[beginSlot];
+}
+
+dirCacheEntry_t *addFreeEntry(dirCache_t *cache,
+			      unsigned int beginSlot,
+			      unsigned int endSlot)
+{
+	return addFreeEndEntry(cache, beginSlot, endSlot, 0);
+}
+
+dirCacheEntry_t *addEndEntry(dirCache_t *cache, unsigned int pos)
+{
+	return allocDirCacheEntry(cache, pos, pos+1u, DCET_END);
+}
+
+dirCacheEntry_t *lookupInDircache(dirCache_t *cache, unsigned 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) {
+		int n;
+		n=freeDirCacheRange(cache, 0, cache->nr_entries);
+		if(n >= 0)
+			low_level_dir_write_end(Stream, n);
+		free(cache);
+		*dcp = 0;
+	}
+}
diff --git a/dirCache.h b/dirCache.h
new file mode 100644
index 0000000..04f9f3e
--- /dev/null
+++ b/dirCache.h
@@ -0,0 +1,55 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+typedef enum {
+	DCET_FREE,
+	DCET_USED,
+	DCET_END
+} dirCacheEntryType_t;
+
+#define DC_BITMAP_SIZE 128
+
+typedef struct dirCacheEntry_t dirCacheEntry_t;
+
+typedef struct dirCache_t {
+	struct dirCacheEntry_t **entries;
+	unsigned 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, unsigned int slot);
+dirCache_t *allocDirCache(Stream_t *Stream, unsigned int slot);
+dirCacheEntry_t *addUsedEntry(dirCache_t *Stream,
+			      unsigned int begin,
+			      unsigned 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 *addFreeEndEntry(dirCache_t *Stream, 
+				 unsigned int begin, unsigned int end,
+				 int isAtEnd);
+dirCacheEntry_t *addEndEntry(dirCache_t *Stream, unsigned int pos);
+dirCacheEntry_t *lookupInDircache(dirCache_t *Stream, unsigned int pos);
+#endif
diff --git a/dirCacheP.h b/dirCacheP.h
new file mode 100644
index 0000000..1857ee4
--- /dev/null
+++ b/dirCacheP.h
@@ -0,0 +1,14 @@
+#ifndef DIRCACHEP_H
+#define DIRCACHEP_H
+
+struct dirCacheEntry_t {
+	dirCacheEntryType_t type;
+	unsigned int beginSlot;
+	unsigned int endSlot;
+	wchar_t *shortName;
+	wchar_t *longName;
+	struct directory dir;
+	int endMarkPos;
+} ;
+
+#endif /* DIRCACHEP_H */
diff --git a/directory.c b/directory.c
new file mode 100644
index 0000000..6a17aa0
--- /dev/null
+++ b/directory.c
@@ -0,0 +1,143 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+#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;
+	unsigned 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 < (int) 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);
+}
+
+void low_level_dir_write_end(Stream_t *Dir, int entry)
+{
+	char zero = ENDMARK;
+	force_write(Dir, &zero, (mt_off_t) entry * MDIR_SIZE, 1);
+}
+
+/*
+ * 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, unsigned 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, unsigned 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..3d79dc9
--- /dev/null
+++ b/direntry.c
@@ -0,0 +1,175 @@
+/*  Copyright 1997,2000-2003,2007-2010 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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)
+{
+	memset(entry, 0, sizeof(direntry_t));
+	entry->entry = -1;
+	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 size_t getPathLen(direntry_t *entry)
+{
+	size_t 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, size_t *len_available)
+{
+	if(entry->entry == -3) {
+		*ptr++ = getDrive(entry->Dir);
+		*ptr++ = ':';
+		*ptr++ = '/';
+		(*len_available) -= 3;
+	} else {
+		size_t bytes_converted;
+		ptr = sprintPwd(getDirentry(entry->Dir), ptr, len_available);
+		if(ptr[-1] != '/') {
+			*ptr++ = '/';
+			(*len_available)--;
+		}
+		bytes_converted = wchar_to_native(entry->name, ptr,
+						  MAX_VNAMELEN, *len_available);
+		ptr += bytes_converted;
+		(*len_available) -= bytes_converted;
+	}
+	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);
+}
+
+static void _fprintShortPwd(FILE *f, direntry_t *entry, int recurs)
+{
+	if(entry->entry == -3) {
+		putc(getDrive(entry->Dir), f);
+		putc(':', f);
+		if(!recurs)
+			putc('/', f);
+	} else {
+		int i,j;
+		_fprintShortPwd(f, getDirentry(entry->Dir), 1);
+		putc('/',f);
+		for(i=7; i>=0 && entry->dir.name[i] == ' ';i--);
+		for(j=0; j<=i; j++)
+			putc(entry->dir.name[j],f);
+		for(i=2; i>=0 && entry->dir.ext[i] == ' ';i--);
+		if(i > 0)
+			putc('.',f);
+		for(j=0; j<=i; j++)
+			putc(entry->dir.ext[j],f);
+	}
+}
+
+void fprintShortPwd(FILE *f, direntry_t *entry)
+{
+	_fprintShortPwd(f, entry, 0);
+}
+
+char *getPwd(direntry_t *entry)
+{
+	size_t size;
+	char *ret;
+	char *end;
+	size_t buf_size;
+
+	size = getPathLen(entry);
+	buf_size = size*4+1;
+	ret = malloc(buf_size);
+	if(!ret)
+		return 0;
+	end = sprintPwd(entry, ret, &buf_size);
+	*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..ccad8c4
--- /dev/null
+++ b/expand.c
@@ -0,0 +1,106 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * Do filename expansion with the shell.
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+#ifndef OS_mingw32msvc
+ssize_t safePopenOut(const char **command, char *output, size_t len)
+{
+	int pipefd[2];
+	pid_t pid;
+	int status;
+	ssize_t 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
+	ssize_t 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..e4419c3
--- /dev/null
+++ b/fat.c
@@ -0,0 +1,996 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 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)
+{
+	size_t nr_entries;
+	size_t 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<<This->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;
+
+	/*fprintf(stderr, "Fat write\n");*/
+
+	if (!This->fat_dirty)
+		return;
+
+	dups = This->num_fat;
+	if (This->fat_error)
+		dups = 1;
+
+
+	for(i=0; i<dups; i++){
+		j = 0;
+		for(slot=0;j<This->fat_len;slot++) {
+			if(!This->FatMap[slot].dirty) {
+				j += SECT_PER_ENTRY;
+				continue;
+			}
+			for(bit=0; 
+			    bit < SECT_PER_ENTRY && j<This->fat_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<<bit);
+			}
+		}
+	}
+	/* write the info sector, if any */
+	if(This->infoSectorLoc && This->infoSectorLoc != MAX32) {
+		/* initialize info sector */
+		InfoSector_t *infoSector;
+		infoSector = (InfoSector_t *) safe_malloc(This->sector_size);
+		if(forceReadSector(This, (char *)infoSector,
+				   This->infoSectorLoc, 1) !=
+		   (signed int) This->sector_size) {
+			fprintf(stderr,"Trouble reading the info sector\n");
+			memset(infoSector->filler1, 0, sizeof(infoSector->filler1));
+			memset(infoSector->filler2, 0, sizeof(infoSector->filler2));
+		}
+		set_dword(infoSector->signature1, INFOSECT_SIGNATURE1);
+		set_dword(infoSector->signature2, INFOSECT_SIGNATURE2);
+		set_dword(infoSector->pos, This->last);
+		set_dword(infoSector->count, This->freeSpace);
+		set_word(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)
+{
+	size_t 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, 
+			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,
+	   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, 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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..f5189a3
--- /dev/null
+++ b/fat_size_calculation.tex
@@ -0,0 +1,228 @@
+%  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 accommodate 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
+accommodate. 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 subtract 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..6ae7555
--- /dev/null
+++ b/file.c
@@ -0,0 +1,724 @@
+/*  Copyright 1996-1999,2001-2003,2007-2009,2011 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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;
+	size_t hint;
+	struct dirCache_t *dcp;
+
+	unsigned int loopDetectRel;
+	unsigned int loopDetectAbs;
+} File_t;
+
+static Class_t FileClass;
+static 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;
+	unsigned 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;
+	unsigned 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(">");
+	}
+}
+
+void printFatWithOffset(Stream_t *Stream, off_t offset) {
+	File_t *This = getUnbufferedFile(Stream);
+	unsigned long n;
+	int rel;
+	off_t clusSize;
+
+	n = This->FirstAbsCluNr;
+	if(!n) {
+		printf("Root directory or empty file\n");
+		return;
+	}
+
+	clusSize = This->Fs->cluster_size * This->Fs->sector_size;
+
+	rel = 0;
+	while(offset >= clusSize) {
+		n = fatDecode(This->Fs, n);
+		rel++;
+		if(loopDetect(This, rel, n) < 0)
+			return;
+		if(n > This->Fs->last_fat)
+			return;
+		offset -= clusSize;
+	}
+
+	printf("%lu", n);
+}
+
+static int normal_map(File_t *This, off_t where, size_t *len, int mode,
+						   mt_off_t *res)
+{
+	unsigned int offset;
+	size_t end;
+	int NrClu; /* number of clusters to read */
+	unsigned int RelCluNr;
+	unsigned int CurCluNr;
+	unsigned int NewCluNr;
+	unsigned int AbsCluNr;
+	unsigned 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 UNUSEDP,
+		    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;
+	}
+
+	sizemaximize(*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);
+	if(tmbuf) {
+		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,
+	0 /* discard */
+};
+
+static unsigned int getAbsCluNr(File_t *This)
+{
+	if(This->FirstAbsCluNr)
+		return This->FirstAbsCluNr;
+	if(isRootDir((Stream_t *) This))
+		return 0;
+	return 1;
+}
+
+static size_t func1(void *Stream)
+{
+	DeclareThis(File_t);
+
+	return getAbsCluNr(This) ^ (long) This->Fs;
+}
+
+static size_t 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..f7669c5
--- /dev/null
+++ b/file.h
@@ -0,0 +1,28 @@
+#ifndef MTOOLS_FILE_H
+#define MTOOLS_FILE_H
+/*  Copyright 1996,1997,2001,2002,2009,2011 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+#include "mtoolsDirentry.h"
+
+Stream_t *OpenFileByDirentry(direntry_t *entry);
+Stream_t *OpenRoot(Stream_t *Dir);
+void printFat(Stream_t *Stream);
+void printFatWithOffset(Stream_t *Stream, off_t offset);
+direntry_t *getDirentry(Stream_t *Stream);
+#endif
diff --git a/file_name.c b/file_name.c
new file mode 100644
index 0000000..8dac0aa
--- /dev/null
+++ b/file_name.c
@@ -0,0 +1,226 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#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, size_t ans_size)
+{
+	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, ans_size);
+	return ans;
+}
+
+typedef enum Case_l {
+	NONE,
+	UPPER,
+	LOWER
+} Case_t;
+
+static void TranslateToDos(doscp_t *toDos, const char *in, char *out,
+			   size_t count, char *end, Case_t *Case, int *mangled)
+{
+	wchar_t buffer[12];
+	wchar_t *s=buffer;
+	size_t t_idx = 0;
+
+	/* 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++) {
+		/* skip spaces & dots */
+		if(*s == ' ' || *s == '.') {
+			*mangled |= 3;
+			continue;
+		}
+
+		if (iswcntrl((wint_t)*s)) {
+			/* "control" characters */
+			*mangled |= 3;
+			buffer[t_idx] = '_';
+		} else if (iswlower((wint_t)*s)) {
+			buffer[t_idx] = ch_towupper(*s);
+			if(*Case == UPPER && !mtools_no_vfat)
+				*mangled |= 1;
+			else
+				*Case = LOWER;
+		} else if (iswupper((wint_t)*s)) {
+			buffer[t_idx] = *s;
+			if(*Case == LOWER && !mtools_no_vfat)
+				*mangled |= 1;
+			else
+				*Case = UPPER;
+		} else
+			buffer[t_idx] = *s;
+		t_idx++;
+	}
+	wchar_to_dos(toDos, buffer, out, t_idx, 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 UNUSEDP,
+	      int *mangled, dos_name_t *dn)
+{
+	char *s, *ext;
+	size_t i;
+	Case_t BaseCase, ExtCase = UPPER;
+
+	*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;
+	}
+}
+
+
+/*
+ * 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 (tname[0] == '\x05')
+		tname[0] = '\xE5';
+
+	if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case)
+		Case |= BASECASE | EXTCASE;
+
+	if(Case & BASECASE)
+		for(i=0;i<8 && tname[i];i++)
+			tname[i] = ch_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] = ch_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; j<num; ++j) {
+		if (*end_p)
+			/* Fill with 0xff */
+			out->uchar = out->lchar = 0xff;
+		else {
+			/* TODO / FIXME : handle case where wchat has more
+			 * than 2 bytes (i.e. bytes 2 or 3 are set.
+			 * ==> generate surrogate pairs?
+			 */
+			out->uchar = (*in & 0xffff) >> 8;
+			out->lchar = *in & 0xff;
+			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..cc7039a
--- /dev/null
+++ b/file_name.h
@@ -0,0 +1,49 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <sysincludes.h>
+#include "mtools.h"
+
+/**
+ * raw dos-name coming straight from the directory entry
+ * MYFILE  TXT
+ */
+struct dos_name_t {
+  char base[8] NONULLTERM;
+  char ext[3] NONULLTERM;
+  char sentinel;
+};
+
+int dos_to_wchar(doscp_t *fromDos, const 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, size_t out_len);
+
+#define WCHAR_TO_NATIVE(wchar,native,len) \
+	wchar_to_native((wchar),(native),(len),sizeof(native))
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#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..00b9eff
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,175 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#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,
+	0, /* get_dosconvert */
+	0  /* discard */
+};
+
+Stream_t *open_filter(Stream_t *Next, int convertCharset UNUSEDP)
+{
+	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..b6aa567
--- /dev/null
+++ b/floppyd.1
@@ -0,0 +1,255 @@
+'\" t
+.TH floppyd 1 "28Nov20" mtools-4.0.26
+.SH Name
+floppyd - floppy daemon for remote access to floppy 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
+.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 daemon 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 multi homed 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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..0dee036
--- /dev/null
+++ b/floppyd.c
@@ -0,0 +1,1327 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <john@nlc.net.au>
+ *
+ * Rewritten in C by Alain Knaff.  Apparently C++ is still not as
+ * portable as C.  */
+
+#define DEBUG 0
+
+#include "sysincludes.h"
+#include "llong.h"
+
+#ifdef USE_FLOPPYD
+
+#define USE_FLOPPYD_BUFFERED_IO  1
+
+#include "sysincludes.h"
+#include "grp.h"
+#include <X11/Xlib.h>
+#include <X11/Xauth.h>
+
+#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!
+	    
+*/
+
+
+#define MAX_XAUTHORITY_LENGTH    3000
+#define MAX_DATA_REQUEST         3000000
+#define BUFFERED_IO_SIZE         16348
+
+unsigned int mtools_lock_timeout=30;
+
+void serve_client(int sock, char **device_name, unsigned 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];
+	
+	size_t in_valid;
+	size_t in_start;
+	size_t 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 ret;
+	
+	if (nbytes <= buf->in_valid) {
+		memcpy(buffer, buf->in_buffer+buf->in_start, nbytes);
+		buf->in_valid -= nbytes;
+		buf->in_start += nbytes;
+		ret = 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) {
+			ssize_t rval = read(buf->handle, buffer, nbytes);
+			if (rval >= 0) {
+				ret = (size_t) rval + buf->in_valid;
+			} else {
+				perror("read error");
+				exit(1);
+			}
+			buf->in_valid = buf->in_start = 0;
+		} else {
+			ssize_t rval = read(buf->handle, buf->in_buffer, 
+					    BUFFERED_IO_SIZE);
+			if (rval >= 0) {
+				if (rval < (ssize_t) nbytes) {
+					memcpy(buffer, buf->in_buffer,
+					       (size_t) rval);
+					ret = (size_t) 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 = (size_t) rval-nbytes;
+					ret = a + nbytes;
+				}
+			} else {
+				perror("read error");
+				exit(1);
+			}
+		}
+	}
+	return ret;
+}
+
+static ssize_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 (ssize_t) 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));
+}
+
+ssize_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, Dword 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)
+{
+	Dword start;
+	size_t 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 ssize_t read_packet(Packet packet, int fd, Dword length) {
+	ssize_t ret;
+	make_new(packet, length);
+	ret = read(fd, packet->data, packet->len);
+	if(ret < 0)
+		return ret;
+	packet->len = (Dword) ret;
+	return 0;
+}
+
+static int write_packet(Packet packet, int fd) {
+	return (int)write(fd, packet->data, packet->len);
+}
+
+static void put_dword(Packet packet, int my_index, Dword val) {
+	dword2byte(val, packet->data+my_index);
+}
+
+static void put_qword(Packet packet, int my_index, Qword val) {
+	qword2byte(val, packet->data+my_index);
+}
+
+static Dword get_dword(Packet packet, int my_index) {
+	return byte2dword(packet->data+my_index);
+}	
+
+static Qword get_qword(Packet packet, int my_index) {
+	return byte2qword(packet->data+my_index);
+}	
+
+static Dword get_length(Packet packet) {
+	return packet->len;
+}
+
+static int eat(unsigned char **ptr, size_t *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, unsigned int *version) 
+{
+	int fd;
+	Display* displ;
+	Packet proto_version = newPacket();
+	Packet mit_cookie;
+	unsigned char *ptr;
+	size_t len;
+
+	char authFile[41]="/tmp/floppyd.XXXXXX";
+	unsigned 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 {
+		Dword cap = FLOPPYD_CAP_EXPLICIT_OPEN;
+		if(sizeof(mt_off_t) >= 8) {
+			cap |= FLOPPYD_CAP_LARGE_SEEK;
+		}
+		make_new(reply, 12);
+		put_dword(reply, 0, AUTH_SUCCESS);
+		put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION);
+		put_dword(reply, 8, cap);
+	}
+	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((char*)ptr+1, 4088);
+	len = strlen((char*)ptr+1);
+	*ptr++ = (unsigned char) len;
+	ptr += len;
+	*ptr++ = 0;
+	*ptr++ = 1;
+	*ptr++ = '0'; /* Display number */
+	*ptr++ = '\0';
+
+	if(write(fd, template, len+8) < (ssize_t) (len + 8)) {
+		close(fd);
+		return 0;
+	}
+	ptr = 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) < (ssize_t) 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 uint16_t getportnum(char *portnum)
+{
+	char		*digits = portnum;
+	struct servent	*serv;
+	uint16_t	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 = 0;
+				}
+			endservent();
+		}
+
+#if DEBUG
+	fprintf(stderr, "Port lookup %s -> %hd\n", portnum, port);
+#endif
+
+	return (port);
+}
+
+/*
+ * Return the IP address of the specified host.
+ */
+static in_addr_t getipaddress(char *ipaddr)
+{
+	struct hostent	*host;
+	in_addr_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(in_addr_t bind_ip, uint16_t 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 UNUSEDP) NORETURN;
+static void alarm_signal(int a UNUSEDP)
+{
+	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,
+			     unsigned  int n_dev) NORETURN;
+static void server_main_loop(int sock, char **device_name,
+			     unsigned 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) NORETURN;
+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;
+	in_addr_t		bind_ip = INADDR_ANY;
+	uint16_t		bind_port = 0;
+	uid_t			run_uid = 65535;
+	gid_t			run_gid = 65535;
+	char*			username = strdup("nobody");
+	int			sock;
+
+	char **device_name = NULL; 
+	const char *floppy0 = "/dev/fd0";
+	unsigned 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;
+						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);
+						break;
+					case 'x':
+						dispName = strdup(optarg);
+						break;
+
+					case 'h':
+						usage(argv[0], NULL, 0);
+					case '?':
+						usage(argv[0], NULL, 1);
+				}
+		}
+
+	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)) {
+			bind_port = ntohs(addr.sin_port);
+		}
+	}
+
+	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, run_gid);
+					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);
+				}
+		
+		/*
+		 * 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, Dword 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, (Dword) errno);
+	}
+	send_packet(reply, sock);
+	destroyPacket(reply);
+}
+
+static void send_reply64(int rval, io_buffer sock, mt_off_t len) {
+	Packet reply = newPacket();
+
+	make_new(reply, 12);
+	put_qword(reply, 0, len);
+	if (rval == -1) {
+		put_dword(reply, 8, 0);
+	} else {
+		put_dword(reply, 8, (Dword) errno);
+	}
+	send_packet(reply, sock);
+	destroyPacket(reply);
+}
+
+static void cleanup(int x UNUSEDP) NORETURN;
+static void cleanup(int x UNUSEDP) {
+	unlink(XauFileName());
+	exit(-1);
+}
+
+#include "lockdev.h"
+
+void serve_client(int sockhandle, char **device_name, unsigned int n_dev,
+		  int close_stderr) {
+	Packet opcode;
+	Packet parm;
+
+	int readOnly;
+	int devFd;
+	io_buffer sock;
+	int stopLoop;
+	unsigned 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|O_LARGEFILE);
+		
+		if (devFd < 0) {
+			readOnly = 1;
+			devFd = open(device_name[0], 
+				     O_RDONLY|O_LARGEFILE);
+		}
+		if(devFd < 0) {
+			send_reply(0, sock, devFd >= 0 ? 0 : DWORD_ERR);
+			stopLoop = 1;
+		}
+		lock_dev(devFd, !readOnly, NULL);
+	}
+
+
+	while(!stopLoop) {
+		uint32_t 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);
+
+		/* on its own, floppyd does several small writes,
+		 * running into the performance issue described in
+		 * https://eklitzke.org/the-caveats-of-tcp-nodelay
+		 * Cork fixes this by stalling the small writes until
+		 * floppyd has assembled its entire message, thus
+		 * preventing the bad interaction between Nagle's
+		 * algorithm and Linux' delayed ACKs. Another fix
+		 * would be to not send the small batches immediately,
+		 * but instead keep them around and submit them to the
+		 * kernel in one go using writev. However, writev is
+		 * not available everywhere
+		 */
+		cork(sock->handle, 1);
+
+		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, DWORD_ERR);
+					break;
+				}
+
+				devFd = open(device_name[dev_nr],
+					     O_RDONLY | O_LARGEFILE);
+#if DEBUG
+				fprintf(stderr, "Device opened\n");
+#endif
+				if(devFd >= 0 && lock_dev(devFd, 0, NULL)) {
+					send_reply(0, sock, DWORD_ERR);
+					break;
+				}
+				send_reply(0, sock,
+					   devFd >= 0 ? 0 : DWORD_ERR);
+				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, DWORD_ERR);
+					break;
+				}
+				devFd = open(device_name[dev_nr], O_RDWR);
+				if(devFd >= 0 && lock_dev(devFd, 1, NULL)) {
+					send_reply(0, sock, DWORD_ERR);
+					break;
+				}
+				send_reply(0, sock,
+					   devFd >= 0 ? 0 : DWORD_ERR);
+				readOnly = 0;
+				break;
+			case OP_READ:
+#if DEBUG
+				fprintf(stderr, "READ:\n");
+#endif
+				if(read_packet(parm, devFd,
+					       get_dword(parm, 0)) < 0)
+					send_reply(devFd, sock, DWORD_ERR);
+				else {
+					send_reply(devFd, sock,
+						   get_length(parm));
+					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, 
+					   (Dword) lseek(devFd, 0, SEEK_CUR));
+				break;
+			case OP_SEEK64:
+				if(sizeof(mt_off_t) < 8) {
+#if DEBUG
+					fprintf(stderr, "64 bit requested where not available!\n");
+#endif
+					errno = EINVAL;
+					send_reply(devFd, sock, DWORD_ERR);
+					break;
+				}
+#if DEBUG
+				fprintf(stderr, "SEEK64:\n");
+#endif
+				mt_lseek(devFd, 
+					 get_qword(parm,0), get_dword(parm,8));
+				send_reply64(devFd, 
+					     sock, 
+					     mt_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, DWORD_ERR);
+				break;
+		}
+		cork(sock->handle, 0);
+		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 <stdio.h>
+
+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..5be5466
--- /dev/null
+++ b/floppyd_installtest.1
@@ -0,0 +1,94 @@
+'\" t
+.TH floppyd_installtest 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+\&\fR\&\f(CWFloppyd_installtest\fR is used to check for the presence of a running
+floppyd daemon. This is useful, if you have a small front-end 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..98043c8
--- /dev/null
+++ b/floppyd_installtest.c
@@ -0,0 +1,326 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+/* ######################################################################## */
+
+static 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 uint32_t authenticate_to_floppyd(char fullauth, int sock, char *display, 
+					uint32_t protoversion)
+{
+	size_t filelen=0;
+	Byte buf[16];
+	const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
+	char *xcookie = NULL;
+	Dword errcode;
+	uint32_t bytesRead;
+	uint32_t cap=0;
+
+	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;
+	}
+
+	protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;	
+	if(bytesRead >= 12) {
+	    protoversion = read_dword(sock);
+	    cap = read_dword(sock);
+	}
+	
+	fprintf(stderr, "Protocol Version=%d\n", protoversion);
+	if(protoversion >= FLOPPYD_PROTOCOL_VERSION) {
+	  fprintf(stderr, "Capabilities:%s%s\n",		  
+		  (cap & FLOPPYD_CAP_EXPLICIT_OPEN) ? " ExplicitOpen" : "",
+		  (cap & FLOPPYD_CAP_LARGE_SEEK) ? " LargeFiles" : "");
+	}
+
+	if (fullauth) {
+		dword2byte(filelen, (Byte *) xcookie);
+		if(write(sock, xcookie, filelen+4) < (ssize_t)(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,
+			     uint16_t* port)
+{
+	char* newname = strdup(name);
+	char* p;
+	char* p2;
+
+	p = newname;
+	while (*p != '/' && *p) p++;
+	p2 = p;
+	if (*p) p++;
+	*p2 = 0;
+	
+	*port = atou16(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 in_addr_t getipaddress(char *ipaddr)
+{
+	
+	struct hostent  *host;
+	in_addr_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(in_addr_t ip, uint16_t 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;
+	uint16_t port;
+	int sock;
+	uint32_t reply;
+	int rval;
+	uint32_t 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..d243bc4
--- /dev/null
+++ b/floppyd_io.c
@@ -0,0 +1,678 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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
+
+/* ######################################################################## */
+
+
+static 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;
+	unsigned int version;
+	unsigned int capabilities;
+	int drive;
+} RemoteFile_t;
+
+
+#include "byte_dword.h"
+#include "read_dword.h"
+
+
+/* ######################################################################## */
+
+static unsigned int authenticate_to_floppyd(RemoteFile_t *floppyd,
+					    int sock, char *display)
+{
+	size_t filelen;
+	ssize_t newlen;
+	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);
+	newlen = safePopenOut(command, xcookie+4, filelen);
+	if(newlen < 1)
+		return AUTH_AUTHFAILED;
+	filelen = (size_t) newlen;
+	
+	/* Version negotiation */
+	dword2byte(4,buf);
+	dword2byte(floppyd->version,buf+4);
+	if(write(sock, buf, 8) < 8)
+		return AUTH_IO_ERROR;
+
+	if ( (l = (int) 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) < ((ssize_t) (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, size_t len) 
+{
+	Dword errcode;
+	Dword gotlen;
+	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 != (Dword) -1) {
+		size_t l;
+		unsigned int start;
+		if (read_dword(fd) != gotlen) {
+			errno = EIO;
+			return -1;
+		}
+		for (start = 0, l = 0; start < gotlen; start += l) {
+			ssize_t ret = read(fd, buffer+start, gotlen-start);
+			if( ret < 0)
+				return -1;
+			if (ret == 0) {
+				errno = EIO;
+				return -1;
+			}
+			l = (size_t) ret;
+		}
+	} else {
+		errno = errcode;
+	}
+	return gotlen;
+}
+
+static int floppyd_writer(int fd, char* buffer, size_t len) 
+{
+	Dword errcode;
+	Dword gotlen;
+	Byte buf[16];
+
+	dword2byte(1, buf);
+	buf[4] = OP_WRITE;
+	dword2byte(len, buf+5);
+
+	cork(fd, 1);
+	if(write(fd, buf, 9) < 9)
+		return AUTH_IO_ERROR;
+	if(write(fd, buffer, len) < len)
+		return AUTH_IO_ERROR;
+	cork(fd, 0);
+	
+	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 mt_off_t floppyd_lseek64(int fd, mt_off_t offset, int whence) 
+{
+	Dword errcode;
+	Qword gotlen;
+	Byte buf[32];
+	
+	dword2byte(1, buf);
+	buf[4] = OP_SEEK64;
+	
+	dword2byte(12, buf+5);
+	qword2byte(offset, buf+9);
+	dword2byte(whence, buf+17);
+	
+	if(write(fd, buf, 21) < 21)
+		return AUTH_IO_ERROR;
+       
+	if (read_dword(fd) != 12) {
+		errno = EIO;
+		return -1;
+	}
+
+	gotlen = read_qword(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 *, size_t);
+
+static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, size_t len,
+		      iofn io)
+{
+	DeclareThis(RemoteFile_t);
+	int ret;
+
+	where += This->offset;
+
+	if (where != This->lastwhere ){
+		if(This->capabilities & FLOPPYD_CAP_LARGE_SEEK) {
+			if(floppyd_lseek64( This->fd, where, SEEK_SET) < 0 ){
+				perror("floppyd_lseek64");
+				This->lastwhere = (mt_off_t) -1;
+				return -1;
+			}
+		} else {
+			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, 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, 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];
+	unsigned int gotlen;
+	unsigned 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 UNUSEDP,
+			int media, union bootsector *boot)
+{
+	size_t tot_sectors;
+	unsigned 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(setDeviceFromOldDos(media, dev) < 0)
+			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,
+	0, /* pre_allocate */
+	0, /* get_dosConvert */
+	0  /* discard */
+};
+
+/* ######################################################################## */
+
+static int get_host_and_port_and_drive(const char* name, char** hostname,
+				       char **display, uint16_t* 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 = strtou16(p, &p, 0);
+	if(*p == '/')
+	  p++;
+	*drive = 0;
+	if(*p >= '0' && *p <= '9')
+	  *drive = strtoi(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 in_addr_t getipaddress(char *ipaddr)
+{
+	struct hostent  *host;
+	in_addr_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(in_addr_t ip, uint16_t 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, 
+		      char *name, int mode, char *errmsg,
+		      mt_size_t *maxSize)
+{
+	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;
+	}
+
+	if(maxSize) {
+		*maxSize = 
+			(This->capabilities & FLOPPYD_CAP_LARGE_SEEK) ?
+			max_off_t_seek : max_off_t_31;
+	}
+	return (Stream_t *) This;
+}
+
+static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name, 
+			    char *errmsg) 
+{
+	char* hostname;
+	char* display;
+	uint16_t port;
+	int rval = get_host_and_port_and_drive(name, &hostname, &display, 
+					       &port, &floppyd->drive);
+	int sock;
+	unsigned 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..58f763f
--- /dev/null
+++ b/floppyd_io.h
@@ -0,0 +1,87 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef USE_FLOPPYD
+
+#include "stream.h"
+
+typedef uint8_t Byte;
+typedef uint32_t Dword;
+typedef uint64_t Qword;
+
+#define DWORD_ERR ((Dword) -1)
+
+/*extern int ConnectToFloppyd(const char* name, Class_t** ioclass);*/
+Stream_t *FloppydOpen(struct device *dev, 
+		      char *name, int mode, char *errmsg,
+		      mt_size_t *maxSize);
+
+#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,
+	OP_SEEK64
+};
+
+enum AuthErrorsEnum {
+	AUTH_SUCCESS,
+	AUTH_PACKETOVERSIZE,
+	AUTH_AUTHFAILED,
+	AUTH_WRONGVERSION,
+	AUTH_DEVLOCKED,
+	AUTH_BADPACKET,
+	AUTH_IO_ERROR
+};
+
+
+UNUSED(static inline void cork(int sockhandle, int on))
+{
+#ifdef TCP_CORK
+	if(setsockopt(sockhandle, IPPROTO_TCP, 
+		      TCP_CORK, (char *)&on, sizeof(on)) < 0) {
+		perror("setsockopt cork");
+	}
+#else
+	on = 1 ^ on;
+	if(setsockopt(sockhandle, IPPROTO_TCP, 
+		      TCP_NODELAY, (char *)&on, sizeof(on)) < 0) {
+		perror("setsockopt nodelay");
+	}
+#endif
+}
+
+
+#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 <http://www.gnu.org/licenses/>.
+ *
+ * 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..7708c06
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+
+
+typedef struct FsPublic_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;
+} 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..3fb88e4
--- /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 <http://www.gnu.org/licenses/>.
+ */
+#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,
+			 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..3f526aa
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,222 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * hash.c - hash table.
+ */
+
+#include "sysincludes.h"
+#include "htable.h"
+#include "mtools.h"
+
+struct hashtable {
+  T_HashFunc f1,f2;
+  T_ComparFunc compar;
+  size_t size;  /* actual size of the array */
+  size_t fill;  /* number of deleted or in use slots */
+  size_t inuse; /* number of slots in use */
+  size_t max;   /* maximal number of elements to keep efficient */
+  T_HashTableEl *entries;
+};
+
+static size_t 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, size_t size)
+{
+  int i;
+  size_t ii;
+
+  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(ii=0; ii < size; ii++)
+    H->entries[ii] = &unallocated;
+  return 0;
+}
+
+int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, size_t 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)
+{
+  size_t 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, size_t *hint)
+{
+  size_t f2, pos;
+  int ctr;
+
+  pos = H->f1(E) % H->size;
+  f2 = (size_t) -1;
+  ctr = 0;
+  while(H->entries[pos] != &unallocated &&
+	H->entries[pos] != &deleted){
+    if (f2 == (size_t) -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)
+{
+  size_t 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, size_t *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,
+			size_t *hint, int isIdentity)
+{
+	size_t f2, pos, upos, ttl;
+
+  pos = H->f1(E) % H->size;
+  ttl = H->size;
+  f2 = (size_t) -1;
+  upos = (size_t) -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 == (size_t) -1)
+      f2 = H->f2(E) % (H->size - 1);
+    if (upos == (size_t) -1 && H->entries[pos] == &deleted)
+      upos = pos;
+    pos = (pos+f2+1) % H->size;
+    ttl--;
+  }
+  if(H->entries[pos] == &unallocated || !ttl)
+    return -1;
+  if (upos != (size_t) -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,
+		size_t *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, size_t 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);
+  }
+  H->inuse--;
+  H->entries[hint] = &deleted;
+  return 0;
+}
diff --git a/htable.h b/htable.h
new file mode 100644
index 0000000..0754e14
--- /dev/null
+++ b/htable.h
@@ -0,0 +1,33 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * hashtable
+ */
+
+typedef struct hashtable T_HashTable;
+typedef void *T_HashTableEl;
+typedef size_t (*T_HashFunc)(void *);
+typedef int (*T_ComparFunc)(void *, void *);
+
+
+int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, size_t size,
+	    T_HashTable **H);
+int hash_add(T_HashTable *H, T_HashTableEl *E, size_t *hint);
+int hash_remove(T_HashTable *H, T_HashTableEl *E, size_t hint);
+int hash_lookup(T_HashTable *H, T_HashTableEl *E, T_HashTableEl **E2,
+		size_t *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..62574f9
--- /dev/null
+++ b/init.c
@@ -0,0 +1,440 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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
+
+/*
+ * Read the boot sector.  We glean the disk parameters from this sector.
+ */
+static int read_boot(Stream_t *Stream, union bootsector * boot, int size)
+{
+	size_t boot_sector_size; /* sector size, as stored in boot sector */
+
+	/* 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;
+
+	boot_sector_size = WORD(secsiz);		
+	if(boot_sector_size < sizeof(boot->bytes)) {
+		/* zero rest of in-memory boot sector */
+		memset(boot->bytes+boot_sector_size, 0,
+		       sizeof(boot->bytes) - boot_sector_size);
+	}
+
+	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 */
+	0 /* discard */
+};
+
+/**
+ * Get media type byte from boot sector (BIOS Parameter Block 2) or
+ * from FAT (if media byte from BPB 2 looks fishy)
+ * Return the media byte + 0x100 if found in BPB 2, or as is if found in FAT.
+ */
+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 */
+		/* we assume 512-byte sectors here */
+		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;
+}
+
+/**
+ * Tries out all device definitions for the given drive number, until one
+ * is found that is able to read from the device
+ * Parameters
+ *  - drive: drive letter to check
+ *  - mode: file open mode
+ *  - out_dev: device parameters (geometry, etc.) are returned here
+ *  - boot: boot sector is read from the disk into this structure
+ *  - name: "name" of device definition (returned)
+ *  - media: media byte is returned here (ored with 0x100 if there is a
+ *    BIOS Parameter block present)
+ *  - maxSize: maximal size supported by (physical) drive returned here
+ *  - isRop: whether device is read-only is returned here
+ * Return value:
+ *  - a Stream allowing to read from this device, must be closed by caller
+ */
+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, name, mode,
+					 errmsg, maxSize);
+#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;
+	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;
+
+	cylinder_size = dev.heads * dev.sectors;
+	This->serialized = 0;
+	if ((media & ~7) == 0xf8){
+		/* This bit of code is only entered if there is no BPB, or
+		 * else result of the AND would be 0x1xx
+		 */
+		struct OldDos_t *params=getOldDosByMedia(media);
+		if(params == NULL)
+			return NULL;
+		This->cluster_size = params->cluster_size;
+		tot_sectors = cylinder_size * params->tracks;
+		This->fat_start = 1;
+		This->fat_len = params->fat_len;
+		This->dir_len = params->dir_len;
+		This->num_fat = 2;
+		This->sector_size = 512;
+		This->sectorShift = 9;
+		This->sectorMask = 511;
+		This->fat_bits = 12;
+	} else {
+		struct label_blk_t *labelBlock;
+		int i;
+		
+		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;
+
+		/*
+		 * 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);	
+
+		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(has_BPB4) {
+			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);
+	}
+
+	/* 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, 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..95383f7
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 */
+static 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..8c01918
--- /dev/null
+++ b/llong.h
@@ -0,0 +1,110 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#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
+# if SIZEOF_SIZE_T == 4
+/* Some systems (NetBSD) apparently have 64 bit off_t, but 32 bit size_t ... */
+#  define MT_SIZE_T off_t
+# else
+#  define MT_SIZE_T size_t
+# endif
+#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);
+
+int mt_lseek(int fd, mt_off_t where, int whence);
+
+unsigned int log_2(int);
+
+#endif
diff --git a/lockdev.c b/lockdev.c
new file mode 100644
index 0000000..3a6eab9
--- /dev/null
+++ b/lockdev.c
@@ -0,0 +1,174 @@
+/*  Copyright 2005,2009,2018 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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.
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+#include "lockdev.h"
+
+#if (defined HAVE_SIGACTION && defined HAVE_ALARM)
+# define ALRM
+#endif
+
+
+#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && (defined(LOCK_NB) || defined(ALRM)))
+     
+# ifdef ALRM
+#  define USE_FLOCK_W
+# else
+#  define USE_FLOCK
+# endif
+
+#else /* FLOCK */
+
+#if (defined(HAVE_LOCKF) && (defined(F_TLOCK) || defined(ALRM)))
+
+# ifdef ALRM
+#  define USE_LOCKF_W
+# else
+#  define USE_LOCKF
+# endif
+     
+#else /* LOCKF */
+
+#if (defined(F_SETLK) && defined(F_WRLCK))
+
+# if (defined ALRM && defined F_SETLKW)
+#  define USE_SETLK_W
+# else
+#  define USE_SETLK_W
+# endif
+
+#else
+
+#endif /* FCNTL */
+#endif /* LOCKF */
+#endif /* FLOCK */
+
+#if  defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
+static void alrm(int a UNUSEDP) {
+}
+#endif
+
+int lock_dev(int fd, int mode, struct device *dev)
+{
+	unsigned int retries = 0;
+	if(IS_NOLOCK(dev))
+		return 0;
+
+	while(1) {
+		int ret=0;
+#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
+		struct sigaction alrm_action, old_alrm_action;
+		int old_alrm = alarm(0);
+		memset(&alrm_action, 0, sizeof(alrm_action));
+		alrm_action.sa_handler = alrm;
+		alrm_action.sa_flags = 0;
+		sigaction(SIGALRM, &alrm_action, &old_alrm_action);
+		alarm(mtools_lock_timeout);
+#endif
+
+#ifdef USE_FLOCK
+		ret = flock(fd, (mode ? LOCK_EX : LOCK_SH)|LOCK_NB);
+#endif
+		
+#ifdef USE_FLOCK_W
+		ret = flock(fd, (mode ? LOCK_EX : LOCK_SH));
+#endif
+
+#if (defined(USE_LOCKF) || defined(USE_LOCKF_W))
+		if(mode)
+# ifdef USE_LOCKF
+			ret = lockf(fd, F_TLOCK, 0);
+# else
+			ret = lockf(fd, F_LOCK, 0);
+# endif
+		else
+			ret = 0;
+#endif
+		
+#if (defined(USE_SETLK) || defined(USE_SETLK_W))
+		{
+			struct flock flk;
+			flk.l_type = mode ? F_WRLCK : F_RDLCK;
+			flk.l_whence = 0;
+			flk.l_start = 0L;
+			flk.l_len = 0L;
+
+# ifdef USE_SETLK_W
+			ret = fcntl(fd, F_SETLKW, &flk);
+# else
+			ret = fcntl(fd, F_SETLK, &flk);
+# endif
+		}
+#endif
+		
+#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
+		/* Cancel the alarm */
+		sigaction(SIGALRM, &old_alrm_action, NULL);
+		alarm(old_alrm);
+#endif
+
+		if(ret < 0) {
+#if defined(USE_FLOCK_W) || defined(USE_LOCKF_W) || defined (USE_SETLK_W)
+			/* ALARM fired ==> this means we are still locked */
+			if(errno == EINTR) {
+				return 1;
+			}
+#endif
+			
+			if(
+#ifdef EWOULDBLOCK
+				(errno != EWOULDBLOCK)
+#else
+				1
+#endif
+				&&
+#ifdef EAGAIN
+				(errno != EAGAIN)
+#else
+				1
+#endif
+				&&
+#ifdef EINTR
+				(errno != EINTR)
+#else
+				1
+#endif
+			) {
+				/* Error other than simply being locked */
+				return -1;
+			}
+			/* Locked ==> continue until timeout */
+		} else /* no error => we got the lock! */
+			return 0;
+
+#ifdef HAVE_USLEEP
+		if(retries++ < mtools_lock_timeout * 10)
+			usleep(100000);
+#else
+		if(retries++ < mtools_lock_timeout)
+			sleep(1);
+#endif
+		else
+			/* waited for too long => give up */
+			return 1;
+	}
+}
diff --git a/lockdev.h b/lockdev.h
new file mode 100644
index 0000000..61801d6
--- /dev/null
+++ b/lockdev.h
@@ -0,0 +1,27 @@
+#ifndef LOCK_DEV
+#define LOCK_DEV
+
+/*  Copyright 2005,2009,2018 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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.
+ */
+
+extern int lock_dev(int fd, int mode, struct device *dev);
+
+#endif
diff --git a/lz.1 b/lz.1
new file mode 100644
index 0000000..af90462
--- /dev/null
+++ b/lz.1
@@ -0,0 +1,42 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for lz
+.\"
+.\" Copyright (C), 2000, Robert A.R. King
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Fri Dec  1 01:50:54 EST 2000 Robert A.R. King (Robert.King@mailbox.gu.edu.au)
+.\" 
+.TH LZ 1 "Wed Feb 23 00:00:00 EET 2000" "" "Mtools Users Manual"
+.SH NAME
+lz \- gunzips and shows a listing of a gzip'd tar'd archive
+.SH SYNOPSIS
+.\" The command line
+.B lz 
+.I file
+.SH DESCRIPTION
+.B lz
+provides a listing of a gzip'd tar'd archive, that is a \fBtar\fR(1) archive
+compressed with the \fBgzip\fR(1) utility.
+It is not strictly necessary on Debian GNU/Linux, because the GNU
+\fBtar\fR(1) program provides the same capability with the command
+
+.B tar -tzf
+.I file
+
+but this utility is provided in the mtools package for other platforms and 
+is retained here for completeness.
+
+.SH AUTHOR
+Robert King (Robert.King@mailbox.gu.edu.au) wrote this page for the
+.I Debian/GNU
+mtools package.
+
+.SH "SEE ALSO"
+.BR mtools (1), 
+.BR gzip (1),
+.BR tar (1),
+.BR uz (1).
diff --git a/mainloop.c b/mainloop.c
new file mode 100644
index 0000000..cfd91bf
--- /dev/null
+++ b/mainloop.c
@@ -0,0 +1,674 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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] == ':') {
+		memcpy(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 = ch_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 UNUSEDP, MainParam_t *mp, char *arg,
+	      int follow_dir_link);
+
+static int _unix_loop(Stream_t *Dir, MainParam_t *mp,
+		      const char *filename UNUSEDP)
+{
+	return unix_dir_loop(Dir, mp);
+}
+
+int unix_loop(Stream_t *Stream UNUSEDP, MainParam_t *mp,
+	      char *arg, int follow_dir_link)
+{
+	int ret;
+	int isdir=0;
+	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(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,"Ambiguous\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.data, mp->shortname.len,
+			     mp->longname.data, mp->longname.len)) == 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.data, mp->shortname.len,
+			     mp->longname.data, mp->longname.len)) == 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 = ch_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, "Ambiguous %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.data = mp->longname.data = 0;
+	mp->shortname.len = mp->longname.len = 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, sizeof(mp->targetBuffer));
+		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..a2ff666
--- /dev/null
+++ b/mainloop.h
@@ -0,0 +1,108 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/param.h>
+#include "vfat.h"
+#include "mtoolsDirentry.h"
+
+typedef struct bounded_string {
+	char *data; /* storage of converted string, including final null byte */
+	size_t len; /* max length of converted string, including final null 
+		     * byte */
+} bounded_string;
+
+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 */
+
+	bounded_string shortname; /* where to put the short name of the 
+				   * matched file */
+	bounded_string 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..8ba3b50
--- /dev/null
+++ b/match.c
@@ -0,0 +1,167 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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((wint_t)a) == towupper((wint_t)b);
+}
+
+static int exactcmp(wchar_t a,wchar_t b)
+{
+	return a == b;
+}
+
+
+static int is_in_range(wchar_t ch, const wchar_t **p, int *reverse) {
+	wchar_t first, last;
+	int found=0;
+	if (**p == '^') {
+		*reverse = 1;
+		(*p)++;
+	} else
+		*reverse=0;
+	while( (first = **p) != ']') {
+		if(!first)
+			/* Malformed pattern, range not closed */
+			return 0;
+		if(*(++(*p)) == '-') {
+			last = *(++(*p));				
+			if(last==']') {
+				/* Last "-" in range designates itself */
+				if(ch == first || ch == '-')
+					found = 1;
+				break;
+			}
+			(*p)++;
+
+			/* a proper range */
+			if(ch >= first && ch <= last)
+				found = 1;
+		} else
+			/* a Just one character */
+			if(ch == first)
+				found = 1;
+	}
+	return found;
+}
+
+static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out,
+		       int (*compfn)(wchar_t a, wchar_t b))
+{
+	int reverse;
+	const wchar_t *p0 = *p;
+	const wchar_t *p1 = *p;
+	if(out)
+		*out = *s;
+	if(is_in_range(*s, p, &reverse))
+		return 1 ^ reverse;
+	if(compfn == exactcmp)
+		return reverse;
+	if(is_in_range((wchar_t)towlower((wint_t)*s), &p0, &reverse)) {
+		if(out)
+			*out = (wchar_t)towlower((wint_t)*s);
+		return 1 ^ reverse;
+	}
+	if(is_in_range((wchar_t)towupper((wint_t)*s), &p1, &reverse)) {
+		if(out)
+			*out = (wchar_t)towupper((wint_t)*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..10984af
--- /dev/null
+++ b/mattrib.1
@@ -0,0 +1,128 @@
+'\" t
+.TH mattrib 1 "28Nov20" mtools-4.0.26
+.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
+.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 without any whitespace padding.  If
+neither the "/" option is given, nor the \fImsdosfile\fR contains a
+wildcard, and there is only one MS-DOS 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 \fR\&\f(CWmformat\fR commands that will
+reproduce the current situation, starting from a situation as left by
+untarring the MS-DOS file system.  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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..c684e76
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ * mattrib.c
+ * Change MSDOS file attribute flags
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "mainloop.h"
+
+typedef struct Arg_t {
+	unsigned 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 UNUSEDP)
+{
+	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 UNUSEDP)
+{
+	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 UNUSEDP) NORETURN;
+void mattrib(int argc, char **argv, int type UNUSEDP)
+{
+	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);
+				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..a4975ed
--- /dev/null
+++ b/mbadblocks.1
@@ -0,0 +1,115 @@
+'\" t
+.TH mbadblocks 1 "28Nov20" mtools-4.0.26
+.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 mark some clusters on an
+MS-DOS filesystem bad. It has the following syntax:
+.PP
+\&\fR\&\f(CWmbadblocks\fR [\fR\&\f(CW-s\fR \fIsectorlist\fR|\fR\&\f(CW-c\fR \fIclusterlist\fR|-w] \fIdrive\fR\fR\&\f(CW:\fR
+.PP
+If no command line flags are supplied, \fR\&\f(CWMbadblocks\fR scans an
+MS-DOS filesystem for bad blocks by simply trying to read them and
+flag them if read fails. All blocks that are unused are scanned, and
+if detected bad are marked as such in the FAT.
+.PP
+This command is intended to be used right after \fR\&\f(CWmformat\fR.  It is
+not intended to salvage data from bad disks.
+.PP
+.SH Command\ line\ options
+.TP
+\&\fR\&\f(CWc\ \fIfile\fR\&\f(CW\fR\ 
+Use a list of bad clusters, rather than scanning for bad clusters
+itself.
+.TP
+\&\fR\&\f(CWs\ \fIfile\fR\&\f(CW\fR\ 
+Use a list of bad sectors (counted from beginning of filesystem),
+rather than trying for bad clusters itself.
+.TP
+\&\fR\&\f(CWw\fR\ 
+Write a random pattern to each cluster, then read it back and flag
+cluster as bad if mismatch. Only free clusters are tested in such a
+way, so any file data is preserved.
+.PP
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..37b4207
--- /dev/null
+++ b/mbadblocks.c
@@ -0,0 +1,283 @@
+/*  Copyright 1995-1999,2001-2003,2007,2009,2011 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 <http://www.gnu.org/licenses/>.
+ *
+ * mbadblocks.c
+ * Mark bad blocks on disk
+ *
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "mainloop.h"
+#include "fsP.h"
+
+#define N_PATTERN 311
+
+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: [-c clusterList] [-s sectorList] [-c] [-V] device\n",
+		progname);
+	exit(ret);
+}
+
+static void checkListTwice(char *filename) {
+	if(filename != NULL) {
+		fprintf(stderr, "Only one of the -c or -s options may be given\n");
+		exit(1);
+	}
+}
+
+/**
+ * Marks given cluster as bad, but prints error instead if cluster already used
+ */
+static void mark(Fs_t *Fs, long offset, unsigned int badClus) {
+	unsigned int old = Fs->fat_decode((Fs_t*)Fs, offset);
+	if(old == 0) {
+		fatEncode((Fs_t*)Fs, offset, badClus);
+		return;
+	}
+	if(old == badClus) {
+		fprintf(stderr, "Cluster %ld already marked\n", offset);
+	} else {
+		fprintf(stderr, "Cluster %ld is busy\n", offset);
+	}
+}
+
+static char *in_buf;
+static char *pat_buf;
+static size_t in_len;
+
+
+static void progress(unsigned int i, unsigned int total) {
+	if(i % 10 == 0)
+		fprintf(stderr,	"                     \r%d/%d\r", i, total);
+}
+
+static int scan(Fs_t *Fs, Stream_t *dev,
+		long cluster, unsigned int badClus,
+		char *buffer, int doWrite) {
+	off_t start;
+	off_t ret;
+	off_t pos;
+	int bad=0;
+
+	if(Fs->fat_decode((Fs_t*)Fs, cluster))
+		/* cluster busy, or already marked */
+		return 0;
+	start = (cluster - 2) * Fs->cluster_size + Fs->clus_start;
+	pos = sectorsToBytes((Stream_t*)Fs, start);
+	if(doWrite) {
+		ret = force_write(dev, buffer, pos, in_len);
+		if(ret < (off_t) in_len )
+			bad = 1;
+	} else {
+		ret = force_read(dev, in_buf, pos, in_len);
+		if(ret < (off_t) in_len )
+			bad = 1;
+		else if(buffer) {
+			size_t i;
+			for(i=0; i<in_len; i++)
+				if(in_buf[i] != buffer[i]) {
+					bad = 1;
+					break;
+				}
+		}
+	}
+
+	if(bad) {
+		printf("Bad cluster %ld found\n", cluster);
+		fatEncode((Fs_t*)Fs, cluster, badClus);
+		return 1;
+	}
+	return 0;
+}
+
+void mbadblocks(int argc, char **argv, int type UNUSEDP) NORETURN;
+void mbadblocks(int argc, char **argv, int type UNUSEDP)
+{
+	unsigned int i;
+	unsigned int startSector=2;
+	unsigned int endSector=0;
+	struct MainParam_t mp;
+	Fs_t *Fs;
+	Stream_t *Dir;
+	int ret;
+	char *filename = NULL;
+	int c;
+	unsigned int badClus;
+	int sectorMode=0;
+	int writeMode=0;
+
+	while ((c = getopt(argc, argv, "i:s:cwS:E:")) != EOF) {
+		switch(c) {
+		case 'i':
+			set_cmd_line_image(optarg);
+			break;
+		case 'c':
+			checkListTwice(filename);
+			filename = strdup(optarg);
+			break;
+		case 's':
+			checkListTwice(filename);
+			filename = strdup(optarg);
+			sectorMode = 1;
+			break;
+		case 'S':
+			startSector = atoui(optarg); 
+			break;
+		case 'E':
+			endSector = atoui(optarg); 
+			break;
+		case 'w':
+			writeMode = 1;
+			break;
+		case 'h':
+			usage(0);
+		default:
+			usage(1);
+		}
+	}
+
+	if (argc != optind+1 ||
+	    !argv[optind][0] || argv[optind][1] != ':' || argv[optind][2]) {
+		usage(1);
+	}
+
+	init_mp(&mp);
+
+	Dir = open_root_dir(argv[optind][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) {
+		printOom();
+		ret = 1;
+		goto exit_0;
+	}
+	if(writeMode) {
+		pat_buf=malloc(in_len * N_PATTERN);
+		if(!pat_buf) {
+			printOom();
+			ret = 1;
+			goto exit_0;
+		}
+		init_random();
+		for(i=0; i < in_len * N_PATTERN; i++) {
+			pat_buf[i] = random();
+		}
+	}
+	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");
+			goto exit_0;
+		}
+		if(ret < (signed int) Fs->sector_size){
+			fprintf(stderr,"end of file in file_read\n");
+			ret = 1;
+			goto exit_0;
+		}
+	}
+	ret = 0;
+
+	badClus = Fs->last_fat + 1;
+
+	if(startSector < 2)
+		startSector = 2;
+	if(endSector > Fs->num_clus + 2 || endSector <= 0) 
+		endSector = Fs->num_clus + 2;
+
+	if(filename) {
+		char line[80];
+
+		FILE *f = fopen(filename, "r");
+		if(f == NULL) {
+			fprintf(stderr, "Could not open %s (%s)\n",
+				filename, strerror(errno));
+			ret = 1;
+			goto exit_0;
+		}
+		while(fgets(line, sizeof(line), f)) {
+			char *ptr = line + strspn(line, " \t");
+			long offset = strtol(ptr, 0, 0);
+			if(sectorMode)
+				offset = (offset-Fs->clus_start)/Fs->cluster_size + 2;
+			if(offset < 2) {
+				fprintf(stderr, "Sector before start\n");
+			} else if(offset >= Fs->num_clus) {
+				fprintf(stderr, "Sector beyond end\n");
+			} else {
+				mark(Fs, offset, badClus);
+				ret = 1;
+			}
+		}
+	} else {
+		Stream_t *dev;
+		dev = Fs->Next;
+		if(dev->Next)
+			dev = dev->Next;
+
+		in_len = Fs->cluster_size * Fs->sector_size;
+		if(writeMode) {
+			/* Write pattern */
+			for(i=startSector; i< endSector; i++){
+				if(got_signal)
+					break;
+				progress(i, Fs->num_clus);
+				ret |= scan(Fs, dev, i, badClus, 
+					    pat_buf + in_len * (i % N_PATTERN),
+					    1);
+			}
+
+			/* Flush cache, so that we are sure we read the data
+			   back from disk, rather than from the cache */
+			if(!got_signal)
+				DISCARD(dev);
+
+			/* Read data back, and compare to pattern */
+			for(i=startSector; i< endSector; i++){
+				if(got_signal)
+					break;
+				progress(i, Fs->num_clus);
+				ret |= scan(Fs, dev, i, badClus, 
+					    pat_buf + in_len * (i % N_PATTERN),
+					    0);
+			}
+
+		} else {
+
+			for(i=startSector; i< endSector; i++){
+				if(got_signal)
+					break;
+				progress(i, Fs->num_clus);
+				ret |= scan(Fs, dev, i, badClus, NULL, 0);
+			}
+		}
+	}
+ exit_0:
+	FREE(&Dir);
+	exit(ret);
+}
diff --git a/mcat.1 b/mcat.1
new file mode 100644
index 0000000..630582b
--- /dev/null
+++ b/mcat.1
@@ -0,0 +1,100 @@
+'\" t
+.TH mcat 1 "28Nov20" mtools-4.0.26
+.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
+.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 low-level 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..60dff53
--- /dev/null
+++ b/mcat.c
@@ -0,0 +1,164 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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) NORETURN;
+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 512u
+#else
+#define BUF_SIZE 16000u
+#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 UNUSEDP) NORETURN;
+void mcat(int argc, char **argv, int type UNUSEDP)
+{
+	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 = ch_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, name, 
+					     mode, errmsg, NULL);
+#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..24528e8
--- /dev/null
+++ b/mcd.1
@@ -0,0 +1,111 @@
+'\" t
+.TH mcd 1 "28Nov20" mtools-4.0.26
+.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
+.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
+.PP
+ 
+\&\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 file system.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..a11909b
--- /dev/null
+++ b/mcd.c
@@ -0,0 +1,63 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 UNUSEDP)
+{
+	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 UNUSEDP) NORETURN;
+void mcd(int argc, char **argv, int type UNUSEDP)
+{
+	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..1ca4328
--- /dev/null
+++ b/mclasserase.1
@@ -0,0 +1,112 @@
+'\" t
+.TH mclasserase 1 "28Nov20" mtools-4.0.26
+.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
+.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
+.PP
+ 
+\&\fR
+.PP
+MS-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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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/mclasserase.c b/mclasserase.c
new file mode 100644
index 0000000..8e71e3b
--- /dev/null
+++ b/mclasserase.c
@@ -0,0 +1,352 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <getopt.h>
+#endif
+
+#include "file.h"
+
+#include <unistd.h>
+#include <stdio.h>
+
+/**
+ * Prints the Usage Message to STDOUT<br>
+ *
+ * @author  stefan feuz<br>
+ *          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.<br>
+ *
+ * @author  Lukas Meyer<br>
+ *          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) NORETURN;
+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[3];		/* Stores the drive letter */
+
+
+  int i = 0;
+
+  /* FILE *forf; */
+
+  char dummy[2];       /* dummy input for debugging purposes.. */
+  int icount=0;
+  int iTotalErase = 0;
+
+/* How many times we'll overwrite the media: */
+#define CYCLES 3
+  unsigned 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:", ch_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 <ENTER> to continue\n");
+        printf("Press <x> and <ENTER> 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 won't
+ * be ANY bits of old files on the disk.<br>
+ * </b>
+ * @author  stefan feuz<br>
+ *          thomas locher<br>
+ *          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<br>
+ *          int     -1 if there is something wrong
+ *
+ * @info    mclasserase [-p tempFilePath] [-d] drive:
+ *
+ *
+ */
+void mclasserase(int argc, char **argv, int type UNUSEDP) NORETURN;
+void mclasserase(int argc, char **argv, int type UNUSEDP)
+{
+  /* declaration of all variables */
+  int c;
+  int debug=0;
+  /* char* tempFilePath=NULL; */
+  char drive='a';
+
+  extern int 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 = ch_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);
+}
diff --git a/mcomp.1 b/mcomp.1
new file mode 100644
index 0000000..a6719af
--- /dev/null
+++ b/mcomp.1
@@ -0,0 +1,44 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for mcomp
+.\"
+.\" Copyright (C), 2003, Luis Bustamante
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Mon Mar  3 11:58:15 COT 2003 Luis Bustamante <luferbu@fluidsignal.com>
+.\" 
+.TH MCOMP 1 "Mon Mar  3 11:58:15 COT 2003" "" "Mtools Users Manual"
+.SH NAME
+mcomp \- Compares two files using mtools
+.SH SYNOPSIS
+.\" The command line
+.B mcomp
+.I file-on-floppy
+.I local-file
+.SH DESCRIPTION
+.B mcomp
+compares two files, the first one must be on a floppy disk so it can
+be accessed via \fBmtools\fR.
+It is not strictly necessary on Debian GNU/Linux, because the diffutils
+\fBcmp\fR(1) program provides the same capability after copying the
+file locally with
+
+.B mcopy
+.I file
+.I destination
+
+but this utility is provided in the mtools package for other platforms and 
+is retained here for completeness.
+
+.SH AUTHOR
+Luis Bustamante <luferbu@fluidsignal.com> wrote this page for the
+.I Debian/GNU
+mtools package.
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR cmp (1), 
+.BR mcopy (1)
diff --git a/mcopy.1 b/mcopy.1
new file mode 100644
index 0000000..9ce0804
--- /dev/null
+++ b/mcopy.1
@@ -0,0 +1,178 @@
+'\" t
+.TH mcopy 1 "28Nov20" mtools-4.0.26
+.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
+.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
+.PP
+ 
+\&\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 MS-DOS to Unix, and vice-versa when
+copying from Unix to MS-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(CWASCII\fR translates incoming carriage
+return/line feeds to line feeds.
+.TP
+\&\fR\&\f(CWT\fR\ 
+Text (ASCII) file transfer with character set conversion.  Differs from
+\&\fR\&\f(CW-a\fR in the \fR\&\f(CWASCII\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(CWASCII\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 (see \(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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..c9a8900
--- /dev/null
+++ b/mcopy.c
@@ -0,0 +1,630 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * mcopy.c
+ * Copy an MSDOS files to and from Unix
+ *
+ */
+
+
+#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(MainParam_t *mp, int needfilter, const char *unixFile);
+
+/* Write the Unix file */
+static int unix_write(MainParam_t *mp, int needfilter)
+{
+	Arg_t *arg=(Arg_t *) mp->arg;
+
+	if(arg->type)
+		return _unix_write(mp, needfilter, "-");
+	else {
+		char *unixFile = mpBuildUnixFilename(mp);
+		int ret;
+		if(!unixFile) {
+			printOom();
+			return ERROR_ONE;
+		}
+		ret = _unix_write(mp, needfilter, unixFile);
+		free(unixFile);
+		return ret;
+	}
+}
+
+
+/* Write the Unix file */
+static int _unix_write(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 && !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 UNUSEDP, MainParam_t *mp)
+{
+	return unix_write(mp, 1);
+}
+
+
+static  int unix_to_unix(MainParam_t *mp)
+{
+	return unix_write(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, 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) NORETURN;
+void mcopy(int argc, char **argv, int mtype)
+{
+	Arg_t arg;
+	int c, fastquit;
+	
+
+	/* get command line options */
+
+	init_clash_handling(& arg.ch);
+
+	/* get command line options */
+	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);
+				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];
+		}
+
+		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..ea8dcd4
--- /dev/null
+++ b/mdel.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mdel 1 "28Nov20" mtools-4.0.26
+.SH Name
+mdel - delete 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(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 file system.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..e650d71
--- /dev/null
+++ b/mdel.c
@@ -0,0 +1,210 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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, sizeof(shortname),
+				     NULL, 0)) == 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) NORETURN;
+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);
+				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<argc;i++) {
+		size_t b, l;
+		if(argv[i][0] && argv[i][1] == ':')
+			b = 2;
+		else
+			b = 0;
+		l = strlen(argv[i]+b);
+		if(l > 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..8707f73
--- /dev/null
+++ b/mdeltree.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mdeltree 1 "28Nov20" mtools-4.0.26
+.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
+.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 file system. 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..40f607a
--- /dev/null
+++ b/mdir.1
@@ -0,0 +1,118 @@
+'\" t
+.TH mdir 1 "28Nov20" mtools-4.0.26
+.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
+.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 MS-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 file systems, which store
+the size explicitly.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..788ef5a
--- /dev/null
+++ b/mdir.c
@@ -0,0 +1,621 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 mdir_shortname[4*12+1];
+static char mdir_longname[4*MAX_VNAMELEN+1];
+
+
+/*
+ * 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)
+{
+	size_t len;
+	register char *srcp, *dstp;
+	int size;
+
+	unsigned long numlo;
+	unsigned long numhi;
+
+	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, sizeof(shortname),
+			  longname, sizeof(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="<out-of-memory>";
+
+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(&currentDir);
+}
+
+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 UNUSEDP)
+{
+	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] = ch_towlower(ext[i]);
+	}
+	ext[3] = '\0';
+	if (entry->dir.name[0] == '\x05') {
+		dos_to_wchar(cp, "\xE5", name, 1);
+		dos_to_wchar(cp, entry->dir.name+1, name+1, 7);
+	} else {
+		dos_to_wchar(cp, entry->dir.name, name, 8);
+	}
+	if(Case & BASECASE){
+		for(i=0; i<8;i++)
+			name[i] = ch_towlower(name[i]);
+	}
+	name[8]='\0';
+	if(wide){
+		if(IS_DIR(entry))
+			printf("[%s]%*s", mdir_shortname,
+			       (int) (15 - 2 - strlen(mdir_shortname)), "");
+		else
+			printf("%-15s", mdir_shortname);
+	} else if(!concise) {				
+		char tmpBasename[4*8+1];
+		char tmpExt[4*3+1];
+		WCHAR_TO_NATIVE(name,tmpBasename,8);
+		WCHAR_TO_NATIVE(ext,tmpExt,3);
+
+		if (name[0] == ' ') 
+			printf("             ");
+		else if(mtools_dotted_dir)
+			printf("%-12s ", mdir_shortname);
+		else
+			printf("%s %s ", tmpBasename, tmpExt);
+		/* is a subdirectory */
+		if(IS_DIR(entry))
+			printf("<DIR>    ");
+		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(*mdir_longname)
+			printf(" %s", mdir_longname);
+		printf("\n");
+	} else {
+		char tmp[4*MAX_VNAMELEN+1];
+		wchar_to_native(entry->name,tmp,
+				MAX_VNAMELEN, sizeof(tmp));
+
+		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 UNUSEDP,
+				 MainParam_t *mp UNUSEDP)
+{
+	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 UNUSEDP) NORETURN;
+void mdir(int argc, char **argv, int type UNUSEDP)
+{
+	int ret;
+	MainParam_t mp;
+	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);
+				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 */
+	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.data = mdir_longname;
+	mp.longname.len = sizeof(mdir_longname);
+	mp.shortname.data = mdir_shortname;
+	mp.shortname.len = sizeof(mdir_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..5cbe06c
--- /dev/null
+++ b/mdoctorfat.c
@@ -0,0 +1,186 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * Test program for doctoring the fat
+ */
+
+
+#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;
+	uint32_t 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 UNUSEDP)
+{
+	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 UNUSEDP) NORETURN;
+void mdoctorfat(int argc, char **argv, int mtype UNUSEDP)
+{
+	Arg_t arg;
+	int c, ret;
+	unsigned int address;
+	unsigned int begin, end;
+	char *number, *eptr;
+	int i;
+	unsigned int 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) {
+		char *endptr = NULL;
+		errno=0;
+		switch (c) {
+			case 'i':
+				set_cmd_line_image(optarg);
+				break;
+			case 'b':
+				arg.markbad = 1;
+				break;
+			case 'o':
+				offset = strtoui(optarg,&endptr,0);
+				break;
+			case 's':
+				arg.setsize=1;
+				arg.size = strtoul(optarg,&endptr,0);
+				break;
+			case 'h':
+				usage(0);
+			case '?':
+				usage(1);
+		}
+		check_number_parse_errno(c, optarg, endptr);
+	}
+
+	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 = strtoui(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++) {
+		unsigned int j;
+		number = argv[i];
+		if (*number == '<') {
+			number++;
+		}
+		begin = strtoui(number, &eptr, 0);
+		if (eptr && *eptr == '-') {
+			number = eptr+1;
+			end = strtoui(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..564d9e4
--- /dev/null
+++ b/mdu.1
@@ -0,0 +1,95 @@
+'\" t
+.TH mdu 1 "28Nov20" mtools-4.0.26
+.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
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..b6a7523
--- /dev/null
+++ b/mdu.c
@@ -0,0 +1,141 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 UNUSEDP) NORETURN;
+void mdu(int argc, char **argv, int type UNUSEDP)
+{
+	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);
+				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..89fd43a
--- /dev/null
+++ b/mformat.1
@@ -0,0 +1,334 @@
+'\" t
+.TH mformat 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+The \fR\&\f(CWmformat\fR command is used to add an MS-DOS file system 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-T\fR \fItot_sectors\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-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]
+  [\fR\&\f(CW-K\fR \fIbackup_boot\fR]
+  [\fR\&\f(CW-R\fR \fInb_reserved_sectors\fR]
+  [\fR\&\f(CW-c\fR \fIclusters_per_sector\fR]
+  [\fR\&\f(CW-d\fR \fIfat_copies\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]
+  \fIdrive:\fR
+.fi
+.ft R
+ 
+.PP
+\&\fR\&\f(CWMformat\fR adds a minimal MS-DOS file system (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 MS-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, mformat will
+assign no label to the disk.
+.TP
+\&\fR\&\f(CWf\fR\ 
+Specifies the size of the DOS file system 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(CWT\fR\ 
+Specifies the number of total sectors on the disk. Only one of these 2
+options may be specified (tracks or total sectors)
+.TP
+\&\fR\&\f(CWh\fR\ 
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWs\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
+MS-DOS 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 size code. 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 file system. 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 file system 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. If no
+cluster size is specified explicitly, mtools uses a default value as
+described in section ``Number of sectors per cluster'' below.
+.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 boot sector 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 file system data are updated to match the target
+disks parameters.
+.TP
+\&\fR\&\f(CWK\fR\ 
+Sets the sector number where the backup of the boot sector should be
+stored (only relevant on FAT32).
+.TP
+\&\fR\&\f(CWR\fR\ 
+Sets the number of reserved sectors for this filesystem. This must be
+at least 1 for non-FAT32 disks, and at least 3 for FAT disks (in order
+to accommodate the boot sector, the info sector and the backup boot
+sector).
+.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 Number\ of\ sectors\ per\ cluster
+.PP
+If the user indicates no cluster size, mformat figures out a default
+value for it.
+.PP
+For FAT32 it uses the following table to determine the number of
+sectors per cluster, depending on the total number of sectors on the
+filesystem.
+.PP
+more than 32*1024*1024*2: 64 sectors
+.br
+between 16*1024*1024*2 and 32*1024*1024*2: 32 sectors
+.br
+between 8*1024*1024*2 and 16*1024*1024*2: 16 sectors
+.br
+between 260*1024*2 and 81024*1024*2: 1 sectors
+.br
+.PP
+This is derived from information on page 20 of Microsoft's
+\&\fR\&\f(CWfatgen103\fR document, which currently can be found at the
+following address:
+.PP
+\&\fR\&\f(CWhttps://staff.washington.edu/dittrich/misc/fatgen103.pdf\fR
+.PP
+For FAT12 and FAT16, mformat uses an iterative approach, where it
+starts with a set value, which it doubles until it is able to fill up
+the disk using that cluster size and a number of cluster less than the
+maximum allowed.
+.PP
+The starting value is 1 for disks with one head or less than 2000
+sectors, and 2 for disks with more than one head, and more than 2000
+sectors.
+.PP
+The number of sectors per cluster cannot go beyond 128.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..cd2e5f3
--- /dev/null
+++ b/mformat.c
@@ -0,0 +1,1548 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <assert.h>
+#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,
+			      uint8_t sectors0,
+			      uint8_t rate_0, uint8_t rate_any,
+			      unsigned long *tot_sectors, int keepBoot)
+{
+	int nb_renum;
+	int sector2;
+	int sum;
+
+	set_word(boot->boot.nsect, dev->sectors);
+	set_word(boot->boot.nheads, dev->heads);
+
+#ifdef HAVE_ASSERT_H
+	assert(*tot_sectors != 0);
+#endif
+
+	if (*tot_sectors <= UINT16_MAX){
+		set_word(boot->boot.psect, (uint16_t) *tot_sectors);
+		set_dword(boot->boot.bigsect, 0);
+	} else if(*tot_sectors <= UINT32_MAX){
+		set_word(boot->boot.psect, 0);
+		set_dword(boot->boot.bigsect, (uint32_t) *tot_sectors);
+	} else {
+		fprintf(stderr, "Too many sectors %ld\n", *tot_sectors);
+		exit(1);
+	}
+
+	if (dev->use_2m & 0x7f){
+		int bootOffset;
+		uint8_t j;
+		uint8_t size2;
+		uint16_t i;
+		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; j<i; j++)
+			sum += boot->bytes[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(Fs->cluster_size == 0 &&
+			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) { // 0x0ff5
+ *  // Volume is FAT12
+ * } else if (CountofClusters < 65525) { // 0xfff5
+ *  // Volume is FAT16
+ * } else {
+ *  //Volume is FAT32
+ * }
+ *
+ * This document can be found at the following URL:
+ * https://staff.washington.edu/dittrich/misc/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;
+	unsigned int i;
+	struct ClashHandling_t ch;
+	unsigned int dirlen;
+
+	init_clash_handling(&ch);
+	ch.name_converter = label_name_uc;
+	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);
+}
+
+
+#ifdef USE_XDF
+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);
+}
+#endif
+
+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;
+	unsigned 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:
+			/*
+			   FAT32 cluster sizes for disks with 512 block size
+			   according to Microsoft specification fatgen103.doc:
+			
+			   32.5 MB - 260 MB   cluster_size =  1
+			    260 MB -   8 GB   cluster_size =  8
+			      8 GB -  16 GB   cluster_size = 16
+			     16 GB -  32 GB   cluster_size = 32
+			     32 GB -   2 TB   cluster_size = 64
+			
+			   Below calculation is generalized and does not depend
+			   on 512 block size.
+			 */
+			Fs->cluster_size = tot_sectors > 32*1024*1024*2 ? 64 :
+			                   tot_sectors > 16*1024*1024*2 ? 32 :
+			                   tot_sectors >  8*1024*1024*2 ? 16 :
+			                   tot_sectors >     260*1024*2 ? 8 : 1;
+			return;
+		default:
+			fprintf(stderr,"Bad fat size\n");
+			exit(1);
+	}
+
+	if(tot_sectors <= Fs->fat_start + Fs->num_fat + Fs->dir_len) {
+		/* we need at least enough sectors to fit boot, fat and root
+		 * dir */
+		fprintf(stderr, "Not enough sectors\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;
+	}
+}
+
+
+static int old_dos_size_to_geom(size_t size,
+				unsigned int *cyls,
+				unsigned short *heads,
+				unsigned short *sects)
+{
+	struct OldDos_t *params = getOldDosBySize(size);
+	if(params != NULL) {
+		*cyls = params->tracks;
+		*heads = params->heads;
+		*sects = params->sectors;
+		return 0;
+	} else
+		return 1;
+}
+
+
+static void calc_fs_parameters(struct device *dev, unsigned long tot_sectors,
+			       struct Fs_t *Fs, union bootsector *boot)
+{
+	struct OldDos_t *params=NULL;
+	if(dev->fat_bits == 0 || abs(dev->fat_bits) == 12)
+		params = getOldDosByParams(dev->tracks,dev->heads,dev->sectors,
+					   Fs->dir_len, Fs->cluster_size);
+	if(params != NULL) {
+		boot->boot.descr = params->media;
+		Fs->cluster_size = params->cluster_size;
+		Fs->dir_len = params->dir_len;
+		Fs->fat_len = params->fat_len;
+		Fs->fat_bits = 12;
+	} else {
+		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) || tot_sectors % (dev->sectors * dev->heads))
+			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);
+#ifdef USE_XDF
+		if(Fs->fat_len)
+			xdf_calc_fat_size(Fs, tot_sectors, dev->fat_bits);
+		else
+#endif
+		{
+			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)
+{
+	unsigned long num_clus;
+	if(DWORD(nhs))
+		boot->boot.descr = 0xf8;
+	else
+		boot->boot.descr = 0xf0;
+
+	if(!Fs->cluster_size)
+		calc_cluster_size(Fs, tot_sectors, 32);
+	Fs->dir_len = 0;
+	num_clus = tot_sectors / Fs->cluster_size;
+	/* Maximal number of clusters on FAT32 is 0xffffff6 */
+	if (num_clus > 0xffffff6) {
+		fprintf(stderr, "Too many clusters\n");
+		exit(1);
+	}
+	Fs->num_clus = (unsigned int) num_clus;
+	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) NORETURN;
+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_sector_size(int fd, char *errmsg) {
+	int sec_size;
+	if (ioctl(fd, BLKSSZGET, &sec_size) != 0 || sec_size <= 0) {
+		sprintf(errmsg, "Could not get sector size of device (%s)",
+			strerror(errno));
+		return -1;
+	}
+
+	/* Cap sector size at 4096 */
+	if(sec_size > 4096)
+		sec_size = 4096;
+	return sec_size;
+}
+
+static int get_block_geom(int fd, struct device *dev, char *errmsg) {
+	struct hd_geometry geom;
+	int sec_size;
+	long size;
+	uint16_t heads=dev->heads;
+	uint16_t sectors=dev->sectors;
+	unsigned 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;
+	}
+
+	sec_size = get_sector_size(fd, errmsg);
+	if(sec_size < 0)
+		return -1;
+	
+	dev->ssize = 0;
+	while (dev->ssize < 0x7F && (128 << dev->ssize) < sec_size)
+		dev->ssize++;
+
+	if(!heads)
+		heads = geom.heads;
+	if(!sectors)
+		sectors = geom.sectors;
+
+	sect_per_track = heads * sectors;
+	if(!dev->hidden) {
+		unsigned long hidden;
+		hidden = geom.start % sect_per_track;
+		if(hidden && hidden != sectors) {
+			sprintf(errmsg,
+				"Hidden (%ld) 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) / sect_per_track;
+	return 0;
+}
+#endif
+
+static int get_lba_geom(Stream_t *Direct, unsigned long tot_sectors, struct device *dev, char *errmsg) {
+	int sect_per_track;
+	unsigned long tracks;
+
+	/* if one value is already specified we do not want to overwrite it */
+	if (dev->heads || dev->sectors || dev->tracks) {
+		sprintf(errmsg, "Number of heads or sectors or tracks was already specified");
+		return -1;
+	}
+
+	if (!tot_sectors) {
+#ifdef OS_linux
+		int fd;
+		int sec_size;
+		long size;
+		struct MT_STAT stbuf;
+
+		fd = get_fd(Direct);
+		if (MT_FSTAT(fd, &stbuf) < 0) {
+			sprintf(errmsg, "Could not stat file (%s)", strerror(errno));
+			return -1;
+		}
+
+		if (S_ISBLK(stbuf.st_mode)) {
+			if (ioctl(fd, BLKGETSIZE, &size) != 0) {
+				sprintf(errmsg, "Could not get size of device (%s)",
+					strerror(errno));
+				return -1;
+			}
+			sec_size = get_sector_size(fd, errmsg);
+			if(sec_size < 0)
+				return -1;
+
+			if (!(dev->ssize & 0x80)) {
+				dev->ssize = 0;
+				while (dev->ssize < 0x7F && (128 << dev->ssize) < sec_size)
+				dev->ssize++;
+			}
+			if ((dev->ssize & 0x7f) > 2)
+				tot_sectors = size >> ((dev->ssize & 0x7f) - 2);
+			else
+				tot_sectors = size << (2 - (dev->ssize & 0x7f));
+		} else if (S_ISREG(stbuf.st_mode)) {
+			tot_sectors = stbuf.st_size >> ((dev->ssize & 0x7f) + 7);
+		} else {
+			sprintf(errmsg, "Could not get size of device (%s)",
+				"No method available");
+			return -1;
+		}
+#else
+		mt_size_t size;
+		GET_DATA(Direct, 0, &size, 0, 0);
+		if (size == 0) {
+			sprintf(errmsg, "Could not get size of device (%s)",
+				"No method available");
+			return -1;
+		}
+		tot_sectors = size >> ((dev->ssize & 0x7f) + 7);
+#endif
+	}
+
+	dev->sectors = 63;
+
+	if (tot_sectors < 16*63*1024)
+		dev->heads = 16;
+	else if (tot_sectors < 32*63*1024)
+		dev->heads = 32;
+	else if (tot_sectors < 64*63*1024)
+		dev->heads = 64;
+	else if (tot_sectors < 128*63*1024)
+		dev->heads = 128;
+	else
+		dev->heads = 255;
+
+	sect_per_track = dev->heads * dev->sectors;
+	tracks = (tot_sectors + dev->hidden % sect_per_track) / sect_per_track;
+	if (tracks > 0xFFFFFFFF) {
+		sprintf(errmsg, "Device is too big, it has too many tracks");
+		return -1;
+	}
+
+	dev->tracks = (uint32_t) tracks;
+
+	return 0;
+}
+
+void mformat(int argc, char **argv, int dummy UNUSEDP) NORETURN;
+void mformat(int argc, char **argv, int dummy UNUSEDP)
+{
+	int r; /* generic return value */
+	Fs_t Fs;
+	unsigned int hs;
+	int hs_set;
+	unsigned int arguse_2m = 0;
+	uint8_t sectors0=18; /* number of sectors on track 0 */
+	int create = 0;
+	uint8_t rate_0, rate_any;
+	int mangled;
+	uint8_t 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;
+	unsigned int argtracks;
+	uint16_t argheads, argsectors;
+	unsigned long tot_sectors=0;
+	int blocksize;
+
+	char drive, name[EXPAND_BUF];
+
+	char label[VBUFSIZE];
+
+	dos_name_t shortlabel;
+	struct device *dev;
+	char errmsg[2100];
+
+	uint32_t serial;
+ 	int serial_set;
+	int fsVersion;
+	int mediaDesc=-1;
+
+	mt_size_t maxSize;
+
+	int Atari = 0; /* should we add an Atari-style serial number ? */
+
+	unsigned int backupBoot = 6;
+	int backupBootSet = 0;
+
+	unsigned int resvSects = 0;
+	
+	char *endptr;
+
+	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 = atoui(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 = atoui(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"
+			   "kK:R:B:r:L:I:FCc:Xh:s:T:l:N:H:M:S:2:30:Aad:m:"))!= EOF) {
+		errno = 0;
+		endptr = NULL;
+		switch (c) {
+			case 'i':
+				set_cmd_line_image(optarg);
+				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(atoul(optarg),
+						       &argtracks, &argheads,
+						       &argsectors);
+				if(r) {
+					fprintf(stderr,
+						"Bad size %s\n", optarg);
+					exit(1);
+				}
+				break;
+			case 't':
+				argtracks = atou16(optarg);
+				break;
+
+			case 'T':
+				tot_sectors = atoui(optarg);
+				break;
+
+			case 'n': /*non-standard*/
+			case 's':
+				argsectors = atou16(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 = atou8(optarg) | 0x80;
+				if(argssize < 0x80)
+					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 = atou8(optarg);
+				break;
+			case '3':
+				arguse_2m = 0x80;
+				break;
+
+			case '0': /* rate on track 0 */
+				rate_0 = atou8(optarg);
+				break;
+			case 'A': /* rate on other tracks */
+				rate_any = atou8(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 = strtou32(optarg,&endptr,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 = atoui(optarg);
+				hs_set = 1;
+				break;
+
+			case 'I':
+				fsVersion = strtoi(optarg,&endptr,0);
+				break;
+
+			case 'c':
+				Fs.cluster_size = atoui(optarg);
+				break;
+
+			case 'r':
+				Fs.dir_len = strtoui(optarg,&endptr,0);
+				break;
+			case 'L':
+				Fs.fat_len = strtoui(optarg,&endptr,0);
+				break;
+
+
+			case 'B':
+				bootSector = optarg;
+				break;
+			case 'k':
+				keepBoot = 1;
+				break;
+			case 'K':
+				backupBoot = atoui(optarg);
+				backupBootSet=1;
+				if(backupBoot < 2) {
+				  fprintf(stderr, "Backupboot must be greater than 2\n");
+				  exit(1);
+				}
+				break;
+			case 'R':
+				resvSects = atoui(optarg);
+				break;
+			case 'h':
+				argheads = atou16(optarg);
+				break;
+			case 'd':
+				Fs.num_fat = atoui(optarg);
+				break;
+			case 'm':
+				mediaDesc = strtoi(optarg,&endptr,0);
+				if(*endptr)
+					mediaDesc = strtoi(optarg,&endptr,16);
+				break;
+			default:
+				usage(1);
+		}
+		check_number_parse_errno(c, optarg, endptr);
+	}
+
+	if (argc - optind > 1)
+		usage(1);
+	if(argc - optind == 1) {
+	    if(!argv[optind][0] || argv[optind][1] != ':')
+		usage(1);
+	    drive = ch_toupper(argv[argc -1][0]);
+	} else {
+	    drive = get_default_drive();
+	    if(drive != ':') {
+	      /* Use default drive only if it is ":" (image file), as else
+		 it would be too dangerous... */
+	      fprintf(stderr, "Drive letter missing\n");
+	      exit(1);
+	    }
+	}
+
+	if(argtracks && tot_sectors) {
+		fprintf(stderr, "Only one of -t or -T may be specified\n");
+		usage(1);
+	}
+
+#ifdef USE_XDF
+	if(create && format_xdf) {
+		fprintf(stderr,"Create and XDF can't be used together\n");
+		exit(1);
+	}
+#endif
+
+	/* 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, name,
+						O_RDWR | create,
+						errmsg, &maxSize);
+#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))
+			    /* If the following get_block_geom fails, do not 
+			     * continue to next drive description, but allow
+			     * get_lba_geom to kick in
+			     */
+			    get_block_geom(fd, &used_dev, errmsg);
+		}
+#endif
+
+		if ((!used_dev.tracks && !tot_sectors) ||
+		     !used_dev.heads || !used_dev.sectors){
+			if (get_lba_geom(Fs.Direct, tot_sectors, &used_dev,
+					 errmsg) < 0) {
+				sprintf(errmsg, "%s: "
+					"Complete geometry of the disk "
+					"was not specified, \n"
+					"neither in /etc/mtools.conf nor "
+					"on the command line. \n"
+					"LBA Assist Translation for "
+					"calculating CHS geometry "
+					"of the disk failed.\n", argv[0]);
+				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) {
+#ifdef HAVE_SNPRINTF
+			snprintf(errmsg, sizeof(errmsg)-1,
+				 "Error reading from '%s', wrong parameters?",
+				 name);
+#else
+			sprintf(errmsg,
+				"Error reading from '%s', wrong parameters?",
+				name);
+#endif
+			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 */
+	if(tot_sectors == 0) {
+		unsigned long sect_per_track = used_dev.heads*used_dev.sectors;
+		tot_sectors = used_dev.tracks*sect_per_track - used_dev.hidden%sect_per_track;
+		/* Number of sectors must fit into 32bit value */
+		if (tot_sectors > 0xFFFFFFFF) {
+			fprintf(stderr, "Too many sectors\n");
+			exit(1);
+		}
+	}
+
+	/* 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;
+		close(fd);
+	}
+	if(!keepBoot && !(used_dev.use_2m & 0x7f))
+		memset(boot.characters, '\0', Fs.sector_size);
+	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(!keepBoot && !(used_dev.use_2m & 0x7f)) {
+		if(!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,
+				    used_dev.fat_bits);
+		}
+	}
+
+	if(used_dev.fat_bits == 32) {
+		Fs.primaryFat = 0;
+		Fs.writeAllFats = 1;
+		if(resvSects) {
+			if(resvSects < 3) {
+				fprintf(stderr,
+					"For FAT 32, reserved sectors need to be at least 3\n");
+				resvSects = 32;
+			}
+
+			if(resvSects <= backupBoot && !backupBootSet)
+				backupBoot = resvSects - 1;
+			Fs.fat_start = resvSects;
+		} else 
+			Fs.fat_start = 32;
+
+		if(Fs.fat_start <= backupBoot) {
+			fprintf(stderr,
+				"Reserved sectors (%d) must be more than backupBoot (%d)\n", Fs.fat_start, backupBoot);
+			backupBoot = 6;
+			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, backupBoot);
+
+		labelBlock = & boot.boot.ext.fat32.labelBlock;
+	} else {
+		Fs.infoSectorLoc = 0;
+		if(resvSects) {
+			if(resvSects < 1) {
+				fprintf(stderr,
+					"Reserved sectors need to be at least 1\n");
+				resvSects = 1;
+			}
+			Fs.fat_start = resvSects;
+		} else 
+			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)
+		init_random();
+	if (!serial_set)
+		serial=(uint32_t) random();
+	set_dword(labelBlock->serial, serial);
+	label_name_pc(GET_DOSCONVERT((Stream_t *)&Fs),
+		      label[0] ? label : "NO NAME    ", 0,
+		      &mangled, &shortlabel);
+	strncpy(labelBlock->label, shortlabel.base, 8);
+	strncpy(labelBlock->label+8, shortlabel.ext, 3);
+	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] = (char) random();
+		boot.boot.banner[6] = (char) random();
+		boot.boot.banner[7] = (char) 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(used_dev.fat_bits == 32) {
+	  WRITES((Stream_t *)&Fs, boot.characters,
+		 (mt_off_t) backupBoot * Fs.sector_size, 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..5d8fecd
--- /dev/null
+++ b/minfo.1
@@ -0,0 +1,99 @@
+'\" t
+.TH minfo 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+The \fR\&\f(CWminfo\fR command prints the parameters of a MS-DOS file system, such
+as number of sectors, heads and cylinders.  It also prints an mformat
+command line which can be used to create a similar MS-DOS file system on
+another media.  However, this doesn't work with 2m or XDF media, and
+with MS-DOS 1.0 file systems
+.ft I
+.nf
+\&\fR\&\f(CWminfo\fR \fIdrive\fR:
+.fi
+.ft R
+ 
+.PP
+Minfo supports the following option:
+.TP
+\&\fR\&\f(CWv\fR\ 
+Prints a hexdump of the boot sector, 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..05c4e9d
--- /dev/null
+++ b/minfo.c
@@ -0,0 +1,259 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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));
+}
+
+
+static void displayBPB(Stream_t *Stream, union bootsector *boot) {
+	struct label_blk_t *labelBlock;
+
+	printf("bootsector information\n");
+	printf("======================\n");
+	printf("banner:\"%.8s\"\n", boot->boot.banner);
+	printf("sector size: %d bytes\n", WORD(secsiz));
+	printf("cluster size: %d sectors\n", boot->boot.clsiz);
+	printf("reserved (boot) sectors: %d\n", WORD(nrsvsect));
+	printf("fats: %d\n", boot->boot.nfat);
+	printf("max available root directory slots: %d\n", 
+	       WORD(dirents));
+	printf("small size: %d sectors\n", WORD(psect));
+	printf("media descriptor byte: 0x%x\n", boot->boot.descr);
+	printf("sectors per fat: %d\n", WORD(fatlen));
+	printf("sectors per track: %d\n", WORD(nsect));
+	printf("heads: %d\n", WORD(nheads));
+	printf("hidden sectors: %d\n", DWORD(nhs));
+	printf("big size: %d sectors\n", DWORD(bigsect));
+
+	if(WORD(fatlen)) {
+		labelBlock = &boot->boot.ext.old.labelBlock;
+	} else {
+		labelBlock = &boot->boot.ext.fat32.labelBlock;
+	}
+
+	if(has_BPB4) {
+		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(fatlen)){
+		printf("Big fatlen=%u\n",
+		       DWORD(ext.fat32.bigFat));
+		printf("Extended flags=0x%04x\n",
+		       WORD(ext.fat32.extFlags));
+		printf("FS version=0x%04x\n",
+		       WORD(ext.fat32.fsVersion));
+		printf("rootCluster=%u\n",
+		       DWORD(ext.fat32.rootCluster));
+		if(WORD(ext.fat32.infoSector) != MAX16)
+			printf("infoSector location=%d\n",
+			       WORD(ext.fat32.infoSector));
+		if(WORD(ext.fat32.backupBoot) != MAX16)
+			printf("backup boot sector=%d\n",
+			       WORD(ext.fat32.backupBoot));
+		displayInfosector(Stream, boot);
+	}
+}
+
+void minfo(int argc, char **argv, int type UNUSEDP) NORETURN;
+void minfo(int argc, char **argv, int type UNUSEDP)
+{
+	union bootsector boot;
+
+	char name[EXPAND_BUF];
+	int media;
+	int haveBPB;
+	int size_code;
+	int i;
+	struct device dev;
+	char drive;
+	int verbose=0;
+	int c;
+	Stream_t *Stream;
+	int have_drive = 0;
+
+	unsigned long sect_per_track;
+
+	char *imgFile=NULL;
+	
+	if(helpFlag(argc, argv))
+		usage(0);
+	while ((c = getopt(argc, argv, "i:vh")) != EOF) {
+		switch (c) {
+			case 'i':
+				set_cmd_line_image(optarg);
+				imgFile=optarg;
+				break;
+			case 'v':
+				verbose = 1;
+				break;
+			case 'h':
+				usage(0);
+			default:
+				usage(1);
+		}
+	}
+
+	for(;optind <= argc; optind++) {
+		if(optind == argc) {
+			if(have_drive)
+				break;
+			drive = get_default_drive();
+		} else {
+			if(!argv[optind][0] || argv[optind][1] != ':')
+				usage(1);
+			drive = ch_toupper(argv[optind][0]);
+		}
+		have_drive = 1;
+
+		if(! (Stream = find_device(drive, O_RDONLY, &dev, &boot, 
+					   name, &media, 0, NULL)))
+			exit(1);
+
+		haveBPB = media >= 0x100;
+		media = media & 0xff;
+		
+		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("media byte: %02x\n\n", media & 0xff);
+
+		sect_per_track = dev.sectors * dev.heads;
+		if(sect_per_track != 0) {
+			unsigned int hidden;
+			unsigned long tot_sectors;
+			int tracks_match=0;
+			printf("mformat command line: mformat ");
+
+			if(haveBPB) {
+				int sector_size;
+				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;
+					}
+				}
+				if(media == 0xf0)
+					hidden = DWORD_S(nhs);
+				else
+					hidden = 0;
+			} else {
+				tot_sectors = dev.tracks * sect_per_track;
+				size_code=2;
+				hidden = 0;
+			}
+
+			if(tot_sectors ==
+			   dev.tracks * sect_per_track - hidden % sect_per_track) {
+				tracks_match=1;
+				printf("-t %d ", dev.tracks);
+			} else {
+				printf("-T %ld ", tot_sectors);
+			}
+			printf ("-h %d -s %d ", dev.heads, dev.sectors);
+			if(haveBPB && (hidden || !tracks_match))
+				printf("-H %d ", hidden);
+			if(size_code != 2)
+				printf("-S %d ",size_code);
+			if(imgFile != NULL)
+				printf("-i \"%s\" ", imgFile);
+			printf("%c:\n", ch_tolower(drive));
+			printf("\n");
+		}
+
+		if(haveBPB || verbose)
+			displayBPB(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..21796d1
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,294 @@
+/*  Copyright 1996-2002,2005,2007,2009,2011 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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");
+	}
+}
+
+#if (SIZEOF_TIME_T > SIZEOF_LONG) && defined (HAVE_STRTOLL)
+# define STRTOTIME strtoll
+#else
+# define STRTOTIME strtol
+#endif
+
+time_t getTimeNow(time_t *now)
+{
+	static int haveTime = 0;
+	static time_t sharedNow;
+
+	if(!haveTime) {
+		const char *source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+		if (source_date_epoch) {
+			char *endptr;
+			time_t epoch =
+				STRTOTIME(source_date_epoch, &endptr, 10);
+			errno = 0;
+
+			if (endptr == source_date_epoch)
+				fprintf(stderr,
+					"SOURCE_DATE_EPOCH \"%s\" invalid\n",
+					source_date_epoch);
+			else if (errno != 0)
+				fprintf(stderr,
+					"SOURCE_DATE_EPOCH: strtoll: %s: %s\n",
+					strerror(errno), source_date_epoch);
+			else if (*endptr != '\0')
+				fprintf(stderr,
+					"SOURCE_DATE_EPOCH has trailing garbage \"%s\"\n",
+					endptr);
+			else {
+				sharedNow = epoch;
+				haveTime = 1;
+			}
+		}
+	}
+	
+	if(!haveTime) {
+		time(&sharedNow);
+		haveTime = 1;
+	}
+	if(now)
+		*now = sharedNow;
+	return sharedNow;
+}
+
+/* Convert a string to an offset. The string should be a number,
+   optionally followed by S (sectors), K (K-Bytes), M (Megabytes), G
+   (Gigabytes) */
+off_t str_to_offset(char *str) {
+	char s, *endp = NULL;
+	off_t ofs;
+
+	ofs = strtol(str, &endp, 0);
+	if (ofs <= 0)
+		return 0; /* invalid or missing offset */
+	s = *endp++;
+	if (s) {   /* trailing char, see if it is a size specifier */
+		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 */
+	}
+	return ofs;
+}
+
+#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 allocated=%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..271fe0b
--- /dev/null
+++ b/missFuncs.c
@@ -0,0 +1,498 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+#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 */
+
+#ifndef HAVE_STRNDUP
+char *strndup( const char *s, size_t n )
+{
+    size_t nAvail;
+    char *p;
+
+    if ( !s )
+        return 0;
+
+    nAvail = min( strlen(s) + 1, n + 1 );
+    p      = malloc( nAvail );
+    if ( !p )
+	    return 0;
+    memcpy( p, s, nAvail );
+    p[nAvail - 1] = '\0';
+
+    return p;
+}
+#endif /* HAVE_STRNDUP */
+
+
+#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 initial 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<l; i++) {
+    if(str[i] == 0)
+      break;
+  }
+  return i;
+}
+#endif /* HAVE_STRNLEN */
+
+#ifdef HAVE_WCHAR_H
+#ifndef HAVE_WCSNLEN
+size_t wcsnlen(const wchar_t *wcs, size_t l)
+{
+  size_t i;
+  for(i=0; i<l; i++) {
+    if(wcs[i] == 0)
+      break;
+  }
+  return i;
+}
+#endif /* HAVE_WCSNLEN */
+#endif
diff --git a/mk_direntry.c b/mk_direntry.c
new file mode 100644
index 0000000..37015ea
--- /dev/null
+++ b/mk_direntry.c
@@ -0,0 +1,709 @@
+/*  Copyright 1995-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 <http://www.gnu.org/licenses/>.
+ *
+ * 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';
+	if (dn->base[0] == '\xE5')
+		dn->base[0] = '\x05';
+	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 
+	 * <Return> to get it.
+	 */
+#if 0
+	fprintf(stderr,"Entering ask_rename, isprimary=%d.\n", isprimary);
+#endif
+
+	if(!opentty(0))
+		return 0;
+
+	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;
+}
+
+/**
+ * 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, sizeof(*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(!ch->is_label &&
+		  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;
+	ch->is_label = 0;
+}
+
+int handle_clash_options(ClashHandling_t *ch, char c)
+{
+	int isprimary;
+	if(isupper(c))
+		isprimary = 0;
+	else
+		isprimary = 1;
+	c = ch_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 <http://www.gnu.org/licenses/>.
+
+# 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..d9ffdf8
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,50 @@
+#! /bin/sh
+
+# Copyright 1993 Noah Friedman <friedman@prep.ai.mit.edu>
+# 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 <http://www.gnu.org/licenses/>.
+
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# 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 -p "$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..4f398fb
--- /dev/null
+++ b/mkmanifest.1
@@ -0,0 +1,180 @@
+'\" t
+.TH mkmanifest 1 "28Nov20" mtools-4.0.26
+.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
+.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
+.PP
+ 
+\&\fR
+.PP
+\&\fR\&\f(CWASCII\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..1ccf37f
--- /dev/null
+++ b/mkmanifest.c
@@ -0,0 +1,113 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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] <list-of-files>\n");
+		return 1;
+	}
+
+	for (i=1; i<argc; i++) {
+		/* zap the leading path */
+		name = _basename(argv[i]);
+		/* create new name */
+		new_name = dos_name2(name);
+
+		if (strcasecmp(new_name, name))
+			printf("mv %s %s\n", new_name, name);
+	}
+	return 0;
+}
+
+static char *dos_name2(const char *name)
+{
+	static const char *dev[9] = {"con", "aux", "com1", "com2", "lpt1", 
+				     "prn", "lpt2", "lpt3", "nul"};
+	char *s;
+	char *ext,*temp;
+	char buf[MAX_PATH];
+	int i, dot;
+	static char ans[13];
+
+	strncpy(buf, name, MAX_PATH-1);
+	temp = buf;
+					/* separate the name from extension */
+	ext = 0;
+	dot = 0;
+	for (i=strlen(buf)-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] = ch_tolower(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);
+		ans[12] = '\0';
+	}
+	if (ext && *ext) {
+		strcat(ans, ".");
+		strcat(ans, ext);
+	}
+	return(ans);
+}
diff --git a/mkmanpages b/mkmanpages
new file mode 100755
index 0000000..cc10eb1
--- /dev/null
+++ b/mkmanpages
@@ -0,0 +1,147 @@
+#!/bin/bash
+
+# Copyright 1997,1999,2001,2002,2004,2009,2010 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 <http://www.gnu.org/licenses/>.
+
+# 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()
+{
+  command=$1
+  echo extracting $command
+  outfile=`echo $command | tr '[A-Z]' '[a-z]'`.1
+  exec 4>&1
+  exec >$outfile
+
+  echo \'\\\" t
+# '
+  echo .TH\ $command\ 1\ \"$date\" $package
+  echo .SH Name
+  egrep -i "^$command " cmdname | fgrep -v '#'
+  #echo ".SH Description"
+  
+  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 |
+  sed -e '/^\.iX/d'
+  exec 1>&4
+#  echo ".SH See Also"
+#  echo "Mtools' texinfo doc"
+}
+
+
+for name in `fgrep -v '#' cmdname | cut -f1 -d\  ` ; do
+  extract $name
+done
+
+rm -f mtools.tmpl.1
+exec >mtools.tmpl.1
+echo \'\\\" t
+# '
+echo .TH mtools 1 \"$date\" $package
+echo .SH Name
+echo "mtools - utilities to access DOS disks in Unix."
+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" \
+	 -e "s%@value{SYSCONFDIR}%SYSCONFDIR%g" |
+	texi2roff -ma  |
+	sed -f strip-pp.sed |
+	sed -e '/^\.iX/d'
+
+echo .SH See also
+echo floppyd_installtest
+echo mattrib
+echo mbadblocks
+echo mcd
+echo mclasserase
+echo mcopy
+echo mdel
+echo mdeltree
+echo mdir
+echo mdu
+echo mformat
+echo minfo
+echo mkmanifest
+echo mlabel
+echo mmd
+echo mmount
+echo mmove
+echo mrd
+echo mren
+echo mshortname
+echo mshowfat
+echo mtoolstest
+echo mtype
+
+rm -f mtools.tmpl.5
+exec >mtools.tmpl.5
+echo \'\\\" t
+# '
+echo .TH mtools 5 \"$date\" "MTOOLS" "MTOOLS"
+echo .SH Name
+echo "mtools.conf - mtools configuration files"
+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 "s%@value{SYSCONFDIR}%SYSCONFDIR%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 -e '/^\.iX/d' -e 's/\.SS Description/.SH Description/'
+
+echo .SH See also
+echo mtools
diff --git a/mlabel.1 b/mlabel.1
new file mode 100644
index 0000000..6f24f7a
--- /dev/null
+++ b/mlabel.1
@@ -0,0 +1,118 @@
+'\" t
+.TH mlabel 1 "28Nov20" mtools-4.0.26
+.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
+.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
+The label is limited to 11 single-byte characters,
+e.g. \fR\&\f(CWName1234567\fR.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..c90c722
--- /dev/null
+++ b/mlabel.c
@@ -0,0 +1,335 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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"
+
+static void _label_name(doscp_t *cp, const char *filename, int verbose UNUSEDP,
+			int *mangled, dos_name_t *ans, int preserve_case)
+{
+	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<len; i++){
+		if(islower(wbuffer[i]))
+			have_lower = 1;
+		if(isupper(wbuffer[i]))
+			have_upper = 1;
+		if(!preserve_case)
+			wbuffer[i] = ch_towupper(wbuffer[i]);
+		if(
+#ifdef HAVE_WCHAR_H
+		   wcschr(L"^+=/[]:,?*\\<>|\".", 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);
+}
+
+void label_name_uc(doscp_t *cp, const char *filename, int verbose,
+		   int *mangled, dos_name_t *ans)
+{
+	_label_name(cp, filename, verbose, mangled, ans, 0);
+}
+
+void label_name_pc(doscp_t *cp, const char *filename, int verbose,
+		   int *mangled, dos_name_t *ans)
+{
+	_label_name(cp, filename, verbose, mangled, ans, 1);
+}
+
+int labelit(struct dos_name_t *dosname,
+	    char *longname UNUSEDP,
+	    void *arg0 UNUSEDP,
+	    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 UNUSEDP) NORETURN;
+void mlabel(int argc, char **argv, int type UNUSEDP)
+{
+
+	const 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;
+	uint32_t 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;
+	char drive;
+
+	init_clash_handling(&ch);
+	ch.name_converter = label_name_uc;
+	ch.ignore_entry = -2;
+	ch.is_label = 1;
+
+	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);
+				break;
+			case 'v':
+				verbose = 1;
+				break;
+			case 'c':
+				clear = 1;
+				break;
+			case 's':
+				show = 1;
+				break;
+			case 'n':
+				set_serial = SER_RANDOM;
+				init_random();
+				serial=random();
+				break;
+			case 'N':
+				set_serial = SER_SET;
+				errno=0;
+				serial = strtou32(optarg, &eptr, 16);
+				if(*eptr) {
+					fprintf(stderr,
+						"%s not a valid serial number\n",
+						optarg);
+					exit(1);
+				}
+				check_number_parse_errno(c, optarg, eptr);
+				break;
+			case 'h':
+				usage(0);
+			default:
+				usage(1);
+			}
+	}
+
+	if (argc - optind > 1)
+		usage(1);
+	if(argc - optind == 1) {
+	    if(!argv[optind][0] || argv[optind][1] != ':')
+		usage(1);
+	    drive = ch_toupper(argv[argc -1][0]);
+	    newLabel = argv[optind]+2;
+	} else {
+	    drive = get_default_drive();
+	}
+
+	init_mp(&mp);
+	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;
+	}
+	if(clear && newLabel[0]) {
+		/* Clear and new label specified both */
+		fprintf(stderr, "Both clear and new label specified\n");
+		FREE(&RootDir);
+		exit(1);
+	}		
+	RootDir = open_root_dir(drive, 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, sizeof(shortname),
+		      longname, sizeof(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){
+		saved_sig_state ss; 
+		newLabel = longname;
+		allow_interrupts(&ss);
+		fprintf(stderr,"Enter the new volume label : ");
+		if(fgets(longname, VBUFSIZE, stdin) == NULL) {
+			fprintf(stderr, "\n");
+			if(errno == EINTR) {
+				FREE(&RootDir);
+				exit(1);
+			}
+			longname[0] = '\0';
+		}
+		if(longname[0])
+			longname[strlen(newLabel)-1] = '\0';
+	}
+
+	if(strlen(newLabel) > 11) {
+		fprintf(stderr,"New label too long\n");
+		FREE(&RootDir);
+		exit(1);
+	}
+
+	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_pc(cp, shrtLabel, verbose, &mangled, &dosname);
+
+		if(have_boot && boot.boot.descr >= 0xf0 && has_BPB4) {
+			strncpy(labelBlock->label, dosname.base, 8);
+			strncpy(labelBlock->label+8, dosname.ext, 3);
+			need_write_boot = 1;
+
+		}
+	}
+
+	if((set_serial != SER_NONE) & have_boot) {
+		if(have_boot && boot.boot.descr >= 0xf0 && has_BPB4) {
+			set_dword(labelBlock->serial, serial);	
+			need_write_boot = 1;
+		}
+	}
+
+	if(need_write_boot) {
+		force_write(Fs, (char *)&boot, 0, sizeof(boot));
+		/* If this is fat 32, write backup boot sector too */
+		if(!WORD_S(fatlen)) {
+			int backupBoot = WORD_S(ext.fat32.backupBoot);
+			force_write(Fs, (char *)&boot, 
+				    backupBoot * WORD_S(secsiz),
+				    sizeof(boot));
+		}
+	}
+
+	FREE(&RootDir);
+	exit(result);
+}
diff --git a/mmd.1 b/mmd.1
new file mode 100644
index 0000000..37063f5
--- /dev/null
+++ b/mmd.1
@@ -0,0 +1,91 @@
+'\" t
+.TH mmd 1 "28Nov20" mtools-4.0.26
+.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
+.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 file system. 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..c6b34eb
--- /dev/null
+++ b/mmd.c
@@ -0,0 +1,197 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * mmd.c
+ * Makes an MSDOS directory
+ */
+
+
+#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 UNUSEDP,
+		  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 UNUSEDP, 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 UNUSEDP) NORETURN;
+void mmd(int argc, char **argv, int type UNUSEDP)
+{
+	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);
+				break;
+			case '?':
+				usage(1);
+			case 'o':
+				handle_clash_options(&arg.ch, (char) c);
+				break;
+			case 'D':
+				if(handle_clash_options(&arg.ch, *optarg))
+					usage(1);
+				break;
+			case 'h':
+				usage(0);
+			default:
+				usage(1);
+		}
+	}
+
+	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..90b983a
--- /dev/null
+++ b/mmount.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mmount 1 "28Nov20" mtools-4.0.26
+.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
+.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
+configuration of 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..aee0330
--- /dev/null
+++ b/mmount.c
@@ -0,0 +1,108 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <sys/wait.h>
+#include "mainloop.h"
+#include "fs.h"
+
+void mmount(int argc, char **argv, int type UNUSEDP) NORETURN;
+void mmount(int argc, char **argv, int type UNUSEDP)
+{
+	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 = ch_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..08082d3
--- /dev/null
+++ b/mmove.1
@@ -0,0 +1,99 @@
+'\" t
+.TH mmove 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+The \fR\&\f(CWmmove\fR command is used to move or rename 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 file system. Data cannot be moved from MS-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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..d9221cf
--- /dev/null
+++ b/mmove.c
@@ -0,0 +1,324 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * mmove.c
+ * Renames/moves an MSDOS file
+ *
+ */
+
+
+#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 UNUSEDP,
+		    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, 0, NULL, 0)) {
+			    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) NORETURN;
+void mmove(int argc, char **argv, int oldsyntax)
+{
+	Arg_t arg;
+	int c;
+	char shortname[12*4+1];
+	char longname[4*MAX_VNAMELEN+1];
+	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);
+				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<argc; i++)
+		if(argv[i][0] && argv[i][1] == ':' ){
+			if(!def_drive)
+				def_drive = ch_toupper(argv[i][0]);
+			else if(def_drive != ch_toupper(argv[i][0])){
+				fprintf(stderr,
+					"Cannot move files across different drives\n");
+				exit(1);
+			}
+		}
+
+	if(def_drive)
+		*(arg.mp.mcwd) = def_drive;
+
+	if (oldsyntax && (argc - optind != 2 || strpbrk(":/", argv[argc-1])))
+		oldsyntax = 0;
+
+	arg.mp.lookupflags =
+	  ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS | NO_UNIX;
+
+	if (!oldsyntax){
+		target_lookup(&arg.mp, argv[argc-1]);
+		arg.mp.callback = rename_file;
+		arg.mp.dirCallback = rename_directory;
+	} else {
+		/* do not look up the target; it will be the same dir as the
+		 * source */
+		arg.fromname = argv[optind];
+		if(arg.fromname[0] && arg.fromname[1] == ':')
+			arg.fromname += 2;
+		arg.fromname = _basename(arg.fromname);
+		arg.mp.targetName = strdup(argv[argc-1]);
+		arg.mp.callback = rename_oldsyntax;
+	}
+
+
+	arg.mp.longname.data = longname;
+	arg.mp.longname.len = sizeof(longname);
+	longname[0]='\0';
+
+	arg.mp.shortname.data = shortname;
+	arg.mp.shortname.len = sizeof(shortname);
+	shortname[0]='\0';
+
+	exit(main_loop(&arg.mp, argv + optind, argc - optind - 1));
+}
diff --git a/mpartition.1 b/mpartition.1
new file mode 100644
index 0000000..4c3b9a7
--- /dev/null
+++ b/mpartition.1
@@ -0,0 +1,228 @@
+'\" t
+.TH mpartition 1 "28Nov20" mtools-4.0.26
+.SH Name
+mpartition - partition an MSDOS hard 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
+.PP
+The \fR\&\f(CWmpartition\fR command is used to create MS-DOS file systems 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.
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-p\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-r\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-I\fR [\fR\&\f(CW-B\fR \fIbootSector\fR] \fIdrive\fR 
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-a\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-d\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-c\fR [\fR\&\f(CW-s\fR \fIsectors\fR] [\fR\&\f(CW-h\fR \fIheads\fR]
+[\fR\&\f(CW-t\fR \fIcylinders\fR] [\fR\&\f(CW-v\fR [\fR\&\f(CW-T\fR \fItype\fR] [\fR\&\f(CW-b\fR
+\&\fIbegin\fR] [\fR\&\f(CW-l\fR length] [\fR\&\f(CW-f\fR]
+\&\&
+.fi
+.ft R
+ 
+.PP
+Mpartition supports the following operations:
+.TP
+\&\fR\&\f(CWp\fR\ 
+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 (\fR\&\f(CW-v\fR) is also set,
+prints the current partition table.
+.TP
+\&\fR\&\f(CWr\fR\ 
+Removes the partition described by \fIdrive\fR.
+.TP
+\&\fR\&\f(CWI\fR\ 
+Initializes the partition table, and removes all partitions.
+.TP
+\&\fR\&\f(CWc\fR\ 
+Creates the partition described by \fIdrive\fR.
+.TP
+\&\fR\&\f(CWa\fR\ 
+"Activates" the partition, i.e. makes it bootable.  Only one partition
+can be bootable at a time.
+.TP
+\&\fR\&\f(CWd\fR\ 
+"Deactivates" the partition, i.e. makes it unbootable.
+.PP
+If no operation is given, the current settings are printed.
+.PP
+For partition creations, the following options are available:
+.TP
+\&\fR\&\f(CWs\ \fIsectors\fR\&\f(CW\fR\ 
+The number of sectors per track of the partition (which is also the
+number of sectors per track for the whole drive).
+.TP
+\&\fR\&\f(CWh\ \fIheads\fR\&\f(CW\fR\ 
+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 neighboring partition table
+entries, or guessed from the size.
+.TP
+\&\fR\&\f(CWt\ \fIcylinders\fR\&\f(CW\fR\ 
+The number of cylinders of the partition (not the number of cylinders of
+the whole drive.
+.TP
+\&\fR\&\f(CWb\ \fIbegin\fR\&\f(CW\fR\ 
+The starting offset of the partition, expressed in sectors. If begin
+is not given, \fR\&\f(CWmpartition\fR lets the partition begin at the start
+of the disk (partition number 1), or immediately after the end of the
+previous partition.
+.TP
+\&\fR\&\f(CWl\ \fIlength\fR\&\f(CW\fR\ 
+The size (length) of the partition, expressed in sectors.  If end is
+not given, \fR\&\f(CWmpartition\fR 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.
+.PP
+The following option is available for all operation which modify the
+partition table:
+.TP
+\&\fR\&\f(CWf\fR\ 
+Usually, before writing back any changes to the partition, mpartition
+performs certain consistency checks, such as checking for overlaps and
+proper alignment of the partitions.  If any of these checks fails, the
+partition table is not changed.  The \fR\&\f(CW-f\fR allows you to override
+these safeguards.
+.PP
+The following options are available for all operations:
+.TP
+\&\fR\&\f(CWv\fR\ 
+Together with \fR\&\f(CW-p\fR prints the partition table as it is now (no
+change operation), or as it is after it is modified.
+.TP
+\&\fR\&\f(CWvv\fR\ 
+If the verbosity flag is given twice, \fR\&\f(CWmpartition\fR will print out
+a hexdump of the partition table when reading it from and writing it
+to the device.
+.PP
+The following option is available for partition table initialization:
+.TP
+\&\fR\&\f(CWB\ \fIbootSector\fR\&\f(CW\fR\ 
+Reads the template master boot record from file \fIbootSector\fR.
+.PP
+.SH Choice\ of\ partition\ type
+.PP
+Mpartition proceeds as follows to pick a type for the partition:
+.TP
+-\ \ 
+FAT32 partitions are assigned type 0x0C (``\fR\&\f(CWWin95 FAT32, LBA\fR'')
+.TP
+-\ \ 
+For all others, if the partition fits entirely within the first 65536
+sectors of the disk, assign 0x01 (``\fR\&\f(CWDOS FAT12, CHS\fR'') for FAT12
+partition and 0x04 (``\fR\&\f(CWDOS FAT16, CHS\fR'') for FAT16 partitions
+.TP
+-\ \ 
+If not covered by the above, assign 0x06 (``\fR\&\f(CWDOS BIG FAT16 CHS\fR'') if partition fits entirely within the first 1024 cylinders (CHS mode)
+.TP
+-\ \ 
+All remaining cases get 0x0E (``\fR\&\f(CWWin95 BIG FAT16, LBA\fR'')
+.PP
+If number of fat bits is not known (not specified in drive's
+definition), then FAT12 is assumed for all drives with less than 4096
+sectors, and FAT16 for those with more than 4096 sectors.
+.PP
+This corresponds more or less to the definitions outlined at \fR\&\f(CWhttps://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs\fR
+and
+\&\fR\&\f(CWhttps://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10)\fR,
+with two notable differences:
+.TP
+-\ \ 
+If fat bits are unknown, the reference documents consider drives with
+less than 32680 sectors to be FAT12. Mtools uses 4096 sectors as the
+cutoff point, as older versions of DOS only support FAT12 on disks
+with less than 4096 sectors (and these older versions are the ones
+which would be most likely to use FAT12 in the first place).
+.TP
+-\ \ 
+The reference documents use a 8GB (wikipedia) or a 4GB (Microsoft)
+cutoff between 0x06 (\fR\&\f(CWDOS BIG FAT16 CHS\fR) and 0x0E. Mtools uses
+1024 cylinders. This is because any partition beyond 1024 cylinders
+must be LBA and cannot be CHS. 8GB works out to be the biggest
+capacity which can be represented as CHS (63 sectors, 255 heads and
+1024 cylinders). 4GB is the capacity limit for windows 2000, so it
+makes sense that a documentation for windows 2000 would specify this
+as the upper limit for any partition type.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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/mpartition.c b/mpartition.c
new file mode 100644
index 0000000..1c50ef3
--- /dev/null
+++ b/mpartition.c
@@ -0,0 +1,793 @@
+/*  Copyright 1997-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 <http://www.gnu.org/licenses/>.
+ *
+ * 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, unsigned long 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,
+		 unsigned long begin, unsigned long end,
+		 unsigned int heads, unsigned int sectors,
+		 int activate, int type, int fat_bits)
+{
+	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 (fat_bits == 0) {
+			/**
+			 * Fat bits unknown / not specified. We look
+			 * at size to get a rough estimate what FAT
+			 * bits are used.  Note: this is only an
+			 * estimate, the precise calculation would
+			 * involve the number of clusters, which is
+			 * not necessarily known here.
+			 */
+			/* cc977219 would have a cutoff number of 32680,
+			 * corresponding to a FAT12 partition with 4K
+			 * clusters, however other information hints that
+			 * only partitions with less than 4096 sectors are
+			 * considered */
+			if(end-begin < 4096)
+				fat_bits = 12;
+			else
+				fat_bits = 16;
+		}
+
+		/* Description of various partition types in
+		 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
+		 * and
+		 * https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10)
+		 */
+		if (fat_bits == 32)
+			/* FAT 32 partition. For now, we disregard the
+			 * possibility of FAT 32 CHS partitions */
+			type = 0x0C; /* Win95 FAT32, LBA */
+		else if (end < 65536) {
+			/* FAT 12 or FAT 16 partitions which fit entirely below
+			   the 32M mark */
+			/* The 32M restriction doesn't apply to logical
+			   partitions within an extended partition, but for the
+			   moment mpartition only makes primary partitions */
+			if(fat_bits == 12)
+				/* FAT 12 partition */
+				type = 0x01; /* DOS FAT12, CHS */
+			else if (fat_bits == 16)
+				/* FAT 16 partition */
+				type = 0x04; /* DOS FAT16, CHS */
+		} else if (end <  sectors * heads * 1024)
+			/* FAT 12 or FAT16 partition above the 32M
+			 * mark but below the 1024 cylinder mark.
+			 * Indeed, there can be no CHS partition
+			 * beyond 1024 cylinders */
+			type = 0x06; /* DOS BIG FAT16 or FAT12, CHS */
+		else
+			type = 0x0E; /* Win95 BIG FAT16, LBA */
+	}
+	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)
+{
+	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,
+		   uint16_t *hds,  uint16_t *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,
+		     uint16_t *hds, uint16_t *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 UNUSEDP) NORETURN;
+void mpartition(int argc, char **argv, int dummy UNUSEDP)
+{
+	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;
+	unsigned 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;
+	unsigned int begin=0;
+	unsigned 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[2100];
+	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) {
+		char *endptr=NULL;
+		errno=0;
+		switch (c) {
+			case 'i':
+				set_cmd_line_image(optarg);
+				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 = strtoi(optarg, &endptr, 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 = strtoui(optarg, &endptr, 0);
+				sizetest = 1;
+				break;
+			case 'b':
+				begin_set = 1;
+				begin = strtoui(optarg, &endptr, 0);
+				break;
+			case 'l':
+				size_set = 1;
+				length = strtoui(optarg, &endptr, 0);
+				break;
+
+			default:
+				usage(1);
+		}
+		check_number_parse_errno(c, optarg, endptr);
+	}
+
+	if (argc - optind != 1 ||
+	    !argv[optind][0] || argv[optind][1] != ':')
+		usage(1);
+
+	drive = ch_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,sizeof(errmsg)-1,
+				 "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, sizeof(errmsg)-1,
+				"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(i<dev->partition && !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,
+			    dev->fat_bits);
+	}
+
+	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..215cace
--- /dev/null
+++ b/mrd.1
@@ -0,0 +1,95 @@
+'\" t
+.TH mrd 1 "28Nov20" mtools-4.0.26
+.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
+.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 file system. 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..e89a4b5
--- /dev/null
+++ b/mren.1
@@ -0,0 +1,105 @@
+'\" t
+.TH mren 1 "28Nov20" mtools-4.0.26
+.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
+.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 file system.
+.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 source file), 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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..192228b
--- /dev/null
+++ b/msdos.h
@@ -0,0 +1,269 @@
+#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 <http://www.gnu.org/licenses/>.
+ *
+ * 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) ((uint16_t)((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8)))
+#define _DWORD(x) ((uint32_t)(_WORD(x) + (_WORD((x)+2) << 16)))
+
+#define DELMARK ((char) 0xe5)
+#define ENDMARK ((char) 0x00)
+
+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, uint32_t 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;
+
+#define has_BPB4 (labelBlock->dos4 == 0x28 || labelBlock->dos4 == 0x29)
+
+/* 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] NONULLTERM; 	/* 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)))
+
+/* max FAT12/FAT16 sizes, according to
+   
+ https://staff.washington.edu/dittrich/misc/fatgen103.pdf
+ https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/fatgen103.doc
+
+ 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 0x0ff5 /* max. number + 1 of clusters described by a 12 bit FAT */
+#define FAT16 0xfff5 /* max number + 1 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/mshortname.1 b/mshortname.1
new file mode 100644
index 0000000..35901f7
--- /dev/null
+++ b/mshortname.1
@@ -0,0 +1,95 @@
+'\" t
+.TH mshortname 1 "28Nov20" mtools-4.0.26
+.SH Name
+mshortname - shows short name of a 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(CWmshortname\fR command is used to display the short name of a
+file.  Syntax:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmshortname\fR \fIfiles\fR
+.fi
+.ft R
+ 
+.PP
+The shortname is displayed as it is stored in raw format on disk,
+without any character set conversion.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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/mshortname.c b/mshortname.c
new file mode 100644
index 0000000..495cef5
--- /dev/null
+++ b/mshortname.c
@@ -0,0 +1,77 @@
+/*  Copyright 2010 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 <http://www.gnu.org/licenses/>.
+ *
+ * mshortname.c
+ * Change MSDOS file attribute flags
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "mainloop.h"
+
+static int print_short_name(direntry_t *entry, MainParam_t *mp UNUSEDP)
+{
+	fprintShortPwd(stdout, entry);
+	putchar('\n');
+	return GOT_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 msdosfile [msdosfiles...]\n",
+		progname);
+	exit(ret);
+}
+
+void mshortname(int argc, char **argv, int type UNUSEDP) NORETURN;
+void mshortname(int argc, char **argv, int type UNUSEDP)
+{
+	struct MainParam_t mp;
+	int c;
+
+	if(helpFlag(argc, argv))
+		usage(0);
+	while ((c = getopt(argc, argv, "i:h")) != EOF) {
+		switch (c) {
+			case 'i':
+				set_cmd_line_image(optarg);
+				break;
+			case 'h':
+				usage(0);
+			case '?':
+				usage(1);
+		}
+	}
+
+	if(optind == argc) {
+		usage(0);
+	}
+
+	if (optind >= argc)
+		usage(1);
+
+	init_mp(&mp);
+	mp.callback = print_short_name;
+	mp.arg = NULL;
+	mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR;
+	exit(main_loop(&mp, argv + optind, argc - optind));
+}
diff --git a/mshowfat.1 b/mshowfat.1
new file mode 100644
index 0000000..04a0179
--- /dev/null
+++ b/mshowfat.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mshowfat 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+The \fR\&\f(CWmshowfat\fR command is used to display the FAT entries for a
+file.  Syntax:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmshowfat\fR [\fR\&\f(CW-o\fR \fIoffset\fR] \fIfiles\fR
+.fi
+.ft R
+ 
+.PP
+If no offset is given, a list of all clusters occupied by the file is
+printed. If an offset is given, only the number of the cluster
+containing that offset is printed.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..b04c6e6
--- /dev/null
+++ b/mshowfat.c
@@ -0,0 +1,108 @@
+/*  Copyright 1997,2000-2002,2009,2011 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 <http://www.gnu.org/licenses/>.
+ *
+ * mcopy.c
+ * Copy an MSDOS files to and from Unix
+ *
+ */
+
+
+#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 {
+	MainParam_t mp;
+	off_t offset;
+} Arg_t;
+
+static int dos_showfat(direntry_t *entry, MainParam_t *mp)
+{
+	Stream_t *File=mp->File;
+	Arg_t *arg = (Arg_t *) mp->arg;
+	fprintPwd(stdout, entry,0);
+	putchar(' ');
+	if(arg->offset == -1) {
+		printFat(File);
+	} else {
+		printFatWithOffset(File, arg->offset);
+	}
+	printf("\n");
+	return GOT_ONE;
+}
+
+static int unix_showfat(MainParam_t *mp UNUSEDP)
+{
+	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 UNUSEDP) NORETURN;
+void mshowfat(int argc, char **argv, int mtype UNUSEDP)
+{
+	Arg_t arg;
+	int c, ret;
+	
+	/* get command line options */
+	if(helpFlag(argc, argv))
+		usage(0);
+	arg.offset = -1;
+	while ((c = getopt(argc, argv, "i:ho:")) != EOF) {
+		switch (c) {
+			case 'o':
+				arg.offset = str_to_offset(optarg);
+				break;
+			case 'i':
+				set_cmd_line_image(optarg);
+				break;
+			case 'h':
+				usage(0);
+			case '?':
+				usage(1);
+		}
+	}
+
+	if (argc - optind < 1)
+		usage(1);
+
+	/* only 1 file to handle... */
+	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.1 b/mtools.1
new file mode 100644
index 0000000..b9a127a
--- /dev/null
+++ b/mtools.1
@@ -0,0 +1,500 @@
+'\" t
+.TH mtools 1 "28Nov20" mtools-4.0.26
+.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
+file system (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 file systems.  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
+.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.26.tar.gz
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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 info-mtools @ gnu.org .  Please
+send all bug reports to this list.  You may subscribe to the list at
+https://lists.gnu.org/mailman/listinfo/info-mtools. (N.B. Please
+remove the spaces around the "@". 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
+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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.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 file system),
+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
+.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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.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\ file\ system
+.PP
+The VFAT file system 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 file system, 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 file system allows you 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
+.PP
+Mtools supports a number of formats which allow storage of more data on
+disk than usual. Due to different operating system abilities, these
+formats are not supported on all operating systems. 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(CWhttp://www.fdutils.linux.lu/.
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\fR
+.PP
+See the manual pages 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
+.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 hubris, 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
+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 permits storage of up to 1992K on a 3 1/2 HD disk.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ 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 easier to
+handle by DOS. Indeed this method allows you to have a standard sized
+boot sector, 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, but tells DOS that it
+stores two. Thus the space that would be taken up by the second FAT copy
+is saved.) This also means that you should \fBnever use a 2m disk
+to store anything else than a DOS file system\fR.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ XDF
+.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 \(ifmiscellaneous 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
+mclasserase
+mcopy
+mdel
+mdeltree
+mdir
+mdu
+mformat
+minfo
+mkmanifest
+mlabel
+mmd
+mmount
+mmove
+mrd
+mren
+mshortname
+mshowfat
+mtoolstest
+mtype
diff --git a/mtools.5 b/mtools.5
new file mode 100644
index 0000000..ef5f95e
--- /dev/null
+++ b/mtools.5
@@ -0,0 +1,541 @@
+'\" t
+.TH mtools 5 "28Nov20" 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.26
+.PP
+.SH Description
+.PP
+This manual page describes the configuration files for mtools. They 
+are called \fR\&\f(CW\(if/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
+.PP
+\&\fR\&\f(CW\(if/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
+.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
+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
+.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 long names, 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)
+.TP
+\&\fR\&\f(CWMTOOLS_LOCK_TIMEOUT\fR\ 
+How long, in seconds, to wait for a locked device to become free.
+Defaults to 30.
+.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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+.SS \ \ General\ information
+.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
+.PP
+ 
+\&\fR
+.PP
+.SS \ \ Location\ information
+.PP
+For each drive, you need to describe where its data is physically
+stored (image file, physical device, partition, offset).
+.TP
+\&\fR\&\f(CWfile\fR\ 
+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\ 
+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 Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks 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. partitioned 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\ 
+Describes where in the file the MS-DOS file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system starts right at the
+beginning of the device or file.
+.PP
+.SS \ \ Disk\ Geometry\ Configuration
+.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 Unixes 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
+The number of cylinders. (\fR\&\f(CWcylinders\fR is the preferred form,
+\&\fR\&\f(CWtracks\fR is considered obsolete)
+.TP
+\&\fR\&\f(CWheads\fR\ 
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWsectors\fR\ 
+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
+.PP
+ 
+\&\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
+.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\ 
+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 auto-detected 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 code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+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\ 
+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\ 
+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,
+independently of the sector size registered in the file system'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 auto-detected 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
+omitted, it is enabled.  For example, \fR\&\f(CWscsi\fR is equivalent to
+\&\fR\&\f(CWscsi=1\fR
+.TP
+\&\fR\&\f(CWnolock\fR\ 
+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\ 
+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 system calls, 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
+setuid 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/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\ 
+When set to 1, this instructs mtools to use its setuid and setgid
+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/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 explicitly 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\ 
+.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\ 
+.IP
+Consider the media as a word-swapped Atari disk.
+.TP
+\&\fR\&\f(CWuse_xdf\fR\ 
+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\ 
+Tells mtools to use the geometry for this drive only for mformatting and 
+not for filtering.
+.TP
+\&\fR\&\f(CWfilter\fR\ 
+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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+The configuration files are parsed in the following order:
+.TP
+1.\ 
+compiled-in defaults
+.TP
+2.\ 
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR
+.TP
+3.\ 
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR.
+.TP
+4.\ 
+\&\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/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/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
+.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..ffac8bb
--- /dev/null
+++ b/mtools.c
@@ -0,0 +1,201 @@
+/*  Copyright 1996-2004,2007-2010 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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},
+	{"mshortname", mshortname, 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 <command>"
+	** where <command> 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 <http://www.gnu.org/licenses/>.
+
+# 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..6959a44
--- /dev/null
+++ b/mtools.h
@@ -0,0 +1,365 @@
+#ifndef MTOOLS_MTOOLS_H
+#define MTOOLS_MTOOLS_H
+/*  Copyright 1996-2005,2007-2011 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 <http://www.gnu.org/licenses/>.
+ */
+#include "msdos.h"
+
+typedef struct dos_name_t dos_name_t;
+
+#if defined(OS_sco3)
+#define MAXPATHLEN 1024
+#include <signal.h>
+extern int lockf(int, int, off_t);  /* SCO has no proper include file for lockf */
+#endif 
+
+#define SCSI_FLAG		0x001u
+#define PRIV_FLAG		0x002u
+#define NOLOCK_FLAG		0x004u
+#define USE_XDF_FLAG		0x008u
+#define MFORMAT_ONLY_FLAG	0x010u
+#define VOLD_FLAG		0x020u
+#define FLOPPYD_FLAG		0x040u
+#define FILTER_FLAG		0x080u
+#define SWAP_FLAG		0x100u
+
+#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 */
+
+	int mode;		/* any special open() flags */
+	unsigned int tracks;	/* tracks */
+	uint16_t heads;		/* heads */
+	uint16_t 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 */
+	uint8_t 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;
+
+struct OldDos_t {
+	unsigned int tracks;
+	uint16_t sectors;
+	uint16_t  heads;
+	
+	unsigned int dir_len;
+	unsigned int cluster_size;
+	unsigned int fat_len;
+
+	uint8_t media;
+};
+
+extern struct OldDos_t *getOldDosBySize(size_t size);
+extern struct OldDos_t *getOldDosByMedia(int media);
+extern struct OldDos_t *getOldDosByParams(unsigned int tracks,
+					  unsigned int heads,
+					  unsigned int sectors,
+					  unsigned int dir_len,
+					  unsigned int cluster_size);
+int setDeviceFromOldDos(int media, struct device *dev);
+
+
+#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(target > max) { \
+    target = max; \
+  } \
+} while(0)
+
+#define smaximize(target, max) do {		\
+  if(max < 0) { \
+    if(target > 0) \
+      target = 0; \
+  } else if(target > max) { \
+    target = max; \
+  } \
+} while(0)
+
+#define sizemaximize(target, max) do {		\
+  if(max < 0) { \
+    if(target > 0) \
+      target = 0; \
+  } else if(target > (size_t) 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,
+		      size_t ans_size);
+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, unsigned char attr,
+			   unsigned int fat, size_t size, time_t date,
+			   struct directory *ndir);
+
+struct directory *mk_entry_from_base(const char *base, unsigned 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);
+#ifdef HAVE_SIGACTION
+typedef struct { struct sigaction sa[4]; } saved_sig_state;
+#else
+typedef int saved_sig_state;
+#endif
+
+void allow_interrupts(saved_sig_state *ss);
+void restore_interrupts(saved_sig_state *ss);
+
+#define SET_INT(target, source) \
+if(source)target=source
+
+
+UNUSED(static __inline__ int compare (long ref, long testee))
+{
+	return (ref && ref != testee);
+}
+
+UNUSED(static __inline__ char ch_toupper(char ch))
+{
+        return (char) toupper( (unsigned char) ch);
+}
+
+UNUSED(static __inline__ char ch_tolower(char ch))
+{
+        return (char) tolower( (unsigned char) ch);
+}
+
+UNUSED(static __inline__ wchar_t ch_towupper(wchar_t ch))
+{
+        return (wchar_t) towupper( (wint_t) ch);
+}
+
+UNUSED(static __inline__ wchar_t ch_towlower(wchar_t ch))
+{
+        return (wchar_t) towlower( (wint_t) ch);
+}
+
+UNUSED(static __inline__ void init_random(void))
+{
+	srandom((unsigned int)time (0));
+}
+
+
+Stream_t *GetFs(Stream_t *Fs);
+
+void label_name_uc(doscp_t *cp, const char *filename, int verbose, 
+		   int *mangled, dos_name_t *ans);
+
+void label_name_pc(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_lock_timeout;
+extern unsigned int mtools_twenty_four_hour_clock;
+extern const char *mtools_date_string;
+extern uint8_t 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);
+void check_number_parse_errno(char c, const char *optarg, char *endptr);
+void read_config(void);
+off_t str_to_offset(char *str);
+unsigned int strtoui(const char *nptr, char **endptr, int base);
+unsigned int atoui(const char *nptr);
+#ifndef HAVE_STRTOI
+int strtoi(const char *nptr, char **endptr, int base);
+#endif
+unsigned long atoul(const char *nptr);
+uint8_t strtou8(const char *nptr, char **endptr, int base);
+uint8_t atou8(const char *str);
+uint16_t strtou16(const char *nptr, char **endptr, int base);
+uint16_t atou16(const char *str);
+uint32_t strtou32(const char *nptr, char **endptr, int base);
+uint32_t atou32(const char *str);
+
+extern struct device *devices;
+extern struct device const_devices[];
+extern const unsigned 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 mshortname(int argc, char **argv, int mtype);
+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(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
+ssize_t safePopenOut(const char **command, char *output, size_t 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..e43a18d
--- /dev/null
+++ b/mtools.info
Binary files differ
diff --git a/mtools.spec b/mtools.spec
new file mode 100644
index 0000000..82b31c1
--- /dev/null
+++ b/mtools.spec
@@ -0,0 +1,242 @@
+%define _binary_payload w9.gzdio
+Name:           mtools
+Summary:        mtools, read/write/list/format DOS disks under Unix
+Version:        4.0.26
+Release:        1
+License:        GPLv3+
+Group:          Utilities/System
+URL:            http://www.gnu.org/software/mtools/
+Source:         ftp://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz
+Buildroot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+
+%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
+
+./configure \
+    --prefix=%{buildroot}%{_prefix} \
+    --sysconfdir=/etc \
+    --infodir=%{buildroot}%{_infodir} \
+    --mandir=%{buildroot}%{_mandir} \
+    --enable-floppyd \
+
+%build
+make
+
+%clean
+echo rm -rf $RPM_BUILD_ROOT
+[ X%{buildroot} != X ] && [ X%{buildroot} != X/ ] && rm -fr %{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/mshortname.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}/mshortname
+%{_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
+%doc NEWS
+
+%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
+* Sat Nov 28 2020 Alain Knaff <alain@knaff.lu>
+- Fix compilation on Macintosh
+- Ignore image file locking errors if we are performing a read-only access anyways
+- Minor man-page fixes
+* Sat Oct 24 2020 Alain Knaff <alain@knaff.lu>
+- Preserve non-updated contents of info sector, just in case it contains program code
+- When parsing config file, always use "C" locale for case-insensitive comparisons
+* Sun Mar 22 2020 Alain Knaff <alain@knaff.lu>
+- Spelling fixes in documentation
+- Permit calling "make install" with >= -j2
+- Added AC_SYS_LARGEFILE, needed for compiling on certain ARM procs
+* Sun Dec 09 2018 Alain Knaff <alain@knaff.lu>
+- Address lots of compiler warnings (assignments between different types)
+- Network speedup fixes for floppyd (TCP_CORK)
+- Typo fixes
+- Explicitly pass available target buffer size for character set conversions
+* Sun Dec 02 2018 Alain Knaff <alain@knaff.lu>
+- Fixed -f flag for mformat (size is KBytes, rather than sectors)
+- Fixed toupper/tolower usage (unsigned char rather than plain signed)
+* Sat Nov 24 2018 Alain Knaff <alain@knaff.lu>
+- Fixed compilation for MingW
+- After MingW compilation, make sure executable has .exe extension
+- Addressed compiler warnings
+- Fixed length handling in character set conversion (Unicode file names)
+- Fixed matching of character range, when containing Unicode characters (mdir "c:test[α-ω].exe")
+- Fixed initialization of my_scsi_cmd constructor
+* Sun Nov 11 2018 Alain Knaff <alain@knaff.lu>
+- initialize directory entries to 0
+- bad message "Too few sectors" replaced with "Too many sectors"
+- apostrophe in mlabel no longer causes generation of long entry
+- option to fake system date for file creation using the SOURCE_DATE_EPOCH environment variables
+- can now be compiled with "clang" compiler
+- fallback function for strndup, for those platforms that do not have it
+- fixed a number of -Wextra warnings
+- new compressed archive formats for uz/lz
+- allow to specify number of reserved sectors for FAT32.
+- file/device locking with timeout (rather than immediate failure)
+- fixed support for BPB-less legacy formats.
+- removed check that disk must be an integer number of tracks.
+- removed .eh/.oh macros from manual pages
+* Sat Sep 29 2018 Alain Knaff <alain@knaff.lu>
+- Fix for short file names starting with character 0xE5	(by remapping it to 0x5)
+- mpartition: Partition types closer to what Microsoft uses
+- mformat: figure out LBA geometry as last resort if geometry
+is neither specified in config and/or commandline, nor can be
+queried from the device
+- mformat: use same default cluster size by size as Microsoft for FAT32
+- additional sanity checks
+- document how cluster size is picked in mformat.c man page
+- document how partition types are picked in mpartition.c man page
+* Wed Jan 09 2013 Alain Knaff <alain@knaff.lu>
+- Fix for names of iconv encodings on AIX
+- Fix mt_size_t on NetBSD
+- Fixed compilation on Mingw
+- Fixed doc (especially mformat)
+- Fix mformating of FAT12 filesystems with huge cluster sizes
+- Minfo prints image file name in mformat command line if an image
+- file name was given
+- Always generate gzip-compressed RPMs, in order to remain
+- compatible with older distributions
+- Fixed buffer overflow with drive letter in mclasserase
+* Wed Jun 29 2011 Alain Knaff <alain@knaff.lu>
+- mbadblocks now takes a list of bad blocks (either as sectors
+  or as clusters)
+- mbadblocks now is able to do write scanning for bad blocks
+- mshowfat can show cluster of specific offset
+- Enable mtools to deal with very small sector sizes...
+- Fixed encoding of all-lowercase names (no need to mangle
+  these)
+- Consider every directory entry after an ENDMARK (0x00) to be deleted
+- After writing a new entry at end of a directory, be sure to also add
+  an ENDMARK (0x00)
+- Deal with possibility of a NULL pointer being returned by
+  localtime during timestamp conversion
+* Sat Apr 16 2011 Alain Knaff <alain@knaff.lu>
+- configure.in fixes
+- fixed formatting of fat_size_calculation.tex document
+- compatibility with current autoconfig versions
+- Make it clear that label is limited to 11 characters
+- Fixed typo in initialization of FAT32 info sector
+* Sun Oct 17 2010 Alain Knaff <alain@knaff.lu>
+- Added missing -i option to mshortname
+* Sun Oct 17 2010 Alain Knaff <alain@knaff.lu>
+- Released v4_0_14:
+- New mshortname command
+- Fix floppyd for disks bigger than 2 Gig
+- Remove obsolete -z flag
+- Remove now unsupported AC_USE_SYSTEM_EXTENSIONS
+- Fixed output formatting of mdir if MTOOLS_DOTTED_DIR is set
+- Mformat now correctly writes backup boot sector
+- Fixed signedness of serial number in mlabel
+- Fixed buffer size problem in mlabel
+- Make mlabel write backup boot sector if FAT32
+- Catch situation where both clear and new label are given to mlabel
+- Quote filename parameters to scripts
+- Mformat: Close file descriptor for boot sector
+- Added lzip support to scripts/uz
+- Added Tot_sectors option to mformat
+- Fixed hidden sector handling in mformat
+- Minfo generates mformat command lines containing new -T option
+- Mlabel prints error if label too long
+* Sun Feb 28 2010 Alain Knaff <alain@knaff.lu>
+- Merged Debian patches
+* Tue Nov 03 2009 Alain Knaff <alain@knaff.lu>
+- Mingw compatibility fixes
diff --git a/mtools.texi b/mtools.texi
new file mode 100644
index 0000000..fdcd2bb
--- /dev/null
+++ b/mtools.texi
@@ -0,0 +1,2721 @@
+\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-2011,2013 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
+
+@include sysconfdir.texi
+
+@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
+file system (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 file systems.  For
+instance, commands such as @code{mdir a:} work on the @code{a:} floppy
+without any preliminary mounting or initialization (assuming the default
+@file{@value{SYSCONFDIR}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
+@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 info-mtools @@ gnu.org .  Please
+send all bug reports to this list.  You may subscribe to the list at
+https://lists.gnu.org/mailman/listinfo/info-mtools. (N.B. Please
+remove the spaces around the "@@". 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 file system),
+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 file system
+@cindex Case sensitivity
+
+The VFAT file system 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 file system, 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 file system allows you 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 storage of more data on
+disk than usual. Due to different operating system abilities, these
+formats are not supported on all operating systems. 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{http://www.fdutils.linux.lu/}.
+@end example
+
+See the manual pages 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 hubris, 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 permits storage of 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 easier to
+handle by DOS. Indeed this method allows you to have a standard sized
+boot sector, 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, but tells DOS that it
+stores two. Thus the space that would be taken up by the second FAT copy
+is saved.) This also means that you should @strong{never use a 2m disk
+to store anything else than a DOS file system}.
+
+Mtools supports these formats 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{miscellaneous 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 manual page 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{@value{SYSCONFDIR}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
+* configuration 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 configuration 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 configuration::      Backwards compatibility
+@end menu
+
+@node configuration 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{@value{SYSCONFDIR}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, configuration 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
+@vindex MTOOLS_DOTTED_DIR
+@vindex MTOOLS_NAME_NUMERIC_TAIL
+@vindex MTOOLS_TWENTY_FOUR_HOUR_CLOCK
+@vindex MTOOLS_LOCK_TIMEOUT
+@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 long names, 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)
+@item MTOOLS_LOCK_TIMEOUT
+How long, in seconds, to wait for a locked device to become free.
+Defaults to 30.
+@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
+* miscellaneous variables::        Variables which don't fit in either category
+* miscellaneous 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 (image 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 Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks and
+magneto-optical disks as @samp{giant floppy disks} which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partitioned 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 file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system 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 Unixes 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, miscellaneous 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 miscellaneous variables, miscellaneous 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 auto-detected 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 code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+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,
+independently of the sector size registered in the file system'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 auto-detected value is
+used.
+
+
+
+@node miscellaneous flags, multiple descriptions, miscellaneous 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
+omitted, 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 Syquest disks (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} system calls, 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
+setuid 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{@value{SYSCONFDIR}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 setuid and setgid
+privileges for opening the given drive.  This option is only valid for
+drives described in the system-wide configuration files (such as
+@file{@value{SYSCONFDIR}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 explicitly 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, , miscellaneous 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 configuration, 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{@value{SYSCONFDIR}mtools.conf}
+@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{@value{SYSCONFDIR}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{@value{SYSCONFDIR}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 configuration, , 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 useful 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 file system to a low-level formatted floppy disk
+* minfo::             get information about an MS-DOS file system.
+* 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
+* mshortname::        shows the short name of a 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 daemon 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 multi homed 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 useful, if you have a small front-end 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 without any whitespace padding.  If
+neither the "/" option is given, nor the @var{msdosfile} contains a
+wildcard, and there is only one MS-DOS 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 @code{mformat} commands that will
+reproduce the current situation, starting from a situation as left by
+untarring the MS-DOS file system.  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
+@pindex mbadblocks
+@cindex Marking blocks as bad
+@cindex Bad blocks
+@cindex Read errors
+
+The @code{mbadblocks} command is used to mark some clusters on an
+MS-DOS filesystem bad. It has the following syntax:
+
+@code{mbadblocks} [@code{-s} @var{sectorlist}|@code{-c} @var{clusterlist}|-w] @var{drive}@code{:}
+
+If no command line flags are supplied, @code{Mbadblocks} scans an
+MS-DOS filesystem for bad blocks by simply trying to read them and
+flag them if read fails. All blocks that are unused are scanned, and
+if detected bad are marked as such in the FAT.
+
+This command is intended to be used right after @code{mformat}.  It is
+not intended to salvage data from bad disks.
+
+
+@subsection Command line options
+
+@table @code
+@item c @var{file}
+Use a list of bad clusters, rather than scanning for bad clusters
+itself.
+@item s @var{file}
+Use a list of bad sectors (counted from beginning of filesystem),
+rather than trying for bad clusters itself.
+@item w
+Write a random pattern to each cluster, then read it back and flag
+cluster as bad if mismatch. Only free clusters are tested in such a
+way, so any file data is preserved.
+@end table
+
+@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 low-level 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 file system.
+
+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
+
+MS-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 MS-DOS to Unix, and vice-versa when
+copying from Unix to MS-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{ASCII} translates incoming carriage
+return/line feeds to line feeds.
+@item T
+Text (ASCII) file transfer with character set conversion.  Differs from
+@code{-a} in the @code{ASCII} 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{ASCII} 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 (see @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 file system.
+
+@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 file system. 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 MS-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 file systems, which store
+the size explicitly.
+@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 File system creation
+
+The @code{mformat} command is used to add an MS-DOS file system to a
+low-level formatted diskette. Its syntax is:
+
+@display
+@code{mformat} [@code{-t} @var{cylinders}|@code{-T} @var{tot_sectors}] [@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{-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}]
+  [@code{-K} @var{backup_boot}]
+  [@code{-R} @var{nb_reserved_sectors}]
+  [@code{-c} @var{clusters_per_sector}]
+  [@code{-d} @var{fat_copies}]
+  [@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}]
+  @var{drive:}
+@end display
+
+@code{Mformat} adds a minimal MS-DOS file system (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 MS-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, mformat will
+assign no label to the disk.
+@item f
+Specifies the size of the DOS file system 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 T
+Specifies the number of total sectors on the disk. Only one of these 2
+options may be specified (tracks or total sectors)
+@item h
+The number of heads (sides).
+@item s
+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
+
+MS-DOS 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 size code. 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 file system. 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 file system 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. If no
+cluster size is specified explicitly, mtools uses a default value as
+described in section ``Number of sectors per cluster'' below.
+@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 boot sector 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 file system data are updated to match the target
+disks parameters.
+@item K
+Sets the sector number where the backup of the boot sector should be
+stored (only relevant on FAT32).
+@item R
+Sets the number of reserved sectors for this filesystem. This must be
+at least 1 for non-FAT32 disks, and at least 3 for FAT disks (in order
+to accommodate the boot sector, the info sector and the backup boot
+sector).
+
+@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.
+
+@subsection Number of sectors per cluster
+
+If the user indicates no cluster size, mformat figures out a default
+value for it.
+
+For FAT32 it uses the following table to determine the number of
+sectors per cluster, depending on the total number of sectors on the
+filesystem.
+
+more than 32*1024*1024*2: 64 sectors@*
+between 16*1024*1024*2 and 32*1024*1024*2: 32 sectors@*
+between 8*1024*1024*2 and 16*1024*1024*2: 16 sectors@*
+between 260*1024*2 and 81024*1024*2: 1 sectors@*
+
+This is derived from information on page 20 of Microsoft's
+@code{fatgen103} document, which currently can be found at the
+following address:
+
+@code{https://staff.washington.edu/dittrich/misc/fatgen103.pdf}
+
+For FAT12 and FAT16, mformat uses an iterative approach, where it
+starts with a set value, which it doubles until it is able to fill up
+the disk using that cluster size and a number of cluster less than the
+maximum allowed.
+
+The starting value is 1 for disks with one head or less than 2000
+sectors, and 2 for disks with more than one head, and more than 2000
+sectors.
+
+The number of sectors per cluster cannot go beyond 128.
+
+@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{ASCII}
+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 MS-DOS file system
+
+The @code{minfo} command prints the parameters of a MS-DOS file system, such
+as number of sectors, heads and cylinders.  It also prints an mformat
+command line which can be used to create a similar MS-DOS file system on
+another media.  However, this doesn't work with 2m or XDF media, and
+with MS-DOS 1.0 file systems
+@display
+@code{minfo} @var{drive}:
+@end display
+
+Minfo supports the following option:
+@table @code
+@item v
+Prints a hexdump of the boot sector, 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.
+
+The label is limited to 11 single-byte characters,
+e.g. @code{Name1234567}.
+
+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 file system. 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
+configuration of 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 move or rename 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 file system. Data cannot be moved from MS-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 file systems 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
+"Deactivates" 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 neighboring 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, @code{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, @code{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 consistency checks, such as checking for overlaps and
+proper alignment of the partitions.  If any of these checks fails, the
+partition table is not changed.  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, @code{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
+
+@subsection Choice of partition type
+
+Mpartition proceeds as follows to pick a type for the partition:
+
+@itemize - 
+@item
+FAT32 partitions are assigned type 0x0C (``@code{Win95 FAT32, LBA}'')
+
+@item
+For all others, if the partition fits entirely within the first 65536
+sectors of the disk, assign 0x01 (``@code{DOS FAT12, CHS}'') for FAT12
+partition and 0x04 (``@code{DOS FAT16, CHS}'') for FAT16 partitions
+
+@item
+If not covered by the above, assign 0x06 (``@code{DOS BIG FAT16 CHS}'') if partition fits entirely within the first 1024 cylinders (CHS mode)
+
+@item
+All remaining cases get 0x0E (``@code{Win95 BIG FAT16, LBA}'')
+
+@end itemize
+
+If number of fat bits is not known (not specified in drive's
+definition), then FAT12 is assumed for all drives with less than 4096
+sectors, and FAT16 for those with more than 4096 sectors.
+
+This corresponds more or less to the definitions outlined at @code{https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs}
+and
+@code{https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10)},
+with two notable differences:
+
+@itemize -
+@item
+If fat bits are unknown, the reference documents consider drives with
+less than 32680 sectors to be FAT12. Mtools uses 4096 sectors as the
+cutoff point, as older versions of DOS only support FAT12 on disks
+with less than 4096 sectors (and these older versions are the ones
+which would be most likely to use FAT12 in the first place).
+
+@item
+The reference documents use a 8GB (wikipedia) or a 4GB (Microsoft)
+cutoff between 0x06 (@code{DOS BIG FAT16 CHS}) and 0x0E. Mtools uses
+1024 cylinders. This is because any partition beyond 1024 cylinders
+must be LBA and cannot be CHS. 8GB works out to be the biggest
+capacity which can be represented as CHS (63 sectors, 255 heads and
+1024 cylinders). 4GB is the capacity limit for windows 2000, so it
+makes sense that a documentation for windows 2000 would specify this
+as the upper limit for any partition type.
+
+@end itemize
+
+@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 file system. An error occurs
+if the directory does not exist or is not empty.
+
+@node mren, mshortname, 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 file system.
+
+In verbose mode, @code{Mren} displays the new filename if the name
+supplied is invalid.
+
+If the first syntax is used (only one source file), 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 mshortname, mshowfat, mren, Commands
+@section Mshortname
+@pindex mshortname
+
+The @code{mshortname} command is used to display the short name of a
+file.  Syntax:
+
+@display
+@code{mshortname} @var{files}
+@end display
+
+The shortname is displayed as it is stored in raw format on disk,
+without any character set conversion.
+
+@node mshowfat, mtoolstest, mshortname, 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} [@code{-o} @var{offset}] @var{files}
+@end display
+
+If no offset is given, a list of all clusters occupied by the file is
+printed. If an offset is given, only the number of the cluster
+containing that offset is printed.
+
+@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 HP-UX. 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 password-less 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 adapter's BIOS
+setup).
+
+The ZipTools disk shipped with the drive is also password protected.  On
+MS-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 Google Groups}.  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 file system 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 file system.
+
+
+@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 configuration.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 (file system doesn't start at
+beginning of file system)
+@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 file system 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{@value{SYSCONFDIR}mtools.conf} and
+@code{~/.mtoolsrc} configuration files.
+
+ However, the devices files also allows you 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/mtools.tmpl.1 b/mtools.tmpl.1
new file mode 100644
index 0000000..7676937
--- /dev/null
+++ b/mtools.tmpl.1
@@ -0,0 +1,500 @@
+'\" t
+.TH mtools 1 "28Nov20" mtools-4.0.26
+.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
+file system (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 file systems.  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\(ifSYSCONFDIRmtools.conf\(is\fR works on your machine).  With mtools, one can
+change floppies too without unmounting and mounting.
+.PP
+.SH Where\ to\ get\ mtools
+.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.26.tar.gz
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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 info-mtools @ gnu.org .  Please
+send all bug reports to this list.  You may subscribe to the list at
+https://lists.gnu.org/mailman/listinfo/info-mtools. (N.B. Please
+remove the spaces around the "@". 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
+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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.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 file system),
+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
+.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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.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\ file\ system
+.PP
+The VFAT file system 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 file system, 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 file system allows you 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
+.PP
+Mtools supports a number of formats which allow storage of more data on
+disk than usual. Due to different operating system abilities, these
+formats are not supported on all operating systems. 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(CWhttp://www.fdutils.linux.lu/.
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\fR
+.PP
+See the manual pages 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
+.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 hubris, 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
+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 permits storage of up to 1992K on a 3 1/2 HD disk.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ 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 easier to
+handle by DOS. Indeed this method allows you to have a standard sized
+boot sector, 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, but tells DOS that it
+stores two. Thus the space that would be taken up by the second FAT copy
+is saved.) This also means that you should \fBnever use a 2m disk
+to store anything else than a DOS file system\fR.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ XDF
+.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 \(ifmiscellaneous 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
+mclasserase
+mcopy
+mdel
+mdeltree
+mdir
+mdu
+mformat
+minfo
+mkmanifest
+mlabel
+mmd
+mmount
+mmove
+mrd
+mren
+mshortname
+mshowfat
+mtoolstest
+mtype
diff --git a/mtools.tmpl.5 b/mtools.tmpl.5
new file mode 100644
index 0000000..e58d13d
--- /dev/null
+++ b/mtools.tmpl.5
@@ -0,0 +1,541 @@
+'\" t
+.TH mtools 5 "28Nov20" 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.26
+.PP
+.SH Description
+.PP
+This manual page describes the configuration files for mtools. They 
+are called \fR\&\f(CW\(ifSYSCONFDIRmtools.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
+.PP
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.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
+.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
+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
+.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 long names, 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)
+.TP
+\&\fR\&\f(CWMTOOLS_LOCK_TIMEOUT\fR\ 
+How long, in seconds, to wait for a locked device to become free.
+Defaults to 30.
+.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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+.SS \ \ General\ information
+.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
+.PP
+ 
+\&\fR
+.PP
+.SS \ \ Location\ information
+.PP
+For each drive, you need to describe where its data is physically
+stored (image file, physical device, partition, offset).
+.TP
+\&\fR\&\f(CWfile\fR\ 
+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\ 
+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 Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks 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. partitioned 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\ 
+Describes where in the file the MS-DOS file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system starts right at the
+beginning of the device or file.
+.PP
+.SS \ \ Disk\ Geometry\ Configuration
+.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 Unixes 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
+The number of cylinders. (\fR\&\f(CWcylinders\fR is the preferred form,
+\&\fR\&\f(CWtracks\fR is considered obsolete)
+.TP
+\&\fR\&\f(CWheads\fR\ 
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWsectors\fR\ 
+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
+.PP
+ 
+\&\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
+.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\ 
+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 auto-detected 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 code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+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\ 
+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\ 
+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,
+independently of the sector size registered in the file system'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 auto-detected 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
+omitted, it is enabled.  For example, \fR\&\f(CWscsi\fR is equivalent to
+\&\fR\&\f(CWscsi=1\fR
+.TP
+\&\fR\&\f(CWnolock\fR\ 
+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\ 
+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 system calls, 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
+setuid 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\(ifSYSCONFDIRmtools.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\ 
+When set to 1, this instructs mtools to use its setuid and setgid
+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\(ifSYSCONFDIRmtools.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 explicitly 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\ 
+.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\ 
+.IP
+Consider the media as a word-swapped Atari disk.
+.TP
+\&\fR\&\f(CWuse_xdf\fR\ 
+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\ 
+Tells mtools to use the geometry for this drive only for mformatting and 
+not for filtering.
+.TP
+\&\fR\&\f(CWfilter\fR\ 
+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
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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
+.PP
+The configuration files are parsed in the following order:
+.TP
+1.\ 
+compiled-in defaults
+.TP
+2.\ 
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR
+.TP
+3.\ 
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR.
+.TP
+4.\ 
+\&\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\(ifSYSCONFDIRmtools.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\(ifSYSCONFDIRmtools.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
+.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/mtoolsDirentry.h b/mtoolsDirentry.h
new file mode 100644
index 0000000..2ad0c29
--- /dev/null
+++ b/mtoolsDirentry.h
@@ -0,0 +1,72 @@
+#ifndef MTOOLS_DIRENTRY_H
+#define MTOOLS_DIRENTRY_H
+/*  Copyright 1998,2000-2002,2005,2008-2010 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 <http://www.gnu.org/licenses/>.
+ */
+#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, size_t shortname_len,
+		char *longname, size_t longname_len);
+
+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);
+void low_level_dir_write_end(Stream_t *Dir, int 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);
+void fprintShortPwd(FILE *f, direntry_t *entry);
+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 <http://www.gnu.org/licenses/>.
+ *
+ * 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..7fd1292
--- /dev/null
+++ b/mtoolstest.1
@@ -0,0 +1,90 @@
+'\" t
+.TH mtoolstest 1 "28Nov20" mtools-4.0.26
+.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
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..5ef1c22
--- /dev/null
+++ b/mtype.1
@@ -0,0 +1,114 @@
+'\" t
+.TH mtype 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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/mxtar.1 b/mxtar.1
new file mode 100644
index 0000000..8fc11ab
--- /dev/null
+++ b/mxtar.1
@@ -0,0 +1,48 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for mxtar
+.\"
+.\" Copyright (C), 2003, Luis Bustamante
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Mon Mar  3 11:58:15 COT 2003 Luis Bustamante <luferbu@fluidsignal.com>
+.\" 
+.TH MXTAR 1 "Mon Mar  3 11:58:15 COT 2003" "" "Mtools Users Manual"
+.SH NAME
+mxtar \- Wrapper for using GNU tar directly from a floppy disk
+.SH SYNOPSIS
+.\" The command line
+.B mxtar 
+[
+.B \-
+]
+.I [ tar-options ]
+.I file
+.SH DESCRIPTION
+.B mxtar
+let you use GNU \fBtar\fR(1) on a floppy disk without mounting it using
+\fBmtools\fR(1).
+It is not strictly necessary on Debian GNU/Linux, because the GNU
+\fBtar\fR(1) program provides the same capability after copying the
+file locally with
+
+.B mcopy
+.I file
+.I destination
+
+but this utility is provided in the mtools package for other platforms and 
+is retained here for completeness.
+
+.SH AUTHOR
+Luis Bustamante <luferbu@fluidsignal.com> wrote this page for the
+.I Debian/GNU
+mtools package.
+
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR tar (1), 
+.BR mcopy (1)
diff --git a/mzip.1 b/mzip.1
new file mode 100644
index 0000000..4087aee
--- /dev/null
+++ b/mzip.1
@@ -0,0 +1,147 @@
+'\" t
+.TH mzip 1 "28Nov20" mtools-4.0.26
+.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
+.PP
+The \fR\&\f(CWmzip\fR command is used to issue ZIP disk specific commands on
+Linux, Solaris or HP-UX. 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 password-less 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 adapter's BIOS
+setup).
+.PP
+The ZipTools disk shipped with the drive is also password protected.  On
+MS-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 file system 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 file system.
+.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
+.PP
+ 
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+ 
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+ 
+\&\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
+.PP
+ 
+\&\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..8721910
--- /dev/null
+++ b/mzip.c
@@ -0,0 +1,554 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * mzip.c
+ * Iomega Zip/Jaz drive tool
+ * change protection mode and eject disk
+ */
+
+/* mzip.c by Markus Gyger <mgyger@itr.ch> */
+/* 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 <ilya@socio.msu.su>
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+#include "scsi.h"
+
+#ifndef _PASSWORD_LEN
+#define _PASSWORD_LEN 33
+#endif
+
+#ifdef OS_linux
+
+#if __GLIBC__ >=2
+#include <sys/mount.h>
+#else
+#define _LINUX_KDEV_T_H 1  /* don't redefine MAJOR/MINOR */
+#include <linux/fs.h>
+#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) NORETURN;
+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 UNUSEDP) NORETURN;
+void mzip(int argc, char **argv, int type UNUSEDP)
+{
+	void *extra_data = NULL;
+	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);
+				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 = ch_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+1];
+			
+			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 misspelled 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..7c69706
--- /dev/null
+++ b/nameclash.h
@@ -0,0 +1,76 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+	int is_label;
+} 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/old_dos.c b/old_dos.c
new file mode 100644
index 0000000..b5e146b
--- /dev/null
+++ b/old_dos.c
@@ -0,0 +1,76 @@
+#include "sysincludes.h"
+#include "mtools.h"
+
+static struct OldDos_t old_dos[]={
+{   40,  9,  1, 4, 1, 2, 0xfc }, /*  180 KB */
+{   40,  9,  2, 7, 2, 2, 0xfd }, /*  360 KB */
+{   40,  8,  1, 4, 1, 1, 0xfe }, /*  160 KB */
+{   40,  8,  2, 7, 2, 1, 0xff }, /*  320 KB */
+{   80,  9,  2, 7, 2, 3, 0xf9 }, /*  720 KB */
+{   80, 15,  2,14, 1, 7, 0xf9 }, /* 1200 KB */
+{   80, 18,  2,14, 1, 9, 0xf0 }, /* 1440 KB */
+{   80, 36,  2,15, 2, 9, 0xf0 }, /* 2880 KB */
+
+/* Source: https://en.wikipedia.org/w/index.php?title=File_Allocation_Table&oldid=560606333#Exceptions : */
+/* https://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html */
+{   80,  8,  2, 7, 2, 2, 0xfb }, /* 640 KB */
+{   80,  8,  1, 7, 2, 2, 0xfa }, /* 320 KB */
+{   80,  9,  1, 7, 2, 2, 0xf8 }, /* 360 KB */
+};
+
+/**
+ * Get Old Dos parameters for a filesystem of size KBytes (assuming
+ * 512 byte sectors), i.e. number of sectors is double the size
+ */
+struct OldDos_t *getOldDosBySize(size_t size) {
+	size_t 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)
+			return &old_dos[i];
+	}
+	return NULL;
+}
+
+struct OldDos_t *getOldDosByMedia(int media) {
+	size_t i;
+	for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
+		if (old_dos[i].media == media)
+			return &old_dos[i];
+	}
+	fprintf(stderr, "Unknown media type %02x\n", media);
+	return NULL;
+}
+
+struct OldDos_t *getOldDosByParams(unsigned int tracks,
+				   unsigned int heads,
+				   unsigned int sectors,
+				   unsigned int dir_len,
+				   unsigned int cluster_size) {
+	size_t i;
+	for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
+		if (sectors == old_dos[i].sectors &&
+		    tracks == old_dos[i].tracks &&
+		    heads == old_dos[i].heads &&
+		    (dir_len == 0 || dir_len == old_dos[i].dir_len) &&
+		    (cluster_size == 0 ||
+		     cluster_size == old_dos[i].cluster_size)) {
+			return &old_dos[i];
+		}
+	}
+	return NULL;
+}
+
+int setDeviceFromOldDos(int media, struct device *dev) {
+	struct OldDos_t *params=getOldDosByMedia(media);
+	if(params == NULL)
+		return -1;
+	dev->heads = params->heads;
+	dev->tracks = params->tracks;
+	dev->sectors = params->sectors;
+	dev->ssize = 0x80;
+	dev->use_2m = ~1u;
+	return 0;
+}
diff --git a/partition.h b/partition.h
new file mode 100644
index 0000000..7d9aa7b
--- /dev/null
+++ b/partition.h
@@ -0,0 +1,51 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+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,
+		 unsigned long begin, unsigned long end,
+		 unsigned int heads, unsigned int sector,
+		 int activate, int type, int fat_bits);
diff --git a/patchlevel.c b/patchlevel.c
new file mode 100644
index 0000000..b9fd39e
--- /dev/null
+++ b/patchlevel.c
@@ -0,0 +1,27 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+
+const char *mversion="4.0.26";
+
+/* Multiple releases on same day should be marked with (b), (cd), (d) after
+ * date string below */
+const char *mdate = "November 28th, 2020";
+
+const char *mformat_banner = "MTOO4026";
diff --git a/plain_io.c b/plain_io.c
new file mode 100644
index 0000000..10eb0ce
--- /dev/null
+++ b/plain_io.c
@@ -0,0 +1,803 @@
+/*  Copyright 1995-2007,2009,2011 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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"
+
+#ifdef HAVE_LINUX_FS_H
+# include <linux/fs.h>
+#endif
+
+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 dependent 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; i<len; i+=2) {
+		char temp = buf[i];
+		buf[i] = buf[i+1];
+		buf[i+1] = temp;
+	}
+}
+
+
+static int file_io(Stream_t *Stream, char *buf, mt_off_t where, int len,
+				   iofn io)
+{
+	DeclareThis(SimpleFile_t);
+	int ret;
+
+	where += This->offset;
+
+	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 UNUSEDP)
+{
+#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 &&
+		    has_BPB4 &&
+		    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(setDeviceFromOldDos(media, dev) < 0)
+			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;
+}
+
+static int file_discard(Stream_t *Stream)
+{
+#ifdef BLKFLSBUF
+	int ret;
+	DeclareThis(SimpleFile_t);
+	ret= ioctl(This->fd, BLKFLSBUF);
+	if(ret < 0)
+		perror("BLKFLSBUF");
+	return ret;
+#else
+	return 0;
+#endif
+}
+
+/* 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.
+ */
+
+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 aggressively 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 */
+	0, /* dos-convert */
+	file_discard
+};
+
+
+static Class_t SimpleFileClass = {
+	file_read, 
+	file_write,
+	file_flush,
+	file_free,
+	file_geom,
+	file_data,
+	0, /* pre_allocate */
+	0, /* dos-convert */
+	file_discard
+};
+
+
+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;
+	}
+	memset((void*)This, 0, sizeof(SimpleFile_t));
+	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
+
+		if(errno != EOPNOTSUPP || mode == O_RDWR) {
+			/* If error is "not supported", and we're only
+			 * reading from the device anyways, then ignore. Some
+			 * OS'es don't support locks on read-only devices, even
+			 * if they are shared (read-only) locks */
+			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 > (mt_off_t) *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))
+	    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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+#include "msdos.h"
+#ifdef __EMX__
+#include <io.h>
+#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..d31aa01
--- /dev/null
+++ b/precmd.c
@@ -0,0 +1,45 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * Do filename expansion with the shell.
+ */
+
+#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);
+		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..71de4c1
--- /dev/null
+++ b/privileges.c
@@ -0,0 +1,214 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <asm/unistd.h>
+int setresuid(int a, int b, int c)
+{
+	syscall(164, a, b, c);
+
+}
+#endif
+
+static __inline__ void print_privs(const char *message UNUSEDP)
+{
+#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 easier, 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
+				* across 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 != ruid) {
+		unsetenv("SOURCE_DATE_EPOCH");
+	}
+	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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+/* 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..e7150c0
--- /dev/null
+++ b/read_dword.h
@@ -0,0 +1,41 @@
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+static Dword read_dword(int handle) 
+{
+	Byte val[4];
+	
+	if(read(handle, (char *)val, 4) < 4)
+		return (Dword) -1;
+
+	return byte2dword(val);
+}
+
+UNUSED(static Qword read_qword(int handle) )
+{
+	Byte val[8];
+	
+	if(read(handle, (char *)val, 8) < 8)
+		return -1;
+
+	return byte2qword(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 <http://www.gnu.org/licenses/>.
+
+#
+# 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 <http://www.gnu.org/licenses/>.
+#
+#  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 <Card Type> <drive>" >&2
+	echo "<Card Type> has to be defined in amuFormat.sh itself" >&2
+	echo "<drive> 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 <http://www.gnu.org/licenses/>.
+
+
+## (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] <ndisks>"
+	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 <http://www.gnu.org/licenses/>.
+# 
+# /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 <http://www.gnu.org/licenses/>.
+#
+# mcheck [ <DOS drive letter> ]
+#
+# 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..f541eb8
--- /dev/null
+++ b/scripts/mcomp
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Copyright 1996,1997,2001,2002,2006,2010 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 <http://www.gnu.org/licenses/>.
+
+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..49acc49
--- /dev/null
+++ b/scripts/mxtar
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Copyright 1996,1997,2001,2002,2010 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 <http://www.gnu.org/licenses/>.
+
+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 <http://www.gnu.org/licenses/>.
+#
+# 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..d960e7e
--- /dev/null
+++ b/scripts/uz
@@ -0,0 +1,105 @@
+#!/bin/sh
+# Copyright 1994,2002 David C. Niemi.
+# Copyright 1996,1997,2001-2003,2010 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 <http://www.gnu.org/licenses/>.
+# 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
+# 2010/10/16	AKN	Added lzip 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"
+	zipparam=""
+	action="Extracting from "
+	;;
+*lz)
+	tarparam="-tvf"
+	zipparam="-l"
+	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 tar.lz .zip .jar .war .ear .aar .tar.xz; do
+		if [ -r "${1}$suffix" ]; then
+			found=$1$suffix
+			break
+		fi
+	done
+
+	unzip=0
+	case $found in
+		*.tar.bz2 | *.tb2)
+			uzcmd='bzip2 -cd'
+			;;
+		*.zip | *.jar | *.war | *.ear | *.aar)
+			unzip=1
+			;;
+		*.tar.lz)
+			uzcmd='lzip -cd'
+			;;
+		*.tar.xz)
+			uzcmd='xz -cd'
+			;;	
+	esac
+	if [ -z "$found" ]; then
+		echo "$0: could not read \"$1\"." >&2
+	else
+		echo "$action \"$found\"." >&2
+		if [ $unzip = 1 ]; then
+			unzip $zipparam -- "$found"
+		else
+			$uzcmd -- "$found" | tar "$tarparam" -
+		fi
+	fi
+	shift
+done
+
+exit 0
diff --git a/scsi.c b/scsi.c
new file mode 100644
index 0000000..750e0cf
--- /dev/null
+++ b/scsi.c
@@ -0,0 +1,323 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * scsi.c
+ * Iomega Zip/Jaz drive tool
+ * change protection mode and eject disk
+ */
+
+/* scis.c by Markus Gyger <mgyger@itr.ch> */
+/* 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 <sys/scsi.h>
+#endif
+
+#ifdef OS_solaris
+#include <sys/scsi/scsi.h>
+#endif /* solaris */
+
+#ifdef OS_sunos
+#include <scsi/generic/commands.h>
+#include <scsi/impl/uscsi.h>
+#endif /* sunos */
+
+#ifdef sgi
+#include <sys/dsreq.h>
+#endif
+
+#ifdef OS_linux
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#endif
+
+#ifdef _SCO_DS
+#include <sys/scsicmd.h>
+#endif
+
+#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
+#include <camlib.h>
+#endif
+
+#if defined(OS_netbsd) || defined(OS_netbsdelf)
+#include <sys/scsiio.h>
+#endif
+
+int scsi_max_length(void)
+{
+#ifdef OS_linux
+	return 8;
+#else
+	return 255;
+#endif
+}
+
+int scsi_open(const char *name, int flag UNUSEDP, int mode UNUSEDP,
+	      void **extra_data UNUSEDP)
+{
+#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 UNUSEDP)
+{
+#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 sg_io_hdr my_scsi_cmd;
+
+	/*
+	** Init the command
+	*/
+	memset(&my_scsi_cmd,0,sizeof(my_scsi_cmd));
+	my_scsi_cmd.interface_id    = 'S';
+	my_scsi_cmd.dxfer_direction = (mode == SCSI_IO_READ)?(SG_DXFER_FROM_DEV):(SG_DXFER_TO_DEV);
+	my_scsi_cmd.cmd_len         = cmdlen;
+	my_scsi_cmd.mx_sb_len       = 0;
+	my_scsi_cmd.dxfer_len       = len;
+	my_scsi_cmd.dxferp          = data;
+	my_scsi_cmd.cmdp            = cdb;
+	my_scsi_cmd.timeout         = ~0; /* where is MAX_UINT defined??? */
+
+#ifdef DEBUG
+	printf("CMD(%d): %02x%02x%02x%02x%02x%02x %sdevice\n",cmdlen,cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5],
+		(mode==SCSI_IO_READ)?("<-"):("->"));
+	printf("DATA   : len = %d\n",len);
+#endif
+
+	if (ioctl(fd, SG_IO,&my_scsi_cmd) < 0) {
+		perror("scsi_io");
+		return -1;
+	}
+	
+	return my_scsi_cmd.status & STATUS_MASK;
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#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..46880a9
--- /dev/null
+++ b/signal.c
@@ -0,0 +1,134 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+#undef got_signal
+
+int got_signal = 0;
+
+static void signal_handler(int dummy UNUSEDP)
+{
+	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
+}
+
+#ifdef HAVE_SIGACTION
+static void _allow_interrupt(saved_sig_state *ss, int sig, int slot)
+{
+  struct sigaction new;
+
+  bzero(&new, sizeof(new));
+  new.sa_handler = signal_handler;
+  new.sa_flags &= ~SA_RESTART;
+
+  if(sigaction(sig, &new, &ss->sa[slot]) < 0) {
+    perror("sigaction");
+    exit(1);
+  }
+}
+#endif
+
+/* Allow syscalls to be interrupted by signal */
+void allow_interrupts(saved_sig_state *ss)
+{
+#ifdef HAVE_SIGACTION
+
+# ifdef SIGHUP
+  _allow_interrupt(ss, SIGINT, 0);
+# endif
+
+# ifdef SIGINT
+  _allow_interrupt(ss, SIGINT, 1);
+# endif
+
+# ifdef SIGTERM
+  _allow_interrupt(ss, SIGINT, 2);
+# endif
+
+# ifdef SIGQUIT
+  _allow_interrupt(ss, SIGINT, 3);
+# endif
+
+#endif
+}
+
+#ifdef HAVE_SIGACTION
+static void _restore_interrupt(saved_sig_state *ss, int sig, int slot)
+{
+  if(sigaction(sig, &ss->sa[slot], NULL) < 0) {
+    perror("restore sigaction");
+    exit(1);
+  }
+}
+#endif
+
+/* Restore syscalls to be interrupted by signal */
+void restore_interrupts(saved_sig_state *ss)
+{
+#ifdef HAVE_SIGACTION
+
+# ifdef SIGHUP
+  _restore_interrupt(ss, SIGINT, 0);
+# endif
+
+# ifdef SIGINT
+  _restore_interrupt(ss, SIGINT, 1);
+# endif
+
+# ifdef SIGTERM
+  _restore_interrupt(ss, SIGINT, 2);
+# endif
+
+# ifdef SIGQUIT
+  _restore_interrupt(ss, SIGINT, 3);
+# endif
+
+#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 <http://www.gnu.org/licenses/>.
+ */
+
+#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..f027ece
--- /dev/null
+++ b/stream.h
@@ -0,0 +1,107 @@
+#ifndef MTOOLS_STREAM_H
+#define MTOOLS_STREAM_H
+
+/*  Copyright 1996-1999,2001,2002,2005,2006,2008,2009,2011 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 <http://www.gnu.org/licenses/>.
+ */
+
+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 *);
+
+	int (*discard)(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))
+
+#define DISCARD(stream)			\
+	(stream)->Class->discard((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);
+
+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);
+
+#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 <http://www.gnu.org/licenses/>.
+ *
+ * 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..0707b76
--- /dev/null
+++ b/strip-pp.sed
@@ -0,0 +1,22 @@
+# 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 <http://www.gnu.org/licenses/>.
+:1
+/^\.[IlP][pP]$/N
+s/^\.[IlP][pP]\n\(\.[IlTP][pP]\)$/\1/
+s/^\.l[pP]/.PP/
+/^\.PP$/b1
+/^\.eh/d
+/^\.oh/d
diff --git a/strtonum.c b/strtonum.c
new file mode 100644
index 0000000..d6324dc
--- /dev/null
+++ b/strtonum.c
@@ -0,0 +1,87 @@
+/*  Copyright 2018 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "sysincludes.h"
+#include "mtools.h"
+
+static long strtol_with_range(const char *nptr, char **endptr, int base,
+			      long min, long max) {
+    long l = strtol(nptr, endptr, base);
+    if(l > max) {
+	errno = ERANGE;
+	return max;
+    }
+    if(l < min) {
+	errno = ERANGE;
+	return min;
+    }
+    return l;
+}
+
+static long strtoul_with_range(const char *nptr, char **endptr, int base,
+			      unsigned long max) {
+    unsigned long l = strtoul(nptr, endptr, base);
+    if(l > max) {
+	errno = ERANGE;
+	return max;
+    }
+    return l;
+}
+
+#ifndef HAVE_STRTOUI
+unsigned int strtoui(const char *nptr, char **endptr, int base) {
+    return (unsigned int) strtoul_with_range(nptr, endptr, base, UINT_MAX);
+}
+#endif
+
+unsigned int atoui(const char *str) {
+    return strtoui(str, 0, 0);
+}
+
+#ifndef HAVE_STRTOI
+int strtoi(const char *nptr, char **endptr, int base) {
+    return (int) strtol_with_range(nptr, endptr, base, INT_MIN, INT_MAX);
+}
+#endif
+
+unsigned long atoul(const char *str) {
+    return strtoul(str, 0, 0);
+}
+
+uint8_t strtou8(const char *nptr, char **endptr, int base) {
+    return (uint8_t) strtoul_with_range(nptr, endptr, base, UINT8_MAX);
+}
+
+uint8_t atou8(const char *str) {
+    return strtou8(str, 0, 0);
+}
+
+uint16_t strtou16(const char *nptr, char **endptr, int base) {
+    return (uint16_t) strtoul_with_range(nptr, endptr, base, UINT16_MAX);
+}
+
+uint16_t atou16(const char *str) {
+    return strtou16(str, 0, 0);
+}
+
+uint32_t strtou32(const char *nptr, char **endptr, int base) {
+    return (uint32_t) strtoul_with_range(nptr, endptr, base, UINT32_MAX);
+}
+
+uint32_t atou32(const char *str) {
+    return strtou32(str, 0, 0);
+}
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 <http://www.gnu.org/licenses/>.
+ */
+
+#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/sysconfdir.texi b/sysconfdir.texi
new file mode 100644
index 0000000..359518f
--- /dev/null
+++ b/sysconfdir.texi
@@ -0,0 +1 @@
+@set SYSCONFDIR /etc/
diff --git a/sysincludes.h b/sysincludes.h
new file mode 100644
index 0000000..0bfc818
--- /dev/null
+++ b/sysincludes.h
@@ -0,0 +1,639 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 dependencies 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
+
+#ifndef HAVE_CADDR_T
+typedef void *caddr_t;
+#endif
+
+
+/***********************************************************************/
+/*                                                                     */
+/* Compiler dependencies                                               */
+/*                                                                     */
+/***********************************************************************/
+
+
+#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
+#  define UNUSEDP __attribute__ ((unused))
+# endif
+# define NORETURN __attribute__ ((noreturn))
+# if __GNUC__ >= 8
+#  define NONULLTERM __attribute__ ((nonstring))
+# endif
+#endif
+
+#ifndef UNUSED
+# define UNUSED(x) x
+# define UNUSEDP /* */
+#endif
+
+#ifndef PACKED
+# define PACKED /* */
+#endif
+
+#ifndef NORETURN
+# define NORETURN /* */
+#endif
+
+#ifndef NONULLTERM
+# define NONULLTERM /* */
+#endif
+
+/***********************************************************************/
+/*                                                                     */
+/* Include files                                                       */
+/*                                                                     */
+/***********************************************************************/
+
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE
+
+
+#ifdef HAVE_FEATURES_H
+# include <features.h>
+#endif
+
+
+#include <sys/types.h>
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LINUX_UNISTD_H
+# include <linux/unistd.h>
+#endif
+
+#ifdef HAVE_LIBC_H
+# include <libc.h>
+#endif
+
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# ifndef sunos
+# include <sys/ioctl.h>
+#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 <sys/time.h>
+# include <time.h>
+#else
+# ifdef HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#ifndef NO_TERMIO
+# ifdef HAVE_TERMIO_H
+#  include <termio.h>
+# elif defined HAVE_SYS_TERMIO_H
+#  include <sys/termio.h>
+# 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 <termios.h>
+#  elif defined HAVE_SYS_TERMIOS_H
+#   include <sys/termios.h>
+#  endif
+# endif
+# ifdef HAVE_STTY_H
+#  include <sgtty.h>
+# 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 <mntent.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#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 <sys/stat.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+#ifndef OS_mingw32msvc
+#include <pwd.h>
+#endif
+
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+#  include <strings.h>
+# endif
+#endif
+
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#else
+# ifdef HAVE_SYS_SIGNAL_H
+#  include <sys/signal.h>
+# endif
+#endif
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# ifndef DONT_NEED_WAIT
+#  include <sys/wait.h>
+# endif
+#endif
+
+#ifdef HAVE_WCHAR_H
+# include <wchar.h>
+# 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 <wctype.h>
+#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 <locale.h>
+#endif
+
+#ifdef HAVE_XLOCALE_H
+# include <xlocale.h>
+#endif
+
+#ifdef USE_FLOPPYD
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_X11_XAUTH_H
+#include <X11/Xauth.h>
+#endif
+
+#ifdef HAVE_X11_XLIB_H
+#include <X11/Xlib.h>
+#endif
+
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+
+
+#ifdef sgi
+#define MSGIHACK __EXTENSIONS__
+#undef __EXTENSIONS__
+#endif
+#include <math.h>
+#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_STRNDUP
+extern char *strndup(const char *s, size_t n);
+#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 <os2.h>
+#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..3c7051d
--- /dev/null
+++ b/texinfo.tex
@@ -0,0 +1,11772 @@
+% 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{2020-10-24.12}
+%
+% Copyright 1985, 1986, 1988, 1990-2020 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 <https://www.gnu.org/licenses/>.
+%
+% 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 Exception is an additional permission under section 7
+% of the GNU General Public License, version 3 ("GPLv3").
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   https://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or
+%   https://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or
+%   https://www.gnu.org/software/texinfo/ (the Texinfo home page)
+% 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 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 https://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}
+
+% LaTeX's \typeout.  This ensures that the messages it is used for
+% are identical in format to the corresponding ones from latex/pdflatex.
+\def\typeout{\immediate\write17}%
+
+\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\ptexraggedright=\raggedright
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexsp=\sp
+\let\ptexstar=\*
+\let\ptexsup=\sup
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode
+
+% 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\putworderror\undefined     \gdef\putworderror{error}\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
+
+% Give the space character the catcode for a space.
+\def\spaceisspace{\catcode`\ =10\relax}
+
+% Likewise for ^^M, the end of line character.
+\def\endlineisspace{\catcode13=10\relax}
+
+\chardef\dashChar  = `\-
+\chardef\slashChar = `\/
+\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
+}
+
+% 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\thisisundefined\else % etex gives us more logging
+    \tracingscantokens1
+    \tracingifs1
+    \tracinggroups1
+    \tracingnesting2
+    \tracingassigns1
+  \fi
+  \tracingcommands3  % 3 gives us more in etex
+  \errorcontextlines16
+}%
+
+% @errormsg{MSG}.  Do the index-like expansions on MSG, but if things
+% aren't perfect, it's not the end of the world, being an error message,
+% after all.
+%
+\def\errormsg{\begingroup \indexnofonts \doerrormsg}
+\def\doerrormsg#1{\errmessage{#1}}
+
+% 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}
+
+% Output routine
+%
+
+% 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 }
+
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\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.
+
+% \domark is called twice inside \chapmacro, to add one
+% mark before the section break, and one after.
+%   In the second call \prevchapterdefs is the same as \currentchapterdefs,
+% and \prevsectiondefs is the same as \currentsectiondefs.
+%   Then if the page is not broken at the mark, some of the previous
+% section appears on the page, and we can get the name of this section
+% from \firstmark for @everyheadingmarks top.
+%   @everyheadingmarks bottom uses \botmark.
+%
+% See page 260 of The TeXbook.
+\def\domark{%
+  \toks0=\expandafter{\currentchapterdefs}%
+  \toks2=\expandafter{\currentsectiondefs}%
+  \toks4=\expandafter{\prevchapterdefs}%
+  \toks6=\expandafter{\prevsectiondefs}%
+  \toks8=\expandafter{\currentcolordefs}%
+  \mark{%
+                   \the\toks0 \the\toks2  % 0: marks for @everyheadingmarks top
+      \noexpand\or \the\toks4 \the\toks6  % 1: for @everyheadingmarks bottom
+    \noexpand\else \the\toks8             % 2: color marks
+  }%
+}
+
+% \gettopheadingmarks, \getbottomheadingmarks,
+% \getcolormarks - extract needed part of mark.
+%
+% \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\the\savedtopmark\fi
+  \ifx\thischapter\empty \ifcase0\firstmark\fi \fi
+}
+\def\getbottomheadingmarks{\ifcase1\botmark\fi}
+\def\getcolormarks{\ifcase2\the\savedtopmark\fi}
+
+% Avoid "undefined control sequence" errors.
+\def\currentchapterdefs{}
+\def\currentsectiondefs{}
+\def\currentsection{}
+\def\prevchapterdefs{}
+\def\prevsectiondefs{}
+\def\currentcolordefs{}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\txipagewidth \newdimen\txipageheight
+
+% Main output routine.
+%
+\chardef\PAGE = 255
+\newtoks\defaultoutput
+\defaultoutput = {\savetopmark\onepageout{\pagecontents\PAGE}}
+\output=\expandafter{\the\defaultoutput}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% When outputting the double column layout for indices, an output routine
+% is run several times, which hides the original value of \topmark.  This
+% can lead to a page heading being output and duplicating the chapter heading
+% of the index.  Hence, save the contents of \topmark at the beginning of
+% the output routine.  The saved contents are valid until we actually
+% \shipout a page.
+%
+% (We used to run a short output routine to actually set \topmark and
+% \firstmark to the right values, but if this was called with an empty page
+% containing whatsits for writing index entries, the whatsits would be thrown
+% away and the index auxiliary file would remain empty.)
+%
+\newtoks\savedtopmark
+\newif\iftopmarksaved
+\topmarksavedtrue
+\def\savetopmark{%
+  \iftopmarksaved\else
+    \global\savedtopmark=\expandafter{\topmark}%
+    \global\topmarksavedtrue
+  \fi
+}
+
+% \onepageout takes a vbox as an argument.
+% \shipout a vbox for a single page, adding an optional header, footer
+% and footnote.  This also causes index entries for this page to be written
+% to the auxiliary files.
+%
+\def\onepageout#1{%
+  \hoffset=\normaloffset
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  \checkchapterpage
+  %
+  % Retrieve the information for the headings from the marks in the page,
+  % and call Plain TeX's \makeheadline and \makefootline, which use the
+  % values in \headline and \footline.
+  %
+  % Common context changes for both heading and footing.
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \def\commonheadfootline{\let\hsize=\txipagewidth \texinfochars}
+  %
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  \global\setbox\headlinebox = \vbox{\commonheadfootline \makeheadline}%
+  \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi
+  \global\setbox\footlinebox = \vbox{\commonheadfootline \makefootline}%
+  %
+  {%
+    % Set context for writing to auxiliary files like index files.
+    % 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.
+    %
+    \atdummies         % don't expand commands in the output.
+    \turnoffactive
+    \shipout\vbox{%
+      % Do this early so pdf references go to the beginning of the page.
+      \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\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
+      %
+    }%
+  }%
+  \global\topmarksavedfalse
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+% Main part of page, including any footnotes
+\def\pagebody#1{\vbox to\txipageheight{\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}
+}
+
+% Check if we are on the first page of a chapter.  Used for printing headings.
+\newif\ifchapterpage
+\def\checkchapterpage{%
+  % Get the chapter that was current at the end of the last page
+  \ifcase1\the\savedtopmark\fi
+  \let\prevchaptername\thischaptername
+  %
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  \let\curchaptername\thischaptername
+  %
+  \ifx\curchaptername\prevchaptername
+    \chapterpagefalse
+  \else
+    \chapterpagetrue
+  \fi
+}
+
+% Argument parsing
+
+% 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.
+% For example, \def\foo{\parsearg\fooxxx}.
+%
+\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.  Pass the result on to
+% \argcheckspaces.
+\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 `<space>\^^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 - define a command taking an argument on the line
+%
+% \parseargdef\foo{...}
+%	is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+\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
+    outside 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.
+    \expandafter\checkenv\csname#1\endcsname
+    \csname E#1\endcsname
+    \endgroup
+  \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+% 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\*{\unskip\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.
+  \addgroupbox
+  \prevdepth = \dimen1
+  \checkinserts
+}
+
+\def\addgroupbox{
+  % \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 = \txipageheight   \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\txipageheight
+      \page
+    \fi
+  \fi
+  \box\groupbox
+}
+
+%
+% 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
+
+\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'.  Not documented, written for gawk manual.
+%
+\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.
+    \wlog{texinfo.tex: doing @include of #1^^J}%
+    \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\centersub\centerH
+  \else
+    \let\centersub\centerV
+  \fi
+  \centersub{\hfil \ignorespaces#1\unskip \hfil}%
+  \let\centersub\relax % don't let the definition persist, just in case
+}
+\def\centerH#1{{%
+  \hfil\break
+  \advance\hsize by -\leftskip
+  \advance\hsize by -\rightskip
+  \line{#1}%
+  \break
+}}
+%
+\newcount\centerpenalty
+\def\centerV#1{%
+  % The idea here is the same as in \startdefun, \cartouche, etc.: if
+  % @center is the first thing after a section heading, we need to wipe
+  % out the negative parskip inserted by \sectionheading, but still
+  % prevent a page break here.
+  \centerpenalty = \lastpenalty
+  \ifnum\centerpenalty>10000 \vskip\parskip \fi
+  \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi
+  \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\c{\begingroup \catcode`\^^M=\active%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\cxxx}
+{\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}}
+%
+\let\comment\c
+
+% @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 = {}%
+}
+
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% @setfilename INFO-FILENAME - ignored
+\let\setfilename=\comment
+
+% @bye.
+\outer\def\bye{\chappager\pagelabels\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
+\newbox\boxB
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+%
+% For LuaTeX
+%
+
+\newif\iftxiuseunicodedestname
+\txiuseunicodedestnamefalse % For pdfTeX etc.
+
+\ifx\luatexversion\thisisundefined
+\else
+  % Use Unicode destination names
+  \txiuseunicodedestnametrue
+  % Escape PDF strings with converting UTF-16 from UTF-8
+  \begingroup
+    \catcode`\%=12
+    \directlua{
+      function UTF16oct(str)
+        tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377')
+        for c in string.utfvalues(str) do
+          if c < 0x10000 then
+            tex.sprint(
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o',
+                            math.floor(c / 256), math.floor(c % 256)))
+          else
+            c = c - 0x10000
+            local c_hi = c / 1024 + 0xd800
+            local c_lo = c % 1024 + 0xdc00
+            tex.sprint(
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o',
+                            math.floor(c_hi / 256), math.floor(c_hi % 256),
+                            math.floor(c_lo / 256), math.floor(c_lo % 256)))
+          end
+        end
+      end
+    }
+  \endgroup
+  \def\pdfescapestrutfsixteen#1{\directlua{UTF16oct('\luaescapestring{#1}')}}
+  % Escape PDF strings without converting
+  \begingroup
+    \directlua{
+      function PDFescstr(str)
+        for c in string.bytes(str) do
+          if c <= 0x20 or c >= 0x80 or c == 0x28 or c == 0x29 or c == 0x5c then
+            tex.sprint(-2,
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o',
+                            c))
+          else
+            tex.sprint(-2, string.char(c))
+          end
+        end
+      end
+    }
+    % The -2 in the arguments here gives all the input to TeX catcode 12
+    % (other) or 10 (space), preventing undefined control sequence errors. See
+    % https://lists.gnu.org/archive/html/bug-texinfo/2019-08/msg00031.html
+    %
+  \endgroup
+  \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}}
+  \ifnum\luatexversion>84
+    % For LuaTeX >= 0.85
+    \def\pdfdest{\pdfextension dest}
+    \let\pdfoutput\outputmode
+    \def\pdfliteral{\pdfextension literal}
+    \def\pdfcatalog{\pdfextension catalog}
+    \def\pdftexversion{\numexpr\pdffeedback version\relax}
+    \let\pdfximage\saveimageresource
+    \let\pdfrefximage\useimageresource
+    \let\pdflastximage\lastsavedimageresourceindex
+    \def\pdfendlink{\pdfextension endlink\relax}
+    \def\pdfoutline{\pdfextension outline}
+    \def\pdfstartlink{\pdfextension startlink}
+    \def\pdffontattr{\pdfextension fontattr}
+    \def\pdfobj{\pdfextension obj}
+    \def\pdflastobj{\numexpr\pdffeedback lastobj\relax}
+    \let\pdfpagewidth\pagewidth
+    \let\pdfpageheight\pageheight
+    \edef\pdfhorigin{\pdfvariable horigin}
+    \edef\pdfvorigin{\pdfvariable vorigin}
+  \fi
+\fi
+
+% 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 being undefined.
+\ifx\pdfoutput\thisisundefined
+\else
+  \ifx\pdfoutput\relax
+  \else
+    \ifcase\pdfoutput
+    \else
+      \pdftrue
+    \fi
+  \fi
+\fi
+
+\newif\ifpdforxetex
+\pdforxetexfalse
+\ifpdf
+  \pdforxetextrue
+\fi
+\ifx\XeTeXrevision\thisisundefined\else
+  \pdforxetextrue
+\fi
+
+
+% Output page labels information.
+% See PDF reference v.1.7 p.594, section 8.3.1.
+\ifpdf
+\def\pagelabels{%
+  \def\title{0 << /P (T-) /S /D >>}%
+  \edef\roman{\the\romancount << /S /r >>}%
+  \edef\arabic{\the\arabiccount << /S /D >>}%
+  %
+  % Page label ranges must be increasing.  Remove any duplicates.
+  % (There is a slight chance of this being wrong if e.g. there is
+  % a @contents but no @titlepage, etc.)
+  %
+  \ifnum\romancount=0 \def\roman{}\fi
+  \ifnum\arabiccount=0 \def\title{}%
+  \else
+    \ifnum\romancount=\arabiccount \def\roman{}\fi
+  \fi
+  %
+  \ifnum\romancount<\arabiccount
+    \pdfcatalog{/PageLabels << /Nums [\title \roman \arabic ] >> }\relax
+  \else
+    \pdfcatalog{/PageLabels << /Nums [\title \arabic \roman ] >> }\relax
+  \fi
+}
+\else
+  \let\pagelabels\relax
+\fi
+
+\newcount\pagecount \pagecount=0
+\newcount\romancount \romancount=0
+\newcount\arabiccount \arabiccount=0
+\ifpdf
+  \let\ptxadvancepageno\advancepageno
+  \def\advancepageno{%
+    \ptxadvancepageno\global\advance\pagecount by 1
+  }
+\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.
+%
+% See 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.  pdftex 1.30.0 (ca.2005) introduced a primitive to
+% do this reliably, so we use it.
+
+% #1 is a control sequence in which to do the replacements,
+% which we \xdef.
+\def\txiescapepdf#1{%
+  \ifx\pdfescapestring\thisisundefined
+    % No primitive available; should we give a warning or log?
+    % Many times it won't matter.
+    \xdef#1{#1}%
+  \else
+    % The expandable \pdfescapestring primitive escapes parentheses,
+    % backslashes, and other special chars.
+    \xdef#1{\pdfescapestring{#1}}%
+  \fi
+}
+\def\txiescapepdfutfsixteen#1{%
+  \ifx\pdfescapestrutfsixteen\thisisundefined
+    % No UTF-16 converting macro available.
+    \txiescapepdf{#1}%
+  \else
+    \xdef#1{\pdfescapestrutfsixteen{#1}}%
+  \fi
+}
+
+\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 using ideas from 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. The dark red here is dark enough to print on paper as
+  % nearly black, but still distinguishable for online viewing.  We use
+  % black by default, though.
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  % rg sets the color for filling (usual text, etc.);
+  % RG 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\currentcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\currentcolordefs{}
+  %
+  \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\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % pdftex (and the PDF format) support .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\pdfimgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errhelp = \nopdfimagehelp
+                  \errmessage{Could not find image file #1 for pdf}%
+                \else \gdef\pdfimgext{JPG}%
+                \fi
+              \else \gdef\pdfimgext{jpeg}%
+              \fi
+            \else \gdef\pdfimgext{jpg}%
+            \fi
+          \else \gdef\pdfimgext{png}%
+          \fi
+        \else \gdef\pdfimgext{PDF}%
+        \fi
+      \else \gdef\pdfimgext{pdf}%
+      \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 \pdfimagewidth \fi
+      \ifdim \wd2 >0pt height \pdfimageheight \fi
+      \ifnum\pdftexversion<13
+         #1.\pdfimgext
+       \else
+         {#1.\pdfimgext}%
+       \fi
+    \ifnum\pdftexversion < 14 \else
+      \pdfrefximage \pdflastximage
+    \fi}
+  %
+  \def\setpdfdestname#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
+    \makevalueexpandable
+    \turnoffactive
+    \iftxiuseunicodedestname
+      \ifx \declaredencoding \latone
+        % Pass through Latin-1 characters.
+        % LuaTeX with byte wise I/O converts Latin-1 characters to Unicode.
+      \else
+        \ifx \declaredencoding \utfeight
+          % Pass through Unicode characters.
+        \else
+          % Use ASCII approximations in destination names.
+          \passthroughcharsfalse
+        \fi
+      \fi
+    \else
+      % Use ASCII approximations in destination names.
+      \passthroughcharsfalse
+    \fi
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+  }}
+  %
+  \def\setpdfoutlinetext#1{{%
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \ifx \declaredencoding \latone
+      % The PDF format can use an extended form of Latin-1 in bookmark
+      % strings.  See Appendix D of the PDF Reference, Sixth Edition, for
+      % the "PDFDocEncoding".
+      \passthroughcharstrue
+      % Pass through Latin-1 characters.
+      %   LuaTeX: Convert to Unicode
+      %   pdfTeX: Use Latin-1 as PDFDocEncoding
+      \def\pdfoutlinetext{#1}%
+    \else
+      \ifx \declaredencoding \utfeight
+        \ifx\luatexversion\thisisundefined
+          % For pdfTeX  with UTF-8.
+          % TODO: the PDF format can use UTF-16 in bookmark strings,
+          % but the code for this isn't done yet.
+          % Use ASCII approximations.
+          \passthroughcharsfalse
+          \def\pdfoutlinetext{#1}%
+        \else
+          % For LuaTeX with UTF-8.
+          % Pass through Unicode characters for title texts.
+          \passthroughcharstrue
+          \def\pdfoutlinetext{#1}%
+        \fi
+      \else
+        % For non-Latin-1 or non-UTF-8 encodings.
+        % Use ASCII approximations.
+        \passthroughcharsfalse
+        \def\pdfoutlinetext{#1}%
+      \fi
+    \fi
+    % LuaTeX: Convert to UTF-16
+    % pdfTeX: Use Latin-1 as PDFDocEncoding
+    \txiescapepdfutfsixteen\pdfoutlinetext
+  }}
+  %
+  \def\pdfmkdest#1{%
+    \setpdfdestname{#1}%
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }
+  %
+  % used to mark target names; must be expandable.
+  \def\pdfmkpgn#1{#1}
+  %
+  % by default, use black for everything.
+  \def\urlcolor{\rgbBlack}
+  \def\linkcolor{\rgbBlack}
+  \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.
+    \setpdfoutlinetext{#1}
+    \setpdfdestname{#3}
+    \ifx\pdfdestname\empty
+      \def\pdfdestname{#4}%
+    \fi
+    %
+    \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      % Read toc silently, to get counts of subentries for \pdfoutline.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \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.
+      %
+      % Currently we prefix the section name with the section number
+      % for chapter and appendix headings only in order to avoid too much
+      % horizontal space being required in the PDF viewer.
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##2 ##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+      \def\unnchapentry##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.
+      %
+      % TODO this right, we have to translate 8-bit characters to
+      % their "best" equivalent, based on the @documentencoding.  Too
+      % much work for too little return.  Just use the ASCII equivalents
+      % we use for the index sort strings.
+      %
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+  %
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\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}
+  % \pdfgettoks - Surround page numbers in #1 with @pdflink.  #1 may
+  % be a simple number, or a list of numbers in the case of an index
+  % entry.
+  \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
+
+%
+% For XeTeX
+%
+\ifx\XeTeXrevision\thisisundefined
+\else
+  %
+  % XeTeX version check
+  %
+  \ifnum\strcmp{\the\XeTeXversion\XeTeXrevision}{0.99996}>-1
+    % TeX Live 2016 contains XeTeX 0.99996 and xdvipdfmx 20160307.
+    % It can use the `dvipdfmx:config' special (from TeX Live SVN r40941).
+    % For avoiding PDF destination name replacement, we use this special
+    % instead of xdvipdfmx's command line option `-C 0x0010'.
+    \special{dvipdfmx:config C 0x0010}
+    % XeTeX 0.99995+ comes with xdvipdfmx 20160307+.
+    % It can handle Unicode destination names for PDF.
+    \txiuseunicodedestnametrue
+  \else
+    % XeTeX < 0.99996 (TeX Live < 2016) cannot use the
+    % `dvipdfmx:config' special.
+    % So for avoiding PDF destination name replacement,
+    % xdvipdfmx's command line option `-C 0x0010' is necessary.
+    %
+    % XeTeX < 0.99995 can not handle Unicode destination names for PDF
+    % because xdvipdfmx 20150315 has a UTF-16 conversion issue.
+    % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+    \txiuseunicodedestnamefalse
+  \fi
+  %
+  % Color support
+  %
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  \def\pdfsetcolor#1{\special{pdf:scolor [#1]}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\currentcolordefs{}
+  %
+  \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
+  }
+  %
+  % PDF outline support
+  %
+  % Emulate pdfTeX primitive
+  \def\pdfdest name#1 xyz{%
+    \special{pdf:dest (#1) [@thispage /XYZ @xpos @ypos null]}%
+  }
+  %
+  \def\setpdfdestname#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
+    \makevalueexpandable
+    \turnoffactive
+    \iftxiuseunicodedestname
+      % Pass through Unicode characters.
+    \else
+      % Use ASCII approximations in destination names.
+      \passthroughcharsfalse
+    \fi
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+  }}
+  %
+  \def\setpdfoutlinetext#1{{%
+    \turnoffactive
+    % Always use Unicode characters in title texts.
+    \def\pdfoutlinetext{#1}%
+    % For XeTeX, xdvipdfmx converts to UTF-16.
+    % So we do not convert.
+    \txiescapepdf\pdfoutlinetext
+  }}
+  %
+  \def\pdfmkdest#1{%
+    \setpdfdestname{#1}%
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }
+  %
+  % by default, use black for everything.
+  \def\urlcolor{\rgbBlack}
+  \def\linkcolor{\rgbBlack}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    \setpdfoutlinetext{#1}
+    \setpdfdestname{#3}
+    \ifx\pdfdestname\empty
+      \def\pdfdestname{#4}%
+    \fi
+    %
+    \special{pdf:out [-] #2 << /Title (\pdfoutlinetext) /A
+      << /S /GoTo /D (\pdfdestname) >> >> }%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      %
+      % For XeTeX, counts of subentries are not necessary.
+      % Therefore, we read toc only once.
+      %
+      % We use node names as destinations.
+      %
+      % Currently we prefix the section name with the section number
+      % for chapter and appendix headings only in order to avoid too much
+      % horizontal space being required in the PDF viewer.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##2 ##1}{1}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{2}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{3}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{4}{##3}{##4}}%
+      %
+      \let\appentry\numchapentry%
+      \let\appsecentry\numsecentry%
+      \let\appsubsecentry\numsubsecentry%
+      \let\appsubsubsecentry\numsubsubsecentry%
+      \def\unnchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{1}{##3}{##4}}%
+      \let\unnsecentry\numsecentry%
+      \let\unnsubsecentry\numsubsecentry%
+      \let\unnsubsubsecentry\numsubsubsecentry%
+      %
+      % For XeTeX, xdvipdfmx converts strings to UTF-16.
+      % Therefore, the encoding and the language may not be considered.
+      %
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+
+  \special{pdf:docview << /PageMode /UseOutlines >> }
+  % ``\special{pdf:tounicode ...}'' is not necessary
+  % because xdvipdfmx converts strings from UTF-8 to UTF-16 without it.
+  % However, due to a UTF-16 conversion issue of xdvipdfmx 20150315,
+  % ``\special{pdf:dest ...}'' cannot handle non-ASCII strings.
+  % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+%
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\relax
+  }
+  % 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}%
+      \special{pdf:bann << /Border [0 0 0]
+        /Subtype /Link /A << /S /URI /URI (#1) >> >>}%
+    \endgroup}
+  \def\endlink{\setcolor{\maincolor}\special{pdf:eann}}
+  \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{%
+    \special{pdf:bann << /Border [0 0 0]
+      /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}%
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+%
+  %
+  % @image support
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\doxeteximage#1#2#3{%
+    \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % XeTeX (and the PDF format) supports .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\xeteximgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errmessage{Could not find image file #1 for XeTeX}%
+                \else \gdef\xeteximgext{JPG}%
+                \fi
+              \else \gdef\xeteximgext{jpeg}%
+              \fi
+            \else \gdef\xeteximgext{jpg}%
+            \fi
+          \else \gdef\xeteximgext{png}%
+          \fi
+        \else \gdef\xeteximgext{PDF}%
+        \fi
+      \else \gdef\xeteximgext{pdf}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    \def\xetexpdfext{pdf}%
+    \ifx\xeteximgext\xetexpdfext
+      \XeTeXpdffile "#1".\xeteximgext ""
+    \else
+      \def\xetexpdfext{PDF}%
+      \ifx\xeteximgext\xetexpdfext
+        \XeTeXpdffile "#1".\xeteximgext ""
+      \else
+        \XeTeXpicfile "#1".\xeteximgext ""
+      \fi
+    \fi
+    \ifdim \wd0 >0pt width \xeteximagewidth \fi
+    \ifdim \wd2 >0pt height \xeteximageheight \fi \relax
+  }
+\fi
+
+
+%
+\message{fonts,}
+
+% 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}
+%
+\newdimen\textleading
+\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\thisisundefined \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 \fontprefix#2.
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit).
+% Example:
+% #1 = \textrm
+% #2 = \rmshape
+% #3 = 10
+% #4 = \mainmagstep
+% #5 = OT1
+%
+\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
+%
+% (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\thisisundefined
+\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.  (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\defsl\slshape{10}{\magstep1}{OT1}
+\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\ttslfont=\defttsl \let\slfont=\defsl \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 math mode superscripts (7pt).
+\def\sevennominalsize{7pt}
+\setfont\sevenrm\rmshape{7}{1000}{OT1}
+\setfont\seventt\ttshape{10}{700}{OT1TT}
+\setfont\sevenbf\bfshape{10}{700}{OT1}
+\setfont\sevenit\itshape{7}{1000}{OT1IT}
+\setfont\sevensl\slshape{10}{700}{OT1}
+\setfont\sevensf\sfshape{10}{700}{OT1}
+\setfont\sevensc\scshape{10}{700}{OT1}
+\setfont\seventtsl\ttslshape{10}{700}{OT1TT}
+\font\seveni=cmmi7
+\font\sevensy=cmsy7
+\def\sevenecsize{0700}
+
+% 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\secrmnotbold\rmshape{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 @acronym 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}
+
+\textleading = 13.2pt % line spacing for 11pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 11pt text font size definitions, \definetextfontsizexi
+
+
+% 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\defsl\slshape{10}{\magstephalf}{OT1}
+\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\slfont=\defsl \let\ttslfont=\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 math mode superscripts (7pt).
+\def\sevennominalsize{7pt}
+\setfont\sevenrm\rmshape{7}{1000}{OT1}
+\setfont\seventt\ttshape{10}{700}{OT1TT}
+\setfont\sevenbf\bfshape{10}{700}{OT1}
+\setfont\sevenit\itshape{7}{1000}{OT1IT}
+\setfont\sevensl\slshape{10}{700}{OT1}
+\setfont\sevensf\sfshape{10}{700}{OT1}
+\setfont\sevensc\scshape{10}{700}{OT1}
+\setfont\seventtsl\ttslshape{10}{700}{OT1TT}
+\font\seveni=cmmi7
+\font\sevensy=cmsy7
+\def\sevenecsize{0700}
+
+% 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 @acronym 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}
+
+\divide\parskip by 2  % reduce space between paragraphs
+\textleading = 12pt   % line spacing for 10pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 10pt text font size definitions, \definetextfontsizex
+
+% 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}
+
+
+% We provide the user-level command
+%   @fonttextsize 10
+% (or 11) to redefine the text font size.  pt is assumed.
+%
+\def\xiword{11}
+\def\xword{10}
+\def\xwordpt{10pt}
+%
+\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
+}
+
+%
+% 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 #1font\endcsname  % change the current font
+}
+
+\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}}\def\ttstylename{tt}
+
+% 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}}
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.
+% We don't bother to reset \scriptscriptfont; awaiting user need.
+%
+\def\resetmathfonts{%
+  \textfont0=\rmfont \textfont1=\ifont \textfont2=\syfont
+  \textfont\itfam=\itfont \textfont\slfam=\slfont \textfont\bffam=\bffont
+  \textfont\ttfam=\ttfont \textfont\sffam=\sffont
+  %
+  % Fonts for superscript.  Note that the 7pt fonts are used regardless
+  % of the current font size.
+  \scriptfont0=\sevenrm \scriptfont1=\seveni \scriptfont2=\sevensy
+  \scriptfont\itfam=\sevenit \scriptfont\slfam=\sevensl
+  \scriptfont\bffam=\sevenbf \scriptfont\ttfam=\seventt
+  \scriptfont\sffam=\sevensf
+}
+
+%
+
+% The font-changing commands (all called \...fonts) redefine the meanings
+% of \STYLEfont, 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 \STYLEfont to set the current font.
+%
+% The fonts used for \ifont are for "math italics"  (\itfont is for italics
+% in regular text).  \syfont is also used in math mode only.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower).  These relative commands are used
+% in, e.g., the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+
+\def\assignfonts#1{%
+  \expandafter\let\expandafter\rmfont\csname #1rm\endcsname
+  \expandafter\let\expandafter\itfont\csname #1it\endcsname
+  \expandafter\let\expandafter\slfont\csname #1sl\endcsname
+  \expandafter\let\expandafter\bffont\csname #1bf\endcsname
+  \expandafter\let\expandafter\ttfont\csname #1tt\endcsname
+  \expandafter\let\expandafter\smallcaps\csname #1sc\endcsname
+  \expandafter\let\expandafter\sffont  \csname #1sf\endcsname
+  \expandafter\let\expandafter\ifont   \csname #1i\endcsname
+  \expandafter\let\expandafter\syfont  \csname #1sy\endcsname
+  \expandafter\let\expandafter\ttslfont\csname #1ttsl\endcsname
+}
+
+\newif\ifrmisbold
+
+% Select smaller font size with the current style.  Used to change font size
+% in, e.g., the LaTeX logo and acronyms.  If we are using bold fonts for
+% normal roman text, also use bold fonts for roman text in the smaller size.
+\def\switchtolllsize{%
+   \expandafter\assignfonts\expandafter{\lllsize}%
+   \ifrmisbold
+     \let\rmfont\bffont
+   \fi
+   \csname\curfontstyle\endcsname
+}%
+
+\def\switchtolsize{%
+   \expandafter\assignfonts\expandafter{\lsize}%
+   \ifrmisbold
+     \let\rmfont\bffont
+   \fi
+   \csname\curfontstyle\endcsname
+}%
+
+\def\definefontsetatsize#1#2#3#4#5{%
+\expandafter\def\csname #1fonts\endcsname{%
+  \def\curfontsize{#1}%
+  \def\lsize{#2}\def\lllsize{#3}%
+  \csname rmisbold#5\endcsname
+  \assignfonts{#1}%
+  \resetmathfonts
+  \setleading{#4}%
+}}
+
+\definefontsetatsize{text}   {reduced}{smaller}{\textleading}{false}
+\definefontsetatsize{title}  {chap}   {subsec} {27pt}  {true}
+\definefontsetatsize{chap}   {sec}    {text}   {19pt}  {true}
+\definefontsetatsize{sec}    {subsec} {reduced}{17pt}  {true}
+\definefontsetatsize{ssec}   {text}   {small}  {15pt}  {true}
+\definefontsetatsize{reduced}{small}  {smaller}{10.5pt}{false}
+\definefontsetatsize{small}  {smaller}{smaller}{10.5pt}{false}
+\definefontsetatsize{smaller}{smaller}{smaller}{9.5pt} {false}
+
+\def\titlefont#1{{\titlefonts\rm #1}}
+\let\subsecfonts = \ssecfonts
+\let\subsubsecfonts = \ssecfonts
+
+% 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.
+
+\let\currentmarkupstyle\empty
+
+\def\setupmarkupstyle#1{%
+  \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}
+}
+
+\let\markupsetuplqcode \markupsetcodequoteleft
+\let\markupsetuprqcode \markupsetcodequoteright
+%
+\let\markupsetuplqexample \markupsetcodequoteleft
+\let\markupsetuprqexample \markupsetcodequoteright
+%
+\let\markupsetuplqkbd     \markupsetcodequoteleft
+\let\markupsetuprqkbd     \markupsetcodequoteright
+%
+\let\markupsetuplqsamp \markupsetcodequoteleft
+\let\markupsetuprqsamp \markupsetcodequoteright
+%
+\let\markupsetuplqverb \markupsetcodequoteleft
+\let\markupsetuprqverb \markupsetcodequoteright
+%
+\let\markupsetuplqverbatim \markupsetcodequoteleft
+\let\markupsetuprqverbatim \markupsetcodequoteright
+
+% Allow an option to not use regular directed right quote/apostrophe
+% (char 0x27), but instead 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{%
+  \ifmonospace
+    \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
+      \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+        '%
+      \else \char'15 \fi
+    \else \char'15 \fi
+   \else
+     '%
+   \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{%
+  \ifmonospace
+    \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
+   \else
+     \relax`%
+   \fi
+}
+
+% Commands to set the quote options.
+%
+\parseargdef\codequoteundirected{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}%
+  \fi\fi
+}
+%
+\parseargdef\codequotebacktick{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}%
+  \fi\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
+
+% Font commands.
+
+% #1 is the font command (\sl or \it), #2 is the text to slant.
+% If we are in a monospaced environment, however, 1) always use \ttsl,
+% and 2) do not add an italic correction.
+\def\dosmartslant#1#2{%
+  \ifusingtt
+    {{\ttsl #2}\let\next=\relax}%
+    {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+  \next
+}
+\def\smartslanted{\dosmartslant\sl}
+\def\smartitalic{\dosmartslant\it}
+
+% Output an italic correction unless \next (presumed to be the following
+% character) is such as not to need one.
+\def\smartitaliccorrection{%
+  \ifx\next,%
+  \else\ifx\next-%
+  \else\ifx\next.%
+  \else\ifx\next\.%
+  \else\ifx\next\comma%
+  \else\ptexslash
+  \fi\fi\fi\fi\fi
+  \aftersmartic
+}
+
+% Unconditional use \ttsl, and no ic.  @var is set to this for defuns.
+\def\ttslanted#1{{\ttsl #1}}
+
+% @cite is like \smartslanted except unconditionally use \sl.  We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+
+\def\aftersmartic{}
+\def\var#1{%
+  \let\saveaftersmartic = \aftersmartic
+  \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
+  \smartslanted{#1}%
+}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\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`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m
+    \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@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 \plainfrenchspacing #1}%
+  \null
+}
+
+% @samp.
+\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}}
+
+% @indicateurl is \samp, that is, with quotes.
+\let\indicateurl=\samp
+
+% @code (and similar) prints in typewriter, but with spaces the same
+% size as normal in the surrounding text, without hyphenation, etc.
+% This is a subroutine for that.
+\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
+    %
+    \plainfrenchspacing
+    #1%
+  }%
+  \null % reset spacefactor to 1000
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% (But see \codedashfinish below.)
+% 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-\normaldash
+     \let_\realunder
+    \fi
+    % Given -foo (with a single dash), we do not want to allow a break
+    % after the hyphen.
+    \global\let\codedashprev=\codedash
+    %
+    \codex
+  }
+  %
+  \gdef\codedash{\futurelet\next\codedashfinish}
+  \gdef\codedashfinish{%
+    \normaldash % always output the dash character itself.
+    %
+    % Now, output a discretionary to allow a line break, unless
+    % (a) the next character is a -, or
+    % (b) the preceding character is a -.
+    % E.g., given --posix, we do not want to allow a break after either -.
+    % Given --foo-bar, we do want to allow a break between the - and the b.
+    \ifx\next\codedash \else
+      \ifx\codedashprev\codedash
+      \else \discretionary{}{}{}\fi
+    \fi
+    % we need the space after the = for the case when \next itself is a
+    % space token; it would get swallowed otherwise.  As in @code{- a}.
+    \global\let\codedashprev= \next
+  }
+}
+\def\normaldash{-}
+%
+\def\codex #1{\tclose{#1}\endgroup}
+
+\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{}{}{}}%
+            {\_}%
+}
+
+% An additional complication: the above will allow breaks after, e.g.,
+% each of the four underscores in __typeof__.  This is bad.
+% @allowcodebreaks provides a document-level way to turn breaking at -
+% and _ on and off.
+%
+\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', must be true|false}%
+  \fi\fi
+}
+
+% For @command, @env, @file, @option quotes seem unnecessary,
+% so use \code rather than \samp.
+\let\command=\code
+\let\env=\code
+\let\file=\code
+\let\option=\code
+
+% @uref (abbreviation for `urlref') aka @url 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.
+
+% TeX-only option to allow changing PDF output to show only the second
+% arg (if given), and not the url (which is then just the link target).
+\newif\ifurefurlonlylink
+
+% The default \pretolerance setting stops the penalty inserted in
+% \urefallowbreak being a discouragement to line breaking.  Set it to
+% a negative value for this paragraph only.  Hopefully this does not
+% conflict with redefinitions of \par done elsewhere.
+\def\nopretolerance{%
+\pretolerance=-1
+\def\par{\endgraf\pretolerance=100 \let\par\endgraf}%
+}
+
+% The main macro is \urefbreak, which allows breaking at expected
+% places within the url.
+\def\urefbreak{\nopretolerance \begingroup \urefcatcodes \dourefbreak}
+\let\uref=\urefbreak
+%
+\def\dourefbreak#1{\urefbreakfinish #1,,,\finish}
+\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example
+  \unsepspaces
+  \pdfurl{#1}%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}% look for second arg
+    \ifdim\wd0 > 0pt
+      \ifpdf
+        % For pdfTeX and LuaTeX
+        \ifurefurlonlylink
+          % PDF plus option to not display url, show just arg
+          \unhbox0
+        \else
+          % PDF, normally display both arg and url for consistency,
+          % visibility, if the pdf is eventually used to print, etc.
+          \unhbox0\ (\urefcode{#1})%
+        \fi
+      \else
+        \ifx\XeTeXrevision\thisisundefined
+          \unhbox0\ (\urefcode{#1})% DVI, always show arg and url
+        \else
+          % For XeTeX
+          \ifurefurlonlylink
+            % PDF plus option to not display url, show just arg
+            \unhbox0
+          \else
+            % PDF, normally display both arg and url for consistency,
+            % visibility, if the pdf is eventually used to print, etc.
+            \unhbox0\ (\urefcode{#1})%
+          \fi
+        \fi
+      \fi
+    \else
+      \urefcode{#1}% only url given, so show it
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% Allow line breaks around only a few characters (only).
+\def\urefcatcodes{%
+  \catcode`\&=\active \catcode`\.=\active
+  \catcode`\#=\active \catcode`\?=\active
+  \catcode`\/=\active
+}
+{
+  \urefcatcodes
+  %
+  \global\def\urefcode{\begingroup
+    \setupmarkupstyle{code}%
+    \urefcatcodes
+    \let&\urefcodeamp
+    \let.\urefcodedot
+    \let#\urefcodehash
+    \let?\urefcodequest
+    \let/\urefcodeslash
+    \codex
+  }
+  %
+  % By default, they are just regular characters.
+  \global\def&{\normalamp}
+  \global\def.{\normaldot}
+  \global\def#{\normalhash}
+  \global\def?{\normalquest}
+  \global\def/{\normalslash}
+}
+
+\def\urefcodeamp{\urefprebreak \&\urefpostbreak}
+\def\urefcodedot{\urefprebreak .\urefpostbreak}
+\def\urefcodehash{\urefprebreak \#\urefpostbreak}
+\def\urefcodequest{\urefprebreak ?\urefpostbreak}
+\def\urefcodeslash{\futurelet\next\urefcodeslashfinish}
+{
+  \catcode`\/=\active
+  \global\def\urefcodeslashfinish{%
+    \urefprebreak \slashChar
+    % Allow line break only after the final / in a sequence of
+    % slashes, to avoid line break between the slashes in http://.
+    \ifx\next/\else \urefpostbreak \fi
+  }
+}
+
+% By default we'll break after the special characters, but some people like to
+% break before the special chars, so allow that.  Also allow no breaking at
+% all, for manual control.
+%
+\parseargdef\urefbreakstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\wordnone
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordbefore
+    \def\urefprebreak{\urefallowbreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordafter
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\urefallowbreak}
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @urefbreakstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\wordafter{after}
+\def\wordbefore{before}
+\def\wordnone{none}
+
+% Allow a ragged right output to aid breaking long URL's.  There can
+% be a break at the \allowbreak with no extra glue (if the existing stretch in
+% the line is sufficient), a break at the \penalty with extra glue added
+% at the end of the line, or no break at all here.
+%   Changing the value of the penalty and/or the amount of stretch affects how
+% preferable one choice is over the other.
+\def\urefallowbreak{%
+  \penalty0\relax
+  \hskip 0pt plus 2 em\relax
+  \penalty1000\relax
+  \hskip 0pt plus -2 em\relax
+}
+
+\urefbreakstyle after
+
+% @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}
+\ifpdforxetex
+  \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
+
+% @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 setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}}
+
+\def\xkey{\key}
+\def\kbdsub#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
+}
+
+% 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}
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow   (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% 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}
+
+% @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{%
+  {\switchtolsize #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @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
+  \null % reset \spacefactor=1000
+}
+
+% @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 math (or tt) \.
+% FYI, plain.tex uses \\ as a temporary control sequence (for no
+% particular reason), but this is not advertised and we don't care.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+  \ifmmode\else % only go into math if not in math mode already
+    \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
+    % have to provide another name for sup operator
+    \let\mathopsup=\sup
+  $\expandafter\finishmath\fi
+}
+\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
+  }
+}
+
+% for @sub and @sup, if in math mode, just do a normal sub/superscript.
+% If in text, use math to place as sub/superscript, but switch
+% into text mode, with smaller fonts.  This is a different font than the
+% one used for real math sub/superscripts (8pt vs. 7pt), but let's not
+% fix it (significant additions to font machinery) until someone notices.
+%
+\def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi}
+\def\finishsub#1{$\sb{\hbox{\switchtolllsize #1}}$}%
+%
+\def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi}
+\def\finishsup#1{$\ptexsp{\hbox{\switchtolllsize #1}}$}%
+
+% provide this command from LaTeX as it is very common
+\def\frac#1#2{{{#1}\over{#2}}}
+
+% @displaymath.
+% \globaldefs is needed to recognize the end lines in \tex and
+% \end tex.  Set \thisenv as @end displaymath is seen before @end tex.
+{\obeylines
+\globaldefs=1
+\envdef\displaymath{%
+\tex
+\def\thisenv{\displaymath}%
+$$%
+}
+
+\def\Edisplaymath{$$
+\def\thisenv{\tex}%
+\end tex
+}}
+
+% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
+% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
+% except specified as a normal braced arg, so no newlines to worry about.
+%
+\def\outfmtnametex{tex}
+%
+\long\def\inlinefmt#1{\doinlinefmt #1,\finish}
+\long\def\doinlinefmt#1,#2,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi
+}
+%
+% @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if
+% FMTNAME is tex, else ELSE-TEXT.
+\long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish}
+\long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi
+}
+%
+% For raw, must switch into @tex before parsing the argument, to avoid
+% setting catcodes prematurely.  Doing it this way means that, for
+% example, @inlineraw{html, foo{bar} gets a parse error instead of being
+% ignored.  But this isn't important because if people want a literal
+% *right* brace they would have to use a command anyway, so they may as
+% well use a command to get a left brace too.  We could re-use the
+% delimiter character idea from \verb, but it seems like overkill.
+%
+\long\def\inlineraw{\tex \doinlineraw}
+\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish}
+\def\doinlinerawtwo#1,#2,\finish{%
+  \def\inlinerawname{#1}%
+  \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi
+  \endgroup % close group opened by \tex.
+}
+
+% @inlineifset{VAR, TEXT} expands TEXT if VAR is @set.
+%
+\long\def\inlineifset#1{\doinlineifset #1,\finish}
+\long\def\doinlineifset#1,#2,\finish{%
+  \def\inlinevarname{#1}%
+  \expandafter\ifx\csname SET\inlinevarname\endcsname\relax
+  \else\ignorespaces#2\fi
+}
+
+% @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set.
+%
+\long\def\inlineifclear#1{\doinlineifclear #1,\finish}
+\long\def\doinlineifclear#1,#2,\finish{%
+  \def\inlinevarname{#1}%
+  \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi
+}
+
+
+\message{glyphs,}
+% and logos.
+
+% @@ prints an @, as does @atchar{}.
+\def\@{\char64 }
+\let\atchar=\@
+
+% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
+\def\lbracechar{{\ifmonospace\char123\else\ensuremath\lbrace\fi}}
+\def\rbracechar{{\ifmonospace\char125\else\ensuremath\rbrace\fi}}
+\let\{=\lbracechar
+\let\}=\rbracechar
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \ptexc
+\let\dotaccent = \ptexdot
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \ptext
+\let\ubaraccent = \ptexb
+\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{\switchtolllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\switchtolllsize \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{%
+     \ifx\textnominalsize\xwordpt
+       % for 10pt running text, lllsize (8pt) is too small for the A in LaTeX.
+       % Revert to plain's \scriptsize, which is 7pt.
+       \count255=\the\fam $\fam\count255 \scriptstyle A$%
+     \else
+       % For 11pt, we can use our lllsize.
+       \switchtolllsize A%
+     \fi
+     }%
+     \vss
+  }}%
+  \kern-.15em
+  \TeX
+}
+
+% Some math mode symbols.  Define \ensuremath to switch into math mode
+% unless we are already there.  Expansion tricks may not be needed here,
+% but safer, and can't hurt.
+\def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi}
+\def\ensuredmath#1{$\relax#1$}
+%
+\def\bullet{\ensuremath\ptexbullet}
+\def\geq{\ensuremath\ge}
+\def\leq{\ensuremath\le}
+\def\minus{\ensuremath-}
+
+% @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
+}
+
+% @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
+%
+{\ttfont \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 \putworderror\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{\ifmonospace{\ecfont\char"BF}\else{\it\$}\fi}
+
+% @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 European Computer Modern fonts (cm-super in outline format)
+% for non-CM glyphs.  That is ec* for regular text and tc* for the text
+% companion symbols (LaTeX TS1 encoding).  Both are part of the ec
+% package and follow the same conventions.
+%
+\def\ecfont{\etcfont{e}}
+\def\tcfont{\etcfont{t}}
+%
+\def\etcfont#1{%
+  % 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}%
+  \ifmonospace
+    % typewriter:
+    \font\thisecfont = #1ctt\ecsize \space at \nominalsize
+  \else
+    \ifx\curfontstyle\bfstylename
+      % bold:
+      \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize
+    \else
+      % regular:
+      \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize
+    \fi
+  \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{\switchtolllsize 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\thisisundefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+% Quotes.
+\chardef\quoteleft=`\`
+\chardef\quoteright=`\'
+
+% only change font for tt for correct kerning and to avoid using
+% \ecfont unless necessary.
+\def\quotedblleft{%
+  \ifmonospace{\ecfont\char"10}\else{\char"5C}\fi
+}
+
+\def\quotedblright{%
+  \ifmonospace{\ecfont\char"11}\else{\char`\"}\fi
+}
+
+
+\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
+
+% @setcontentsaftertitlepage used to do an implicit @contents or
+% @shortcontents after @end titlepage, but it is now obsolete.
+\def\setcontentsaftertitlepage{%
+  \errmessage{@setcontentsaftertitlepage has been removed as a Texinfo
+              command; move your @contents command if you want the contents
+              after the title page.}}%
+\def\setshortcontentsaftertitlepage{%
+  \errmessage{@setshortcontentsaftertitlepage has been removed as a Texinfo
+              command; move your @shortcontents and @contents commands if you
+              want the contents after the title page.}}%
+
+\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
+}
+
+\def\finishtitlepage{%
+  \vskip4pt \hrule height 2pt width \hsize
+  \vskip\titlepagebottomglue
+  \finishedtitlepagetrue
+}
+
+% Settings used for typesetting titles: no hyphenation, no indentation,
+% don't worry much about spacing, ragged right.  This should be used
+% inside a \vbox, and fonts need to be set appropriately first. \par should
+% be specified before the end of the \vbox, since a vbox is a group.
+%
+\def\raggedtitlesettings{%
+  \rm
+  \hyphenpenalty=10000
+  \parindent=0pt
+  \tolerance=5000
+  \ptexraggedright
+}
+
+% Macros to be used within @titlepage:
+
+\let\subtitlerm=\rmfont
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+  \checkenv\titlepage
+  \vbox{\titlefonts \raggedtitlesettings #1\par}%
+  % 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\rm \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\evenchapheadline% headline on even pages with a new chapter
+\newtoks\oddchapheadline % headline on odd pages with a new chapter
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make \makeheadline and \makefootline in Plain TeX use those variables
+\headline={{\textfonts\rm
+            \ifchapterpage
+              \ifodd\pageno\the\oddchapheadline\else\the\evenchapheadline\fi
+            \else
+              \ifodd\pageno\the\oddheadline\else\the\evenheadline\fi
+            \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}}
+  \global\evenchapheadline=\evenheadline}
+
+\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}}%
+  \global\oddchapheadline=\oddheadline}
+
+\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\txipageheight 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
+
+% These define \getoddheadingmarks, \getevenheadingmarks,
+% \getoddfootingmarks, and \getevenfootingmarks, each to one of
+% \gettopheadingmarks, \getbottomheadingmarks.
+%
+\def\evenheadingmarks{\headingmarks{even}{heading}}
+\def\oddheadingmarks{\headingmarks{odd}{heading}}
+\def\evenfootingmarks{\headingmarks{even}{footing}}
+\def\oddfootingmarks{\headingmarks{odd}{footing}}
+\parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1}
+                          \headingmarks{odd}{heading}{#1} }
+\parseargdef\everyfootingmarks{\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.
+
+\parseargdef\headings{\csname HEADINGS#1\endcsname}
+
+\def\headingsoff{% non-global headings elimination
+  \evenheadline={\hfil}\evenfootline={\hfil}\evenchapheadline={\hfil}%
+   \oddheadline={\hfil}\oddfootline={\hfil}\oddchapheadline={\hfil}%
+}
+
+\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting
+\HEADINGSoff  % it's the default
+
+% When we turn headings on, set the page number to 1.
+\def\pageone{
+  \global\pageno=1
+  \global\arabiccount = \pagecount
+}
+
+% 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{%
+\pageone
+\HEADINGSdoublex
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\pageone
+\HEADINGSsinglex
+}
+\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\evenchapheadline={\line{\folio\hfil}}
+\global\oddchapheadline={\line{\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\evenchapheadline={\line{\hfil\folio}}
+\global\oddchapheadline={\line{\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% for @setchapternewpage off
+\def\HEADINGSsinglechapoff{%
+\pageone
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\evenchapheadline=\evenheadline
+\global\oddchapheadline=\oddheadline
+\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\thisisundefined
+\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\relax
+      \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 so 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}%
+   %
+   \ifinner\else
+     \vadjust{\penalty 1200}% not good to break after first line of item.
+   \fi
+   % We can be in inner vertical mode in a footnote, although an
+   % @itemize looks awful there.
+  }%
+  \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 <number>.
+    %
+    \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 below 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
+  \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings
+  \global\everytab={\bf}% can't use \headitemfont since the parsing differs
+  \the\everytab % for the first item
+}%
+%
+% default for tables with no headings.
+\let\headitemcrhook=\relax
+%
+% 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={}% Reset from possible headitem.
+      \global\colcount=0 % Reset the column counter.
+      %
+      % Check for saved footnotes, etc.:
+      \checkinserts
+      %
+      % Perhaps a \nobreak, then reset:
+      \headitemcrhook
+      \global\let\headitemcrhook=\relax
+    }%
+  }%
+  %
+  \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-\normaldash \let_\normalunderscore
+  }
+}
+
+\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
+}
+
+% Like \expandablevalue, but completely expandable (the \message in the
+% definition above operates at the execution level of TeX).  Used when
+% writing to auxiliary files, due to the expansion that \write does.
+% If flag is undefined, pass through an unexpanded @value command: maybe it
+% will be set by the time it is read back in.
+%
+% NB flag names containing - or _ may not work here.
+\def\dummyvalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \string\value{#1}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% Used for @value's in index entries to form the sort key: expand the @value
+% if possible, otherwise sort late.
+\def\indexnofontsvalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    ZZZZZZZ%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get the special treatment we need for `@end ifset,' we call
+% \makecond and then 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 executes 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}}
+
+% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written
+% without the @) is in fact defined.  We can only feasibly check at the
+% TeX level, so something like `mathcode' is going to considered
+% defined even though it is not a Texinfo command.
+%
+\makecond{ifcommanddefined}
+\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}}
+%
+\def\doifcmddefined#1#2{{%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname #2\endcsname\relax
+      #1% If not defined, \let\next as above.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifcmddefinedfail{\doignore{ifcommanddefined}}
+
+% @ifcommandnotdefined CMD ... handled similar to @ifclear above.
+\makecond{ifcommandnotdefined}
+\def\ifcommandnotdefined{%
+  \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}}
+\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}}
+
+% Set the `txicommandconditionals' variable, so documents have a way to
+% test if the @ifcommand...defined conditionals are available.
+\set txicommandconditionals
+
+% @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 IX.
+% It automatically defines \IXindex such that
+% \IXindex ...rest of line... puts an entry in the index IX.
+% It also defines \IXindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is IX.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \expandafter\chardef\csname#1indfile\endcsname=0
+  \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{%
+  \expandafter\chardef\csname#1indfile\endcsname=0
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}%
+}
+
+% The default indices:
+\newindex{cp}%      concepts,
+\newcodeindex{fn}%  functions,
+\newcodeindex{vr}%  variables,
+\newcodeindex{tp}%  types,
+\newcodeindex{ky}%  keys
+\newcodeindex{pg}%  and programs.
+
+
+% @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{%
+  \requireopenindexfile{#3}%
+  % 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 index macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is the two-letter name of the index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx}
+\def\doindexxxx #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx}
+\def\docodeindexxxx #1{\docind{\indexname}{#1}}
+
+
+% Used for the aux, toc and index files to prevent expansion of Texinfo
+% commands.
+%
+\def\atdummies{%
+  \definedummyletter\@%
+  \definedummyletter\ %
+  \definedummyletter\{%
+  \definedummyletter\}%
+  \definedummyletter\&%
+  %
+  % Do the redefinitions.
+  \definedummies
+  \otherbackslash
+}
+
+% \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.
+%
+% 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).
+%
+% For control letters, we have \definedummyletter, which omits the
+% space.
+%
+\def\definedummyword  #1{\def#1{\string#1\space}}%
+\def\definedummyletter#1{\def#1{\string#1}}%
+\let\definedummyaccent\definedummyletter
+
+% Called from \atdummies to prevent the expansion of commands.
+%
+\def\definedummies{%
+  %
+  \let\commondummyword\definedummyword
+  \let\commondummyletter\definedummyletter
+  \let\commondummyaccent\definedummyaccent
+  \commondummiesnofonts
+  %
+  \definedummyletter\_%
+  \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\ampchar
+  \definedummyword\atchar
+  \definedummyword\arrow
+  \definedummyword\backslashchar
+  \definedummyword\bullet
+  \definedummyword\comma
+  \definedummyword\copyright
+  \definedummyword\registeredsymbol
+  \definedummyword\dots
+  \definedummyword\enddots
+  \definedummyword\entrybreak
+  \definedummyword\equiv
+  \definedummyword\error
+  \definedummyword\euro
+  \definedummyword\expansion
+  \definedummyword\geq
+  \definedummyword\guillemetleft
+  \definedummyword\guillemetright
+  \definedummyword\guilsinglleft
+  \definedummyword\guilsinglright
+  \definedummyword\lbracechar
+  \definedummyword\leq
+  \definedummyword\mathopsup
+  \definedummyword\minus
+  \definedummyword\ogonek
+  \definedummyword\pounds
+  \definedummyword\point
+  \definedummyword\print
+  \definedummyword\quotedblbase
+  \definedummyword\quotedblleft
+  \definedummyword\quotedblright
+  \definedummyword\quoteleft
+  \definedummyword\quoteright
+  \definedummyword\quotesinglbase
+  \definedummyword\rbracechar
+  \definedummyword\result
+  \definedummyword\sub
+  \definedummyword\sup
+  \definedummyword\textdegree
+  %
+  \definedummyword\subentry
+  %
+  % We want to disable all macros so that they are not expanded by \write.
+  \macrolist
+  \let\value\dummyvalue
+  %
+  \normalturnoffactive
+}
+
+% \commondummiesnofonts: common to \definedummies and \indexnofonts.
+% Define \commondummyletter, \commondummyaccent and \commondummyword before
+% using.  Used for accents, font commands, and various control letters.
+%
+\def\commondummiesnofonts{%
+  % Control letters and accents.
+  \commondummyletter\!%
+  \commondummyaccent\"%
+  \commondummyaccent\'%
+  \commondummyletter\*%
+  \commondummyaccent\,%
+  \commondummyletter\.%
+  \commondummyletter\/%
+  \commondummyletter\:%
+  \commondummyaccent\=%
+  \commondummyletter\?%
+  \commondummyaccent\^%
+  \commondummyaccent\`%
+  \commondummyaccent\~%
+  \commondummyword\u
+  \commondummyword\v
+  \commondummyword\H
+  \commondummyword\dotaccent
+  \commondummyword\ogonek
+  \commondummyword\ringaccent
+  \commondummyword\tieaccent
+  \commondummyword\ubaraccent
+  \commondummyword\udotaccent
+  \commondummyword\dotless
+  %
+  % Texinfo font commands.
+  \commondummyword\b
+  \commondummyword\i
+  \commondummyword\r
+  \commondummyword\sansserif
+  \commondummyword\sc
+  \commondummyword\slanted
+  \commondummyword\t
+  %
+  % Commands that take arguments.
+  \commondummyword\abbr
+  \commondummyword\acronym
+  \commondummyword\anchor
+  \commondummyword\cite
+  \commondummyword\code
+  \commondummyword\command
+  \commondummyword\dfn
+  \commondummyword\dmn
+  \commondummyword\email
+  \commondummyword\emph
+  \commondummyword\env
+  \commondummyword\file
+  \commondummyword\image
+  \commondummyword\indicateurl
+  \commondummyword\inforef
+  \commondummyword\kbd
+  \commondummyword\key
+  \commondummyword\math
+  \commondummyword\option
+  \commondummyword\pxref
+  \commondummyword\ref
+  \commondummyword\samp
+  \commondummyword\strong
+  \commondummyword\tie
+  \commondummyword\U
+  \commondummyword\uref
+  \commondummyword\url
+  \commondummyword\var
+  \commondummyword\verb
+  \commondummyword\w
+  \commondummyword\xref
+}
+
+\let\indexlbrace\relax
+\let\indexrbrace\relax
+\let\indexatchar\relax
+\let\indexbackslash\relax
+
+{\catcode`\@=0
+\catcode`\\=13
+  @gdef@backslashdisappear{@def\{}}
+}
+
+{
+\catcode`\<=13
+\catcode`\-=13
+\catcode`\`=13
+  \gdef\indexnonalnumdisappear{%
+    \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else
+      % @set txiindexlquoteignore makes us ignore left quotes in the sort term.
+      % (Introduced for FSFS 2nd ed.)
+      \let`=\empty
+    \fi
+    %
+    \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else
+      \backslashdisappear
+    \fi
+    %
+    \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else
+      \def-{}%
+    \fi
+    \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else
+      \def<{}%
+    \fi
+    \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else
+      \def\@{}%
+    \fi
+  }
+
+  \gdef\indexnonalnumreappear{%
+    \let-\normaldash
+    \let<\normalless
+  }
+}
+
+
+% \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\commondummyaccent##1{\let##1\asis}%
+  % We can just ignore other control letters.
+  \def\commondummyletter##1{\let##1\empty}%
+  % All control words become @asis by default; overrides below.
+  \let\commondummyword\commondummyaccent
+  \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\@{@}%
+  \def\_{\normalunderscore}%
+  \def\-{}% @- shouldn't affect sorting
+  %
+  \uccode`\1=`\{ \uppercase{\def\{{1}}%
+  \uccode`\1=`\} \uppercase{\def\}{1}}%
+  \let\lbracechar\{%
+  \let\rbracechar\}%
+  %
+  %
+  \let\do\indexnofontsdef
+  %
+  % Non-English letters.
+  \do\AA{AA}%
+  \do\AE{AE}%
+  \do\DH{DZZ}%
+  \do\L{L}%
+  \do\OE{OE}%
+  \do\O{O}%
+  \do\TH{TH}%
+  \do\aa{aa}%
+  \do\ae{ae}%
+  \do\dh{dzz}%
+  \do\exclamdown{!}%
+  \do\l{l}%
+  \do\oe{oe}%
+  \do\ordf{a}%
+  \do\ordm{o}%
+  \do\o{o}%
+  \do\questiondown{?}%
+  \do\ss{ss}%
+  \do\th{th}%
+  %
+  \do\LaTeX{LaTeX}%
+  \do\TeX{TeX}%
+  %
+  % Assorted special characters.
+  \do\atchar{@}%
+  \do\arrow{->}%
+  \do\bullet{bullet}%
+  \do\comma{,}%
+  \do\copyright{copyright}%
+  \do\dots{...}%
+  \do\enddots{...}%
+  \do\equiv{==}%
+  \do\error{error}%
+  \do\euro{euro}%
+  \do\expansion{==>}%
+  \do\geq{>=}%
+  \do\guillemetleft{<<}%
+  \do\guillemetright{>>}%
+  \do\guilsinglleft{<}%
+  \do\guilsinglright{>}%
+  \do\leq{<=}%
+  \do\lbracechar{\{}%
+  \do\minus{-}%
+  \do\point{.}%
+  \do\pounds{pounds}%
+  \do\print{-|}%
+  \do\quotedblbase{"}%
+  \do\quotedblleft{"}%
+  \do\quotedblright{"}%
+  \do\quoteleft{`}%
+  \do\quoteright{'}%
+  \do\quotesinglbase{,}%
+  \do\rbracechar{\}}%
+  \do\registeredsymbol{R}%
+  \do\result{=>}%
+  \do\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\value\indexnofontsvalue
+}
+
+% Give the control sequence a definition that removes the {} that follows
+% its use, e.g. @AA{} -> AA
+\def\indexnofontsdef#1#2{\def#1##1{#2}}%
+
+
+
+
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{%
+  \iflinks
+  {%
+    %
+    \requireopenindexfile{#1}%
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \def\indextext{#2}%
+    \safewhatsit\doindwrite
+  }%
+  \fi
+}
+
+% Same as \doind, but for code indices
+\def\docind#1#2{%
+  \iflinks
+  {%
+    %
+    \requireopenindexfile{#1}%
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \def\indextext{#2}%
+    \safewhatsit\docindwrite
+  }%
+  \fi
+}
+
+% Check if an index file has been opened, and if not, open it.
+\def\requireopenindexfile#1{%
+\ifnum\csname #1indfile\endcsname=0
+  \expandafter\newwrite \csname#1indfile\endcsname
+  \edef\suffix{#1}%
+  % A .fls suffix would conflict with the file extension for the output
+  % of -recorder, so use .f1s instead.
+  \ifx\suffix\indexisfl\def\suffix{f1}\fi
+  % Open the file
+  \immediate\openout\csname#1indfile\endcsname \jobname.\suffix
+  % Using \immediate above here prevents an object entering into the current
+  % box, which could confound checks such as those in \safewhatsit for
+  % preceding skips.
+  \typeout{Writing index file \jobname.\suffix}%
+\fi}
+\def\indexisfl{fl}
+
+% Definition for writing index entry sort key.
+{
+\catcode`\-=13
+\gdef\indexwritesortas{%
+  \begingroup
+  \indexnonalnumreappear
+  \indexwritesortasxxx}
+\gdef\indexwritesortasxxx#1{%
+  \xdef\indexsortkey{#1}\endgroup}
+}
+
+\def\indexwriteseealso#1{
+  \gdef\pagenumbertext{\string\seealso{#1}}%
+}
+\def\indexwriteseeentry#1{
+  \gdef\pagenumbertext{\string\seeentry{#1}}%
+}
+
+% The default definitions
+\def\sortas#1{}%
+\def\seealso#1{\i{\putwordSeeAlso}\ #1}% for sorted index file only
+\def\putwordSeeAlso{See also}
+\def\seeentry#1{\i{\putwordSee}\ #1}% for sorted index file only
+
+
+% Given index entry text like "aaa @subentry bbb @sortas{ZZZ}":
+%   * Set \bracedtext to "{aaa}{bbb}"
+%   * Set \fullindexsortkey to "aaa @subentry ZZZ"
+%   * If @seealso occurs, set \pagenumbertext
+%
+\def\splitindexentry#1{%
+  \gdef\fullindexsortkey{}%
+  \xdef\bracedtext{}%
+  \def\sep{}%
+  \def\seealso##1{}%
+  \def\seeentry##1{}%
+  \expandafter\doindexsegment#1\subentry\finish\subentry
+}
+
+% append the results from the next segment
+\def\doindexsegment#1\subentry{%
+  \def\segment{#1}%
+  \ifx\segment\isfinish
+  \else
+    %
+    % Fully expand the segment, throwing away any @sortas directives, and
+    % trim spaces.
+    \edef\trimmed{\segment}%
+    \edef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}%
+    \ifincodeindex
+      \edef\trimmed{\noexpand\code{\trimmed}}%
+    \fi
+    %
+    \xdef\bracedtext{\bracedtext{\trimmed}}%
+    %
+    % Get the string to sort by.  Process the segment with all
+    % font commands turned off.
+    \bgroup
+      \let\sortas\indexwritesortas
+      \let\seealso\indexwriteseealso
+      \let\seeentry\indexwriteseeentry
+      \indexnofonts
+      % The braces around the commands are recognized by texindex.
+      \def\lbracechar{{\string\indexlbrace}}%
+      \def\rbracechar{{\string\indexrbrace}}%
+      \let\{=\lbracechar
+      \let\}=\rbracechar
+      \def\@{{\string\indexatchar}}%
+      \def\atchar##1{\@}%
+      \def\backslashchar{{\string\indexbackslash}}%
+      \uccode`\~=`\\ \uppercase{\let~\backslashchar}%
+      %
+      \let\indexsortkey\empty
+      \global\let\pagenumbertext\empty
+      % Execute the segment and throw away the typeset output.  This executes
+      % any @sortas or @seealso commands in this segment.
+      \setbox\dummybox = \hbox{\segment}%
+      \ifx\indexsortkey\empty{%
+        \indexnonalnumdisappear
+        \xdef\trimmed{\segment}%
+        \xdef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}%
+        \xdef\indexsortkey{\trimmed}%
+        \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi
+      }\fi
+      %
+      % Append to \fullindexsortkey.
+      \edef\tmp{\gdef\noexpand\fullindexsortkey{%
+                  \fullindexsortkey\sep\indexsortkey}}%
+      \tmp
+    \egroup
+    \def\sep{\subentry}%
+    %
+    \expandafter\doindexsegment
+  \fi
+}
+\def\isfinish{\finish}%
+\newbox\dummybox % used above
+
+\let\subentry\relax
+
+% Use \ instead of @ in index files.  To support old texi2dvi and texindex.
+% This works without changing the escape character used in the toc or aux
+% files because the index entries are fully expanded here, and \string uses
+% the current value of \escapechar.
+\def\escapeisbackslash{\escapechar=`\\}
+
+% Use \ in index files by default.  texi2dvi didn't support @ as the escape
+% character (as it checked for "\entry" in the files, and not "@entry").  When
+% the new version of texi2dvi has had a chance to become more prevalent, then
+% the escape character can change back to @ again.  This should be an easy
+% change to make now because both @ and \ are only used as escape characters in
+% index files, never standing for themselves.
+%
+\set txiindexescapeisbackslash
+
+% Write the entry in \indextext to the index file.
+%
+
+\newif\ifincodeindex
+\def\doindwrite{\incodeindexfalse\doindwritex}
+\def\docindwrite{\incodeindextrue\doindwritex}
+
+\def\doindwritex{%
+  \maybemarginindex
+  %
+  \atdummies
+  %
+  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax\else
+    \escapeisbackslash
+  \fi
+  %
+  % For texindex which always views { and } as separators.
+  \def\{{\lbracechar{}}%
+  \def\}{\rbracechar{}}%
+  \uccode`\~=`\\ \uppercase{\def~{\backslashchar{}}}%
+  %
+  % Split the entry into primary entry and any subentries, and get the index
+  % sort key.
+  \splitindexentry\indextext
+  %
+  % 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{\fullindexsortkey}%
+        {\ifx\pagenumbertext\empty\noexpand\folio\else\pagenumbertext\fi}%
+        \bracedtext}%
+  }%
+  \temp
+}
+
+% Put the index entry in the margin if desired (undocumented).
+\def\maybemarginindex{%
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \relax\indextext}}%
+  \fi
+}
+\let\SETmarginindex=\relax
+
+
+% 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}
+%  \entry {topic}{}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+%  \secondary {subtopic}{}
+%     for a subtopic with sub-subtopics
+%  \tertiary {subtopic}{subsubtopic}{pagelist}
+%     for each sub-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}
+
+% 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 comment in \requireopenindexfile.
+  \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi
+  %
+  % See if the index file exists and is nonempty.
+  \openin 1 \jobname.\indexname s
+  \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
+    \typeout{No file \jobname.\indexname s.}%
+  \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 \thisline
+    \ifeof 1
+      \putwordIndexIsEmpty
+    \else
+      \expandafter\printindexzz\thisline\relax\relax\finish%
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% If the index file starts with a backslash, forgo reading the index
+% file altogether.  If somebody upgrades texinfo.tex they may still have
+% old index files using \ as the escape character.  Reading this would
+% at best lead to typesetting garbage, at worst a TeX syntax error.
+\def\printindexzz#1#2\finish{%
+  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax
+    \uccode`\~=`\\ \uppercase{\if\noexpand~}\noexpand#1
+      \expandafter\ifx\csname SETtxiskipindexfileswithbackslash\endcsname\relax
+\errmessage{%
+ERROR: A sorted index file in an obsolete format was skipped.
+To fix this problem, please upgrade your version of 'texi2dvi'
+or 'texi2pdf' to that at <https://ftp.gnu.org/gnu/texinfo>.
+If you are using an old version of 'texindex' (part of the Texinfo
+distribution), you may also need to upgrade to a newer version (at least 6.0).
+You may be able to typeset the index if you run
+'texindex \jobname.\indexname' yourself.
+You could also try setting the 'txiindexescapeisbackslash' flag by
+running a command like
+'texi2dvi -t "@set txiindexescapeisbackslash" \jobname.texi'.  If you do
+this, Texinfo will try to use index files in the old format.
+If you continue to have problems, deleting the index files and starting again
+might help (with 'rm \jobname.?? \jobname.??s')%
+}%
+      \else
+        (Skipped sorted index file in obsolete format)
+      \fi
+    \else
+      \begindoublecolumns
+      \input \jobname.\indexname s
+      \enddoublecolumns
+    \fi
+  \else
+    \begindoublecolumns
+    \catcode`\\=0\relax
+    %
+    % Make @ an escape character to give macros a chance to work.  This
+    % should work because we (hopefully) don't otherwise use @ in index files.
+    %\catcode`\@=12\relax
+    \catcode`\@=0\relax
+    \input \jobname.\indexname s
+    \enddoublecolumns
+  \fi
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+{\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13
+\catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13
+\catcode`\$=3
+\gdef\initialglyphs{%
+  % special control sequences used in the index sort key
+  \let\indexlbrace\{%
+  \let\indexrbrace\}%
+  \let\indexatchar\@%
+  \def\indexbackslash{\math{\backslash}}%
+  %
+  % Some changes for non-alphabetic characters.  Using the glyphs from the
+  % math fonts looks more consistent than the typewriter font used elsewhere
+  % for these characters.
+  \uccode`\~=`\\ \uppercase{\def~{\math{\backslash}}}
+  %
+  % In case @\ is used for backslash
+  \uppercase{\let\\=~}
+  % Can't get bold backslash so don't use bold forward slash
+  \catcode`\/=13
+  \def/{{\secrmnotbold \normalslash}}%
+  \def-{{\normaldash\normaldash}}% en dash `--'
+  \def^{{\chapbf \normalcaret}}%
+  \def~{{\chapbf \normaltilde}}%
+  \def\_{%
+     \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }%
+  \def|{$\vert$}%
+  \def<{$\less$}%
+  \def>{$\gtr$}%
+  \def+{$\normalplus$}%
+}}
+
+\def\initial{%
+  \bgroup
+  \initialglyphs
+  \initialx
+}
+
+\def\initialx#1{%
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  %
+  % We like breaks before the index initials, so insert a bonus.
+  % The glue before the bonus allows a little bit of space at the
+  % bottom of a column to reduce an increase in inter-line spacing.
+  \nobreak
+  \vskip 0pt plus 5\baselineskip
+  \penalty -300
+  \vskip 0pt plus -5\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 1\baselineskip
+  \leftline{\secfonts \kern-0.05em \secbf #1}%
+  % \secfonts is inside the argument of \leftline so that the change of
+  % \baselineskip will not affect any glue inserted before the vbox that
+  % \leftline creates.
+  % Do our best not to break after the initial.
+  \nobreak
+  \vskip .33\baselineskip plus .1\baselineskip
+  \egroup % \initialglyphs
+}
+
+\newdimen\entryrightmargin
+\entryrightmargin=0pt
+
+% \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.
+%
+\def\entry{%
+  \begingroup
+    %
+    % Start a new paragraph if necessary, so our assignments below can't
+    % affect previous text.
+    \par
+    %
+    % No extra space above this paragraph.
+    \parskip = 0in
+    %
+    % When reading the text of entry, convert explicit line breaks
+    % from @* into spaces.  The user might give these in long section
+    % titles, for instance.
+    \def\*{\unskip\space\ignorespaces}%
+    \def\entrybreak{\hfil\break}% An undocumented command
+    %
+    % Swallow the left brace of the text (first parameter):
+    \afterassignment\doentry
+    \let\temp =
+}
+\def\entrybreak{\unskip\space\ignorespaces}%
+\def\doentry{%
+    % Save the text of the entry
+    \global\setbox\boxA=\hbox\bgroup
+    \bgroup % Instead of the swallowed brace.
+      \noindent
+      \aftergroup\finishentry
+      % And now comes the text of the entry.
+      % Not absorbing as a macro argument reduces the chance of problems
+      % with catcodes occurring.
+}
+{\catcode`\@=11
+\gdef\finishentry#1{%
+    \egroup % end box A
+    \dimen@ = \wd\boxA % Length of text of entry
+    \global\setbox\boxA=\hbox\bgroup
+      \unhbox\boxA
+      % #1 is the page number.
+      %
+      % Get the width of the page numbers, and only use
+      % leaders if they are present.
+      \global\setbox\boxB = \hbox{#1}%
+      \ifdim\wd\boxB = 0pt
+        \null\nobreak\hfill\ %
+      \else
+        %
+        \null\nobreak\indexdotfill % Have leaders before the page number.
+        %
+        \ifpdforxetex
+          \pdfgettoks#1.%
+          \hskip\skip\thinshrinkable\the\toksA
+        \else
+          \hskip\skip\thinshrinkable #1%
+        \fi
+      \fi
+    \egroup % end \boxA
+    \ifdim\wd\boxB = 0pt
+      \noindent\unhbox\boxA\par
+      \nobreak
+    \else\bgroup
+      % We want the text of the entries to be aligned to the left, and the
+      % page numbers to be aligned to the right.
+      %
+      \parindent = 0pt
+      \advance\leftskip by 0pt plus 1fil
+      \advance\leftskip by 0pt plus -1fill
+      \rightskip = 0pt plus -1fil
+      \advance\rightskip by 0pt plus 1fill
+      % Cause last line, which could consist of page numbers on their own
+      % if the list of page numbers is long, to be aligned to the right.
+      \parfillskip=0pt plus -1fill
+      %
+      \advance\rightskip by \entryrightmargin
+      % Determine how far we can stretch into the margin.
+      % This allows, e.g., "Appendix H  GNU Free Documentation License" to
+      % fit on one line in @letterpaper format.
+      \ifdim\entryrightmargin>2.1em
+        \dimen@i=2.1em
+      \else
+        \dimen@i=0em
+      \fi
+      \advance \parfillskip by 0pt minus 1\dimen@i
+      %
+      \dimen@ii = \hsize
+      \advance\dimen@ii by -1\leftskip
+      \advance\dimen@ii by -1\entryrightmargin
+      \advance\dimen@ii by 1\dimen@i
+      \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line
+      \ifdim\dimen@ > 0.8\dimen@ii   % due to long index text
+        % Try to split the text roughly evenly.  \dimen@ will be the length of
+        % the first line.
+        \dimen@ = 0.7\dimen@
+        \dimen@ii = \hsize
+        \ifnum\dimen@>\dimen@ii
+          % If the entry is too long (for example, if it needs more than
+          % two lines), use all the space in the first line.
+          \dimen@ = \dimen@ii
+        \fi
+        \advance\leftskip by 0pt plus 1fill % ragged right
+        \advance \dimen@ by 1\rightskip
+        \parshape = 2 0pt \dimen@ 0em \dimen@ii
+        % Ideally we'd add a finite glue at the end of the first line only,
+        % instead of using \parshape with explicit line lengths, but TeX
+        % doesn't seem to provide a way to do such a thing.
+        %
+        % Indent all lines but the first one.
+        \advance\leftskip by 1em
+        \advance\parindent by -1em
+      \fi\fi
+      \indent % start paragraph
+      \unhbox\boxA
+      %
+      % Do not prefer a separate line ending with a hyphen to fewer lines.
+      \finalhyphendemerits = 0
+      %
+      % Word spacing - no stretch
+      \spaceskip=\fontdimen2\font minus \fontdimen4\font
+      %
+      \linepenalty=1000  % Discourage line breaks.
+      \hyphenpenalty=5000  % Discourage hyphenation.
+      %
+      \par % format the paragraph
+    \egroup % The \vbox
+    \fi
+  \endgroup
+}}
+
+\newskip\thinshrinkable
+\skip\thinshrinkable=.15em minus .15em
+
+% Like plain.tex's \dotfill, except uses up at least 1 em.
+% The filll stretch here overpowers both the fil and fill stretch to push
+% the page number to the right.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll}
+
+
+\def\primary #1{\line{#1\hfil}}
+
+\def\secondary{\indententry{0.5cm}}
+\def\tertiary{\indententry{1cm}}
+
+\def\indententry#1#2#3{%
+  \bgroup
+  \leftskip=#1
+  \entry{#2}{#3}%
+  \egroup
+}
+
+% 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  % private names
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % If not much space left on page, start a new page.
+  \ifdim\pagetotal>0.8\vsize\vfill\eject\fi
+  %
+  % Grab any single-column material above us.
+  \output = {%
+    \savetopmark
+    %
+    \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
+  %
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \advance\vsize by -\ht\partialpage
+  \vsize = 2\vsize
+  %
+  % For the benefit of balancing columns
+  \advance\baselineskip by 0pt plus 0.5pt
+}
+
+% The double-column output routine for all double-column pages except
+% the last, which is done by \balancecolumns.
+%
+\def\doublecolumnout{%
+  %
+  \savetopmark
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit\PAGE to\dimen@ \setbox2=\vsplit\PAGE to\dimen@
+  \global\advance\vsize by 2\ht\partialpage
+  \onepageout\pagesofar % empty except for the first time we are called
+  \unvbox\PAGE
+  \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\txipagewidth{\box0\hfil\box2}%
+}
+
+
+% Finished 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 \txipageheight (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.
+    \savetopmark
+    \balancecolumns
+  }%
+  \eject % call the \output just set
+  \ifdim\pagetotal=0pt
+    % Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.
+    \global\output=\expandafter{\the\defaultoutput}
+    %
+    \endgroup % started in \begindoublecolumns
+    % Leave the double-column material on the current page, no automatic
+    % page break.
+    \box\balancedcolumns
+    %
+    % \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.
+    \global\vsize = \txipageheight %
+    \pagegoal = \txipageheight %
+  \else
+    % We had some left-over material.  This might happen when \doublecolumnout
+    % is called in \balancecolumns.  Try again.
+    \expandafter\enddoublecolumns
+  \fi
+}
+\newbox\balancedcolumns
+\setbox\balancedcolumns=\vbox{shouldnt see this}%
+%
+% Only called for the last of the double column material.  \doublecolumnout
+% does the others.
+\def\balancecolumns{%
+  \setbox0 = \vbox{\unvbox\PAGE}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \ifdim\dimen@<7\baselineskip
+    % Don't split a short final column in two.
+    \setbox2=\vbox{}%
+    \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+  \else
+    % double the leading vertical space
+    \advance\dimen@ by \topskip
+    \advance\dimen@ by-\baselineskip
+    \divide\dimen@ by 2 % target to split to
+    \dimen@ii = \dimen@
+    \splittopskip = \topskip
+    % Loop until left column is at least as high as the right column.
+    {%
+      \vbadness = 10000
+      \loop
+        \global\setbox3 = \copy0
+        \global\setbox1 = \vsplit3 to \dimen@
+      \ifdim\ht1<\ht3
+        \global\advance\dimen@ by 1pt
+      \repeat
+    }%
+    % Now the left column is in box 1, and the right column in box 3.
+    %
+    % Check whether the left column has come out higher than the page itself.
+    % (Note that we have doubled \vsize for the double columns, so
+    % the actual height of the page is 0.5\vsize).
+    \ifdim2\ht1>\vsize
+      % It appears that we have been called upon to balance too much material.
+      % Output some of it with \doublecolumnout, leaving the rest on the page.
+      \setbox\PAGE=\box0
+      \doublecolumnout
+    \else
+      % Compare the heights of the two columns.
+      \ifdim4\ht1>5\ht3
+        % Column heights are too different, so don't make their bottoms
+        % flush with each other.
+        \setbox2=\vbox to \ht1 {\unvbox3\vfill}%
+        \setbox0=\vbox to \ht1 {\unvbox1\vfill}%
+      \else
+        % Make column bottoms flush with each other.
+        \setbox2=\vbox to\ht1{\unvbox3\unskip}%
+        \setbox0=\vbox to\ht1{\unvbox1\unskip}%
+      \fi
+      \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+    \fi
+  \fi
+  %
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% Let's start with @part.
+\outer\parseargdef\part{\partzzz{#1}}
+\def\partzzz#1{%
+  \chapoddpage
+  \null
+  \vskip.3\vsize  % move it down on the page a bit
+  \begingroup
+    \noindent \titlefonts\rm #1\par % the text
+    \let\lastnode=\empty      % no node to associate with
+    \writetocentry{part}{#1}{}% but put it in the toc
+    \headingsoff              % no headline or footline on the part page
+    % This outputs a mark at the end of the page that clears \thischapter
+    % and \thissection, as is done in \startcontents.
+    \let\pchapsepmacro\relax
+    \chapmacro{}{Yomitfromtoc}{}%
+    \chapoddpage
+  \endgroup
+}
+
+% \unnumberedno is an oxymoron.  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}
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achieve this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unnlevel = \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 < \unnlevel
+      \chardef\unnlevel = \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 > \unnlevel
+      \def\headtype{U}%
+    \else
+      \chardef\unnlevel = 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
+}
+
+% normally unnmhead0 calls unnumberedzzz:
+\outer\parseargdef\unnumbered{\unnmhead0{#1}}
+\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<toks register> to achieve this: TeX expands \the<toks> only once,
+  % simply yielding the contents of <toks register>.  (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{%
+  \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}%
+}
+
+% normally calls appendixsectionzzz:
+\outer\parseargdef\appendixsection{\apphead1{#1}}
+\def\appendixsectionzzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+% normally calls unnumberedseczzz:
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}}
+\def\unnumberedseczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+%
+% normally calls numberedsubseczzz:
+\outer\parseargdef\numberedsubsec{\numhead2{#1}}
+\def\numberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+% normally calls appendixsubseczzz:
+\outer\parseargdef\appendixsubsec{\apphead2{#1}}
+\def\appendixsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+% normally calls unnumberedsubseczzz:
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}}
+\def\unnumberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+%
+% normally numberedsubsubseczzz:
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}}
+\def\numberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynumbered}%
+                 {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally appendixsubsubseczzz:
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}}
+\def\appendixsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally unnumberedsubsubseczzz:
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}}
+\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
+
+\def\majorheading{%
+  {\advance\chapheadingskip by 10pt \chapbreak }%
+  \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+  \vbox{\chapfonts \raggedtitlesettings #1\par}%
+  \nobreak\bigskip \nobreak
+  \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}
+
+% Parameter controlling skip before chapter headings (if needed)
+\newskip\chapheadingskip
+
+% Define plain chapter starts, and page on/off switching for it.
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+
+% Start a new page
+\def\chappager{\par\vfill\supereject}
+
+% \chapoddpage - start on an odd page for a new chapter
+% 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
+      \headingsoff
+      \null
+      \chappager
+    \endgroup
+  \fi
+}
+
+\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\def\HEADINGSon{\HEADINGSsinglechapoff}}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% \chapmacro - Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+% Not used for @heading series.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yappendixkeyword{Yappendix}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+%
+\def\chapmacro#1#2#3{%
+  \expandafter\ifx\thisenv\titlepage\else
+    \checkenv{}% chapters, etc., should not start inside an environment.
+  \fi
+  % Insert the first mark before the heading break (see notes for \domark).
+  \let\prevchapterdefs=\currentchapterdefs
+  \let\prevsectiondefs=\currentsectiondefs
+  \gdef\currentsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}%
+                        \gdef\thissection{}}%
+  %
+  \def\temptype{#2}%
+  \ifx\temptype\Ynothingkeyword
+    \gdef\currentchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{\thischaptername}}%
+  \else\ifx\temptype\Yomitfromtockeyword
+    \gdef\currentchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{}}%
+  \else\ifx\temptype\Yappendixkeyword
+    \toks0={#1}%
+    \xdef\currentchapterdefs{%
+      \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\currentchapterdefs{%
+      \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=\currentchapterdefs
+  \let\prevsectiondefs=\currentsectiondefs
+  \domark
+  %
+  {%
+    \chapfonts \rm
+    \let\footnote=\errfootnoteheading % give better error message
+    %
+    % Have to define \currentsection 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\currentsection{#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{\raggedtitlesettings \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
+}
+
+
+% 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 of the title,
+% #2 is the section level (sec/subsec/subsubsec),
+% #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc),
+% #4 is the section number.
+%
+\def\seckeyword{sec}
+%
+\def\sectionheading#1#2#3#4{%
+  {%
+    \def\sectionlevel{#2}%
+    \def\temptype{#3}%
+    %
+    % It is ok for the @heading series commands to appear inside an
+    % environment (it's been historically allowed, though the logic is
+    % dubious), but not the others.
+    \ifx\temptype\Yomitfromtockeyword\else
+      \checkenv{}% non-@*heading should not be in an environment.
+    \fi
+    \let\footnote=\errfootnoteheading
+    %
+    % Switch to the right set of fonts.
+    \csname #2fonts\endcsname \rm
+    %
+    % Insert first mark before the heading break (see notes for \domark).
+    \let\prevsectiondefs=\currentsectiondefs
+    \ifx\temptype\Ynothingkeyword
+      \ifx\sectionlevel\seckeyword
+        \gdef\currentsectiondefs{\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\currentsectiondefs{%
+          \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\currentsectiondefs{%
+          \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.
+    \global\let\prevsectiondefs=\currentsectiondefs
+    \domark
+    %
+    % Only insert the space after the number if we have a section number.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unn}%
+      \gdef\currentsection{#1}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      % for @headings -- no section number, don't include in toc,
+      % and don't redefine \currentsection.
+      \setbox0 = \hbox{}%
+      \def\toctype{omit}%
+      \let\sectionlevel=\empty
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{app}%
+      \gdef\currentsection{#1}%
+    \else
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{num}%
+      \gdef\currentsection{#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.)  However, when a paragraph is not started next
+  % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out
+  % or the negative glue will cause weirdly wrong output, typically
+  % obscuring the section heading with something else.
+  \vskip-\parskip
+  %
+  % This is so the last item on the main vertical list is a known
+  % \penalty > 10000, so \startdefun, etc., can recognize the situation
+  % and do the needful.
+  \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'.
+  \ifpdforxetex
+    \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.
+  \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.
+    \entryrightmargin=\contentsrightmargin % Don't use the full line length.
+    %
+    % Roman numerals for page numbers.
+    \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+    \def\thistitle{}% no title in double-sided headings
+    % Record where the Roman numerals started.
+    \ifnum\romancount=0 \global\romancount=\pagecount \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
+  \contentsendroman
+}
+
+% And just the chapters.
+\def\summarycontents{%
+  \startcontents{\putwordShortTOC}%
+    %
+    \let\partentry = \shortpartentry
+    \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
+  \contentsendroman
+}
+\let\shortcontents = \summarycontents
+
+% Get ready to use Arabic numerals again
+\def\contentsendroman{%
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+  %
+  % If \romancount > \arabiccount, the contents are at the end of the
+  % document.  Otherwise, advance where the Arabic numerals start for
+  % the page numbers.
+  \ifnum\romancount>\arabiccount\else\global\arabiccount=\pagecount\fi
+}
+
+% 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, ...
+
+% Parts, in the main contents.  Replace the part number, which doesn't
+% exist, with an empty box.  Let's hope all the numbers have the same width.
+% Also ignore the page number, which is conventionally not printed.
+\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}}
+\def\partentry#1#2#3#4{%
+  % Add stretch and a bonus for breaking the page before the part heading.
+  % This reduces the chance of the page being broken immediately after the
+  % part heading, before a following chapter heading.
+  \vskip 0pt plus 5\baselineskip
+  \penalty-300
+  \vskip 0pt plus -5\baselineskip
+  \dochapentry{\numeralbox\labelspace#1}{}%
+}
+%
+% Parts, in the short toc.
+\def\shortpartentry#1#2#3#4{%
+  \penalty-300
+  \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip
+  \shortchapentry{{\bf #1}}{\numeralbox}{}{}%
+}
+
+% 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}\hskip.7em#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
+     % Move the page numbers slightly to the right
+     \advance\entryrightmargin by -0.05em
+     \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 @ 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
+  %
+  % ' is active in math mode (mathcode"8000).  So reset it, and all our
+  % other math active characters (just in case), to plain's definitions.
+  \mathactive
+  %
+  % Inverse of the list at the beginning of the file.
+  \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\sp=\ptexsp
+  \let\*=\ptexstar
+  %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode
+  \let\t=\ptext
+  \expandafter \let\csname top\endcsname=\ptextop  % we've made it 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
+      \ifnum\lastpenalty<10000
+        % Penalize breaking before the environment, because preceding text
+        % often leads into it.
+        \penalty100
+      \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+\def\afterenvbreak{{%
+  % =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
+}}
+
+% \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.
+
+%
+\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
+
+% only require the font if @cartouche is actually used
+\def\cartouchefontdefs{%
+  \font\circle=lcircle10\relax
+  \circthick=\fontdimen8\circle
+}
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+
+
+\envdef\cartouche{%
+  \cartouchefontdefs
+  \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
+  %
+  % If this cartouche directly follows a sectioning command, we need the
+  % \parskip glue (backspaced over by default) or the cartouche can
+  % collide with the section heading.
+  \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi
+  %
+  \setbox\groupbox=\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
+  \addgroupbox
+  \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\newdimen\nonfillparindent
+\def\nonfillstart{%
+  \aboveenvbreak
+  \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % 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 in one command.  #1 is the env name, #2 the definition.
+\def\makedispenvdef#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 environment synonyms (#1 and #2) for an environment.
+\def\maketwodispenvdef#1#2#3{%
+  \makedispenvdef{#1}{#3}%
+  \makedispenvdef{#2}{#3}%
+}
+%
+% @lisp: indented, narrowed, typewriter font;
+% @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvdef{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.
+%
+\makedispenvdef{display}{%
+  \nonfillstart
+  \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenvdef{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\relax
+  \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification.  From plain.tex.
+\envdef\raggedright{%
+  \rightskip0pt plus2.4em \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.
+%
+\makedispenvdef{quotation}{\quotationstart}
+%
+\def\quotationstart{%
+  \indentedblockstart % same as \indentedblock, but increase right margin too.
+  \ifx\nonarrowing\relax
+    \advance\rightskip by \lispnarrowing
+  \fi
+  \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+  \par
+  \ifx\quotationauthor\thisisundefined\else
+    % indent a bit.
+    \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+  \fi
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallquotation{\Equotation}
+
+% 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
+}
+
+% @indentedblock is like @quotation, but indents only on the left and
+% has no optional argument.
+%
+\makedispenvdef{indentedblock}{\indentedblockstart}
+%
+\def\indentedblockstart{%
+  {\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
+    \exdentamount = \lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+}
+
+% Keep a nonzero parskip for the environment, since we're doing normal filling.
+%
+\def\Eindentedblock{%
+  \par
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallindentedblock{\Eindentedblock}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> 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
+%
+% We typeset each line of the verbatim in an \hbox, so we can handle
+% tabs.
+\newbox\verbbox
+\def\starttabbox{\setbox\verbbox=\hbox\bgroup}
+%
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabexpand{%
+    \catcode`\^^I=\active
+    \def^^I{\leavevmode\egroup
+      \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab
+      \divide\dimen\verbbox by\tabw
+      \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw
+      \advance\dimen\verbbox by\tabw  % advance to next multiple of \tabw
+      \wd\verbbox=\dimen\verbbox
+      \leavevmode\box\verbbox \starttabbox
+    }%
+  }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \tt % easiest (and conventionally used) font for verbatim
+  \def\par{\egroup\leavevmode\box\verbbox\endgraf\starttabbox}%
+  \tabexpand
+  \setupmarkupstyle{verbatim}%
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count.
+  % Must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+}
+
+% 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'{'<char>#1<char>'}'{#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{%
+    \starttabbox#2\egroup\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.
+  % The \egroup ends the \verbbox started at the end of the last line in
+  % the block.
+\endgroup
+%
+\envdef\verbatim{%
+    \setnormaldispenv\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.
+      \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}%
+      \edef\tmp{\noexpand\input #1 }
+      \expandafter
+    }\expandafter\starttabbox\tmp\egroup
+    \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 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 further 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\relax
+    \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 { (defn. of \deffnheader) }
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+  \envdef#1{%
+    \startdefun
+    \doingtypefnfalse    % distinguish typed functions from all else
+    \parseargusing\activeparens{\printdefunline#3}%
+  }%
+  \def#2{\dodefunx#1}%
+  \def#3%
+}
+
+\newif\ifdoingtypefn       % doing typed function?
+\newif\ifrettypeownline    % typeset return type on its own line?
+
+% @deftypefnnewline on|off says whether the return type of typed functions
+% are printed on their own line.  This affects @deftypefn, @deftypefun,
+% @deftypeop, and @deftypemethod.
+%
+\parseargdef\deftypefnnewline{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @txideftypefnnl value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+% \dosubind {index}{topic}{subtopic}
+%
+% If SUBTOPIC is present, precede it with a space, and call \doind.
+% (At some time during the 20th century, this made a two-level entry in an
+% index such as the operation index.  Nobody seemed to notice the change in
+% behaviour though.)
+\def\dosubind#1#2#3{%
+  \def\thirdarg{#3}%
+  \ifx\thirdarg\empty
+    \doind{#1}{#2}%
+  \else
+    \doind{#1}{#2\space#3}%
+  \fi
+}
+
+% 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{%
+  \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}%
+  \doingtypefntrue
+  \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 {} }
+
+% Types:
+
+% @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{%
+  \par
+  % Get the values of \leftskip and \rightskip as they were outside the @def...
+  \advance\leftskip by -\defbodyindent
+  %
+  % Determine if we are typesetting the return type of a typed function
+  % on a line by itself.
+  \rettypeownlinefalse
+  \ifdoingtypefn  % doing a typed function specifically?
+    % then check user option for putting return type on its own line:
+    \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
+      \rettypeownlinetrue
+    \fi
+  \fi
+  %
+  % How we'll format the category 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.  We'll always have at
+  % least two.
+  \tempnum = 2
+  %
+  % 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
+  %
+  % If doing a return type on its own line, we'll have another line.
+  \ifrettypeownline
+    \advance\tempnum by 1
+    \def\maybeshapeline{0in \hsize}%
+  \else
+    \def\maybeshapeline{}%
+  \fi
+  %
+  % The continuations:
+  \dimen2=\hsize  \advance\dimen2 by -\defargsindent
+  %
+  % The final paragraph shape:
+  \parshape \tempnum  0in \dimen0  \maybeshapeline  \defargsindent \dimen2
+  %
+  % Put the category name at 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}% text of the return type
+    \ifx\temp\empty\else
+      \tclose{\temp}% typeset the return type
+      \ifrettypeownline
+        % put return type on its own line; prohibit line break following:
+        \hfil\vadjust{\nobreak}\break
+      \else
+        \space  % type on same line, so just followed by a space
+      \fi
+    \fi           % no return type
+    #3% output function name
+  }%
+  {\rm\enskip}% hskip 0.5 em of \rmfont
+  %
+  \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.  We used to recommend @var for that, so
+  % leave the code in, but it's strange for @var to lead to typewriter.
+  % Nowadays we recommend @code, since the difference between a ttsl hyphen
+  % and a tt hyphen is pretty tiny.  @code also disables ?` !`.
+  \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}
+}
+\let\ampchar\&
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\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\thisisundefined
+  \newwrite\macscribble
+  \def\scantokens#1{%
+    \toks0={#1}%
+    \immediate\openout\macscribble=\jobname.tmp
+    \immediate\write\macscribble{\the\toks0}%
+    \immediate\closeout\macscribble
+    \input \jobname.tmp
+  }
+\fi
+
+% Used at the time of macro expansion.
+% Argument is macro body with arguments substituted
+\def\scanmacro#1{%
+  \newlinechar`\^^M
+  \def\xeatspaces{\eatspaces}%
+  %
+  % Process the macro body under the current catcode regime.
+  \scantokens{#1@comment}%
+  %
+  % The \comment is to remove the \newlinechar added by \scantokens, and
+  % can be noticed by \parsearg.  Note \c isn't used because this means cedilla
+  % in math mode.
+}
+
+% Used for copying and captions
+\def\scanexp#1{%
+  \expandafter\scanmacro\expandafter{#1}%
+}
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+
+% List of all defined macros in the form
+%    \commondummyword\macro1\commondummyword\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\commondummyword#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 \
+% to recognize macro arguments; this is the job of \mbodybackslash.
+%
+% 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{% used as subroutine
+  \catcode`\"=\other
+  \catcode`\+=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\^=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\~=\other
+  \passthroughcharstrue
+}
+
+\def\scanargctxt{% used for copying and captions, not macros.
+  \scanctxt
+  \catcode`\@=\other
+  \catcode`\\=\other
+  \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{% used for @macro definitions
+  \scanctxt
+  \catcode`\ =\other
+  \catcode`\@=\other
+  \catcode`\{=\other
+  \catcode`\}=\other
+  \catcode`\^^M=\other
+  \usembodybackslash
+}
+
+% Used when scanning braced macro arguments.  Note, however, that catcode
+% changes here are ineffectual if the macro invocation was nested inside
+% an argument to another Texinfo command.
+\def\macroargctxt{%
+  \scanctxt
+  \catcode`\ =\active
+  \catcode`\@=\other
+  \catcode`\^^M=\other
+  \catcode`\\=\active
+}
+
+\def\macrolineargctxt{% used for whole-line arguments without braces
+  \scanctxt
+  \catcode`\@=\other
+  \catcode`\{=\other
+  \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\margbackslash#1{\char`\#1 }
+
+\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\relax
+  \else
+     \expandafter\parsemargdef \argl;%
+     \if\paramno>256\relax
+       \ifx\eTeXversion\thisisundefined
+         \errhelp = \EMsimple
+         \errmessage{You need eTeX to compile a file with macros with more than 256 arguments}
+       \fi
+     \fi
+  \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\commondummyword\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\commondummyword \noexpand#1%
+  \fi
+}
+
+% \getargs -- Parse the arguments to a @macro line.  Set \macname to
+% the name of the macro, and \argl to the braced argument list.
+\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}}
+% This made use of the feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+
+% Parse the optional {params} list to @macro or @rmacro.
+% Set \paramno to the number of arguments,
+% and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a
+% three-param macro.)  Define \macarg.BLAH for each BLAH in the params
+% list to some hook where the argument is to be expanded.  If there are
+% less than 10 arguments that hook is to be replaced by ##N where N
+% is the position in that list, that is to say the macro arguments are to be
+% defined `a la TeX in the macro body.
+%
+% That gets used by \mbodybackslash (above).
+%
+% If there are 10 or more arguments, a different technique is used: see
+% \parsemmanyargdef.
+%
+\def\parsemargdef#1;{%
+  \paramno=0\def\paramlist{}%
+  \let\hash\relax
+  % \hash is redefined to `#' later to get it into definitions
+  \let\xeatspaces\relax
+  \parsemargdefxxx#1,;,%
+  \ifnum\paramno<10\relax\else
+    \paramno0\relax
+    \parsemmanyargdef@@#1,;,% 10 or more arguments
+  \fi
+}
+\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}
+
+% \parsemacbody, \parsermacbody
+%
+% Read recursive and nonrecursive macro bodies. (They're different since
+% rec and nonrec macros end differently.)
+%
+% We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro
+% body to be transformed.
+% Set \macrobody to the body of the macro, and call \defmacro.
+%
+{\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+{\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+
+% Make @ a letter, so that we can make private-to-Texinfo macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
+%%%%%%%%%%%%%% Code for > 10 arguments only   %%%%%%%%%%%%%%%%%%
+
+% If there are 10 or more arguments, a different technique is used, where the
+% hook remains in the body, and when macro is to be expanded the body is
+% processed again to replace the arguments.
+%
+% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the
+% argument N value and then \edef the body (nothing else will expand because of
+% the catcode regime under which the body was input).
+%
+% If you compile with TeX (not eTeX), and you have macros with 10 or more
+% arguments, no macro can have more than 256 arguments (else error).
+%
+% In case that there are 10 or more arguments we parse again the arguments
+% list to set new definitions for the \macarg.BLAH macros corresponding to
+% each BLAH argument. It was anyhow needed to parse already once this list
+% in order to count the arguments, and as macros with at most 9 arguments
+% are by far more frequent than macro with 10 or more arguments, defining
+% twice the \macarg.BLAH macros does not cost too much processing power.
+\def\parsemmanyargdef@@#1,{%
+  \if#1;\let\next=\relax
+  \else
+    \let\next=\parsemmanyargdef@@
+    \edef\tempb{\eatspaces{#1}}%
+    \expandafter\def\expandafter\tempa
+       \expandafter{\csname macarg.\tempb\endcsname}%
+    % Note that we need some extra \noexpand\noexpand, this is because we
+    % don't want \the  to be expanded in the \parsermacbody  as it uses an
+    % \xdef .
+    \expandafter\edef\tempa
+      {\noexpand\noexpand\noexpand\the\toks\the\paramno}%
+    \advance\paramno by 1\relax
+  \fi\next}
+
+
+\let\endargs@\relax
+\let\nil@\relax
+\def\nilm@{\nil@}%
+\long\def\nillm@{\nil@}%
+
+% This macro is expanded during the Texinfo macro expansion, not during its
+% definition.  It gets all the arguments' values and assigns them to macros
+% macarg.ARGNAME
+%
+% #1 is the macro name
+% #2 is the list of argument names
+% #3 is the list of argument values
+\def\getargvals@#1#2#3{%
+  \def\macargdeflist@{}%
+  \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion.
+  \def\paramlist{#2,\nil@}%
+  \def\macroname{#1}%
+  \begingroup
+  \macroargctxt
+  \def\argvaluelist{#3,\nil@}%
+  \def\@tempa{#3}%
+  \ifx\@tempa\empty
+    \setemptyargvalues@
+  \else
+    \getargvals@@
+  \fi
+}
+\def\getargvals@@{%
+  \ifx\paramlist\nilm@
+      % Some sanity check needed here that \argvaluelist is also empty.
+      \ifx\argvaluelist\nillm@
+      \else
+        \errhelp = \EMsimple
+        \errmessage{Too many arguments in macro `\macroname'!}%
+      \fi
+      \let\next\macargexpandinbody@
+  \else
+    \ifx\argvaluelist\nillm@
+       % No more arguments values passed to macro.  Set remaining named-arg
+       % macros to empty.
+       \let\next\setemptyargvalues@
+    \else
+      % pop current arg name into \@tempb
+      \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\paramlist}%
+       % pop current argument value into \@tempc
+      \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\argvaluelist}%
+       % Here \@tempb is the current arg name and \@tempc is the current arg value.
+       % First place the new argument macro definition into \@tempd
+       \expandafter\macname\expandafter{\@tempc}%
+       \expandafter\let\csname macarg.\@tempb\endcsname\relax
+       \expandafter\def\expandafter\@tempe\expandafter{%
+         \csname macarg.\@tempb\endcsname}%
+       \edef\@tempd{\long\def\@tempe{\the\macname}}%
+       \push@\@tempd\macargdeflist@
+       \let\next\getargvals@@
+    \fi
+  \fi
+  \next
+}
+
+\def\push@#1#2{%
+  \expandafter\expandafter\expandafter\def
+  \expandafter\expandafter\expandafter#2%
+  \expandafter\expandafter\expandafter{%
+  \expandafter#1#2}%
+}
+
+% Replace arguments by their values in the macro body, and place the result
+% in macro \@tempa.
+%
+\def\macvalstoargs@{%
+  %  To do this we use the property that token registers that are \the'ed
+  % within an \edef  expand only once. So we are going to place all argument
+  % values into respective token registers.
+  %
+  % First we save the token context, and initialize argument numbering.
+  \begingroup
+    \paramno0\relax
+    % Then, for each argument number #N, we place the corresponding argument
+    % value into a new token list register \toks#N
+    \expandafter\putargsintokens@\saveparamlist@,;,%
+    % Then, we expand the body so that argument are replaced by their
+    % values. The trick for values not to be expanded themselves is that they
+    % are within tokens and that tokens expand only once in an \edef .
+    \edef\@tempc{\csname mac.\macroname .body\endcsname}%
+    % Now we restore the token stack pointer to free the token list registers
+    % which we have used, but we make sure that expanded body is saved after
+    % group.
+    \expandafter
+  \endgroup
+  \expandafter\def\expandafter\@tempa\expandafter{\@tempc}%
+  }
+
+% Define the named-macro outside of this group and then close this group.
+%
+\def\macargexpandinbody@{%
+  \expandafter
+  \endgroup
+  \macargdeflist@
+  % First the replace in body the macro arguments by their values, the result
+  % is in \@tempa .
+  \macvalstoargs@
+  % Then we point at the \norecurse or \gobble (for recursive) macro value
+  % with \@tempb .
+  \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname
+  % Depending on whether it is recursive or not, we need some tailing
+  % \egroup .
+  \ifx\@tempb\gobble
+     \let\@tempc\relax
+  \else
+     \let\@tempc\egroup
+  \fi
+  % And now we do the real job:
+  \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}%
+  \@tempd
+}
+
+\def\putargsintokens@#1,{%
+  \if#1;\let\next\relax
+  \else
+    \let\next\putargsintokens@
+    % First we allocate the new token list register, and give it a temporary
+    % alias \@tempb .
+    \toksdef\@tempb\the\paramno
+    % Then we place the argument value into that token list register.
+    \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname
+    \expandafter\@tempb\expandafter{\@tempa}%
+    \advance\paramno by 1\relax
+  \fi
+  \next
+}
+
+% Trailing missing arguments are set to empty.
+%
+\def\setemptyargvalues@{%
+  \ifx\paramlist\nilm@
+    \let\next\macargexpandinbody@
+  \else
+    \expandafter\setemptyargvaluesparser@\paramlist\endargs@
+    \let\next\setemptyargvalues@
+  \fi
+  \next
+}
+
+\def\setemptyargvaluesparser@#1,#2\endargs@{%
+  \expandafter\def\expandafter\@tempa\expandafter{%
+    \expandafter\def\csname macarg.#1\endcsname{}}%
+  \push@\@tempa\macargdeflist@
+  \def\paramlist{#2}%
+}
+
+% #1 is the element target macro
+% #2 is the list macro
+% #3,#4\endargs@ is the list value
+\def\pop@#1#2#3,#4\endargs@{%
+   \def#1{#3}%
+   \def#2{#4}%
+}
+\long\def\longpop@#1#2#3,#4\endargs@{%
+   \long\def#1{#3}%
+   \long\def#2{#4}%
+}
+
+
+%%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%%
+
+
+% This defines a Texinfo @macro or @rmacro, called by \parsemacbody.
+%    \macrobody has the body of the macro in it, with placeholders for
+% its parameters, looking like "\xeatspaces{\hash 1}".
+%    \paramno is the number of parameters
+%    \paramlist is a TeX parameter text, e.g. "#1,#2,#3,"
+% There are four cases: macros of zero, one, up to nine, and many arguments.
+% \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
+  \ifnum\paramno=1
+    \def\xeatspaces##1{##1}%
+    % This removes the pair of braces around the argument.  We don't
+    % use \eatspaces, because this can cause ends of lines to be lost
+    % when the argument to \eatspaces is read, leading to line-based
+    % commands like "@itemize" not being read correctly.
+  \else
+    \let\xeatspaces\relax % suppress expansion
+  \fi
+  \ifcase\paramno
+  % 0
+    \expandafter\xdef\csname\the\macname\endcsname{%
+      \bgroup
+        \noexpand\spaceisspace
+        \noexpand\endlineisspace
+        \noexpand\expandafter % skip any whitespace after the macro name.
+        \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+    \expandafter\xdef\csname\the\macname @@@\endcsname{%
+      \egroup
+      \noexpand\scanmacro{\macrobody}}%
+  \or % 1
+    \expandafter\xdef\csname\the\macname\endcsname{%
+       \bgroup
+       \noexpand\braceorline
+       \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+    \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+      \egroup
+      \noexpand\scanmacro{\macrobody}%
+      }%
+  \else % at most 9
+    \ifnum\paramno<10\relax
+      % @MACNAME sets the context for reading the macro argument
+      % @MACNAME@@ gets the argument, processes backslashes and appends a
+      % comma.
+      % @MACNAME@@@ removes braces surrounding the argument list.
+      % @MACNAME@@@@ scans the macro body with arguments substituted.
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \bgroup
+        \noexpand\expandafter  % This \expandafter skip any spaces after the
+        \noexpand\macroargctxt % macro before we change the catcode of space.
+        \noexpand\expandafter
+        \expandafter\noexpand\csname\the\macname @@\endcsname}%
+      \expandafter\xdef\csname\the\macname @@\endcsname##1{%
+          \noexpand\passargtomacro
+          \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
+      \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+        \csname\the\macname @@@@\endcsname\paramlist{%
+          \egroup\noexpand\scanmacro{\macrobody}}%
+    \else % 10 or more:
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\getargvals@{\the\macname}{\argl}%
+      }%
+      \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
+      \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
+    \fi
+  \fi}
+
+\catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+{\catcode`\@=0 \catcode`\\=13  % We need to manipulate \ so use @ as escape
+@catcode`@_=11  % private names
+@catcode`@!=11  % used as argument separator
+
+% \passargtomacro#1#2 -
+% Call #1 with a list of tokens #2, with any doubled backslashes in #2
+% compressed to one.
+%
+% This implementation works by expansion, and not execution (so we cannot use
+% \def or similar).  This reduces the risk of this failing in contexts where
+% complete expansion is done with no execution (for example, in writing out to
+% an auxiliary file for an index entry).
+%
+% State is kept in the input stream: the argument passed to
+% @look_ahead, @gobble_and_check_finish and @add_segment is
+%
+% THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN  (... rest of input)
+%
+% where:
+% THE_MACRO - name of the macro we want to call
+% ARG_RESULT - argument list we build to pass to that macro
+% PENDING_BS - either a backslash or nothing
+% NEXT_TOKEN - used to look ahead in the input stream to see what's coming next
+
+@gdef@passargtomacro#1#2{%
+  @add_segment #1!{}@relax#2\@_finish\%
+}
+@gdef@_finish{@_finishx} @global@let@_finishx@relax
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 used to look ahead
+%
+% If the next token is not a backslash, process the rest of the argument;
+% otherwise, remove the next token.
+@gdef@look_ahead#1!#2#3#4{%
+  @ifx#4\%
+   @expandafter@gobble_and_check_finish
+  @else
+   @expandafter@add_segment
+  @fi#1!{#2}#4#4%
+}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 should be a backslash, which is gobbled.
+% #5 looks ahead
+%
+% Double backslash found.  Add a single backslash, and look ahead.
+@gdef@gobble_and_check_finish#1!#2#3#4#5{%
+  @add_segment#1\!{}#5#5%
+}
+
+@gdef@is_fi{@fi}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 is input stream until next backslash
+%
+% Input stream is either at the start of the argument, or just after a
+% backslash sequence, either a lone backslash, or a doubled backslash.
+% NEXT_TOKEN contains the first token in the input stream: if it is \finish,
+% finish; otherwise, append to ARG_RESULT the segment of the argument up until
+% the next backslash.  PENDING_BACKSLASH contains a backslash to represent
+% a backslash just before the start of the input stream that has not been
+% added to ARG_RESULT.
+@gdef@add_segment#1!#2#3#4\{%
+@ifx#3@_finish
+  @call_the_macro#1!%
+@else
+  % append the pending backslash to the result, followed by the next segment
+  @expandafter@is_fi@look_ahead#1#2#4!{\}@fi
+  % this @fi is discarded by @look_ahead.
+  % we can't get rid of it with \expandafter because we don't know how
+  % long #4 is.
+}
+
+% #1 - THE_MACRO
+% #2 - ARG_RESULT
+% #3 discards the res of the conditional in @add_segment, and @is_fi ends the
+% conditional.
+@gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}}
+
+}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% \braceorline MAC is used for a one-argument macro MAC.  It checks
+% whether the next non-whitespace character is a {.  It sets the context
+% for reading the argument (slightly different in the two cases).  Then,
+% to read the argument, in the whole-line case, it then calls the regular
+% \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC.
+%
+\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup
+    \macroargctxt
+    \expandafter\passargtomacro
+  \else
+    \macrolineargctxt\expandafter\parsearg
+  \fi \macnamexxx}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign.  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}\omittopnode}
+
+% Used so that the @top node doesn't have to be wrapped in an @ifnottex
+% conditional.
+% \doignore goes to more effort to skip nested conditionals but we don't need
+% that here.
+\def\omittopnode{%
+   \ifx\lastnode\wordTop
+   \expandafter\ignorenode\fi
+}
+\def\wordTop{Top}
+
+% Until the next @node or @bye command, divert output to a box that is not
+% output.
+\def\ignorenode{\setbox\dummybox\vbox\bgroup\def\node{\egroup\node}%
+\ignorenodebye
+}
+
+{\let\bye\relax
+\gdef\ignorenodebye{\let\bye\ignorenodebyedef}
+\gdef\ignorenodebyedef{\egroup(`Top' node ignored)\bye}}
+% The redefinition of \bye here is because it is declared \outer
+
+\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 \currentsection,
+%                 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
+    {%
+      \requireauxfile
+      \atdummies  % preserve commands, but don't expand them
+      % match definition in \xrdef, \refx, \xrefX.
+      \def\value##1{##1}%
+      \edef\writexrdef##1##2{%
+	\write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+	  ##1}{##2}}% these are parameters of \writexrdef
+      }%
+      \toks0 = \expandafter{\currentsection}%
+      \immediate \writexrdef{title}{\the\toks0 }%
+      \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+      \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout
+    }%
+  \fi
+}
+
+% @xrefautosectiontitle on|off says whether @section(ing) names are used
+% automatically in xrefs, if the third arg is not explicitly specified.
+% This was provided as a "secret" @set xref-automatic-section-title
+% variable, now it's official.
+%
+\parseargdef\xrefautomaticsectiontitle{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @xrefautomaticsectiontitle value `\temp',
+                must be on|off}%
+  \fi\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{\putwordsee{} \xrefXX}
+\def\xref{\putwordSee{} \xrefXX}
+\def\ref{\xrefXX}
+
+\def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX}
+\def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]}
+%
+\newbox\toprefbox
+\newbox\printedrefnamebox
+\newbox\infofilenamebox
+\newbox\printedmanualbox
+%
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \unsepspaces
+  %
+  % Get args without leading/trailing spaces.
+  \def\printedrefname{\ignorespaces #3}%
+  \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}%
+  %
+  \def\infofilename{\ignorespaces #4}%
+  \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
+  %
+  \def\printedmanual{\ignorespaces #5}%
+  \setbox\printedmanualbox  = \hbox{\printedmanual\unskip}%
+  %
+  % If the printed reference name (arg #3) was not explicitly given in
+  % the @xref, figure out what we want to use.
+  \ifdim \wd\printedrefnamebox = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax
+      % Not auto section-title: use node name inside the square brackets.
+      \def\printedrefname{\ignorespaces #1}%
+    \else
+      % Auto section-title: use chapter/section title inside
+      % the square brackets if we have it.
+      \ifdim \wd\printedmanualbox > 0pt
+        % It is in another manual, so we don't have it; use node name.
+        \def\printedrefname{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We (should) 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
+    % For pdfTeX and LuaTeX
+    {\indexnofonts
+     \makevalueexpandable
+     \turnoffactive
+     % This expands tokens, so do it after making catcode changes, so _
+     % etc. don't get their TeX definitions.  This ignores all spaces in
+     % #4, including (wrongly) those in the middle of the filename.
+     \getfilename{#4}%
+     %
+     % This (wrongly) does not take account of leading or trailing
+     % spaces in #1, which should be ignored.
+     \setpdfdestname{#1}%
+     %
+     \ifx\pdfdestname\empty
+       \def\pdfdestname{Top}% no empty targets
+     \fi
+     %
+     \leavevmode
+     \startlink attr{/Border [0 0 0]}%
+     \ifnum\filenamelength>0
+       goto file{\the\filename.pdf} name{\pdfdestname}%
+     \else
+       goto name{\pdfmkpgn{\pdfdestname}}%
+     \fi
+    }%
+    \setcolor{\linkcolor}%
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+    \else
+      % For XeTeX
+      {\indexnofonts
+       \makevalueexpandable
+       \turnoffactive
+       % This expands tokens, so do it after making catcode changes, so _
+       % etc. don't get their TeX definitions.  This ignores all spaces in
+       % #4, including (wrongly) those in the middle of the filename.
+       \getfilename{#4}%
+       %
+       % This (wrongly) does not take account of leading or trailing
+       % spaces in #1, which should be ignored.
+       \setpdfdestname{#1}%
+       %
+       \ifx\pdfdestname\empty
+         \def\pdfdestname{Top}% no empty targets
+       \fi
+       %
+       \leavevmode
+       \ifnum\filenamelength>0
+         % With default settings,
+         % XeTeX (xdvipdfmx) replaces link destination names with integers.
+         % In this case, the replaced destination names of
+         % remote PDFs are no longer known.  In order to avoid a replacement,
+         % you can use xdvipdfmx's command line option `-C 0x0010'.
+         % If you use XeTeX 0.99996+ (TeX Live 2016+),
+         % this command line option is no longer necessary
+         % because we can use the `dvipdfmx:config' special.
+         \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+           << /S /GoToR /F (\the\filename.pdf) /D (\pdfdestname) >> >>}%
+       \else
+         \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+           << /S /GoTo /D (\pdfdestname) >> >>}%
+       \fi
+      }%
+      \setcolor{\linkcolor}%
+    \fi
+  \fi
+  {%
+    % Have to otherify everything special to allow the \csname to
+    % include an _ in the xref name, etc.
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+      \csname XR#1-title\endcsname
+  }%
+  %
+  % Float references are printed completely differently: "Figure 1.2"
+  % instead of "[somenode], p.3".  \iffloat distinguishes them by
+  % \Xthisreftitle being set to a magic string.
+  \iffloat\Xthisreftitle
+    % If the user specified the print name (third arg) to the ref,
+    % print it instead of our usual "Figure 1.2".
+    \ifdim\wd\printedrefnamebox = 0pt
+      \refx{#1-snt}{}%
+    \else
+      \printedrefname
+    \fi
+    %
+    % If the user also gave the printed manual name (fifth arg), append
+    % "in MANUALNAME".
+    \ifdim \wd\printedmanualbox > 0pt
+      \space \putwordin{} \cite{\printedmanual}%
+    \fi
+  \else
+    % node/anchor (non-float) references.
+    %
+    % If we use \unhbox 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 \wd\printedmanualbox > 0pt
+      % Cross-manual reference with a printed manual name.
+      %
+      \crossmanualxref{\cite{\printedmanual\unskip}}%
+    %
+    \else\ifdim \wd\infofilenamebox > 0pt
+      % Cross-manual reference with only an info filename (arg 4), no
+      % printed manual name (arg 5).  This is essentially the same as
+      % the case above; we output the filename, since we have nothing else.
+      %
+      \crossmanualxref{\code{\infofilename\unskip}}%
+    %
+    \else
+      % Reference within this manual.
+      %
+      % 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 the macro below 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}{}%
+      % Add a , if xref followed by a space
+      \if\space\noexpand\tokenafterxref ,%
+      \else\ifx\	\tokenafterxref ,% @TAB
+      \else\ifx\*\tokenafterxref ,%   @*
+      \else\ifx\ \tokenafterxref ,%   @SPACE
+      \else\ifx\
+                \tokenafterxref ,%    @NL
+      \else\ifx\tie\tokenafterxref ,% @tie
+      \fi\fi\fi\fi\fi\fi
+    \fi\fi
+  \fi
+  \endlink
+\endgroup}
+
+% Output a cross-manual xref to #1.  Used just above (twice).
+%
+% Only include the text "Section ``foo'' in" if the foo is neither
+% missing or Top.  Thus, @xref{,,,foo,The Foo Manual} outputs simply
+% "see The Foo Manual", the idea being to refer to the whole manual.
+%
+% But, this being TeX, we can't easily compare our node name against the
+% string "Top" while ignoring the possible spaces before and after in
+% the input.  By adding the arbitrary 7sp below, we make it much less
+% likely that a real node name would have the same width as "Top" (e.g.,
+% in a monospaced font).  Hopefully it will never happen in practice.
+%
+% For the same basic reason, we retypeset the "Top" at every
+% reference, since the current font is indeterminate.
+%
+\def\crossmanualxref#1{%
+  \setbox\toprefbox = \hbox{Top\kern7sp}%
+  \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}%
+  \ifdim \wd2 > 7sp  % nonempty?
+    \ifdim \wd2 = \wd\toprefbox \else  % same as Top?
+      \putwordSection{} ``\printedrefname'' \putwordin{}\space
+    \fi
+  \fi
+  #1%
+}
+
+% 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
+}
+
+% \refx{NAME}{SUFFIX} - reference a cross-reference string named NAME.  SUFFIX
+% is output afterwards if non-empty.
+\def\refx#1#2{%
+  \requireauxfile
+  {%
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \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
+        {\toks0 = {#1}% avoid expansion of possibly-complex value
+         \message{\linenumber Undefined cross reference `\the\toks0'.}}%
+      \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.  Define a control
+% sequence for a cross-reference target (we prepend XR to the control sequence
+% name to avoid collisions).  The value is the page number.  If this is a float
+% type, we have more work to do.
+%
+\def\xrdef#1#2{%
+  {% Expand the node or anchor name to remove control sequences.
+   % \turnoffactive stops 8-bit characters being changed to commands
+   % like @'e.  \refx does the same to retrieve the value in the definition.
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \xdef\safexrefname{#1}%
+  }%
+  %
+  \bgroup
+    \expandafter\gdef\csname XR\safexrefname\endcsname{#2}%
+  \egroup
+  % We put the \gdef inside a group to avoid the definitions building up on
+  % TeX's save stack, which can cause it to run out of space for aux files with
+  % thousands of lines.  \gdef doesn't use the save stack, but \csname does
+  % when it defines an unknown control sequence as \relax.
+  %
+  % 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
+}
+
+% 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 at the beginning of the file.
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% Used when writing to the aux file, or when using data from it.
+\def\requireauxfile{%
+  \iflinks
+    \tryauxfile
+    % Open the new aux file.  TeX will close it automatically at exit.
+    \immediate\openout\auxfile=\jobname.aux
+  \fi
+  \global\let\requireauxfile=\relax   % Only do this once.
+}
+
+% 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
+  \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
+  %
+  \catcode`\\=\active
+  %
+  % @ 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{%
+  \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
+  %
+  % Nested footnotes are not supported in TeX, that would take a lot
+  % more work.  (\startsavinginserts does not suffice.)
+  \let\footnote=\errfootnotenest
+  %
+  % 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=\txipagewidth
+  \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
+  %
+  % Invoke rest of plain TeX footnote routine.
+  \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+\def\errfootnotenest{%
+  \errhelp=\EMsimple
+  \errmessage{Nested footnotes not supported in texinfo.tex,
+    even though they work in makeinfo; sorry}
+}
+
+\def\errfootnoteheading{%
+  \errhelp=\EMsimple
+  \errmessage{Footnotes in chapters, sections, etc., are not supported}
+}
+
+% 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 https://ctan.org/texarchive/macros/texinfo/texinfo/doc/epsf.tex.}
+%
+\def\image#1{%
+  \ifx\epsfbox\thisisundefined
+    \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 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
+  \def\xprocessmacroarg{\eatspaces}% in case we are being used via a macro
+  % If the image is by itself, center it.
+  \ifvmode
+    \imagevmodetrue
+  \else \ifx\centersub\centerV
+    % for @center @image, we need a vbox so we can have our vertical space
+    \imagevmodetrue
+    \vbox\bgroup % vbox has better behavior than vtop herev
+  \fi\fi
+  %
+  \ifimagevmode
+    \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.
+  % However, if we're at the top level, we don't want the
+  %  normal paragraph indentation.
+  % On the other hand, if we are in the case of @center @image, we don't
+  %  want to start a paragraph, which will create a hsize-width box and
+  %  eradicate the centering.
+  \ifx\centersub\centerV\else \noindent \fi
+  %
+  % Output the image.
+  \ifpdf
+    % For pdfTeX and LuaTeX <= 0.80
+    \dopdfimage{#1}{#2}{#3}%
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+      % For epsf.tex
+      % \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}%
+    \else
+      % For XeTeX
+      \doxeteximage{#1}{#2}{#3}%
+    \fi
+  \fi
+  %
+  \ifimagevmode
+    \medskip  % space after a standalone image
+  \fi
+  \ifx\centersub\centerV \egroup \fi
+\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 \currentsection 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\currentsection{\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.
+      {%
+        \requireauxfile
+        \atdummies
+        %
+        \ifx\thisshortcaption\empty
+          \def\gtemp{\thiscaption}%
+        \else
+          \def\gtemp{\thisshortcaption}%
+        \fi
+        \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+          \ifx\gtemp\empty \else : \gtemp \fi}}%
+      }%
+    \fi
+  \egroup  % end of \vtop
+  %
+  \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
+% \currentsection 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{%
+  \tex % read txi-??.tex file in plain TeX.
+    % Read the file by the name they passed if it exists.
+    \let_ = \normalunderscore  % normal _ character for filename test
+    \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
+}
+%
+% 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
+}
+
+% XeTeX and LuaTeX can handle Unicode natively.
+% Their default I/O uses UTF-8 sequences instead of a byte-wise operation.
+% Other TeX engines' I/O (pdfTeX, etc.) is byte-wise.
+%
+\newif\iftxinativeunicodecapable
+\newif\iftxiusebytewiseio
+
+\ifx\XeTeXrevision\thisisundefined
+  \ifx\luatexversion\thisisundefined
+    \txinativeunicodecapablefalse
+    \txiusebytewiseiotrue
+  \else
+    \txinativeunicodecapabletrue
+    \txiusebytewiseiofalse
+  \fi
+\else
+  \txinativeunicodecapabletrue
+  \txiusebytewiseiofalse
+\fi
+
+% Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex
+% for non-UTF-8 (byte-wise) encodings.
+%
+\def\setbytewiseio{%
+  \ifx\XeTeXrevision\thisisundefined
+  \else
+    \XeTeXdefaultencoding "bytes"  % For subsequent files to be read
+    \XeTeXinputencoding "bytes"  % For document root file
+    % Unfortunately, there seems to be no corresponding XeTeX command for
+    % output encoding.  This is a problem for auxiliary index and TOC files.
+    % The only solution would be perhaps to write out @U{...} sequences in
+    % place of non-ASCII characters.
+  \fi
+
+  \ifx\luatexversion\thisisundefined
+  \else
+    \directlua{
+    local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub
+    local function convert_char (char)
+      return utf8_char(byte(char))
+    end
+
+    local function convert_line (line)
+      return gsub(line, ".", convert_char)
+    end
+
+    callback.register("process_input_buffer", convert_line)
+
+    local function convert_line_out (line)
+      local line_out = ""
+      for c in string.utfvalues(line) do
+         line_out = line_out .. string.char(c)
+      end
+      return line_out
+    end
+
+    callback.register("process_output_buffer", convert_line_out)
+    }
+  \fi
+
+  \txiusebytewiseiotrue
+}
+
+
+% 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.
+%
+\def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz}
+\def\documentencodingzzz#1{%
+  %
+  % 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
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \lattwochardefs
+  %
+  \else \ifx \declaredencoding \latone
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \latonechardefs
+  %
+  \else \ifx \declaredencoding \latnine
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \latninechardefs
+  %
+  \else \ifx \declaredencoding \utfeight
+     \iftxinativeunicodecapable
+       % For native Unicode handling (XeTeX and LuaTeX)
+       \nativeunicodechardefs
+     \else
+       % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX)
+       \setnonasciicharscatcode\active
+       % since we already invoked \utfeightchardefs at the top level
+       % (below), do not re-invoke it, otherwise our check for duplicated
+       % definitions gets triggered.  Making non-ascii chars active is
+       % sufficient.
+     \fi
+  %
+  \else
+    \message{Ignoring unknown document encoding: #1.}%
+  %
+  \fi % utfeight
+  \fi % latnine
+  \fi % latone
+  \fi % lattwo
+  \fi % ascii
+  %
+  \ifx\XeTeXrevision\thisisundefined
+  \else
+    \ifx \declaredencoding \utfeight
+    \else
+      \ifx \declaredencoding \ascii
+      \else
+        \message{Warning: XeTeX with non-UTF-8 encodings cannot handle %
+        non-ASCII characters in auxiliary files.}%
+      \fi
+    \fi
+  \fi
+}
+
+% emacs-page
+% A message to be logged when using a character that isn't available
+% the default font encoding (OT1).
+%
+\def\missingcharmsg#1{\message{Character missing, sorry: #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
+%
+
+\def\gdefchar#1#2{%
+\gdef#1{%
+   \ifpassthroughchars
+     \string#1%
+   \else
+     #2%
+   \fi
+}}
+
+% Latin1 (ISO-8859-1) character definitions.
+\def\latonechardefs{%
+  \gdefchar^^a0{\tie}
+  \gdefchar^^a1{\exclamdown}
+  \gdefchar^^a2{{\tcfont \char162}} % cent
+  \gdefchar^^a3{\pounds{}}
+  \gdefchar^^a4{{\tcfont \char164}} % currency
+  \gdefchar^^a5{{\tcfont \char165}} % yen
+  \gdefchar^^a6{{\tcfont \char166}} % broken bar
+  \gdefchar^^a7{\S}
+  \gdefchar^^a8{\"{}}
+  \gdefchar^^a9{\copyright{}}
+  \gdefchar^^aa{\ordf}
+  \gdefchar^^ab{\guillemetleft{}}
+  \gdefchar^^ac{\ensuremath\lnot}
+  \gdefchar^^ad{\-}
+  \gdefchar^^ae{\registeredsymbol{}}
+  \gdefchar^^af{\={}}
+  %
+  \gdefchar^^b0{\textdegree}
+  \gdefchar^^b1{$\pm$}
+  \gdefchar^^b2{$^2$}
+  \gdefchar^^b3{$^3$}
+  \gdefchar^^b4{\'{}}
+  \gdefchar^^b5{$\mu$}
+  \gdefchar^^b6{\P}
+  \gdefchar^^b7{\ensuremath\cdot}
+  \gdefchar^^b8{\cedilla\ }
+  \gdefchar^^b9{$^1$}
+  \gdefchar^^ba{\ordm}
+  \gdefchar^^bb{\guillemetright{}}
+  \gdefchar^^bc{$1\over4$}
+  \gdefchar^^bd{$1\over2$}
+  \gdefchar^^be{$3\over4$}
+  \gdefchar^^bf{\questiondown}
+  %
+  \gdefchar^^c0{\`A}
+  \gdefchar^^c1{\'A}
+  \gdefchar^^c2{\^A}
+  \gdefchar^^c3{\~A}
+  \gdefchar^^c4{\"A}
+  \gdefchar^^c5{\ringaccent A}
+  \gdefchar^^c6{\AE}
+  \gdefchar^^c7{\cedilla C}
+  \gdefchar^^c8{\`E}
+  \gdefchar^^c9{\'E}
+  \gdefchar^^ca{\^E}
+  \gdefchar^^cb{\"E}
+  \gdefchar^^cc{\`I}
+  \gdefchar^^cd{\'I}
+  \gdefchar^^ce{\^I}
+  \gdefchar^^cf{\"I}
+  %
+  \gdefchar^^d0{\DH}
+  \gdefchar^^d1{\~N}
+  \gdefchar^^d2{\`O}
+  \gdefchar^^d3{\'O}
+  \gdefchar^^d4{\^O}
+  \gdefchar^^d5{\~O}
+  \gdefchar^^d6{\"O}
+  \gdefchar^^d7{$\times$}
+  \gdefchar^^d8{\O}
+  \gdefchar^^d9{\`U}
+  \gdefchar^^da{\'U}
+  \gdefchar^^db{\^U}
+  \gdefchar^^dc{\"U}
+  \gdefchar^^dd{\'Y}
+  \gdefchar^^de{\TH}
+  \gdefchar^^df{\ss}
+  %
+  \gdefchar^^e0{\`a}
+  \gdefchar^^e1{\'a}
+  \gdefchar^^e2{\^a}
+  \gdefchar^^e3{\~a}
+  \gdefchar^^e4{\"a}
+  \gdefchar^^e5{\ringaccent a}
+  \gdefchar^^e6{\ae}
+  \gdefchar^^e7{\cedilla c}
+  \gdefchar^^e8{\`e}
+  \gdefchar^^e9{\'e}
+  \gdefchar^^ea{\^e}
+  \gdefchar^^eb{\"e}
+  \gdefchar^^ec{\`{\dotless i}}
+  \gdefchar^^ed{\'{\dotless i}}
+  \gdefchar^^ee{\^{\dotless i}}
+  \gdefchar^^ef{\"{\dotless i}}
+  %
+  \gdefchar^^f0{\dh}
+  \gdefchar^^f1{\~n}
+  \gdefchar^^f2{\`o}
+  \gdefchar^^f3{\'o}
+  \gdefchar^^f4{\^o}
+  \gdefchar^^f5{\~o}
+  \gdefchar^^f6{\"o}
+  \gdefchar^^f7{$\div$}
+  \gdefchar^^f8{\o}
+  \gdefchar^^f9{\`u}
+  \gdefchar^^fa{\'u}
+  \gdefchar^^fb{\^u}
+  \gdefchar^^fc{\"u}
+  \gdefchar^^fd{\'y}
+  \gdefchar^^fe{\th}
+  \gdefchar^^ff{\"y}
+}
+
+% Latin9 (ISO-8859-15) encoding character definitions.
+\def\latninechardefs{%
+  % Encoding is almost identical to Latin1.
+  \latonechardefs
+  %
+  \gdefchar^^a4{\euro{}}
+  \gdefchar^^a6{\v S}
+  \gdefchar^^a8{\v s}
+  \gdefchar^^b4{\v Z}
+  \gdefchar^^b8{\v z}
+  \gdefchar^^bc{\OE}
+  \gdefchar^^bd{\oe}
+  \gdefchar^^be{\"Y}
+}
+
+% Latin2 (ISO-8859-2) character definitions.
+\def\lattwochardefs{%
+  \gdefchar^^a0{\tie}
+  \gdefchar^^a1{\ogonek{A}}
+  \gdefchar^^a2{\u{}}
+  \gdefchar^^a3{\L}
+  \gdefchar^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdefchar^^a5{\v L}
+  \gdefchar^^a6{\'S}
+  \gdefchar^^a7{\S}
+  \gdefchar^^a8{\"{}}
+  \gdefchar^^a9{\v S}
+  \gdefchar^^aa{\cedilla S}
+  \gdefchar^^ab{\v T}
+  \gdefchar^^ac{\'Z}
+  \gdefchar^^ad{\-}
+  \gdefchar^^ae{\v Z}
+  \gdefchar^^af{\dotaccent Z}
+  %
+  \gdefchar^^b0{\textdegree{}}
+  \gdefchar^^b1{\ogonek{a}}
+  \gdefchar^^b2{\ogonek{ }}
+  \gdefchar^^b3{\l}
+  \gdefchar^^b4{\'{}}
+  \gdefchar^^b5{\v l}
+  \gdefchar^^b6{\'s}
+  \gdefchar^^b7{\v{}}
+  \gdefchar^^b8{\cedilla\ }
+  \gdefchar^^b9{\v s}
+  \gdefchar^^ba{\cedilla s}
+  \gdefchar^^bb{\v t}
+  \gdefchar^^bc{\'z}
+  \gdefchar^^bd{\H{}}
+  \gdefchar^^be{\v z}
+  \gdefchar^^bf{\dotaccent z}
+  %
+  \gdefchar^^c0{\'R}
+  \gdefchar^^c1{\'A}
+  \gdefchar^^c2{\^A}
+  \gdefchar^^c3{\u A}
+  \gdefchar^^c4{\"A}
+  \gdefchar^^c5{\'L}
+  \gdefchar^^c6{\'C}
+  \gdefchar^^c7{\cedilla C}
+  \gdefchar^^c8{\v C}
+  \gdefchar^^c9{\'E}
+  \gdefchar^^ca{\ogonek{E}}
+  \gdefchar^^cb{\"E}
+  \gdefchar^^cc{\v E}
+  \gdefchar^^cd{\'I}
+  \gdefchar^^ce{\^I}
+  \gdefchar^^cf{\v D}
+  %
+  \gdefchar^^d0{\DH}
+  \gdefchar^^d1{\'N}
+  \gdefchar^^d2{\v N}
+  \gdefchar^^d3{\'O}
+  \gdefchar^^d4{\^O}
+  \gdefchar^^d5{\H O}
+  \gdefchar^^d6{\"O}
+  \gdefchar^^d7{$\times$}
+  \gdefchar^^d8{\v R}
+  \gdefchar^^d9{\ringaccent U}
+  \gdefchar^^da{\'U}
+  \gdefchar^^db{\H U}
+  \gdefchar^^dc{\"U}
+  \gdefchar^^dd{\'Y}
+  \gdefchar^^de{\cedilla T}
+  \gdefchar^^df{\ss}
+  %
+  \gdefchar^^e0{\'r}
+  \gdefchar^^e1{\'a}
+  \gdefchar^^e2{\^a}
+  \gdefchar^^e3{\u a}
+  \gdefchar^^e4{\"a}
+  \gdefchar^^e5{\'l}
+  \gdefchar^^e6{\'c}
+  \gdefchar^^e7{\cedilla c}
+  \gdefchar^^e8{\v c}
+  \gdefchar^^e9{\'e}
+  \gdefchar^^ea{\ogonek{e}}
+  \gdefchar^^eb{\"e}
+  \gdefchar^^ec{\v e}
+  \gdefchar^^ed{\'{\dotless{i}}}
+  \gdefchar^^ee{\^{\dotless{i}}}
+  \gdefchar^^ef{\v d}
+  %
+  \gdefchar^^f0{\dh}
+  \gdefchar^^f1{\'n}
+  \gdefchar^^f2{\v n}
+  \gdefchar^^f3{\'o}
+  \gdefchar^^f4{\^o}
+  \gdefchar^^f5{\H o}
+  \gdefchar^^f6{\"o}
+  \gdefchar^^f7{$\div$}
+  \gdefchar^^f8{\v r}
+  \gdefchar^^f9{\ringaccent u}
+  \gdefchar^^fa{\'u}
+  \gdefchar^^fb{\H u}
+  \gdefchar^^fc{\"u}
+  \gdefchar^^fd{\'y}
+  \gdefchar^^fe{\cedilla t}
+  \gdefchar^^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
+}
+
+% Give non-ASCII bytes the active definitions for processing UTF-8 sequences
+\begingroup
+  \catcode`\~13
+  \catcode`\$12
+  \catcode`\"12
+
+  % Loop from \countUTFx to \countUTFy, performing \UTFviiiTmp
+  % substituting ~ and $ with a character token of that value.
+  \def\UTFviiiLoop{%
+    \global\catcode\countUTFx\active
+    \uccode`\~\countUTFx
+    \uccode`\$\countUTFx
+    \uppercase\expandafter{\UTFviiiTmp}%
+    \advance\countUTFx by 1
+    \ifnum\countUTFx < \countUTFy
+      \expandafter\UTFviiiLoop
+    \fi}
+
+  % For bytes other than the first in a UTF-8 sequence.  Not expected to
+  % be expanded except when writing to auxiliary files.
+  \countUTFx = "80
+  \countUTFy = "C2
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "C2
+  \countUTFy = "E0
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "E0
+  \countUTFy = "F0
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "F0
+  \countUTFy = "F4
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiFourOctets\expandafter$\fi
+        }}%
+  \UTFviiiLoop
+\endgroup
+
+\def\globallet{\global\let} % save some \expandafter's below
+
+% @U{xxxx} to produce U+xxxx, if we support it.
+\def\U#1{%
+  \expandafter\ifx\csname uni:#1\endcsname \relax
+    \iftxinativeunicodecapable
+      % All Unicode characters can be used if native Unicode handling is
+      % active.  However, if the font does not have the glyph,
+      % letters are missing.
+      \begingroup
+        \uccode`\.="#1\relax
+        \uppercase{.}
+      \endgroup
+    \else
+      \errhelp = \EMsimple
+      \errmessage{Unicode character U+#1 not supported, sorry}%
+    \fi
+  \else
+    \csname uni:#1\endcsname
+  \fi
+}
+
+% These macros are used here to construct the name of a control
+% sequence to be defined.
+\def\UTFviiiTwoOctetsName#1#2{%
+  \csname u8:#1\string #2\endcsname}%
+\def\UTFviiiThreeOctetsName#1#2#3{%
+  \csname u8:#1\string #2\string #3\endcsname}%
+\def\UTFviiiFourOctetsName#1#2#3#4{%
+  \csname u8:#1\string #2\string #3\string #4\endcsname}%
+
+% For UTF-8 byte sequences (TeX, e-TeX and pdfTeX),
+% provide a definition macro to replace a Unicode character;
+% this gets used by the @U command
+%
+\begingroup
+  \catcode`\"=12
+  \catcode`\<=12
+  \catcode`\.=12
+  \catcode`\,=12
+  \catcode`\;=12
+  \catcode`\!=12
+  \catcode`\~=13
+  \gdef\DeclareUnicodeCharacterUTFviii#1#2{%
+    \countUTFz = "#1\relax
+    \begingroup
+      \parseXMLCharref
+
+      % Give \u8:... its definition.  The sequence of seven \expandafter's
+      % expands after the \gdef three times, e.g.
+      %
+      % 1.  \UTFviiTwoOctetsName B1 B2
+      % 2.  \csname u8:B1 \string B2 \endcsname
+      % 3.  \u8: B1 B2  (a single control sequence token)
+      %
+      \expandafter\expandafter
+      \expandafter\expandafter
+      \expandafter\expandafter
+      \expandafter\gdef       \UTFviiiTmp{#2}%
+      %
+      \expandafter\ifx\csname uni:#1\endcsname \relax \else
+       \message{Internal error, already defined: #1}%
+      \fi
+      %
+      % define an additional control sequence for this code point.
+      \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp
+    \endgroup}
+  %
+  % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp
+  % to the corresponding UTF-8 sequence.
+  \gdef\parseXMLCharref{%
+    \ifnum\countUTFz < "A0\relax
+      \errhelp = \EMsimple
+      \errmessage{Cannot define Unicode char value < 00A0}%
+    \else\ifnum\countUTFz < "800\relax
+      \parseUTFviiiA,%
+      \parseUTFviiiB C\UTFviiiTwoOctetsName.,%
+    \else\ifnum\countUTFz < "10000\relax
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiB E\UTFviiiThreeOctetsName.{,;}%
+    \else
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiA!%
+      \parseUTFviiiB F\UTFviiiFourOctetsName.{!,;}%
+    \fi\fi\fi
+  }
+
+  % Extract a byte from the end of the UTF-8 representation of \countUTFx.
+  % It must be a non-initial byte in the sequence.
+  % Change \uccode of #1 for it to be used in \parseUTFviiiB as one
+  % of the bytes.
+  \gdef\parseUTFviiiA#1{%
+    \countUTFx = \countUTFz
+    \divide\countUTFz by 64
+    \countUTFy = \countUTFz  % Save to be the future value of \countUTFz.
+    \multiply\countUTFz by 64
+
+    % \countUTFz is now \countUTFx with the last 5 bits cleared.  Subtract
+    % in order to get the last five bits.
+    \advance\countUTFx by -\countUTFz
+
+    % Convert this to the byte in the UTF-8 sequence.
+    \advance\countUTFx by 128
+    \uccode `#1\countUTFx
+    \countUTFz = \countUTFy}
+
+  % Used to put a UTF-8 byte sequence into \UTFviiiTmp
+  % #1 is the increment for \countUTFz to yield a the first byte of the UTF-8
+  %    sequence.
+  % #2 is one of the \UTFviii*OctetsName macros.
+  % #3 is always a full stop (.)
+  % #4 is a template for the other bytes in the sequence.  The values for these
+  %    bytes is substituted in here with \uppercase using the \uccode's.
+  \gdef\parseUTFviiiB#1#2#3#4{%
+    \advance\countUTFz by "#10\relax
+    \uccode `#3\countUTFz
+    \uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
+\endgroup
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro that sets a catcode to `other' non-globally
+%
+\def\DeclareUnicodeCharacterNativeOther#1#2{%
+  \catcode"#1=\other
+}
+
+% https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M
+% U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
+% U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)
+% U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A
+% U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B
+%
+% Many of our renditions are less than wonderful, and all the missing
+% characters are available somewhere.  Loading the necessary fonts
+% awaits user request.  We can't truly support Unicode without
+% reimplementing everything that's been done in LaTeX for many years,
+% plus probably using luatex or xetex, and who knows what else.
+% We won't be doing that here in this simple file.  But we can try to at
+% least make most of the characters not bomb out.
+%
+\def\unicodechardefs{%
+  \DeclareUnicodeCharacter{00A0}{\tie}%
+  \DeclareUnicodeCharacter{00A1}{\exclamdown}%
+  \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent
+  \DeclareUnicodeCharacter{00A3}{\pounds{}}%
+  \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency
+  \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen
+  \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar
+  \DeclareUnicodeCharacter{00A7}{\S}%
+  \DeclareUnicodeCharacter{00A8}{\"{ }}%
+  \DeclareUnicodeCharacter{00A9}{\copyright{}}%
+  \DeclareUnicodeCharacter{00AA}{\ordf}%
+  \DeclareUnicodeCharacter{00AB}{\guillemetleft{}}%
+  \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}%
+  \DeclareUnicodeCharacter{00AD}{\-}%
+  \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}%
+  \DeclareUnicodeCharacter{00AF}{\={ }}%
+  %
+  \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}%
+  \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}%
+  \DeclareUnicodeCharacter{00B2}{$^2$}%
+  \DeclareUnicodeCharacter{00B3}{$^3$}%
+  \DeclareUnicodeCharacter{00B4}{\'{ }}%
+  \DeclareUnicodeCharacter{00B5}{$\mu$}%
+  \DeclareUnicodeCharacter{00B6}{\P}%
+  \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}%
+  \DeclareUnicodeCharacter{00B8}{\cedilla{ }}%
+  \DeclareUnicodeCharacter{00B9}{$^1$}%
+  \DeclareUnicodeCharacter{00BA}{\ordm}%
+  \DeclareUnicodeCharacter{00BB}{\guillemetright{}}%
+  \DeclareUnicodeCharacter{00BC}{$1\over4$}%
+  \DeclareUnicodeCharacter{00BD}{$1\over2$}%
+  \DeclareUnicodeCharacter{00BE}{$3\over4$}%
+  \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{00D7}{\ensuremath\times}%
+  \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{00F7}{\ensuremath\div}%
+  \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{010A}{\dotaccent{C}}%
+  \DeclareUnicodeCharacter{010B}{\dotaccent{c}}%
+  \DeclareUnicodeCharacter{010C}{\v{C}}%
+  \DeclareUnicodeCharacter{010D}{\v{c}}%
+  \DeclareUnicodeCharacter{010E}{\v{D}}%
+  \DeclareUnicodeCharacter{010F}{d'}%
+  %
+  \DeclareUnicodeCharacter{0110}{\DH}%
+  \DeclareUnicodeCharacter{0111}{\dh}%
+  \DeclareUnicodeCharacter{0112}{\=E}%
+  \DeclareUnicodeCharacter{0113}{\=e}%
+  \DeclareUnicodeCharacter{0114}{\u{E}}%
+  \DeclareUnicodeCharacter{0115}{\u{e}}%
+  \DeclareUnicodeCharacter{0116}{\dotaccent{E}}%
+  \DeclareUnicodeCharacter{0117}{\dotaccent{e}}%
+  \DeclareUnicodeCharacter{0118}{\ogonek{E}}%
+  \DeclareUnicodeCharacter{0119}{\ogonek{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{0122}{\cedilla{G}}%
+  \DeclareUnicodeCharacter{0123}{\cedilla{g}}%
+  \DeclareUnicodeCharacter{0124}{\^H}%
+  \DeclareUnicodeCharacter{0125}{\^h}%
+  \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}%
+  \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}%
+  \DeclareUnicodeCharacter{0128}{\~I}%
+  \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}%
+  \DeclareUnicodeCharacter{012A}{\=I}%
+  \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}%
+  \DeclareUnicodeCharacter{012C}{\u{I}}%
+  \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}%
+  \DeclareUnicodeCharacter{012E}{\ogonek{I}}%
+  \DeclareUnicodeCharacter{012F}{\ogonek{i}}%
+  %
+  \DeclareUnicodeCharacter{0130}{\dotaccent{I}}%
+  \DeclareUnicodeCharacter{0131}{\dotless{i}}%
+  \DeclareUnicodeCharacter{0132}{IJ}%
+  \DeclareUnicodeCharacter{0133}{ij}%
+  \DeclareUnicodeCharacter{0134}{\^J}%
+  \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}%
+  \DeclareUnicodeCharacter{0136}{\cedilla{K}}%
+  \DeclareUnicodeCharacter{0137}{\cedilla{k}}%
+  \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}%
+  \DeclareUnicodeCharacter{0139}{\'L}%
+  \DeclareUnicodeCharacter{013A}{\'l}%
+  \DeclareUnicodeCharacter{013B}{\cedilla{L}}%
+  \DeclareUnicodeCharacter{013C}{\cedilla{l}}%
+  \DeclareUnicodeCharacter{013D}{L'}% should kern
+  \DeclareUnicodeCharacter{013E}{l'}% should kern
+  \DeclareUnicodeCharacter{013F}{L\U{00B7}}%
+  %
+  \DeclareUnicodeCharacter{0140}{l\U{00B7}}%
+  \DeclareUnicodeCharacter{0141}{\L}%
+  \DeclareUnicodeCharacter{0142}{\l}%
+  \DeclareUnicodeCharacter{0143}{\'N}%
+  \DeclareUnicodeCharacter{0144}{\'n}%
+  \DeclareUnicodeCharacter{0145}{\cedilla{N}}%
+  \DeclareUnicodeCharacter{0146}{\cedilla{n}}%
+  \DeclareUnicodeCharacter{0147}{\v{N}}%
+  \DeclareUnicodeCharacter{0148}{\v{n}}%
+  \DeclareUnicodeCharacter{0149}{'n}%
+  \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}%
+  \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}%
+  \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{0156}{\cedilla{R}}%
+  \DeclareUnicodeCharacter{0157}{\cedilla{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{0165}{\v{t}}%
+  \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}%
+  \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}%
+  \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{0172}{\ogonek{U}}%
+  \DeclareUnicodeCharacter{0173}{\ogonek{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{017F}{\missingcharmsg{LONG S}}%
+  %
+  \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{02BC}{'}%
+  %
+  \DeclareUnicodeCharacter{02DB}{\ogonek{ }}%
+  %
+  % Greek letters upper case
+  \DeclareUnicodeCharacter{0391}{{\it A}}%
+  \DeclareUnicodeCharacter{0392}{{\it B}}%
+  \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}%
+  \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}%
+  \DeclareUnicodeCharacter{0395}{{\it E}}%
+  \DeclareUnicodeCharacter{0396}{{\it Z}}%
+  \DeclareUnicodeCharacter{0397}{{\it H}}%
+  \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}%
+  \DeclareUnicodeCharacter{0399}{{\it I}}%
+  \DeclareUnicodeCharacter{039A}{{\it K}}%
+  \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}%
+  \DeclareUnicodeCharacter{039C}{{\it M}}%
+  \DeclareUnicodeCharacter{039D}{{\it N}}%
+  \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}%
+  \DeclareUnicodeCharacter{039F}{{\it O}}%
+  \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}%
+  \DeclareUnicodeCharacter{03A1}{{\it P}}%
+  %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma
+  \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}%
+  \DeclareUnicodeCharacter{03A4}{{\it T}}%
+  \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}%
+  \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}%
+  \DeclareUnicodeCharacter{03A7}{{\it X}}%
+  \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}%
+  \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}%
+  %
+  % Vowels with accents
+  \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}%
+  \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}%
+  \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}%
+  \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}%
+  \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}%
+  \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}%
+  %
+  % Standalone accent
+  \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}%
+  %
+  % Greek letters lower case
+  \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}%
+  \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}%
+  \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}%
+  \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}%
+  \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}%
+  \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}%
+  \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}%
+  \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}%
+  \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}%
+  \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}%
+  \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}%
+  \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}%
+  \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}%
+  \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}%
+  \DeclareUnicodeCharacter{03BF}{{\it o}}% omicron
+  \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}%
+  \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}%
+  \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}%
+  \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}%
+  \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}%
+  \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}%
+  \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}%
+  \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}%
+  \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}%
+  \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}%
+  %
+  % More Greek vowels with accents
+  \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}%
+  \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}%
+  \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}%
+  \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}%
+  \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}%
+  %
+  % Variant Greek letters
+  \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}%
+  \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}%
+  \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}%
+  %
+  \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}%
+  %
+  % Punctuation
+  \DeclareUnicodeCharacter{2013}{--}%
+  \DeclareUnicodeCharacter{2014}{---}%
+  \DeclareUnicodeCharacter{2018}{\quoteleft{}}%
+  \DeclareUnicodeCharacter{2019}{\quoteright{}}%
+  \DeclareUnicodeCharacter{201A}{\quotesinglbase{}}%
+  \DeclareUnicodeCharacter{201C}{\quotedblleft{}}%
+  \DeclareUnicodeCharacter{201D}{\quotedblright{}}%
+  \DeclareUnicodeCharacter{201E}{\quotedblbase{}}%
+  \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}%
+  \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}%
+  \DeclareUnicodeCharacter{2022}{\bullet{}}%
+  \DeclareUnicodeCharacter{202F}{\thinspace}%
+  \DeclareUnicodeCharacter{2026}{\dots{}}%
+  \DeclareUnicodeCharacter{2039}{\guilsinglleft{}}%
+  \DeclareUnicodeCharacter{203A}{\guilsinglright{}}%
+  %
+  \DeclareUnicodeCharacter{20AC}{\euro{}}%
+  %
+  \DeclareUnicodeCharacter{2192}{\expansion{}}%
+  \DeclareUnicodeCharacter{21D2}{\result{}}%
+  %
+  % Mathematical symbols
+  \DeclareUnicodeCharacter{2200}{\ensuremath\forall}%
+  \DeclareUnicodeCharacter{2203}{\ensuremath\exists}%
+  \DeclareUnicodeCharacter{2208}{\ensuremath\in}%
+  \DeclareUnicodeCharacter{2212}{\minus{}}%
+  \DeclareUnicodeCharacter{2217}{\ast}%
+  \DeclareUnicodeCharacter{221E}{\ensuremath\infty}%
+  \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}%
+  \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}%
+  \DeclareUnicodeCharacter{2229}{\ensuremath\cap}%
+  \DeclareUnicodeCharacter{2261}{\equiv{}}%
+  \DeclareUnicodeCharacter{2264}{\ensuremath\leq}%
+  \DeclareUnicodeCharacter{2265}{\ensuremath\geq}%
+  \DeclareUnicodeCharacter{2282}{\ensuremath\subset}%
+  \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}%
+  %
+  \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}%
+  \DeclareUnicodeCharacter{2032}{\ensuremath\prime}%
+  \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}%
+  \DeclareUnicodeCharacter{2111}{\ensuremath\Im}%
+  \DeclareUnicodeCharacter{2113}{\ensuremath\ell}%
+  \DeclareUnicodeCharacter{2118}{\ensuremath\wp}%
+  \DeclareUnicodeCharacter{211C}{\ensuremath\Re}%
+  \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}%
+  \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}%
+  \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}%
+  \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}%
+  \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}%
+  \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}%
+  \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}%
+  \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}%
+  \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}%
+  \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}%
+  \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}%
+  \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}%
+  \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}%
+  \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}%
+  \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}%
+  \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}%
+  \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}%
+  \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}%
+  \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}%
+  \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}%
+  \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}%
+  \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}%
+  \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}%
+  \DeclareUnicodeCharacter{2202}{\ensuremath\partial}%
+  \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}%
+  \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}%
+  \DeclareUnicodeCharacter{2209}{\ensuremath\notin}%
+  \DeclareUnicodeCharacter{220B}{\ensuremath\owns}%
+  \DeclareUnicodeCharacter{220F}{\ensuremath\prod}%
+  \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}%
+  \DeclareUnicodeCharacter{2211}{\ensuremath\sum}%
+  \DeclareUnicodeCharacter{2213}{\ensuremath\mp}%
+  \DeclareUnicodeCharacter{2218}{\ensuremath\circ}%
+  \DeclareUnicodeCharacter{221A}{\ensuremath\surd}%
+  \DeclareUnicodeCharacter{221D}{\ensuremath\propto}%
+  \DeclareUnicodeCharacter{2220}{\ensuremath\angle}%
+  \DeclareUnicodeCharacter{2223}{\ensuremath\mid}%
+  \DeclareUnicodeCharacter{2228}{\ensuremath\vee}%
+  \DeclareUnicodeCharacter{222A}{\ensuremath\cup}%
+  \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}%
+  \DeclareUnicodeCharacter{222E}{\ensuremath\oint}%
+  \DeclareUnicodeCharacter{223C}{\ensuremath\sim}%
+  \DeclareUnicodeCharacter{2240}{\ensuremath\wr}%
+  \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}%
+  \DeclareUnicodeCharacter{2245}{\ensuremath\cong}%
+  \DeclareUnicodeCharacter{2248}{\ensuremath\approx}%
+  \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}%
+  \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}%
+  \DeclareUnicodeCharacter{2260}{\ensuremath\neq}%
+  \DeclareUnicodeCharacter{226A}{\ensuremath\ll}%
+  \DeclareUnicodeCharacter{226B}{\ensuremath\gg}%
+  \DeclareUnicodeCharacter{227A}{\ensuremath\prec}%
+  \DeclareUnicodeCharacter{227B}{\ensuremath\succ}%
+  \DeclareUnicodeCharacter{2283}{\ensuremath\supset}%
+  \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}%
+  \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}%
+  \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}%
+  \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}%
+  \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}%
+  \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}%
+  \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}%
+  \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}%
+  \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}%
+  \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}%
+  \DeclareUnicodeCharacter{2299}{\ensuremath\odot}%
+  \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}%
+  \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}%
+  \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}%
+  \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}%
+  \DeclareUnicodeCharacter{22A8}{\ensuremath\models}%
+  \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}%
+  \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}%
+  \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}%
+  \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}%
+  \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}%
+  \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}%
+  \DeclareUnicodeCharacter{22C6}{\ensuremath\star}%
+  \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}%
+  \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}%
+  \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}%
+  \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}%
+  \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}%
+  \DeclareUnicodeCharacter{2322}{\ensuremath\frown}%
+  \DeclareUnicodeCharacter{2323}{\ensuremath\smile}%
+  %
+  \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}%
+  \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}%
+  \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}%
+  \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}%
+  \DeclareUnicodeCharacter{25C7}{\ensuremath\diamond}%
+  \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}%
+  \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}%
+  \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}%
+  \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}%
+  \DeclareUnicodeCharacter{266D}{\ensuremath\flat}%
+  \DeclareUnicodeCharacter{266E}{\ensuremath\natural}%
+  \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}%
+  \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}%
+  \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}%
+  \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}%
+  \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}%
+  \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}%
+  \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}%
+  \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}%
+  \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}%
+  \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}%
+  \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}%
+  \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}%
+  \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}%
+  \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}%
+  \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}%
+  \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}%
+  \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}%
+  \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}%
+  %
+  \global\mathchardef\checkmark="1370% actually the square root sign
+  \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}%
+}% end of \unicodechardefs
+
+% UTF-8 byte sequence (pdfTeX) definitions (replacing and @U command)
+% It makes the setting that replace UTF-8 byte sequence.
+\def\utfeightchardefs{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterUTFviii
+  \unicodechardefs
+}
+
+% Whether the active definitions of non-ASCII characters expand to
+% non-active tokens with the same character code.  This is used to
+% write characters literally, instead of using active definitions for
+% printing the correct glyphs.
+\newif\ifpassthroughchars
+\passthroughcharsfalse
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro to replace/pass-through a Unicode character
+%
+\def\DeclareUnicodeCharacterNative#1#2{%
+  \catcode"#1=\active
+  \def\dodeclareunicodecharacternative##1##2##3{%
+    \begingroup
+      \uccode`\~="##2\relax
+      \uppercase{\gdef~}{%
+        \ifpassthroughchars
+          ##1%
+        \else
+          ##3%
+        \fi
+      }
+    \endgroup
+  }
+  \begingroup
+    \uccode`\.="#1\relax
+    \uppercase{\def\UTFNativeTmp{.}}%
+    \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}%
+  \endgroup
+}
+
+% Native Unicode handling (XeTeX and LuaTeX) character replacing definition.
+% It activates the setting that replaces Unicode characters.
+\def\nativeunicodechardefs{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNative
+  \unicodechardefs
+}
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% make the character token expand
+% to the sequences given in \unicodechardefs for printing.
+\def\DeclareUnicodeCharacterNativeAtU#1#2{%
+  \def\UTFAtUTmp{#2}
+  \expandafter\globallet\csname uni:#1\endcsname \UTFAtUTmp
+}
+
+% @U command definitions for native Unicode handling (XeTeX and LuaTeX).
+\def\nativeunicodechardefsatu{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNativeAtU
+  \unicodechardefs
+}
+
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+   \relax
+}
+
+% Define all Unicode characters we know about.  This makes UTF-8 the default
+% input encoding and allows @U to work.
+\iftxinativeunicodecapable
+  \nativeunicodechardefsatu
+\else
+  \utfeightchardefs
+\fi
+
+\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 very finicky about underfull hboxes, either.
+\hbadness = 6666
+
+% 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
+  \txipageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \txipagewidth = \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
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+      \special{papersize=#8,#7}%
+    \else
+      \pdfpageheight #7\relax
+      \pdfpagewidth #8\relax
+      % XeTeX does not have \pdfhorigin and \pdfvorigin.
+    \fi
+  \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
+  \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
+  \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
+  \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
+  \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
+}}
+
+\def\bsixpaper{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{140mm}{100mm}%
+                    {-6.35mm}{-12.7mm}%
+                    {\bindingoffset}{14pt}%
+                    {176mm}{125mm}%
+  \let\SETdispenvsize=\smallword
+  \lispnarrowing = 0.2in
+  \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 2.5in % default 1in margin above heading line
+                           % and 1.5in to include heading, footing and
+                           % bottom margin
+  %
+  \dimen2 = \hsize
+  \advance\dimen2 by 2in % default to 1 inch margin on each side
+  %
+  \internalpagesizes{#1}{\hsize}%
+                    {\voffset}{\normaloffset}%
+                    {\bindingoffset}{44pt}%
+                    {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+% Default value of \hfuzz, for suppressing warnings about overfull hboxes.
+\hfuzz = 1pt
+
+
+\message{and turning on texinfo input format.}
+
+\def^^L{\par} % remove \outer, so ^L can appear in an @comment
+
+% 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 \def\normaldoublequote{"}
+\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix
+\catcode`\+=\other \def\normalplus{+}
+\catcode`\<=\other \def\normalless{<}
+\catcode`\>=\other \def\normalgreater{>}
+\catcode`\^=\other \def\normalcaret{^}
+\catcode`\_=\other \def\normalunderscore{_}
+\catcode`\|=\other \def\normalverticalbar{|}
+\catcode`\~=\other \def\normaltilde{~}
+
+% 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}
+
+% Set catcodes for Texinfo file
+
+% Active characters for printing the wanted glyph.
+% 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\activetilde{{\tt\char126}} \let~ = \activetilde
+\chardef\hatchar=`\^
+\catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+\let\realunder=_
+
+\catcode`\|=\active \def|{{\tt\char124}}
+
+\chardef \less=`\<
+\catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless
+\chardef \gtr=`\>
+\catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr
+\catcode`\+=\active \def+{{\tt \char 43}}
+\catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+\catcode`\-=\active \let-=\normaldash
+
+
+% used for headline/footline in the output routine, in case the page
+% breaks in the middle of an @tex block.
+\def\texinfochars{%
+  \let< = \activeless
+  \let> = \activegtr
+  \let~ = \activetilde
+  \let^ = \activehat
+  \markupsetuplqdefault \markupsetuprqdefault
+  \let\b = \strong
+  \let\i = \smartitalic
+  % in principle, all other definitions in \tex have to be undone too.
+}
+
+% 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=`\\
+
+% \realbackslash is an actual character `\' with catcode other.
+{\catcode`\\=\other @gdef@realbackslash{\}}
+
+% In Texinfo, backslash is an active character; it prints the backslash
+% in fixed width font.
+\catcode`\\=\active  % @ for escape char from now on.
+
+% Print a typewriter backslash.  For math mode, we can't simply use
+% \backslashcurfont: the story here is that in math mode, the \char
+% of \backslashcurfont ends up printing the roman \ from the math symbol
+% font (because \char in math mode uses the \mathcode, and plain.tex
+% sets \mathcode`\\="026E).  Hence we use an explicit \mathchar,
+% which is the decimal equivalent of "715c (class 7, e.g., use \fam;
+% ignored family value; char position "5C).  We can't use " for the
+% usual hex value because it has already been made active.
+
+@def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}}
+@let@backslashchar = @ttbackslash % @backslashchar{} is for user documents.
+
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other.
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.
+%
+{@catcode`- = @active
+ @gdef@normalturnoffactive{%
+   @passthroughcharstrue
+   @let-=@normaldash
+   @let"=@normaldoublequote
+   @let$=@normaldollar %$ font-lock fix
+   @let+=@normalplus
+   @let<=@normalless
+   @let>=@normalgreater
+   @let^=@normalcaret
+   @let_=@normalunderscore
+   @let|=@normalverticalbar
+   @let~=@normaltilde
+   @let\=@ttbackslash
+   @markupsetuplqdefault
+   @markupsetuprqdefault
+   @unsepspaces
+ }
+}
+
+% 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 @fixbackslash turn them back on.
+@catcode`+=@other @catcode`@_=@other
+
+% \enablebackslashhack - allow file to begin `\input texinfo'
+%
+% 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.
+% If the file did not have a `\input texinfo', then it is turned off after
+% the first line; otherwise the first `\' in the file would cause an error.
+% This is used on the very last line of this file, texinfo.tex.
+% We also use @c to call @fixbackslash, in case ends of lines are hidden.
+{
+@catcode`@^=7
+@catcode`@^^M=13@gdef@enablebackslashhack{%
+  @global@let\ = @eatinput%
+  @catcode`@^^M=13%
+  @def@c{@fixbackslash@c}%
+  % Definition for the newline at the end of this file.
+  @def ^^M{@let^^M@secondlinenl}%
+  % Definition for a newline in the main Texinfo file.
+  @gdef @secondlinenl{@fixbackslash}%
+  % In case the first line has a whole-line command on it
+  @let@originalparsearg@parsearg
+  @def@parsearg{@fixbackslash@originalparsearg}
+}}
+
+{@catcode`@^=7 @catcode`@^^M=13%
+@gdef@eatinput input texinfo#1^^M{@fixbackslash}}
+
+% Emergency active definition of newline, in case an active newline token
+% appears by mistake.
+{@catcode`@^=7 @catcode13=13%
+@gdef@enableemergencynewline{%
+  @gdef^^M{%
+    @par%
+    %<warning: active newline>@par%
+}}}
+
+
+@gdef@fixbackslash{%
+  @ifx\@eatinput @let\ = @ttbackslash @fi
+  @catcode13=5 % regular end of line
+  @enableemergencynewline
+  @let@c=@comment
+  @let@parsearg@originalparsearg
+  % Also turn back on active characters that might appear in the input
+  % file name, in case not using a pre-dumped format.
+  @catcode`+=@active
+  @catcode`@_=@active
+  %
+  % If texinfo.cnf is present on the system, read it.
+  % Useful for site-wide @afourpaper, etc.  This macro, @fixbackslash, gets
+  % called at the beginning of every Texinfo file.  Not opening texinfo.cnf
+  % directly in this file, texinfo.tex, makes it possible to make a format
+  % file for Texinfo.
+  %
+  @openin 1 texinfo.cnf
+  @ifeof 1 @else @input texinfo.cnf @fi
+  @closein 1
+}
+
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These (along with & and #) are made active for url-breaking, so need
+% active definitions as the normal characters.
+@def@normaldot{.}
+@def@normalquest{?}
+@def@normalslash{/}
+
+% These look ok in all fonts, so just make them not special.
+% @hashchar{} gets its own user-level command, because of #line.
+@catcode`@& = @other @def@normalamp{&}
+@catcode`@# = @other @def@normalhash{#}
+@catcode`@% = @other @def@normalpercent{%}
+
+@let @hashchar = @normalhash
+
+@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 'before-save-hook 'time-stamp)
+@c page-delimiter: "^\\\\message\\|emacs-page"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@enablebackslashhack
diff --git a/tgz.1 b/tgz.1
new file mode 100644
index 0000000..fea8b17
--- /dev/null
+++ b/tgz.1
@@ -0,0 +1,56 @@
+.\" tgz.1
+.\"		(c) 2001 Filip Van Raemdonck <mechanix@debian.org>
+.\"
+.\" This manpage is free documentation.
+.\" Permission is granted to copy, distribute and/or modify this document
+.\" under the terms of the GNU Free Documentation License, Version 1.1 or any
+.\" later version published by the Free Software Foundation; with no Invariant
+.\" Sections, no Front-Cover Texts, and no Back Cover Texts.
+.\"
+.\" This  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.
+.\"
+.\" You should have received a copy of the GNU Free Documentation License
+.\" along with this program; if not, write to: 
+.\"		Free Software Foundation, Inc.
+.\"		59 Temple Place - Suite 330
+.\"		Boston, MA  02111-1307, USA.
+.\"
+.\"
+.ig
+A copy of the GNU Free Documentation License is available in the
+Debian package in the file /usr/share/doc/mtools/copyright.
+..
+.ig
+A copy of the GNU Free Documentation License is available in the 
+Debian source package in the file debian/copyright.
+..
+.TH TGZ "1" "May 2002" "mtools 3.9.8" "Mtools Users Manual"
+.SH NAME
+tgz \- makes a gzip'd tar archive
+.SH SYNOPSIS
+.B tgz
+[
+.I destination
+[
+.I source ...
+] ]
+.SH DESCRIPTION
+Make a gzip'd tar archive with the name of the first parameter out of specified
+files or, if no source files are specified, from everything in the current
+directory.
+If the first parameter is omitted as well, the archive will be written to
+stdout.
+.SH BUGS
+.B tgz
+requires gzip in the user's path.
+It also needs gnu tar or something close due to use of --exclude, --totals
+and -S.
+.SH AUTHOR
+Filip Van Raemdonck (mechanix@debian.org) wrote this page for the
+.I Debian/GNU
+mtools package.
+.SH "SEE ALSO"
+.BR gzip (1),
+.BR tar (1)
diff --git a/tty.c b/tty.c
new file mode 100644
index 0000000..77529f8
--- /dev/null
+++ b/tty.c
@@ -0,0 +1,225 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdarg.h>
+#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
+#ifdef future
+#define FAIL (-1)
+#endif
+#define DONE 0
+static Terminal in_orig;
+
+/*--------------- Signal Handler routines -------------*/
+
+static void tty_time_out(int dummy UNUSEDP) NORETURN;
+static void tty_time_out(int dummy UNUSEDP)
+{
+	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..1f71d92
--- /dev/null
+++ b/unixdir.c
@@ -0,0 +1,168 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 <dirent.h>
+
+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 */
+	0, /* get_dosConvert */
+	0 /* discard */
+};
+
+#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(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/uz.1 b/uz.1
new file mode 100644
index 0000000..08cede9
--- /dev/null
+++ b/uz.1
@@ -0,0 +1,43 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for uz
+.\"
+.\" Copyright (C), 2000, Robert A.R. King
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Fri Dec  1 01:50:54 EST 2000 Robert A.R. King (Robert.King@mailbox.gu.edu.au)
+.\" 
+.TH UZ 1 "Wed Feb 23 00:00:00 EET 2000" "" "Mtools Users Manual"
+.SH NAME
+uz \- gunzips and extracts a gzip'd tar'd archive
+.SH SYNOPSIS
+.\" The command line
+.B uz 
+.I file
+.SH DESCRIPTION
+.B uz
+extracts a gzip'd tar'd archive, that is a \fBtar\fR(1) archive
+compressed with the \fBgzip\fR(1) utility.
+It is not strictly necessary on Debian GNU/Linux, because the GNU
+\fBtar\fR(1) program provides the same capability with the command
+
+.B tar -xzf
+.I file
+
+but this utility is provided in the mtools package for other platforms and 
+is retained here for completeness.
+
+.SH AUTHOR
+Robert King (Robert.King@mailbox.gu.edu.au) wrote this page for the
+.I Debian/GNU
+mtools package.
+
+
+.SH "SEE ALSO"
+.BR mtools (1), 
+.BR gzip (1),
+.BR tar (1),
+.BR lz (1).
diff --git a/version.texi b/version.texi
new file mode 100644
index 0000000..442de8e
--- /dev/null
+++ b/version.texi
@@ -0,0 +1,3 @@
+@set EDITION 4.0.26
+@set VERSION 4.0.26
+@set UPDATED November 2020
diff --git a/vfat.c b/vfat.c
new file mode 100644
index 0000000..3ca0fa3
--- /dev/null
+++ b/vfat.c
@@ -0,0 +1,840 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 "dirCacheP.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<end; ++name)
+		sum = ((sum & 1) ? 0x80 : 0) + (sum >> 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<<v->subentries) - 1)) != (1<<v->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 */
+}
+
+/**
+ * Read one complete entry from directory (main name plus any VSEs
+ * belonging to it)
+ */
+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;
+	int endmarkSeen = 0;
+
+	/* 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;
+			}
+			addFreeEndEntry(cache, initpos, direntry->entry,
+					endmarkSeen);
+			return addEndEntry(cache, direntry->entry);
+		}
+		
+		if (endmarkSeen || direntry->dir.name[0] == ENDMARK){
+				/* the end of the directory */
+			if(lookForFreeSpace) {
+				endmarkSeen = 1;
+				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;
+		if (direntry->dir.name[0] == '\x05') {
+			ptr += dos_to_wchar(cp, "\xE5", ptr, 1);
+			ptr += dos_to_wchar(cp, direntry->dir.name+1, ptr, 7);
+		} else {
+			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;
+#ifdef DEBUG
+		default:
+			fprintf(stderr, "Unexpected entry type %d\n",
+				dce->type);
+			return RES_ERROR;
+#endif
+	}
+
+	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, size_t shortname_size,
+		char *longname, size_t longname_size)
+{
+	dirCacheEntry_t *dce;
+	result_t result;
+	dirCache_t *cache;
+	int io_error;
+	wchar_t wfilename[MAX_VNAMELEN+1];
+	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
+		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, longname_size);
+			else
+				*longname ='\0';
+		}
+		if(shortname)
+			wchar_to_native(dce->shortName, shortname,
+					12, shortname_size);
+		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 & 1)
+		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 <http://www.gnu.org/licenses/>.
+ */
+
+#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..db02414
--- /dev/null
+++ b/xdf_io.c
@@ -0,0 +1,709 @@
+/*  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 <http://www.gnu.org/licenses/>.
+ *
+ * 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;
+
+
+static 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;
+	unsigned int FatSize;
+	unsigned 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, unsigned 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, unsigned 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, &sector, &head);
+
+		/* second fat */
+		ptr=fill_phantoms(This, ptr, This->FatSize);
+
+		/* root dir */
+		ptr=fill_t0(This, ptr, This->RootDirSize, &sector, &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,
+			      &sector, &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);
+	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);
+	smaximize(end, (off_t)len2);
+	len2 -= begin;
+	sizemaximize(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 UNUSEDP, struct device *dev, 
+		       struct device *orig_dev UNUSEDP, 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 */
+	0, /* get_dosConvert */
+	0 /* discard */
+};
+
+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..ac45a37
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "msdos.h"
+#include "stream.h"
+
+struct xdf_info {
+  unsigned int FatSize;
+  unsigned int RootDirSize;
+  unsigned int BadSectors;
+};
+
+Stream_t *XdfOpen(struct device *dev, char *name,
+		  int mode, char *errmsg, struct xdf_info *info);
+
+#endif