Initial import package mtools: Programs for accessing MS-DOS disks without mounting... 2.0alpha 2.0alpha-wayland accepted/2.0alpha-wayland/20121108.021112 accepted/2.0alpha/20121108.004306 submit/2.0alpha-wayland/20121108.010314 submit/2.0alpha/20121108.010412
authorvivian, zhang <vivian.zhang@intel.com>
Sun, 3 Jun 2012 03:13:50 +0000 (11:13 +0800)
committervivian, zhang <vivian.zhang@intel.com>
Sun, 3 Jun 2012 03:13:50 +0000 (11:13 +0800)
168 files changed:
COPYING [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.Be [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
README.BEBOX [new file with mode: 0644]
Release.notes [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
buffer.c [new file with mode: 0644]
buffer.h [new file with mode: 0644]
byte_dword.h [new file with mode: 0644]
charsetConv.c [new file with mode: 0644]
cleanconfig [new file with mode: 0644]
codepage.h [new file with mode: 0644]
codepages.c [new file with mode: 0644]
config.c [new file with mode: 0644]
config.guess [new file with mode: 0644]
config.h.Be [new file with mode: 0644]
config.h.in [new file with mode: 0644]
config.sub [new file with mode: 0644]
configure [new file with mode: 0755]
configure.in [new file with mode: 0644]
copyfile.c [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/mtools.postinst [new file with mode: 0755]
debian/mtools.prerm [new file with mode: 0755]
debian/rules [new file with mode: 0755]
devices.c [new file with mode: 0644]
devices.h [new file with mode: 0644]
dirCache.c [new file with mode: 0644]
dirCache.h [new file with mode: 0644]
directory.c [new file with mode: 0644]
direntry.c [new file with mode: 0644]
expand.c [new file with mode: 0644]
fat.c [new file with mode: 0644]
fat_free.c [new file with mode: 0644]
fat_size_calculation.tex [new file with mode: 0644]
file.c [new file with mode: 0644]
file.h [new file with mode: 0644]
file_name.c [new file with mode: 0644]
file_name.h [new file with mode: 0644]
file_read.c [new file with mode: 0644]
filter.c [new file with mode: 0644]
floppyd.1 [new file with mode: 0644]
floppyd.c [new file with mode: 0644]
floppyd_installtest.1 [new file with mode: 0644]
floppyd_installtest.c [new file with mode: 0644]
floppyd_io.c [new file with mode: 0644]
floppyd_io.h [new file with mode: 0644]
force_io.c [new file with mode: 0644]
fs.h [new file with mode: 0644]
fsP.h [new file with mode: 0644]
hash.c [new file with mode: 0644]
htable.h [new file with mode: 0644]
init.c [new file with mode: 0644]
install-sh [new file with mode: 0755]
llong.c [new file with mode: 0644]
llong.h [new file with mode: 0644]
lockdev.h [new file with mode: 0644]
mainloop.c [new file with mode: 0644]
mainloop.h [new file with mode: 0644]
man-warning-end.texi [new file with mode: 0644]
man-warning.texi [new file with mode: 0644]
match.c [new file with mode: 0644]
mattrib.1 [new file with mode: 0644]
mattrib.c [new file with mode: 0644]
mbadblocks.1 [new file with mode: 0644]
mbadblocks.c [new file with mode: 0644]
mcat.1 [new file with mode: 0644]
mcat.c [new file with mode: 0644]
mcd.1 [new file with mode: 0644]
mcd.c [new file with mode: 0644]
mclasserase.1 [new file with mode: 0644]
mclasserase.c [new file with mode: 0644]
mcopy.1 [new file with mode: 0644]
mcopy.c [new file with mode: 0644]
mdel.1 [new file with mode: 0644]
mdel.c [new file with mode: 0644]
mdeltree.1 [new file with mode: 0644]
mdir.1 [new file with mode: 0644]
mdir.c [new file with mode: 0644]
mdoctorfat.c [new file with mode: 0644]
mdu.1 [new file with mode: 0644]
mdu.c [new file with mode: 0644]
mformat.1 [new file with mode: 0644]
mformat.c [new file with mode: 0644]
minfo.1 [new file with mode: 0644]
minfo.c [new file with mode: 0644]
misc.c [new file with mode: 0644]
missFuncs.c [new file with mode: 0644]
mk_direntry.c [new file with mode: 0644]
mkdosboot [new file with mode: 0755]
mkinstalldirs [new file with mode: 0755]
mkmanifest.1 [new file with mode: 0644]
mkmanifest.c [new file with mode: 0644]
mkmanpages [new file with mode: 0755]
mlabel.1 [new file with mode: 0644]
mlabel.c [new file with mode: 0644]
mmd.1 [new file with mode: 0644]
mmd.c [new file with mode: 0644]
mmount.1 [new file with mode: 0644]
mmount.c [new file with mode: 0644]
mmove.1 [new file with mode: 0644]
mmove.c [new file with mode: 0644]
mpartition.1 [new file with mode: 0644]
mpartition.c [new file with mode: 0644]
mrd.1 [new file with mode: 0644]
mren.1 [new file with mode: 0644]
msdos.h [new file with mode: 0644]
mshowfat.1 [new file with mode: 0644]
mshowfat.c [new file with mode: 0644]
mtools.1 [new file with mode: 0644]
mtools.5 [new file with mode: 0644]
mtools.c [new file with mode: 0644]
mtools.conf [new file with mode: 0644]
mtools.h [new file with mode: 0644]
mtools.info [new file with mode: 0644]
mtools.spec [new file with mode: 0644]
mtools.texi [new file with mode: 0644]
mtoolsDirentry.h [new file with mode: 0644]
mtoolsPaths.h [new file with mode: 0644]
mtoolstest.1 [new file with mode: 0644]
mtype.1 [new file with mode: 0644]
mzip.1 [new file with mode: 0644]
mzip.c [new file with mode: 0644]
nameclash.h [new file with mode: 0644]
packaging/fix_mlabel_initialisation.patch [new file with mode: 0644]
packaging/mtools-3.9.6-config.patch [new file with mode: 0644]
packaging/mtools-3.9.7-bigdisk.patch [new file with mode: 0644]
packaging/mtools.changes [new file with mode: 0644]
packaging/mtools.spec [new file with mode: 0644]
partition.h [new file with mode: 0644]
patchlevel.c [new file with mode: 0644]
plain_io.c [new file with mode: 0644]
plain_io.h [new file with mode: 0644]
precmd.c [new file with mode: 0644]
privileges.c [new file with mode: 0644]
privtest.c [new file with mode: 0644]
read_dword.h [new file with mode: 0644]
scripts/add-disk [new file with mode: 0755]
scripts/amuFormat.sh [new file with mode: 0755]
scripts/download [new file with mode: 0755]
scripts/format.dat [new file with mode: 0644]
scripts/mcheck [new file with mode: 0755]
scripts/mcomp [new file with mode: 0755]
scripts/mxtar [new file with mode: 0755]
scripts/tgz [new file with mode: 0755]
scripts/uz [new file with mode: 0755]
scsi.c [new file with mode: 0644]
scsi.h [new file with mode: 0644]
signal.c [new file with mode: 0644]
stream.c [new file with mode: 0644]
stream.h [new file with mode: 0644]
streamcache.c [new file with mode: 0644]
strip-pp.sed [new file with mode: 0644]
subdir.c [new file with mode: 0644]
sysincludes.h [new file with mode: 0644]
texinfo.tex [new file with mode: 0644]
tty.c [new file with mode: 0644]
unixdir.c [new file with mode: 0644]
version.texi [new file with mode: 0644]
vfat.c [new file with mode: 0644]
vfat.h [new file with mode: 0644]
xdf_io.c [new file with mode: 0644]
xdf_io.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
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 (file)
index 0000000..db7bbb4
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,30 @@
+% Copyright 1996,1997,1999,2001,2002 Alain Knaff.
+
+% This documentation is for Mtools which is a collection of tools to
+% allow Unix systems to manipulate MS-DOS files.
+
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.3 or
+% any later version published by the Free Software Foundation; with no
+% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+% Texts.  A copy of the license is included in the section entitled
+% ``GNU Free Documentation License''.
+
+Installation of mtools is now pretty straightforward:
+
+  1. Run ./configure
+  2. Run make
+
+ Configuration options:
+
+  * Use ./configure --enable-vold to compile mtools to use Solaris'
+vold instead of directly accessing the floppy disk
+  * Use ./configure --disable-xdf to disable support for Xdf disks on Linux
+  * Use ./configure --enable-new-vold to compile mtools to use the *new* 
+vold for Solaris. With this, you no longer need precmd=volcheck, and
+users don't need to type "eject" before pushing the button.
+
+Further doc can be found in the manpages, and in the texinfo doc. The
+texinfo doc contains the same info as the manpages, but is more up to
+date. To generate a printable doc, make dvi. To generate an info file,
+make info.
diff --git a/Makefile.Be b/Makefile.Be
new file mode 100644 (file)
index 0000000..8dee7d3
--- /dev/null
@@ -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 (file)
index 0000000..85c82ba
--- /dev/null
@@ -0,0 +1,328 @@
+#  Copyright 1996-2004,2006-2009 Alain Knaff.
+#  This file is part of mtools.
+#
+#  Mtools is free software: you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation, either version 3 of the License, or
+#  (at your option) any later version.
+#
+#  Mtools is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with Mtools.  If not, see <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@
+EXE         = @EXEEXT@
+
+INSTALL         = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA    = @INSTALL_DATA@
+INSTALL_INFO   = @INSTALL_INFO@
+
+.SUFFIXES:
+.SUFFIXES: .o .c
+.SUFFIXES: .o .c
+
+MAN1 = floppyd.1 floppyd_installtest.1 mattrib.1 mbadblocks.1 mcat.1 mcd.1 \
+mclasserase.1 mcopy.1 mdel.1 mdeltree.1 mdir.1 mdu.1 mformat.1  minfo.1 \
+mkmanifest.1 mlabel.1 mmd.1 mmount.1 mmove.1 mpartition.1 \
+mrd.1 mren.1 mshowfat.1 mtoolstest.1 mtools.1 mtype.1 mzip.1
+MAN1EXT        = 1
+MAN1DIR        = $(DESTDIR)$(mandir)/man${MAN1EXT}
+MAN5   = mtools.5
+MAN5EXT        = 5
+MAN5DIR        = $(DESTDIR)$(mandir)/man${MAN5EXT}
+
+# all files in this directory included in the distribution
+DIST = \
+COPYING Changelog INSTALL Makefile Makefile.in README Release.notes \
+buffer.c buffer.h charsetConv.c codepage.h codepages.c config.c \
+config.guess config.h.in config.log config.sub configure configure.in \
+copyfile.c devices.c devices.h dirCache.c dirCache.h directory.c direntry.c \
+expand.c fat.c \
+fat_free.c file.c file.h file_name.h file_name.c files filter.c floppyd.1 \
+floppyd.c floppyd_io.c floppyd_io.h force_io.c fs.h fsP.h \
+getopt.h hash.c htable.h init.c llong.c mainloop.c match.c mattrib.1 \
+mattrib.c mbadblocks.1 mbadblocks.c mcat.1 mcat.c mcd.1 mcd.c mclasserase.c \
+mcopy.1 \
+mcopy.c mdel.1 mdel.c mdeltree.1 mdir.1 mdir.c mdu.c mdu.1 mformat.1 \
+mformat.c minfo.c \
+misc.c tty.c scsi.c missFuncs.c mk_direntry.c mkmanifest.1 mkmanifest.c \
+mlabel.1 mlabel.c mmd.1 mmd.c mmount.1 mmount.c mmove.1 mmove.c \
+mpartition.1 mpartition.c mrd.1 \
+mren.1 msdos.h mshowfat.1 mtoolstest.1 mtools.1 mtools.5 mtools.c \
+mtools.conf mtools.h mtype.1 nameclash.h patchlevel.c \
+plain_io.c plain_io.h precmd.c privileges.c scripts signal.c stream.c stream.h \
+streamcache.c streamcache.h subdir.c sysincludes.h unixdir.c todo \
+vfat.c vfat.h xdf_io.c xdf_io.h
+
+OBJS1 = buffer.o charsetConv.o codepages.o config.o copyfile.o \
+devices.o dirCache.o directory.o direntry.o expand.o fat.o fat_free.o file.o  \
+file_name.o filter.o floppyd_io.o force_io.o hash.o init.o llong.o match.o \
+mainloop.o mattrib.o mbadblocks.o mcat.o mcd.o mclasserase.o mcopy.o mdel.o \
+mdir.o mdoctorfat.o mdu.o \
+mformat.o minfo.o misc.o missFuncs.o mk_direntry.o mlabel.o mmd.o mmount.o \
+mmove.o mpartition.o mshowfat.o mzip.o mtools.o patchlevel.o plain_io.o \
+precmd.o privileges.o scsi.o signal.o stream.o streamcache.o subdir.o \
+unixdir.o tty.o vfat.o xdf_io.o
+
+OBJS2 = missFuncs.o mkmanifest.o misc.o patchlevel.o
+
+SRCS3 = floppyd.c
+
+OBJS4 = floppyd_installtest.o misc.o expand.o privileges.o
+
+SRCS = buffer.c codepages.c config.c copyfile.c devices.c \
+dirCache.c directory.c direntry.c expand.c fat.c fat_free.c file.c file_name.c \
+file_read.c filter.c floppyd_io.c force_io.c hash.c init.c match.c mainloop.c \
+mattrib.c mbadblocks.c mcat.c mcd.c mclasserase.c mcopy.c mdel.c mdir.c \
+mdu.c mdoctorfat.c mformat.c minfo.c misc.c \
+missFuncs.c mk_direntry.c mlabel.c mmd.c mmount.c mmove.c mpartition.c \
+mshowfat.c mzip.c mtools.c plain_io.c precmd.c privileges.c scsi.o \
+signal.c stream.c streamcache.c subdir.c unixdir.c tty.o vfat.c \
+xdf_io.c mkmanifest.c
+
+
+SCRIPTS = mcheck mxtar uz tgz mcomp amuFormat.sh
+
+LINKS=mattrib mcat mcd mclasserase mcopy mdel mdeltree mdir mdu mformat minfo \
+mlabel mmd mmount mmove mpartition mrd mren mtype mtoolstest mshowfat \
+mbadblocks mzip
+
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+CFLAGS = $(CPPFLAGS) $(DEFS) $(MYCFLAGS) -fno-strict-aliasing -I. @extraincludedir@ -I@srcdir@ $(USERCFLAGS)
+CXXFLAGS  = $(CPPFLAGS) $(DEFS) $(MYCXXFLAGS) -I. @extraincludedir@ -I@srcdir@ $(USERCFLAGS)
+LINK      = $(CC) $(LDFLAGS) $(USERLDFLAGS) @extralibdir@
+ALLLIBS   = $(USERLDLIBS) $(MACHDEPLIBS) $(SHLIB) $(LIBS)
+X_LDFLAGS = $(X_EXTRA_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lXau -lX11 $(LIBS)
+X_CCFLAGS = $(X_CFLAGS) $(CFLAGS)
+
+all:    mtools $(LINKS) mkmanifest @FLOPPYD@
+
+%.o: %.c
+       $(CC) $(CFLAGS) -c $<
+
+#%.o: %.cpp
+#      $(CXX) $(CXXFLAGS) -c $<
+
+mtools: $(OBJS1)
+       $(LINK) $(OBJS1) -o $@ $(ALLLIBS)
+
+mkmanifest: $(OBJS2)
+       $(LINK) $(OBJS2) -o $@ $(ALLLIBS)
+
+floppyd.o: floppyd.c
+       $(CC) $(X_CCFLAGS) -c $?
+
+floppyd: floppyd.o
+       $(LINK) $? -o $@ $(X_LDFLAGS)
+floppyd_installtest: $(OBJS4)
+       $(LINK) $(OBJS4) -o $@ $(ALLLIBS)
+
+
+$(LINKS): mtools
+       rm -f $@ && $(LN_S) mtools$(EXE) $@
+
+mostlyclean:
+       -rm -f *~ *.orig *.o a.out core 2>/dev/null
+
+clean: mostlyclean
+       -rm -f mtools $(LINKS) floppyd floppyd_installtest mkmanifest *.info* *.dvi *.html 2>/dev/null
+
+
+texclean:
+       -rm -f mtools.aux mtools.toc mtools.log
+       -rm -f mtools.cps mtools.pgs mtools.vrs
+       -rm -f mtools.cp mtools.fn mtools.ky
+       -rm -f mtools.pg mtools.tp mtools.vr
+
+info: mtools.info
+%.info: %.texi
+       $(MAKEINFO) -I$(srcdir) $< --no-split --output=$@
+
+dvi: mtools.dvi
+%.dvi: %.texi
+       $(TEXI2DVI) $<
+
+ps: mtools.ps
+%.ps: %.dvi
+       dvips -f < $< > $@
+
+pdf: mtools.pdf
+%.pdf: %.texi
+       $(TEXI2PDF) $<
+
+
+html: mtools.html mtools_toc.html
+%.html %_toc.html: %.texi
+       $(TEXI2HTML) $<
+
+# Don't cd, to avoid breaking install-sh references.
+install-info: info
+       $(top_srcdir)/mkinstalldirs $(DESTDIR)$(infodir)
+       if test -f mtools.info; then \
+         for i in mtools.info*; do \
+           $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/$$i; \
+         done; \
+       else \
+         for i in $(srcdir)/mtools.info*; do \
+           $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/`echo $$i | sed 's|^$(srcdir)/||'`; \
+         done; \
+       fi; \
+       if [ -n "$(INSTALL_INFO)" ] ; then \
+               $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/mtools.info; \
+       fi
+
+uninstall-info:
+       cd $(DESTDIR)$(infodir) && rm -f mtools.info*
+
+install:       $(DESTDIR)$(bindir)/mtools @BINFLOPPYD@ install-man install-links \
+               $(DESTDIR)$(bindir)/mkmanifest install-scripts install-info
+
+uninstall:     uninstall-bin uninstall-man uninstall-links \
+               uninstall-scripts
+
+distclean: clean texclean
+       rm -f config.cache config.h config.status config.log Makefile
+maintainer-clean: distclean
+
+
+$(DESTDIR)$(bindir)/floppyd: floppyd
+       $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(INSTALL_PROGRAM) floppyd $(DESTDIR)$(bindir)/floppyd
+
+$(DESTDIR)$(bindir)/floppyd_installtest: floppyd_installtest
+       $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(INSTALL_PROGRAM) floppyd_installtest $(DESTDIR)$(bindir)/floppyd_installtest
+
+$(DESTDIR)$(bindir)/mtools: mtools
+       $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(INSTALL_PROGRAM) mtools $(DESTDIR)$(bindir)/mtools
+
+$(DESTDIR)$(bindir)/mkmanifest: mkmanifest
+       $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       $(INSTALL_PROGRAM) mkmanifest $(DESTDIR)$(bindir)/mkmanifest
+
+#$(ETCDIR)/mtools: mtools.etc
+#      cp mtools.etc $(ETCDIR)/mtools
+
+install-links: $(DESTDIR)$(bindir)/mtools
+       @for j in $(LINKS); do \
+               rm -f $(DESTDIR)$(bindir)/$$j ; \
+               $(LN_S) mtools$(EXE) $(DESTDIR)$(bindir)/$$j ; \
+               echo $(DESTDIR)$(bindir)/$$j ; \
+       done
+
+## "z" is the older version of "gz"; the name is just *too* short
+install-scripts: $(DESTDIR)$(bindir)/mtools
+       @$(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+       @for j in $(SCRIPTS) ; do \
+               $(INSTALL_PROGRAM) $(srcdir)/scripts/$$j $(DESTDIR)$(bindir)/$$j ; \
+               echo $(DESTDIR)$(bindir)/$$j ; \
+       done
+       rm -f $(DESTDIR)$(bindir)/lz
+       cd $(DESTDIR)$(bindir) && $(LN_S) uz lz
+
+install-man:
+       @$(top_srcdir)/mkinstalldirs $(MAN1DIR)
+       @for j in $(MAN1); do \
+               $(INSTALL_DATA) $(srcdir)/$$j $(MAN1DIR)/$$j ; \
+               echo $(MAN1DIR)/$$j ; \
+       done
+       @$(top_srcdir)/mkinstalldirs $(MAN5DIR)
+       @for j in $(MAN5); do \
+               $(INSTALL_DATA) $(srcdir)/$$j $(MAN5DIR)/$$j ; \
+               echo $(MAN5DIR)/$$j ; \
+       done
+
+uninstall-bin:
+       @for j in mtools mkmanifest; do \
+               rm -f $(DESTDIR)$(bindir)/$$j ; \
+               echo $(DESTDIR)$(bindir)/$$j ; \
+       done
+
+uninstall-scripts:
+       @for j in $(SCRIPTS); do \
+               rm -f $(DESTDIR)$(bindir)/$$j ; \
+               echo $(DESTDIR)$(bindir)/$$j ; \
+       done
+
+uninstall-man:
+       @for j in $(MAN1); do \
+               rm -f $(MAN1DIR)/$$j ; \
+               echo $(MAN1DIR)/$$j ; \
+       done
+       @for j in $(MAN5); do \
+               rm -f $(MAN5DIR)/$$j ; \
+               echo $(MAN5DIR)/$$j ; \
+       done
+
+uninstall-links:
+       @for j in $(LINKS); \
+               do rm -f $(DESTDIR)$(bindir)/$$j ; \
+               echo $(DESTDIR)$(bindir)/$$j ; \
+       done
+
+depend: $(SRCS)
+       makedepend -- $(CFLAGS) -- $^
+
+check:
+       echo No self tests included
+# check target needed even if empty, in order to make life easyer for
+# automatic tools to install GNU soft
+
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..278d22d
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,1039 @@
+v4_0_12
+       Mingw compatibility fixes
+v4_0_11
+       Fixed compiler warnings in mlabel.c and elsewhere
+       Fixed h flag in mattrib.c
+       Added missing error checking in floppyd and elsewhere
+       
+v4_0_10
+       More copyright stuff...
+       Fixed issues with max filesize (was 2GB instead of 4GB, and
+       warned only after copying the beginning)
+v4_0_9
+       More copyright stuff
+v4_0_8
+       Corrected copyright attributions in the various files
+v4_0_7
+       Fixed conversion to native on OS/2
+       Fix parsing of --help flag
+v4_0_6
+       Fallback for missing wchar_t iconv codepage on OS/2
+       Fixes for LSEEK64 support
+       Support for --help that returns a 0 exit status
+v4_0_5
+       Make setpgrp() usage in floppyd conditional
+       Re-instate PACKED around structure (ARM)
+       LSEEK64
+       
+v4_0_4
+       BSD support: SCSI, use getuserid/getgroupid in floppyd
+       Another attempt at putwc fix for OS/2
+       Further GNU fixes
+       Fallback for putwc if there is wchar (OS/2)
+v4_0_3
+       Fix multipart pathname parsing bug in vfat.c (forgot limited length)
+       Supplied fallback define for putwc
+       Copyright notices in all sources
+v4_0_2
+       Off-by-2 error in unix_name in file_name.c
+v4_0_1
+       Missing functions on Solaris
+v4_0_0
+       Offset for -i-specified image files
+v4_0_0_pre2
+       Use transliteration to represent characters which don't exist in
+       target set
+v4_0_0_pre1
+       Mtools-4 with Unicode support
+       Released 4.0.0_pre1
+v20071226
+       Debian build files
+       Fixed security issue with doctored file names
+       64 bit compilation fixes
+v20070601
+       Fixed misc blunders...
+v20070531
+       Fixed lots of minor items raised by gcc4
+       Merged some of the BSD patches
+       New version of amuFormat.sh written in sh rather than csh
+       Support for config parameters after -i file
+       Released 3.9.11
+v20070411
+       Added sizecode printing on minfo
+       In mformat manpage, use same flag for sector number than printed in
+       minfo
+       Limit sizecode to 6, else it will overflow max sector size defined in
+       msdos.h
+v20070308
+       Applied mingw patch by Jamey Sharp and Josh Triplett
+v20070306
+       Fixed doc about /etc/default
+v20070305
+       Fixed mlabel on read-only disks
+v20060626
+       Merged Redhat/Fedora patches
+v20060531
+       #ifdef linux-dependant code in mformat.c
+v20060525
+       Fix gcc4 warnings
+       Fix reading of boot sector (block size)
+v20060228b
+       Do no longer open floppy devices with O_EXCL, in order to enable
+       work-around against broken cache.
+v20060228
+       If no info dir exists at all, assume dir
+v20060227
+       Support for DESTDIR
+v20051011
+       Fix Unix loop
+v20050410
+       Cygwin compatibility
+v20050317
+       Solaris 8 compatibility
+v20050302
+       Released 3.9.10
+v20050228
+       Support for multiple drives in floppyd
+v20050213b
+       Updated .spec file
+v20050213
+       Fixed some long name directory entry freeing bugs
+v20040505
+       Fixed duplicate FAT writing error. Fixed segfault on short images.
+       Mformat creates images of correct size.
+       CYGWIN compatibility (O_BINARY flag).
+v20040420
+       Cygwin patch for plain_io.c (no locking)
+v20040228
+       Fix a couple of memory leaks in config file parsing. Fix llong.h
+       (redefined same symbol twice)
+       Fix a variable initialization problem in plain_io.c
+       New mclasserase command to erase memory cards
+       C99 "compatibility"
+v20030718
+       Fix rootskip and rate of XDF disks
+v20030705
+       Fix inverted IS_MFORMAT_ONLY conditon in plain_io.c
+v20030609
+       Moved putc after variable description (anybody knows about a -W
+       flag so that gcc warns about these?)
+v20030606
+       Fixed mattrib -p (missing slash)
+v20030605
+       Added -m option to mformat to specify a non-standard mediabyte
+v20030524
+       Added -d options to mformat to specify number of FAT copies. Can
+       also be set using the MTOOLS_NFATS environmental variable.
+       Also added similar env variable for root directory length
+       Signed/unsigned fixes, to satisfy increased pickyness of gcc ;-)
+       CYGWIN fixes for mcat
+       floppyd bugfixes
+v20030213
+       Released 3.9.9 : Identical to pre-3.9.9 except for the version number
+v20030213
+       Released 3.9.9 Pre-1
+       Fixed max numbers of sectors for FAT12 and FAT16 (was off by one...)
+       Improved fat_len calculation
+       Fixed plain_io.c bug (Swap byte applied after partition stuff,
+       instead of before)
+v20030118
+       Fixed mcat end-of-file bugs (mcat went on writing, and writing,
+       and writing, even after end of file)
+v20030105
+       If "standard" CHS specified, but non-standard root dir size do not
+       use table-lookup based geometry ("old-dos media descriptor")
+v20021118
+       David's new uz script, that can use commands other than gzip for
+       compression
+v20021116
+       Fixed vold support for mpartition
+v20021105
+       Added PACKED to unicode_char declaration (Arm)
+       Mpartition can now create the image if -I is specified.
+v20021104
+       Support for geometry-less Atari disks
+       Support for byte-swapping disks
+v20021102b
+       Avoid .(l and .)l in generated man pages
+v20021102
+       -i flag
+       Fix mformat for 2m
+       Fix [] wildcard off-by-one error
+       Avoid overwriting (Unix) file by itself in mcopy
+       Avoid cloberring any file if implicit target is used (the
+       one-argument syntax of mcopy)
+       Added Zip 750 entry to mzip.c
+       SCO Scsi fix
+v20020125
+       Fixes for cygwin
+       Fixes in buffer.c for oddly sized image files
+       Mformat.c fixes to avoid makeing images which would not be
+       readable in windows.
+v20010908
+       Warn for invalid partition numbers
+v20010526
+       Released pre6-3.9.8 : getting rid of linux-gnu references is
+       almost as difficult as exorcising the devil...
+v20010526
+       Released pre5-3.9.8 after fixing a couple of version numbers
+v20010526
+       Applied Adrian Bunk's patches, minus the Stallmanisms.
+       De-stallmanized config.gues and config.sub files
+       pre4-3.9.8
+v20010521
+       Fixed DELMARK translation of mcopy's -T option, pre3-3.9.8
+v20010521
+       Fixed #ifdef DEBUG statements, pre2-3.9.8
+v20010520
+       Released pre-3.9.8
+v20010507
+       Updated config.guess/config.sub to support Darwin
+       Patch for converting contents of files from/to Dos' version of
+       8bit Ascii
+       Fixed bug in to_unix function
+v20010330
+       Updated freebsd floppy device definitions
+v20010325
+       Fixes for floppyd to work with current protocol version of floppyd
+v20010325
+       Fixed parsing of Unix filenames ending with slash
+v20010325
+       Fixed file closing of floppyd
+v20001213
+       Fixed a cindex entry in documentation
+v20001113
+       Rewrote PDF rule to use pdflatex, rather than go through dvi
+       (pdflatex output looks nicer)
+v20001113
+       Fixed JAZ Zip file overwrite bug (actually, this bug could occur
+       on any disk reasonably full...)
+v20001018
+       Fix mzip manpage to include Linux in the list of supported OS'es
+v20001009
+       Protect against division by zero when reading BSD disks...
+v20000829
+       Documentation fixes
+v20000820
+       Hurd openflags fix in mainloop.c
+       Added description for t option to mcopy man page
+       Added -lbsd to list of libraries to be tested for LynxOS
+       Unset LANG in mkmanpages
+       Updated config.gues/config.sub
+       Removed stale documentation for xcopy
+       Fixed typo in mformat man page
+v20000810
+       Zip 250 support in mzip
+v20000708
+       Floppyd robustness
+v20000703
+       Variable initialization in mdir.c
+v20000623
+       Do not use offset_t on AIX ==> broken
+v20000610
+       Large disk fixes, especially for Solaris
+v20000601
+       Released Mtools-3.9.7
+v20000528
+       Mtools-pre2-3.9.7 released: some potential buffer overflows     
+v20000521
+       Mtools-pre-3.9.7 released
+v20000520
+       Added devices for OpenBSD (the previous NetBSD/OpenBSD where wrong
+       for OpenBSD)
+v20000517
+       Fixed a couple of floppyd bugs
+v20000514
+       Added texclean to make distclean, added new "pdf" target.
+v20000510
+       Did away with ipaddr_t and replaced it with IPaddr_t which is
+       guaranteed not to crash anywhere...
+v20000509
+       Defined geometry for default a: devices on Linux and Solaris with vold
+v20000502
+       Carefully navigate Solaris' polluted namespace...
+v20000501
+       Suppressed bogus error message when mcopying to an existing file.
+v20000429
+       Fixed mformat problem with Fat32 (mformat didn't initialize the
+       label and fat type fields in the boot sector, and the other mtools
+       utils didn't check them)
+v20000428
+       Fixed two more scandisk problems:
+               - the infosector should end with 0x55aa
+               - When deleting a file, be sure to DELMARK the VSE's as
+                 well as the main entry
+v20000428
+       Fixed an evasive Fat32 bug: a parent directory entry pointing to
+       the root should have an address of 0 instead of the more logical 2
+v20000416
+       Corrected mdir error handling
+       Fixed a bug in mren (problem when renaming short file names)
+v20000412
+       Corrected a typo in error handling
+v20000410
+       Fixed size problem with Ctrl-Z.
+v20000401
+       (No joke): avoid setting volume serial number on "Old Dos" disks
+v20000320
+       - Re-aligned command line options with Dos
+       - New -n/-N option for mlabel to change volume serial numbers
+       - Mattrib -p escapes file names in order to handle file name
+       containing spaces
+       - Changed mformat serial number format
+v19991121
+       Fixed 2 bugs:
+       - Mtools would never completely use all directory slots, because
+       it overestimated space consumption by 1
+       - Mtools did not initialize the stat struct for pipes, and thus
+       gave occasionnally bogus "Disk full" error messages
+v19991011
+       Rearranged tty open call so that it is only opened when actually
+       needed  
+v19990807
+       Added special case for 0xf7 media descriptor
+v19990729
+       Make O_NDELAY conditional everywhere
+v19990715
+       Return correct return value from mt_lseek, even if off_t is a 64
+       bit quantity
+v19990712
+       Treat OpenBSD the same as NetBsd
+v19990630
+       Released 3.9.6 with the following fixes:
+       - Typoes in xdf_io.c
+       - Make Xdf work in nodma mode
+       - Fix for mformatting MSS disks
+v19990628
+       1st attempt to release 3.9.6 with mostly minor fixes:
+       - platform compatibility
+       - automatic installation of info files
+       - mdir's -X flag no longer implies "recursive"
+v19990419
+       3.9.5 released with mostly minor fixes:
+       - Starting cluster numbers of "." directory entry
+       - Copying of empty Files from Dos to Unix
+       - Misc platform compatibility issues
+v19990315
+       Another embarrassing bug found, 3.9.4 released. When will this
+       nightmare stop?
+v19990314
+       Mtools 3.9.3 released
+v19990314
+       Open BSD SCSI fixes & added GLIBC linux/unistd.h for llseek. These
+       Glibc problems are potentially dangerous, and can lead to data loss.
+v19990314
+       Mtools 3.9.2 released
+v19990310
+       Fixed typo in plain_io.c
+v19990307
+       More rigor about signed vs unsigned issue.  FreeBSD Scsi support
+v19990223
+       Allow for 2GB Jaz drives
+v19990218
+       Rewrote floppyd in C instead of C++
+v19990208
+       More buffer fix
+v19990112
+       Buffer fix
+v19990111
+       "Big disk" fixes
+v19990104
+       OS/2 patch
+v19981211
+       Make sure that fat_type doesn't overwrite byte 62 with zero =>
+       disk unbootable
+v19981204
+       Added support for "replay" listing of mattrib.  Cleaned up version
+       number and date handling (date was not always accurate...)
+v19981204
+       Added geometry autodetection code for Linux harddisks to
+       mpartition and mformat.  Removed misleading references to
+       "non-removable media"
+v19981203
+       Added boot sector template option for mpartition.  Fixed mtools.1
+       man page. Mattrib -s e:/ fix
+v19981031
+       Man pages bug fixes
+v19981029
+       Fixed HP SCSI "big write" bug   
+v19980701
+       Fixed debug mode in vfat.c
+v19980629
+       A few minor floppy related fixes (installation, and replacement
+       for setenv function, which is absent from some platforms)       
+v19980523
+       Added floppyd (remote access to floppy disks)
+v19980522
+       Updated mkmanpages script to dynamically get date and mtools
+       version.  Correct "removable media" error message to talk about
+       /etc/mtools.conf instead of /etc/mtools.  Do init_geom to read
+       geometry if no geometry is set.
+v19980514
+       Mtools 3.9.1 released
+v19980503
+       Mformats makes disks which are readable both as partitioned and as
+       plain
+v19980405
+       Corrected Tim Hoogasian's e-mail address
+v19980404
+       OS/2 additions
+v19980331
+       "Dirty end too big" mformat bug corrected
+v19980330
+       Corrected typoes for IRIX devices, use macros for attribute types,
+       fix 0 length file bug.
+v19980327
+       Loop detection code
+       Bigger array for SCSI command
+v19980323
+       GLIBC portability
+v19980322
+       OS/2 portabilty, GLIBC portability
+v19980320
+       Fixes related to Solaris new vold support
+v19980317
+       Fixed a few BSD typoes, and renamed ALLCFLAGS in the Makefile to
+       CFLAGS for those makes that don't support implicit rules well enough
+v19980310
+       Mtools 3.9 released
+v19980308
+       Various Bugfixes (overwrite mode and directory cache)
+v19980301
+       Added mformat_only flag.
+v19980130
+       Fixed non-batchmode mcopy bug.  Fixed shortname case bug
+v19980130
+       Minfo and mformat boot program bug fixes
+v19980120
+       Allow default block sizes per device which are not equal to 512
+v19980108
+       Allow and interpret back quotes in file names
+v19980101
+       Misc bugfixes
+v19971231
+       Scandir optimizations.  Fixed nasty Heisenbug in hash.c.
+v19971229
+       Fixed integer width problem in fat.c, and minor bugs in hashtable.
+v19971222
+       More performance optization.  Buffer handl
+       ing redone.  New
+       "asynchronous mode".
+v19971216
+       Fixed mtype and mcheck.  Started cleaning up out-of-memory handling
+v19971215
+       Jacked up performance, and corrected signal handling bugs.  Also
+       corrected various "Disk full bugs"
+v19971212
+       Fixed "Bad address" errors which occured when running mdu on empty
+       files.  When copying recursively, do not barf if a directory
+       already exist at the target.  Mcopy operates silently by default.
+v19971212
+       removed mwrite. Obsoleted long ago by mcopy
+v19971211
+       fixed mdir -X, added mattrib -X; document both.  Fix doc for name
+       clash handling
+v19971210
+       fixed polarity of sys_errlist. Renamed some include files which
+       bore the same name as system include files.  Fixed another
+       memory leak in dir_grow. A/UX termio workaround.
+v19971209
+       fixed filedescriptor leak. Make mbadblocks stoppable. Doc
+       fixes.  Fixed one memory leak, another one further down the road
+       remains... Fixed error handling in createDirectory.
+v19971208
+       bugfixes: mbadblocks, fat, unix quit, null pointers in mcopy...
+v19971205
+       Renamed it to pre3-3.9 due to mixup when shipping the pre2-3.9
+       version. No actual code change apart from patchlevel.h
+v19971204
+       Pre2-3.9. Added mpartion manpage.  Added misc.o dependency to
+       mkmanifest.  Fixed mpartition bug with partitions with more
+       than 1023 cylinders
+v19971129
+       Pre-3.9.  Redid the mainloop logic, and got rid of lots of cruft
+       in subdir.c and parse.c.  It is now possible to put wildcards in
+       the directory part of the filename.  Design also became simpler,
+       making it easyer to maintain this part in the future.
+       Added a -u flag to mzip to temporarily unprotect a disk
+       Added a test to mzip to prevent manipulation of mounted disks
+       Added support for partitioned devices in mmount
+v19971116
+       Added mdu and recursive mdir
+v19971112
+       Fixed bugs in recursive copy stuff, added recursive mattrib, and
+       fixed a few buffer overrun bugs
+v19971110
+       Added recursive copy and attribute conservation flags to mtools 
+v19971029
+       Fix parse.c typo
+v19971013
+       Include Sys5 directories on SunOs in order to have a correct
+       timestamp
+       Detect Lilo disks
+v19971006
+       Correct vold typo
+v19971002
+       Use 8 sector clusters for 32-bit FATs: this is what Micro$oft user
+v19970823
+       Corrected gross bug in fat12_decode
+v19970823
+       Simplified fat bits handlings
+v19970820
+       Raw Scsi_io for SGI
+v19970813
+       Buffer.c and FAT bugfixes
+v19970813
+       More FAT32 fixes.  New mshowfat command.
+v19970813
+       Fix FAT32 problem (FAT32 does not use the high nibble)
+v19970812
+       Detect presence of sys_errlist using autoconf instead of
+       making its usage dependent on BSD.
+       Fixed make texclean.
+       Guard against corrupted "next free block" pointer in a FAT32
+       InfoBlock
+v19970715
+       Use root priviliges during scsi_init
+v19970714
+       Fixed close-on-exec bug.
+v19970714
+       Fixed #include in HP_UX. Sys/floppy.h is not known on all flavors
+       of HP_UX
+v19970713
+       Fixed Makefile so that make -j works without errors.  Fixed
+       upper/lower bug in mmount
+v19970708
+       Released 3.8
+v19970629
+       Add option to mformat to keep boot sector, or to read it from
+       a file.  Added various flags to customize directory listing
+       appearance and long name behavior
+v19970629
+       Fix bug in yesterdays fix.  Also make sure to resize hash
+       table if too many deleted entries accumulate.
+v19970628
+       Fixed yet another hash table bug
+v19970619
+       Yet another HPUX fix.
+v19970619
+       Fixed a segfault in mpartition
+v19970617
+       Removed a few Stallmanisms in config.guess
+v19970612
+       3.7 released
+v19970611
+       Corrected a few errors in new vold code
+v19970610
+       Removed extra &'s from string addresses.
+       Added listing of current configuration to mtools -V
+       Updated version number and date in mkmanpages
+v19970604
+       New Bebox patch.  Removes almost all BEBOX specifities because
+       they are no longer needed with the new DR9 release.
+       Small fix for size detection of SCSI disks.
+v19970524
+       Fixed small typo in new vold code
+v19970524
+       Added partition consistency checks for accessing device.
+v19970523
+       New version of Solaris vold code
+v19970516
+       Solaris floppy geometry.  Support for older MO disks (size
+       returned in non-standard location)
+       Corrected ftp address for fdutils
+v19970504
+       Updated README.BEBOX
+v19970504
+       Brought Makefile.Be and config.h.Be up to date with the recent
+       changes
+v19970504
+       Add Ultrix to the list of OS'es which do not define their
+       prototypes
+       Small Makefile fix
+v19970503
+       Various "Next proofintg".
+               * add VENDOR_, CPU_ and OS_ before machine type tags
+               detected by autoconf. Next tends to be a frequently
+               used variable
+               * use utimes preferably before utime
+               * try to include _all_ termios functions.
+               * more precise detection of available termios functions
+v19970501
+       Added knowledge of Zip Tools Disk password to mzip.
+v19970429
+       Went back to using ALLCFLAGS in Makefile for those people who
+       want to override CFLAGS
+v19970426
+       Added note about Alpha site to doc.
+v19970423
+       Prefer termios.h on Ultrix
+v19970422
+       Renamed missing_functions to missFuncs in order to accomodate
+       operating systems with file name size limits.
+v19970420
+       Autoextend size for images that are too small.  Moved BSD
+       dependant #ifdef's after the inclusion of sys/param.h, as it
+       is there where BSD is defined (sigh!)
+v19970419
+       Insist on the fact that mzip's -f flag only makes sense if
+       given in addition to -e
+v19970419
+       Corrected typo in doc.
+v19970417
+       Removed read and write prototypes, they conflict on an Alpha!
+v19970414
+       More HP/UX fixes.
+v19970414
+       3.6 released
+v19970414
+       Do not stat any files in /dev/ on BEOS. Remove spurious system
+       include files from non-sysincludes.h file
+v19970413
+       Fixed Zip disk eject
+v19970412
+       Added Sunos4 and SCO support to scsi.c.  Use tzset before
+       gettimeofday, except for BSD.  Use Z: for a Zip drive, and J:
+       for a Jaz drive instead of D: for both.  Added machine
+       specific libraries and CFLAGS for A/UX.
+v19970410
+       Various A/UX fixes.  Changed scanning order for termio and
+       termios due to problems with the other order on A/UX.
+v19970405
+       Print error message for wrong password.
+v19970405
+       Include mzip man page
+v19970404
+       Document new config flags introduced in 970204.
+       On systems not supporting euid, do not bail out if both euid
+       and ruid are 0.
+v19970404
+       Prevent mmove from moving directories into themselves in order
+       to keep a tree-like directory structure
+v19970403
+       Fixes for mtools_no_vfat
+v19970402
+       Additional config file pointed by MTOOLSRC; possibility to
+       switch off generation of VFAT long names.
+v19970401
+       HP/UX setresuid support. "Mcopy a: ." bugfix.
+v19970331
+       Renamed f_* functions into file_* in order to avoid a clash
+       with a preprocessor macro named f_data on AIX.
+v19970323
+       Released 3.5, Solaris compatibility fix w.r.t. memmove
+v19970323
+       Released 3.4
+v19970319
+       Fixed location of configuration file in doc.
+v19970318
+       Fixed mlabel bug
+v19970316
+       More BSD & 64 bit changes
+v19970308
+       Added at_exit implementation for those boxes who have neither
+       on_exit nor atexit.  Added check to make sure the compiler
+       handels structures in a sane way.
+v19970307
+       Backed out again of the traditional-cpp change on
+       larry.jones@sdrc.com's advice
+v19970306
+       Added traditional-cpp in order to make mtools compilable on a Sun
+v19970304
+       Fixed nolock flag
+v19970227
+       BEOS fixes and support for SCSI devices with a sector size
+       different from 512.
+v19970225
+       Fixed some preprocessor macros.  Added texclean macro to Makefile
+v19970224
+       Clarified the documentation about the Bebox.
+v19970224
+       Released 3.3
+v19970220
+       Made Makefile "AIX-proof".  Added precmd to config.c
+v19970219
+       Fixed typo in mdel.
+v19970217
+       Osf4 support.  Released 3.2
+v19970216
+       Fixed Makefile typo, and fixed various bugs with renaming or
+       moving dot or dot dot
+v19970215
+       Fixed streamcache.c bug
+v19970214
+       Added add-disk script and format.dat file
+v19970214
+       Fixed mrd e:xxx/, tested Xdf support
+v19970210
+       Strange mformat fixes...  Dos always seems to assume a cluster
+       size of at least 8 sectors and 512 root directory entries.  Sigh!       
+v19970209
+       FAT32 support, BeOS patches
+v19970208
+       Added more debugging code to mpartition and minfo.  Added
+       "packed" attribute to the partition structure.
+       Cleaned up argument handling.
+v19970207
+       Fixed partition removal bug in mpartition.c
+v19970206
+       Fixed streamcache allocation bug.  Clearer error message when
+       trying to access a non-existant partition.
+v19970205
+       Added "packed" attribute to some fields of the vfat_subentry
+       structure, in order to work around a bug in a gcc version for
+       SunOS.
+       Use getpass() for password prompting in mzip.c  
+v19970203
+       Various small bug fixes
+v19970202
+       Fixed typoes in plain_io.c, mpartition.c and mtools.texi.
+       Relaxed security in mpartition.c, so non-root users may print
+       a partition, or perform any local changes to it.
+       Mpartition now prints info to recreate partition.
+v19970201
+       Add mpartition command to partition Zip, Jaz and other Scsi
+       devices.
+       Chose between on_exit or atexit using autoconf.
+v19970130
+       Added minfo command to print disk geometry and other parameters.
+v19970129
+       Replaced atexit by onexit. Atexit barfed on SunOs.
+       Replaced O_RDWR flag in mzip with O_RDONLY.
+       Added precmd variable to execute commands before opening a
+       given drive.
+v19970127
+       Shortened README, segregated config file pathnames into a
+       separate file.
+v19970125
+       General cleanup, more enhancements to privilege handling.
+v19970123
+       Added debugging output to mzip.
+       Made expand.c safe and still compatible with suid operation.
+       Fixed mzip typo.
+       Made device locking optional.
+v19970122
+       Added const qualifiers
+v19970120
+       3.1 Released
+v19970116
+       Added kludgy xcopy support
+v19970111
+       Only skip sys_errlist declaration on NetBSD (some older
+       platforms might need this)
+v19970110
+       Upgraded to autoconf 2.12, fixed some Stallmanisms.
+       Added device entry for LynxOs.
+v19970107
+       Use gettimeofday before tzset (for BSD).
+v19970107
+       Use correct location of signal.h.  Removed declaration
+       for sys_errlist.
+v19970107
+       BEOS patches by Marco Nelissen
+       Removed some clashing prototypes
+v19970103
+       Prints privilege debugging message to stderr, and reopens SCSI
+       file with root privileges.
+v19961227
+       Fixed typoes in mzip.  Added pointer to html doc.
+v19961226
+       Fixed Linux Scsi ioctl.
+v19961225
+       Added warnings against cookies, fixed doc to reflect new set-uid
+       policy.
+v19961224
+       Fixed typoes in privilege routines, and removed Heisenbergian
+       parts of the  debugging code.
+v19961223
+       Deleted prototypes for random() and srandom(): they *did*
+       clash (on a DEC Alpha)
+v19961222
+       Solaris & SunOS privilege management.  Fixed date entries in
+       ChangeLog file.
+v19961221
+       Solaris ZIP fix.
+v19961219
+       Cosmetic mzip fixes.  Add pointer to info doc to mtools.1
+v19961219
+       ISC addition. Doc fix for set_parameters ioctl.
+v19961217
+       Mformat doc fix.
+v19961216
+       Replaced zip_* by scsi_*, as these functions are not
+       specifically relevant to the ZIP (they apply to the JAZ as
+       well)
+       Fixed documentation on -n flag for mcopy
+v19961217
+       Include termio before termios because of SCO
+       Applied Jaz patch
+       Do not declare timezone external variable on Ultrix, where it
+       has a different type.   
+v19961215
+       Changed floppy into rfloppy for HP/UX.
+v19961214
+       Added -Q option to mcopy, which aborts copying multiple files
+       as soon as an error for one file is encounteres
+       Removed useless -i option for mcopy
+       Small devices.c portability fixes (ultrix and hpux)
+v19961211
+       Added mzip (eject ZIP disks) (Markus Gyger <mgyger@itr.ch>)
+       Renamed mtest to mtoolstest to please pine.
+v19961210
+       Added warning about running mtools with root privs.
+v19961209
+       Fixed unitialized variable in fat.c and added example for Sun
+       mtools.conf
+v19961209
+       Fixed comment in scripts/tgz
+v19961207
+       Fixed partition handling code (yes, again!)
+       Added code to handle ZIP disks on Solaris/SunOS (many thanks
+       to James P. Dugal (jpd@usl.edu))
+v19961203
+       Proper permissions for main directory.
+v19961202
+       Renamed scripts/gz to scripts/tgz
+v19961202
+       Added raw devices for Solaris, apparently more performant
+       Test first for tzset in autoconfigure (Solaris)
+v19961202
+       Segment fault due to change of buffer size fixed
+       E-mail adress fixed
+v19961117
+       Lots of portability fixes.
+v19961012
+       Yet another typo fix for the partition table code.  Oh Gawd,
+       will this never stop?
+       Fix for proper .mcwd pathname concatenations
+v19961009
+       Backed out partition table "fix": the original code was right
+       after all
+v19960920
+       Corrected a few uninitialised variables
+v19960918
+       Corrected doc about devices file.
+v19960917
+       Added pointer to the doc to the README file
+v19960913
+       Partition table parsing fixed
+v19960807
+       Fujitsu DS/90 (UXP) support
+v19960727
+       ISC device
+       dispatcher cleanup in mtools.h
+       fat_bits 12/16 toggle fix.
+       More space for error message variable in mformat
+       Typo fix in mren.1
+v19960710
+       Fix for CPU names with dots in autoconfigure
+       Some new device descriptions
+       FreeBSD fixes
+v19960624
+       Set XDF mode when formatting an XDF disk (makes sense, after all...)
+v19960623
+       XDF seems to work. Yeah!
+v19960620
+       More ED fixes. More parameter size fixed for 64bit.
+v19960609
+       Beginning of ED and 5 1/4 HD XDF support (doesn't work yet for
+       ED)
+v19960528
+       Make vold and "raw" floppy drive accesible simultaneously on
+       Solaris by calling one A: and the other B:
+       Add missing mbadblock LINK in Makefile.in
+v19960527
+       Inserted missing newline character
+v19960525
+       Treat number of heads or sectors as chars. The BIOS wouldn't
+       allow bigger numbers anyways, thus big numbers are probably
+       due to errors.
+v19960524
+       Pattern match fix.
+       Geometry setting for HP/UX
+v19960522
+       Changed auto array in codepage to malloc'ed one in order to
+       work around buggy compilers
+       OSF ALPHA devices
+       Pointers to other doc in the INSTALL file
+v19960516
+       Do no longer be confused by deleted VSE's
+       Define MAXPATHLEN for SCO
+       Missing lockf prototype for SCO
+v19960514
+       Handle DEBUG flag by autoconf
+       Added Host vendor to compile flags in order to handle Sinix
+       Better Sinix handling in devices.c
+       Only print duplicate VSE messages when running with DEBUG
+       Fix mlabel exit code
+       Read-only locking
+       Doc fixes
+       Xcopy fixes for Sysv
+v19960512
+       3.0 released.
+v19960508
+       pre4-3.0. Lots of bug fixes. Texinfo file
+v19960502
+       pre-3.0
+v19960501
+       use autoconf to get rid once and for all of those pesky OS
+       dependencies.
+v19960429
+       use sys/termio instead of sys/termios to please AIX
+v19960427
+       more spelling fixes.
+v19960426
+       Speling fixes
+v19960424
+       Mmount arg parsing bug fix
+v19960422
+       New partition configuration variable.
+v19960419
+       Spelling fixes, removed warning in README, IRIX floppy devices
+v19960214
+       More Alpha streamlining
+v19960213
+       Alpha patches (64 bit clean-ness)
+       AIX patches (built in drive names)
+       Raw tty patches (no need to type return when confirming an action
+v19960131
+       Solaris patches
+       Replaced include strings.h by string.h everywhere where applicable
+       Changed thousands separator in mdir from a dot to a space to
+       please both Americans and Europeans.
+       Fixed memory allocation bug if no "constant device" is present.
+       #defined strtoul to atol for SunOS
+v19960121
+       Minor cleanup, released 2.5.4
+v19951205
+       Added "magic" header to manpages to have man run them through tbl
+v19951209
+       MTOOLS_LOWER_CASE is back, various small bug fixes over
+       Tuesday's changes
+v19951205
+       Bus strike in Grenoble! Well, let's do something useful and
+       re-arrange the configuration file syntax :-)
+       The syntax has become much more flexible now, and also
+       includes items which used to be only accessible via
+       environmental variables.
+       Moreover, it is now possible to include character translation
+       tables in line.
+v19951126
+       Fixed another Atari disk bug: Atari disks sport a bogus
+       "number of hidden sectors"
+v19951125
+       Fixed missing zero-terminator in autorenamed long names
+       MTOOLS_SKIP_CHECK now implies MTOOLS_FAT_COMPATIBILITY.
+v19951124
+       Fixed small quoted-printable-induced typo in the Makefile.
+       <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 (file)
index 0000000..9befffd
--- /dev/null
+++ b/README
@@ -0,0 +1,76 @@
+Compilation
+-----------
+
+ To compile mtools on Unix, first type ./configure, then make.  To
+compile mtools on a Bebox, refer to README.BEBOX.
+
+Doc
+---
+
+ The most uptodate doc of this package is the texinfo doc. Type 'make
+info' to get online info doc, and 'make dvi ; dvips mtools.dvi' to get
+a printed copy.  The info doc has a concept index.  Make use of it.
+ You may get an info copy using the following command 'make info'.
+This can then be viewed using emacs' info mode, or using a standalone
+info viewer.
+ Man pages are still present, but contain less information.
+ If you do not have the necessary tools to view the texinfo doc, you
+may also find it on the World Wide Web at the following locations:
+  http://ftp.gnu.org/software/mtools/manual/mtools.html
+
+Compiler
+--------
+
+ Mtools should be compiled with an Ansi compiler, preferably gcc
+
+Authors
+-------
+
+Original code (versions through 2.0.7?) by Emmet P. Gray (Texas, USA).
+Viktor Dukhovni (at Princeton, USA) had major input into v2.0.
+
+Since 2.0.7: maintained primarily and until now by Alain Knaff
+(Luxembourg) and David Niemi (Reston, Virginia, USA).
+
+Please report bugs to the mtools mailing list at mtools@www.tux.org.
+Before reporting any problems, check whether they have already been
+fixed in the Alpha patches at http://mtools.linux.lu and
+http://www.tux.org/pub/knaff
+
+You may subscribe to the mtools mailing list by sending a message
+containing 'subscribe mtools' in its body to majordomo@www.tux.org
+
+Since March 3rd 2009, mtools is now officially a GNU package. Special
+thanks to Emmet P. Gray, the original developer of the program, who
+supported dubbing mtools a GNU package.
+
+Current Status
+--------------
+
+Stable release 4.0.x
+
+Copying
+-------
+Mtools is a GNU program published under GPL v3.0 (code) and GNU Free
+Documentation License.
+
+Most files of mtools bears a notice describing the copyright, and
+whether it is covered by GPL or GFDL
+
+GPL:
+
+debian/control         Copyright 2007 Alain Knaff
+
+debian/changelog       Copyright 2007-2009 Alain Knaff
+
+NEWS                   Copyright 1995 David C. Niemi
+                       Copyright 1995-2009 Alain Knaff
+
+mtools.spec            Copyright 2003-2005,2007-2009 Alain Knaff
+
+
+GFDL:
+
+README                 Copyright 1996-1998,2001,2002,2009 Alain Knaff.
+Release.notes          Copyright 1995 Alain Knaff
+
diff --git a/README.BEBOX b/README.BEBOX
new file mode 100644 (file)
index 0000000..29e6bfa
--- /dev/null
@@ -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 (file)
index 0000000..f434b4a
--- /dev/null
@@ -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 (file)
index 0000000..50b2e21
--- /dev/null
@@ -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 (file)
index 0000000..d09030c
--- /dev/null
+++ b/buffer.c
@@ -0,0 +1,392 @@
+/*  Copyright 1997,2001-2003 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 alignemnt,
+                                * but for efficiency, less data may be read */
+       int ever_dirty;         /* was the buffer ever dirty? */
+       size_t dirty_pos;
+       size_t dirty_end;
+       mt_off_t current;               /* first sector in buffer */
+       size_t cur_size;                /* the current size */
+       char *buf;              /* disk read/write buffer */
+} Buffer_t;
+
+/*
+ * Flush a dirty buffer to disk.  Resets Buffer->dirty to zero.
+ * All errors are fatal.
+ */
+
+static int _buf_flush(Buffer_t *Buffer)
+{
+       int ret;
+
+       if (!Buffer->Next || !Buffer->dirty)
+               return 0;
+       if(Buffer->current < 0L) {
+               fprintf(stderr,"Should not happen\n");
+               return -1;
+       }
+#ifdef DEBUG
+       fprintf(stderr, "write %08x -- %02x %08x %08x\n",
+               Buffer,
+               (unsigned char) Buffer->buf[0],
+               Buffer->current + Buffer->dirty_pos,
+               Buffer->dirty_end - Buffer->dirty_pos);
+#endif
+
+       ret = force_write(Buffer->Next,
+                         Buffer->buf + Buffer->dirty_pos,
+                         Buffer->current + Buffer->dirty_pos,
+                         Buffer->dirty_end - Buffer->dirty_pos);
+       if(ret != (signed int) (Buffer->dirty_end - Buffer->dirty_pos)) {
+               if(ret < 0)
+                       perror("buffer_flush: write");
+               else
+                       fprintf(stderr,"buffer_flush: short write\n");
+               return -1;
+       }
+       Buffer->dirty = 0;
+       Buffer->dirty_end = 0;
+       Buffer->dirty_pos = 0;
+       return 0;
+}
+
+static int invalidate_buffer(Buffer_t *Buffer, mt_off_t start)
+{
+       /*fprintf(stderr, "invalidate %x\n", Buffer);*/
+       if(Buffer->sectorSize == 32) {
+               fprintf(stderr, "refreshing directory\n");
+       }
+
+       if(_buf_flush(Buffer) < 0)
+               return -1;
+
+       /* start reading at the beginning of start's sector
+        * don't start reading too early, or we might not even reach
+        * start */
+       Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
+       Buffer->cur_size = 0;
+       return 0;
+}
+
+#undef OFFSET
+#define OFFSET (start - This->current)
+
+typedef enum position_t {
+       OUTSIDE,
+       APPEND,
+       INSIDE,
+       ERROR
+} position_t;
+
+static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
+{
+       if(start >= This->current &&
+          start < This->current + This->cur_size) {
+               maximize(*len, This->cur_size - OFFSET);
+               return INSIDE;
+       } else if(start == This->current + This->cur_size &&
+                 This->cur_size < This->size &&
+                 *len >= This->sectorSize) {
+               /* append to the buffer for this, three conditions have to
+                * be met:
+                *  1. The start falls exactly at the end of the currently
+                *     loaded data
+                *  2. There is still space
+                *  3. We append at least one sector
+                */
+               maximize(*len, This->size - This->cur_size);
+               *len = ROUND_DOWN(*len, This->sectorSize);
+               return APPEND;
+       } else {
+               if(invalidate_buffer(This, start) < 0)
+                       return ERROR;
+               maximize(*len, This->cylinderSize - OFFSET);
+               maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
+               return OUTSIDE;
+       }
+}
+
+static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+       size_t length;
+       int offset;
+       char *disk_ptr;
+       int ret;
+       DeclareThis(Buffer_t);  
+
+       if(!len)
+               return 0;       
+
+       /*fprintf(stderr, "buf read %x   %x %x\n", Stream, start, len);*/
+       switch(isInBuffer(This, start, &len)) {
+               case OUTSIDE:
+               case APPEND:
+                       /* always load until the end of the cylinder */
+                       length = This->cylinderSize -
+                               (This->current + This->cur_size) % This->cylinderSize;
+                       maximize(length, This->size - This->cur_size);
+
+                       /* read it! */
+                       ret=READS(This->Next,
+                                 This->buf + This->cur_size,
+                                 This->current + This->cur_size,
+                                 length);
+                       if ( ret < 0 )
+                               return ret;
+                       This->cur_size += ret;
+                       if (This->current+This->cur_size < start) {
+                               fprintf(stderr, "Short buffer fill\n");
+                               exit(1);
+                       }
+                       break;
+               case INSIDE:
+                       /* nothing to do */
+                       break;
+               case ERROR:
+                       return -1;
+       }
+
+       offset = OFFSET;
+       disk_ptr = This->buf + offset;
+       maximize(len, This->cur_size - offset);
+       memcpy(buf, disk_ptr, len);
+       return len;
+}
+
+static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+       char *disk_ptr;
+       DeclareThis(Buffer_t);  
+       size_t offset;
+
+       if(!len)
+               return 0;
+
+       This->ever_dirty = 1;
+
+#ifdef DEBUG
+       fprintf(stderr, "buf write %x   %02x %08x %08x -- %08x %08x -- %08x\n",
+               Stream, (unsigned char) This->buf[0],
+               start, len, This->current, This->cur_size, This->size);
+       fprintf(stderr, "%d %d %d %x %x\n",
+               start == This->current + This->cur_size,
+               This->cur_size < This->size,
+               len >= This->sectorSize, len, This->sectorSize);
+#endif
+       switch(isInBuffer(This, start, &len)) {
+               case OUTSIDE:
+#ifdef DEBUG
+                       fprintf(stderr, "outside\n");
+#endif
+                       if(start % This->cylinderSize ||
+                          len < This->sectorSize) {
+                               size_t readSize;
+                               int ret;
+
+                               readSize = This->cylinderSize -
+                                       This->current % This->cylinderSize;
+
+                               ret=READS(This->Next, This->buf, This->current, readSize);
+                               /* read it! */
+                               if ( ret < 0 )
+                                       return ret;
+                               if(ret % This->sectorSize) {
+                                 fprintf(stderr, "Weird: read size (%d) not a multiple of sector size (%d)\n", ret, (int) This->sectorSize);
+                                   ret -= ret % This->sectorSize;
+                                   if(ret == 0) {
+                                       fprintf(stderr, "Nothing left\n");
+                                       exit(1);
+                                   }
+                               }
+                               This->cur_size = ret;
+                               /* for dosemu. Autoextend size */
+                               if(!This->cur_size) {
+                                       memset(This->buf,0,readSize);
+                                       This->cur_size = readSize;
+                               }
+                               offset = OFFSET;
+                               break;
+                       }
+                       /* FALL THROUGH */
+               case APPEND:
+#ifdef DEBUG
+                       fprintf(stderr, "append\n");
+#endif
+                       len = ROUND_DOWN(len, This->sectorSize);
+                       offset = OFFSET;
+                       maximize(len, This->size - offset);
+                       This->cur_size += len;
+                       if(This->Next->Class->pre_allocate)
+                               PRE_ALLOCATE(This->Next,
+                                                        This->current + This->cur_size);
+                       break;
+               case INSIDE:
+                       /* nothing to do */
+#ifdef DEBUG
+                       fprintf(stderr, "inside\n");
+#endif
+                       offset = OFFSET;
+                       maximize(len, This->cur_size - offset);
+                       break;
+               case ERROR:
+                       return -1;
+               default:
+#ifdef DEBUG
+                       fprintf(stderr, "Should not happen\n");
+#endif
+                       exit(1);
+       }
+
+       disk_ptr = This->buf + offset;
+
+       /* extend if we write beyond end */
+       if(offset + len > This->cur_size) {
+               len -= (offset + len) % This->sectorSize;
+               This->cur_size = len + offset;
+       }
+
+       memcpy(disk_ptr, buf, len);
+       if(!This->dirty || offset < This->dirty_pos)
+               This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
+       if(!This->dirty || offset + len > This->dirty_end)
+               This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
+       
+       if(This->dirty_end > This->cur_size) {
+               fprintf(stderr,
+                       "Internal error, dirty end too big dirty_end=%x cur_size=%x len=%x offset=%d sectorSize=%x\n",
+                       (unsigned int) This->dirty_end,
+                       (unsigned int) This->cur_size,
+                       (unsigned int) len,
+                       (int) offset, (int) This->sectorSize);
+               fprintf(stderr, "offset + len + grain - 1 = %x\n",
+                               (int) (offset + len + This->sectorSize - 1));
+               fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n",
+                               (int)ROUND_DOWN(offset + len + This->sectorSize - 1,
+                                                               This->sectorSize));
+               fprintf(stderr, "This->dirty = %d\n", This->dirty);
+               exit(1);
+       }
+
+       This->dirty = 1;
+       return len;
+}
+
+static int buf_flush(Stream_t *Stream)
+{
+       int ret;
+       DeclareThis(Buffer_t);
+
+       if (!This->ever_dirty)
+               return 0;
+       ret = _buf_flush(This);
+       if(ret == 0)
+               This->ever_dirty = 0;
+       return ret;
+}
+
+
+static int buf_free(Stream_t *Stream)
+{
+       DeclareThis(Buffer_t);
+
+       if(This->buf)
+               free(This->buf);
+       This->buf = 0;
+       return 0;
+}
+
+static Class_t BufferClass = {
+       buf_read,
+       buf_write,
+       buf_flush,
+       buf_free,
+       0, /* set_geom */
+       get_data_pass_through, /* get_data */
+       0, /* pre-allocate */
+       get_dosConvert_pass_through /* dos convert */
+};
+
+Stream_t *buf_init(Stream_t *Next, int size,
+                  int cylinderSize,
+                  int sectorSize)
+{
+       Buffer_t *Buffer;
+       Stream_t *Stream;
+
+
+       if(size % cylinderSize != 0) {
+               fprintf(stderr, "size not multiple of cylinder size\n");
+               exit(1);
+       }
+       if(cylinderSize % sectorSize != 0) {
+               fprintf(stderr, "cylinder size not multiple of sector size\n");
+               exit(1);
+       }
+
+       if(Next->Buffer){
+               Next->refs--;
+               Next->Buffer->refs++;
+               return Next->Buffer;
+       }
+
+       Stream = (Stream_t *) malloc (sizeof(Buffer_t));
+       if(!Stream)
+               return 0;
+       Buffer = (Buffer_t *) Stream;
+       Buffer->buf = malloc(size);
+       if ( !Buffer->buf){
+               Free(Stream);
+               return 0;
+       }
+       Buffer->size = size;
+       Buffer->dirty = 0;
+       Buffer->cylinderSize = cylinderSize;
+       Buffer->sectorSize = sectorSize;
+
+       Buffer->ever_dirty = 0;
+       Buffer->dirty_pos = 0;
+       Buffer->dirty_end = 0;
+       Buffer->current = 0L;
+       Buffer->cur_size = 0; /* buffer currently empty */
+
+       Buffer->Next = Next;
+       Buffer->Class = &BufferClass;
+       Buffer->refs = 1;
+       Buffer->Buffer = 0;
+       Buffer->Next->Buffer = (Stream_t *) Buffer;
+       return Stream;
+}
+
diff --git a/buffer.h b/buffer.h
new file mode 100644 (file)
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/byte_dword.h b/byte_dword.h
new file mode 100644 (file)
index 0000000..159faf5
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef BYTE_DWORD
+#define BYTE_DWORD
+
+/*  Copyright 2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static Dword byte2dword(Byte* val)
+{
+       Dword l;
+       l = (val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3];
+       
+       return l;
+}      
+
+static void dword2byte(Dword parm, Byte* rval)
+{
+       rval[0] = (parm >> 24) & 0xff;
+       rval[1] = (parm >> 16) & 0xff;
+       rval[2] = (parm >> 8)  & 0xff;
+       rval[3] = parm         & 0xff;
+}
+
+#endif
diff --git a/charsetConv.c b/charsetConv.c
new file mode 100644 (file)
index 0000000..686a878
--- /dev/null
@@ -0,0 +1,418 @@
+/*  Copyright 2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *                              
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or   
+ *  (at your option) any later version.                                 
+ *                                                                      
+ *  Mtools is distributed in the hope that it will be useful,           
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of      
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 char *wcharCp=NULL;
+
+static char* wcharTries[] = {
+       "WCHAR_T",
+       "UTF-32BE", "UTF-32LE",
+       "UTF-16BE", "UTF-16LE",
+       "UTF-32", "UTF-16",
+       "UCS-4BE", "UCS-4LE",
+       "UCS-2BE", "UCS-2LE",
+       "UCS-4", "UCS-2"
+};
+
+static wchar_t *testString = L"ab";
+
+static int try(char *testCp) {
+       size_t res;
+       char *inbuf = (char *)testString;
+       size_t inbufLen = 2*sizeof(wchar_t);
+       char outbuf[3];
+       char *outbufP = outbuf;
+       size_t outbufLen = 2*sizeof(char);
+       iconv_t test = iconv_open("ASCII", testCp);
+
+       if(test == (iconv_t) -1)
+               goto fail0;
+       res = iconv(test,
+                   &inbuf, &inbufLen,
+                   &outbufP, &outbufLen);
+       if(res != 0 || outbufLen != 0 || inbufLen != 0)
+               goto fail;
+       if(memcmp(outbuf, "ab", 2))
+               goto fail;
+       /* fprintf(stderr, "%s ok\n", testCp); */
+       return 1;
+ fail:
+       iconv_close(test);
+ fail0:
+       /*fprintf(stderr, "%s fail\n", testCp);*/
+       return 0;
+}
+
+static const char *getWcharCp() {
+       int i;
+       if(wcharCp != NULL)
+               return wcharCp; 
+       for(i=0; i< sizeof(wcharTries) / sizeof(wcharTries[0]); i++) {
+               if(try(wcharTries[i]))
+                       return (wcharCp=wcharTries[i]);
+       }
+       fprintf(stderr, "No codepage found for wchar_t\n");
+       return NULL;
+}
+
+
+doscp_t *cp_open(int codepage)
+{
+       char dosCp[17];
+       doscp_t *ret;
+       iconv_t *from;
+       iconv_t *to;
+
+       if(codepage == 0)
+               codepage = mtools_default_codepage;
+       if(codepage < 0 || codepage > 9999) {
+               fprintf(stderr, "Bad codepage %d\n", codepage);
+               return NULL;
+       }
+
+       if(getWcharCp() == NULL)
+               return NULL;
+
+       sprintf(dosCp, "CP%d", codepage);
+       from = iconv_open(wcharCp, dosCp);
+       if(from == (iconv_t)-1) {
+               fprintf(stderr, "Error converting to codepage %d %s\n",
+                       codepage, strerror(errno));
+               return NULL;
+       }
+
+       sprintf(dosCp, "CP%d//TRANSLIT", codepage);
+       to   =  iconv_open(dosCp, wcharCp);
+       if(to == (iconv_t)-1) {
+               /* Transliteration not supported? */
+               sprintf(dosCp, "CP%d", codepage);
+               to   =  iconv_open(dosCp, wcharCp);
+       }
+       if(to == (iconv_t)-1) {
+               iconv_close(from);
+               fprintf(stderr, "Error converting to codepage %d %s\n",
+                       codepage, strerror(errno));
+               return NULL;
+       }
+
+       ret = New(doscp_t);
+       if(ret == NULL)
+               return ret;
+       ret->from = from;
+       ret->to   = to;
+       return ret;
+}
+
+void cp_close(doscp_t *cp)
+{
+       iconv_close(cp->to);
+       iconv_close(cp->from);
+       free(cp);
+}
+
+int dos_to_wchar(doscp_t *cp, char *dos, wchar_t *wchar, size_t len)
+{
+       int r;
+       size_t in_len=len;
+       size_t out_len=len*sizeof(wchar_t);
+       wchar_t *dptr=wchar;
+       r=iconv(cp->from, &dos, &in_len, (char **)&dptr, &out_len);
+       if(r < 0)
+               return r;
+       *dptr = L'\0';
+       return dptr-wchar;
+}
+
+/**
+ * Converts len wide character to destination. Caller's responsibility to
+ * ensure that dest is large enough.
+ * mangled will be set if there has been an untranslatable character.
+ */
+static int safe_iconv(iconv_t conv, const wchar_t *wchar, char *dest,
+                     size_t len, int *mangled)
+{
+       int r;
+       int i;
+       size_t in_len=len*sizeof(wchar_t);
+       size_t out_len=len*4;
+       char *dptr = dest;
+
+       while(in_len > 0) {
+               r=iconv(conv, (char**)&wchar, &in_len, &dptr, &out_len);
+               if(r >= 0 || errno != EILSEQ) {
+                       /* everything transformed, or error that is _not_ a bad
+                        * character */
+                       break;
+               }
+               *mangled |= 1;
+
+               if(dptr)
+                       *dptr++ = '_';
+               in_len--;
+
+               wchar++;
+               out_len--;
+       }
+
+       len = dptr-dest; /* how many dest characters have there been
+                           generated */
+
+       /* eliminate question marks which might have been formed by
+          untransliterable characters */
+       for(i=0; 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, mangled);
+}
+
+#else
+
+#include "codepage.h"
+
+struct doscp_t {
+       unsigned char *from_dos;
+       unsigned char to_dos[0x80];
+};
+
+doscp_t *cp_open(int codepage)
+{
+       doscp_t *ret;
+       int i;
+       Codepage_t *cp;
+
+       if(codepage == 0)
+               codepage = 850;
+
+       ret = New(doscp_t);
+       if(ret == NULL)
+               return ret;
+
+       for(cp=codepages; cp->nr ; cp++)
+               if(cp->nr == codepage) {
+                       ret->from_dos = cp->tounix;
+                       break;
+               }
+
+       if(ret->from_dos == NULL) {
+               fprintf(stderr, "Bad codepage %d\n", codepage);
+               free(ret);
+               return NULL;
+       }
+
+       for(i=0; i<0x80; i++) {
+               char native = ret->from_dos[i];
+               if(! (native & 0x80))
+                       continue;
+               ret->to_dos[native & 0x7f] = 0x80 | i;
+       }
+       return ret;
+}
+
+void cp_close(doscp_t *cp)
+{
+       free(cp);
+}
+
+int dos_to_wchar(doscp_t *cp, char *dos, wchar_t *wchar, size_t len)
+{
+       int i;
+
+       for(i=0; i<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)
+{
+#ifdef HAVE_ICONV_H
+       int mangled;
+       int r;
+       initialize_to_native();
+       len = wcsnlen(wchar,len);
+       r=safe_iconv(to_native, wchar, native, len, &mangled);
+       native[r]='\0';
+       return r;
+#else
+       int i;
+       char *dptr = native;
+       mbstate_t ps;
+       memset(&ps, 0, sizeof(ps));
+       for(i=0; i<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, converting at most len wchar
+ * characters. If end is supplied, stop conversion when source pointer
+ * exceeds end. Returns number of converted wchars
+ */
+int native_to_wchar(const char *native, wchar_t *wchar, size_t len,
+                   const char *end, int *mangled)
+{
+       mbstate_t ps;
+       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 substitue
+                          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)
+               *mangled |= 3;
+       wchar[i]='\0';
+       return i;
+}
+
diff --git a/cleanconfig b/cleanconfig
new file mode 100644 (file)
index 0000000..1a4d69e
--- /dev/null
@@ -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 (file)
index 0000000..8775865
--- /dev/null
@@ -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 (file)
index 0000000..5558724
--- /dev/null
@@ -0,0 +1,117 @@
+/*  Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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,
+        "\80\81\82\83\84\85\86\87\88\89\8a\8b\8c\8d\8e\8f"
+        "\90\91\92\93\94\95\96\97\98\99\9a\9b\9c\9d\9e\9f"
+        " ¡¢£¤¥¦§¨©ª«¬­®¯"
+        "°±²³´µ¶·¸¹º»¼½¾¿"
+        "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ"
+        "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß"
+        "àáâãäåæçèéêëìíîï"
+        "ðñòóôõö÷øùúûüýþÿ",
+       },
+
+
+       { 0 }
+};
+
+#endif
diff --git a/config.c b/config.c
new file mode 100644 (file)
index 0000000..33bb6af
--- /dev/null
+++ b/config.c
@@ -0,0 +1,829 @@
+/*  Copyright 1996-2005,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 int flag_mask; /* mask of currently set flags */
+
+/* devices */
+static int cur_devs; /* current number of defined devices */
+static int cur_dev; /* device being filled in. If negative, none */
+static int trusted=0; /* is the currently parsed device entry trusted? */
+static int nr_dev; /* number of devices that the current table can hold */
+struct device *devices; /* the device table */
+static int token_nr; /* number of tokens in line */
+
+static char default_drive='\0'; /* default drive */
+
+/* "environment" variables */
+unsigned int mtools_skip_check=0;
+unsigned int mtools_fat_compatibility=0;
+unsigned int mtools_ignore_short_case=0;
+unsigned int mtools_rate_0=0;
+unsigned int mtools_rate_any=0;
+unsigned int mtools_no_vfat=0;
+unsigned int mtools_numeric_tail=1;
+unsigned int mtools_dotted_dir=0;
+unsigned int mtools_twenty_four_hour_clock=1;
+unsigned int mtools_default_codepage=850;
+const char *mtools_date_string="yyyy-mm-dd";
+char *country_string=0;
+
+typedef struct switches_l {
+    const char *name;
+    caddr_t address;
+    enum {
+       T_INT,
+       T_STRING,
+       T_UINT
+    } type;
+} switches_t;
+
+static switches_t global_switches[] = {
+    { "MTOOLS_LOWER_CASE", (caddr_t) & mtools_ignore_short_case, T_UINT },
+    { "MTOOLS_FAT_COMPATIBILITY", (caddr_t) & mtools_fat_compatibility, T_UINT },
+    { "MTOOLS_SKIP_CHECK", (caddr_t) & mtools_skip_check, T_UINT },
+    { "MTOOLS_NO_VFAT", (caddr_t) & mtools_no_vfat, T_UINT },
+    { "MTOOLS_RATE_0", (caddr_t) &mtools_rate_0, T_UINT },
+    { "MTOOLS_RATE_ANY", (caddr_t) &mtools_rate_any, T_UINT },
+    { "MTOOLS_NAME_NUMERIC_TAIL", (caddr_t) &mtools_numeric_tail, T_UINT },
+    { "MTOOLS_DOTTED_DIR", (caddr_t) &mtools_dotted_dir, T_UINT },
+    { "MTOOLS_TWENTY_FOUR_HOUR_CLOCK",
+      (caddr_t) &mtools_twenty_four_hour_clock, T_UINT },
+    { "MTOOLS_DATE_STRING",
+      (caddr_t) &mtools_date_string, T_STRING },
+    { "DEFAULT_CODEPAGE", (caddr_t) &mtools_default_codepage, T_UINT }
+};
+
+typedef struct {
+    const char *name;
+    int flag;
+} flags_t;
+
+static flags_t openflags[] = {
+#ifdef O_SYNC
+    { "sync",          O_SYNC },
+#endif
+#ifdef O_NDELAY
+    { "nodelay",       O_NDELAY },
+#endif
+#ifdef O_EXCL
+    { "exclusive",     O_EXCL },
+#endif
+    { "none", 0 }  /* hack for those compilers that choke on commas
+                   * after the last element of an array */
+};
+
+static flags_t misc_flags[] = {
+#ifdef USE_XDF
+    { "use_xdf",               USE_XDF_FLAG },
+#endif
+    { "scsi",                  SCSI_FLAG },
+    { "nolock",                        NOLOCK_FLAG },
+    { "mformat_only",  MFORMAT_ONLY_FLAG },
+    { "filter",                        FILTER_FLAG },
+    { "privileged",            PRIV_FLAG },
+    { "vold",                  VOLD_FLAG },
+    { "remote",                        FLOPPYD_FLAG },
+    { "swap",                  SWAP_FLAG },
+};
+
+static struct {
+    const char *name;
+    signed char fat_bits;
+    int tracks;
+    unsigned short heads;
+    unsigned short sectors;
+} default_formats[] = {
+    { "hd514",                 12, 80, 2, 15 },
+    { "high-density-5-1/4",    12, 80, 2, 15 },
+    { "1.2m",                  12, 80, 2, 15 },
+
+    { "hd312",                 12, 80, 2, 18 },
+    { "high-density-3-1/2",    12, 80, 2, 18 },
+    { "1.44m",                 12, 80, 2, 18 },
+
+    { "dd312",                 12, 80, 2, 9 },
+    { "double-density-3-1/2",  12, 80, 2, 9 },
+    { "720k",                  12, 80, 2, 9 },
+
+    { "dd514",                 12, 40, 2, 9 },
+    { "double-density-5-1/4",  12, 40, 2, 9 },
+    { "360k",                  12, 40, 2, 9 },
+
+    { "320k",                  12, 40, 2, 8 },
+    { "180k",                  12, 40, 1, 9 },
+    { "160k",                  12, 40, 1, 8 }
+};
+
+#define OFFS(x) ((caddr_t)&((struct device *)0)->x)
+
+static switches_t dswitches[]= {
+    { "FILE", OFFS(name), T_STRING },
+    { "OFFSET", OFFS(offset), T_UINT },
+    { "PARTITION", OFFS(partition), T_UINT },
+    { "FAT", OFFS(fat_bits), T_INT },
+    { "FAT_BITS", OFFS(fat_bits), T_UINT },
+    { "MODE", OFFS(mode), T_UINT },
+    { "TRACKS",  OFFS(tracks), T_UINT },
+    { "CYLINDERS",  OFFS(tracks), T_UINT },
+    { "HEADS", OFFS(heads), T_UINT },
+    { "SECTORS", OFFS(sectors), T_UINT },
+    { "HIDDEN", OFFS(hidden), T_UINT },
+    { "PRECMD", OFFS(precmd), T_STRING },
+    { "BLOCKSIZE", OFFS(blocksize), T_UINT },
+    { "CODEPAGE", OFFS(codepage), T_UINT }
+};
+
+static void maintain_default_drive(char drive)
+{
+    if(default_drive == ':')
+       return; /* we have an image */
+    if(default_drive == '\0' ||
+       default_drive > drive)
+       default_drive = drive;
+}
+
+char get_default_drive(void)
+{
+    if(default_drive != '\0')
+       return default_drive;
+    else
+       return 'A';
+}
+
+static void syntax(const char *msg, int thisLine)
+{
+    char drive='\0';
+    if(thisLine)
+       lastTokenLinenumber = linenumber;
+    if(cur_dev >= 0)
+       drive = devices[cur_dev].drive;
+    fprintf(stderr,"Syntax error at line %d ", lastTokenLinenumber);
+    if(drive) fprintf(stderr, "for drive %c: ", drive);
+    if(token) fprintf(stderr, "column %ld ", (long)(token - buffer));
+    fprintf(stderr, "in file %s: %s\n", filename, msg);
+    exit(1);
+}
+
+static void get_env_conf(void)
+{
+    char *s;
+    unsigned int i;
+
+    for(i=0; i< sizeof(global_switches) / sizeof(*global_switches); i++) {
+       s = getenv(global_switches[i].name);
+       if(s) {
+           if(global_switches[i].type == T_INT)
+               * ((int *)global_switches[i].address) = (int) strtol(s,0,0);
+           if(global_switches[i].type == T_UINT)
+               * ((int *)global_switches[i].address) = (unsigned int) strtoul(s,0,0);
+           else if (global_switches[i].type == T_STRING)
+               * ((char **)global_switches[i].address) = s;
+       }
+    }
+}
+
+static int mtools_getline(void)
+{
+    if(!fp || !fgets(buffer, MAX_LINE_LEN, fp))
+       return -1;
+    linenumber++;
+    pos = buffer;
+    token_nr = 0;
+    buffer[MAX_LINE_LEN] = '\0';
+    if(strlen(buffer) == MAX_LINE_LEN)
+       syntax("line too long", 1);
+    return 0;
+}
+               
+static void skip_junk(int expect)
+{
+    lastTokenLinenumber = linenumber;
+    while(!pos || !*pos || strchr(" #\n\t", *pos)) {
+       if(!pos || !*pos || *pos == '#') {
+           if(mtools_getline()) {
+               pos = 0;
+               if(expect)
+                   syntax("end of file unexpected", 1);
+               return;
+           }
+       } else
+           pos++;
+    }
+    token_nr++;
+}
+
+/* get the next token */
+static char *get_next_token(void)
+{
+    skip_junk(0);
+    if(!pos) {
+       token_length = 0;
+       token = 0;
+       return 0;
+    }
+    token = pos;
+    token_length = strcspn(token, " \t\n#:=");
+    pos += token_length;
+    return token;
+}
+
+static int match_token(const char *template)
+{
+    return (strlen(template) == token_length &&
+           !strncasecmp(template, token, token_length));
+}
+
+static void expect_char(char c)
+{
+    char buf[11];
+
+    skip_junk(1);
+    if(*pos != c) {
+       sprintf(buf, "expected %c", c);
+       syntax(buf, 1);
+    }
+    pos++;
+}
+
+static char *get_string(void)
+{
+    char *end, *str;
+
+    skip_junk(1);
+    if(*pos != '"')
+       syntax(" \" expected", 0);
+    str = pos+1;
+    end = strchr(str, '\"');
+    if(!end)
+       syntax("unterminated string constant", 1);
+    *end = '\0';
+    pos = end+1;
+    return str;
+}
+
+static unsigned int get_unumber(void)
+{
+    char *last;
+    unsigned int n;
+
+    skip_junk(1);
+    last = pos;
+    n=(unsigned int) strtoul(pos, &pos, 0);
+    if(last == pos)
+       syntax("numeral expected", 0);
+    pos++;
+    token_nr++;
+    return n;
+}
+
+static unsigned int get_number(void)
+{
+    char *last;
+    int n;
+
+    skip_junk(1);
+    last = pos;
+    n=(int) strtol(pos, &pos, 0);
+    if(last == pos)
+       syntax("numeral expected", 0);
+    pos++;
+    token_nr++;
+    return n;
+}
+
+/* purge all entries pertaining to a given drive from the table */
+static void purge(char drive, int fn)
+{
+    int i,j;
+
+    drive = toupper(drive);
+    for(j=0, i=0; i < cur_devs; i++) {
+       if(devices[i].drive != drive ||
+          devices[i].file_nr == fn)
+           devices[j++] = devices[i];
+    }
+    cur_devs = j;
+}
+
+static void grow(void)
+{
+    if(cur_devs >= nr_dev - 2) {
+       nr_dev = (cur_devs + 2) << 1;
+       if(!(devices=Grow(devices, nr_dev, struct device))){
+           printOom();
+           exit(1);
+       }
+    }
+}
+       
+
+static void init_drive(void)
+{
+    memset((char *)&devices[cur_dev], 0, sizeof(struct device));
+    devices[cur_dev].ssize = 2;
+}
+
+/* prepends a device to the table */
+static void prepend(void)
+{
+    int i;
+
+    grow();
+    for(i=cur_devs; i>0; i--)
+       devices[i] = devices[i-1];
+    cur_dev = 0;
+    cur_devs++;
+    init_drive();
+}
+
+
+/* appends a device to the table */
+static void append(void)
+{
+    grow();
+    cur_dev = cur_devs;
+    cur_devs++;
+    init_drive();
+}
+
+
+static void finish_drive_clause(void)
+{
+    char drive;
+    if(cur_dev == -1) {
+       trusted = 0;
+       return;
+    }
+    drive = devices[cur_dev].drive;
+    if(!devices[cur_dev].name)
+       syntax("missing filename", 0);
+    if(devices[cur_dev].tracks ||
+       devices[cur_dev].heads ||
+       devices[cur_dev].sectors) {
+       if(!devices[cur_dev].tracks ||
+          !devices[cur_dev].heads ||
+          !devices[cur_dev].sectors)
+           syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0);
+       if(!(devices[cur_dev].misc_flags &
+            (MFORMAT_ONLY_FLAG | FILTER_FLAG)))
+           syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0);
+    }
+    devices[cur_dev].file_nr = file_nr;
+    devices[cur_dev].cfg_filename = filename;
+    if(! (flag_mask & PRIV_FLAG) && IS_SCSI(&devices[cur_dev]))
+       devices[cur_dev].misc_flags |= PRIV_FLAG;
+    if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) {
+       fprintf(stderr,
+               "Warning: privileged flag ignored for drive %c: defined in file %s\n",
+               toupper(devices[cur_dev].drive), filename);
+       devices[cur_dev].misc_flags &= ~PRIV_FLAG;
+    }
+    trusted = 0;
+    cur_dev = -1;
+}
+
+static int set_var(struct switches_l *switches, int nr,
+                  caddr_t base_address)
+{
+    int i;
+    for(i=0; i < nr; i++) {
+       if(match_token(switches[i].name)) {
+           expect_char('=');
+           if(switches[i].type == T_UINT)
+               * ((int *)((long)switches[i].address+base_address)) =
+                   get_unumber();
+           if(switches[i].type == T_INT)
+               * ((int *)((long)switches[i].address+base_address)) =
+                   get_number();
+           else if (switches[i].type == T_STRING)
+               * ((char**)((long)switches[i].address+base_address))=
+                   strdup(get_string());
+           return 0;
+       }
+    }
+    return 1;
+}
+
+static int set_openflags(struct device *dev)
+{
+    unsigned int i;
+
+    for(i=0; i < sizeof(openflags) / sizeof(*openflags); i++) {
+       if(match_token(openflags[i].name)) {
+           dev->mode |= openflags[i].flag;
+           return 0;
+       }
+    }
+    return 1;
+}
+
+static int set_misc_flags(struct device *dev)
+{
+    unsigned int i;
+
+    for(i=0; i < sizeof(misc_flags) / sizeof(*misc_flags); i++) {
+       if(match_token(misc_flags[i].name)) {
+           flag_mask |= misc_flags[i].flag;
+           skip_junk(0);
+           if(pos && *pos == '=') {
+               pos++;
+               switch(get_number()) {
+                   case 0:
+                       return 0;
+                   case 1:
+                       break;
+                   default:
+                       syntax("expected 0 or 1", 0);
+               }
+           }
+           dev->misc_flags |= misc_flags[i].flag;
+           return 0;
+       }
+    }
+    return 1;
+}
+
+static int set_def_format(struct device *dev)
+{
+    unsigned int i;
+
+    for(i=0; i < sizeof(default_formats)/sizeof(*default_formats); i++) {
+       if(match_token(default_formats[i].name)) {
+           if(!dev->ssize)
+               dev->ssize = 2;
+           if(!dev->tracks)
+               dev->tracks = default_formats[i].tracks;
+           if(!dev->heads)
+               dev->heads = default_formats[i].heads;
+           if(!dev->sectors)
+               dev->sectors = default_formats[i].sectors;
+           if(!dev->fat_bits)
+               dev->fat_bits = default_formats[i].fat_bits;
+           return 0;
+       }
+    }
+    return 1;
+}
+
+static int parse_one(int privilege);
+
+/* check for offset embedded in file name, in the form file@@offset[SKMG] */
+static off_t get_offset(char *name) {
+  char s, *ofsp, *endp = NULL;
+  off_t ofs;
+
+  ofsp = strstr(devices[cur_dev].name, "@@");
+  if (ofsp == NULL)
+    return 0; /* no separator */
+  ofs = strtol(ofsp+2, &endp, 0);
+  if (ofs <= 0)
+    return 0; /* invalid or missing offset */
+  s = *endp++;
+  if (s) {   /* trailing char, see if it is a size specifier */
+    endp++;
+    if (s == 's' || s == 'S')       /* sector */
+      ofs <<= 9;
+    else if (s == 'k' || s == 'K')  /* kb */
+      ofs <<= 10;
+    else if (s == 'm' || s == 'M')  /* Mb */
+      ofs <<= 20;
+    else if (s == 'g' || s == 'G')  /* Gb */
+      ofs <<= 30;
+    else
+      return 0;      /* invalid character */
+    if (*endp)
+      return 0;      /* extra char, invalid */
+  }
+  *ofsp = '\0';                              /* truncate file name */
+  return ofs;
+}
+
+void set_cmd_line_image(char *img, int flags) {
+  char *name;
+  prepend();
+  devices[cur_dev].drive = ':';
+  default_drive = ':';
+  devices[cur_dev].name = name = strdup(img);
+  devices[cur_dev].fat_bits = 0;
+  devices[cur_dev].tracks = 0;
+  devices[cur_dev].heads = 0;
+  devices[cur_dev].sectors = 0;
+  devices[cur_dev].offset = get_offset(name);
+  if (strchr(devices[cur_dev].name, '|')) {
+    char *pipechar = strchr(devices[cur_dev].name, '|');
+    *pipechar = 0;
+    strncpy(buffer, pipechar+1, MAX_LINE_LEN);
+    buffer[MAX_LINE_LEN] = '\0';
+    fp = NULL;
+    filename = "{command line}";
+    linenumber = 0;
+    lastTokenLinenumber = 0;
+    pos = buffer;
+    token = 0;
+    while (parse_one(0));
+  }
+}
+
+static void parse_old_device_line(char drive)
+{
+    char name[MAXPATHLEN];
+    int items;
+    long offset;
+
+    /* finish any old drive */
+    finish_drive_clause();
+
+    /* purge out data of old configuration files */
+    purge(drive, file_nr);
+       
+    /* reserve slot */
+    append();
+    items = sscanf(token,"%c %s %i %i %i %i %li",
+                  &devices[cur_dev].drive,name,&devices[cur_dev].fat_bits,
+                  &devices[cur_dev].tracks,&devices[cur_dev].heads,
+                  &devices[cur_dev].sectors, &offset);
+    devices[cur_dev].offset = (off_t) offset;
+    switch(items){
+       case 2:
+           devices[cur_dev].fat_bits = 0;
+           /* fall thru */
+       case 3:
+           devices[cur_dev].sectors = 0;
+           devices[cur_dev].heads = 0;
+           devices[cur_dev].tracks = 0;
+           /* fall thru */
+       case 6:
+           devices[cur_dev].offset = 0;
+           /* fall thru */
+       default:
+           break;
+       case 0:
+       case 1:
+       case 4:
+       case 5:
+           syntax("bad number of parameters", 1);
+           exit(1);
+    }
+    if(!devices[cur_dev].tracks){
+       devices[cur_dev].sectors = 0;
+       devices[cur_dev].heads = 0;
+    }
+       
+    devices[cur_dev].drive = toupper(devices[cur_dev].drive);
+    maintain_default_drive(devices[cur_dev].drive);
+    if (!(devices[cur_dev].name = strdup(name))) {
+       printOom();
+       exit(1);
+    }
+    finish_drive_clause();
+    pos=0;
+}
+
+static int parse_one(int privilege)
+{
+    int action=0;
+
+    get_next_token();
+    if(!token)
+       return 0;
+
+    if((match_token("drive") && ((action = 1)))||
+       (match_token("drive+") && ((action = 2))) ||
+       (match_token("+drive") && ((action = 3))) ||
+       (match_token("clear_drive") && ((action = 4))) ) {
+       /* finish off the previous drive */
+       finish_drive_clause();
+
+       get_next_token();
+       if(token_length != 1)
+           syntax("drive letter expected", 0);
+
+       if(action==1 || action==4)
+           /* replace existing drive */                        
+           purge(token[0], file_nr);
+       if(action==4)
+           return 1;
+       if(action==3)
+           prepend();
+       else
+           append();
+       memset((char*)(devices+cur_dev), 0, sizeof(*devices));
+       trusted = privilege;
+       flag_mask = 0;
+       devices[cur_dev].drive = toupper(token[0]);
+       maintain_default_drive(devices[cur_dev].drive);
+       expect_char(':');
+       return 1;
+    }
+    if(token_nr == 1 && token_length == 1) {
+       parse_old_device_line(token[0]);
+       return 1;
+    }
+
+    if((cur_dev < 0 ||
+       (set_var(dswitches,
+                sizeof(dswitches)/sizeof(*dswitches),
+                (caddr_t)&devices[cur_dev]) &&
+        set_openflags(&devices[cur_dev]) &&
+        set_misc_flags(&devices[cur_dev]) &&
+        set_def_format(&devices[cur_dev]))) &&
+       set_var(global_switches,
+              sizeof(global_switches)/sizeof(*global_switches), 0))
+       syntax("unrecognized keyword", 1);
+    return 1;
+}
+
+static int parse(const char *name, int privilege)
+{
+    if(fp) {
+       fprintf(stderr, "File descriptor already set (%p)!\n", fp);
+       exit(1);
+    }
+    fp = fopen(name, "r");
+    if(!fp)
+       return 0;
+    file_nr++;
+    filename = name; /* no strdup needed: although lifetime of variable
+                       exceeds this function (due to dev->cfg_filename),
+                       we know that the name is always either
+                       1. a constant
+                       2. a statically allocate buffer
+                       3. an environment variable that stays unchanged
+                    */
+    linenumber = 0;
+    lastTokenLinenumber = 0;
+    pos = 0;
+    token = 0;
+    cur_dev = -1; /* no current device */
+
+    while(parse_one(privilege));
+    finish_drive_clause();
+    fclose(fp);
+    filename = NULL;
+    fp = NULL;
+    return 1;
+}
+
+void read_config(void)
+{
+    char *homedir;
+    char *envConfFile;
+    static char conf_file[MAXPATHLEN+sizeof(CFG_FILE1)];
+
+       
+    /* copy compiled-in devices */
+    file_nr = 0;
+    cur_devs = nr_const_devices;
+    nr_dev = nr_const_devices + 2;
+    devices = NewArray(nr_dev, struct device);
+    if(!devices) {
+       printOom();
+       exit(1);
+    }
+    if(nr_const_devices)
+       memcpy(devices, const_devices,
+              nr_const_devices*sizeof(struct device));
+
+    (void) ((parse(CONF_FILE,1) |
+            parse(LOCAL_CONF_FILE,1) |
+            parse(SYS_CONF_FILE,1)) ||
+           (parse(OLD_CONF_FILE,1) |
+            parse(OLD_LOCAL_CONF_FILE,1)));
+    /* the old-name configuration files only get executed if none of the
+     * new-name config files were used */
+
+    homedir = get_homedir();
+    if ( homedir ){
+       strncpy(conf_file, homedir, MAXPATHLEN );
+       conf_file[MAXPATHLEN]='\0';
+       strcat( conf_file, CFG_FILE1);
+       parse(conf_file,0);
+    }
+    memset((char *)&devices[cur_devs],0,sizeof(struct device));
+
+    envConfFile = getenv("MTOOLSRC");
+    if(envConfFile)
+       parse(envConfFile,0);
+
+    /* environmental variables */
+    get_env_conf();
+    if(mtools_skip_check)
+       mtools_fat_compatibility=1;
+}
+
+void mtoolstest(int argc, char **argv, int type)
+{
+    /* testing purposes only */
+    struct device *dev;
+    char drive='\0';
+
+    if(argc > 1 && argv[1][0] && argv[1][1] == ':') {
+       drive = toupper(argv[1][0]);
+    }
+
+    for (dev=devices; dev->name; dev++) {
+       if(drive && drive != dev->drive)
+           continue;
+       printf("drive %c:\n", dev->drive);
+       printf("\t#fn=%d mode=%d ",
+              dev->file_nr, dev->mode);
+       if(dev->cfg_filename)
+           printf("defined in %s\n", dev->cfg_filename);
+       else
+           printf("builtin\n");
+       printf("\tfile=\"%s\" fat_bits=%d \n",
+              dev->name,dev->fat_bits);
+       printf("\ttracks=%d heads=%d sectors=%d hidden=%d\n",
+              dev->tracks, dev->heads, dev->sectors, dev->hidden);
+       printf("\toffset=0x%lx\n", (long) dev->offset);
+       printf("\tpartition=%d\n", dev->partition);
+
+       if(dev->misc_flags)
+           printf("\t");
+
+       if(DO_SWAP(dev))
+           printf("swap ");
+       if(IS_SCSI(dev))
+           printf("scsi ");
+       if(IS_PRIVILEGED(dev))
+           printf("privileged");
+       if(IS_MFORMAT_ONLY(dev))
+           printf("mformat_only ");
+       if(SHOULD_USE_VOLD(dev))
+           printf("vold ");
+#ifdef USE_XDF
+       if(SHOULD_USE_XDF(dev))
+           printf("use_xdf ");
+#endif
+       if(dev->misc_flags)
+           printf("\n");
+
+       if(dev->mode)
+           printf("\t");
+#ifdef O_SYNC
+       if(dev->mode & O_SYNC)
+           printf("sync ");
+#endif
+#ifdef O_NDELAY
+       if((dev->mode & O_NDELAY))
+           printf("nodelay ");
+#endif
+#ifdef O_EXCL
+       if((dev->mode & O_EXCL))
+           printf("exclusive ");
+#endif
+       if(dev->mode)
+           printf("\n");
+
+       if(dev->precmd)
+           printf("\tprecmd=%s\n", dev->precmd);
+
+       printf("\n");
+    }
+
+    printf("mtools_fat_compatibility=%d\n",mtools_fat_compatibility);
+    printf("mtools_skip_check=%d\n",mtools_skip_check);
+    printf("mtools_lower_case=%d\n",mtools_ignore_short_case);
+
+    exit(0);
+}
diff --git a/config.guess b/config.guess
new file mode 100644 (file)
index 0000000..f32079a
--- /dev/null
@@ -0,0 +1,1526 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
+       if test x"$CC_FOR_BUILD" = x ; then
+         CC_FOR_BUILD=no_compiler_found ;
+       fi
+       ;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+       PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+       # NetBSD (nbsd) targets should (where applicable) match one or
+       # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+       # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+       # switched to ELF, *-*-netbsd* would select the old
+       # object file format.  This provides both forward
+       # compatibility and a consistent mechanism for selecting the
+       # object file format.
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           sh5el) machine=sh5le-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+       esac
+       # The Operating System including object format, if it has switched
+       # to ELF recently, or will in the future.
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
+               if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+                       | grep __ELF__ >/dev/null
+               then
+                   # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+                   # Return netbsd for either.  FIX?
+                   os=netbsd
+               else
+                   os=netbsdelf
+               fi
+               ;;
+           *)
+               os=netbsd
+               ;;
+       esac
+       # The OS release
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
+       # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+       # contains redundant information, the shorter form:
+       # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+       echo "${machine}-${os}${release}"
+       exit ;;
+    *:OpenBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+       exit ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit ;;
+    *:SolidBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+       exit ;;
+    macppc:MirBSD:*:*)
+       echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit ;;
+    alpha:OSF1:*:*)
+       case $UNAME_RELEASE in
+       *4.0)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
+       # A Vn.n version is a released version.
+       # A Tn.n version is a released field test version.
+       # A Xn.n version is an unreleased experimental baselevel.
+       # 1.2 uses "1.2" for uname -r.
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       exit ;;
+    Alpha\ *:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # Should we change UNAME_MACHINE based on the output of uname instead
+       # of the specific Alpha model?
+       echo alpha-pc-interix
+       exit ;;
+    21064:Windows_NT:50:3)
+       echo alpha-dec-winnt3.5
+       exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+       echo m68k-unknown-sysv4
+       exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-amigaos
+       exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
+       exit ;;
+    *:OS/390:*:*)
+       echo i370-ibm-openedition
+       exit ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+       exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+       echo arm-acorn-riscix${UNAME_RELEASE}
+       exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+       echo arm-unknown-riscos
+       exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+       echo hppa1.1-hitachi-hiuxmpp
+       exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+       # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+       if test "`(/bin/universe) 2>/dev/null`" = att ; then
+               echo pyramid-pyramid-sysv3
+       else
+               echo pyramid-pyramid-bsd
+       fi
+       exit ;;
+    NILE*:*:*:dcosx)
+       echo pyramid-pyramid-svr4
+       exit ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7; exit ;;
+       esac ;;
+    sun4H:SunOS:5.*:*)
+       echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+       echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+       echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:6*:*)
+       # According to config.sub, this is the proper way to canonicalize
+       # SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+       # it's likely to be more like Solaris than SunOS4.
+       echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    sun4*:SunOS:*:*)
+       case "`/usr/bin/arch -k`" in
+           Series*|S4*)
+               UNAME_RELEASE=`uname -v`
+               ;;
+       esac
+       # Japanese Language versions have a version number like `4.1.3-JL'.
+       echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+       exit ;;
+    sun3*:SunOS:*:*)
+       echo m68k-sun-sunos${UNAME_RELEASE}
+       exit ;;
+    sun*:*:4.2BSD:*)
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       case "`/bin/arch`" in
+           sun3)
+               echo m68k-sun-sunos${UNAME_RELEASE}
+               ;;
+           sun4)
+               echo sparc-sun-sunos${UNAME_RELEASE}
+               ;;
+       esac
+       exit ;;
+    aushp:SunOS:*:*)
+       echo sparc-auspex-sunos${UNAME_RELEASE}
+       exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+       echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+       exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
+       exit ;;
+    powerpc:machten:*:*)
+       echo powerpc-apple-machten${UNAME_RELEASE}
+       exit ;;
+    RISC*:Mach:*:*)
+       echo mips-dec-mach_bsd4.3
+       exit ;;
+    RISC*:ULTRIX:*:*)
+       echo mips-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    VAX*:ULTRIX*:*:*)
+       echo vax-dec-ultrix${UNAME_RELEASE}
+       exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+       echo clipper-intergraph-clix${UNAME_RELEASE}
+       exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <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:*:[456])
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+       if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+               IBM_ARCH=rs6000
+       else
+               IBM_ARCH=powerpc
+       fi
+       if [ -x /usr/bin/oslevel ] ; then
+               IBM_REV=`/usr/bin/oslevel`
+       else
+               IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+       fi
+       echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+       exit ;;
+    *:AIX:*:*)
+       echo rs6000-ibm-aix
+       exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+       echo romp-ibm-bsd4.4
+       exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+       echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+       exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+       echo rs6000-bull-bosx
+       exit ;;
+    DPX/2?00:B.O.S.:*:*)
+       echo m68k-bull-sysv3
+       exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+       echo m68k-hp-bsd
+       exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+       echo m68k-hp-bsd4.4
+       exit ;;
+    9000/[34678]??:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       case "${UNAME_MACHINE}" in
+           9000/31? )            HP_ARCH=m68000 ;;
+           9000/[34]?? )         HP_ARCH=m68k ;;
+           9000/[678][0-9][0-9])
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <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 __LP64__ >/dev/null
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
+       echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+       exit ;;
+    ia64:HP-UX:*:*)
+       HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+       echo ia64-hp-hpux${HPUX_REV}
+       exit ;;
+    3050*:HI-UX:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <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:*:*)
+       case ${UNAME_MACHINE} in
+           pc98)
+               echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           amd64)
+               echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+           *)
+               echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+       esac
+       exit ;;
+    i*:CYGWIN*:*)
+       echo ${UNAME_MACHINE}-pc-cygwin
+       exit ;;
+    *:MINGW*:*)
+       echo ${UNAME_MACHINE}-pc-mingw32
+       exit ;;
+    i*:windows32*:*)
+       # uname -m includes "-pc" on this system.
+       echo ${UNAME_MACHINE}-mingw32
+       exit ;;
+    i*:PW*:*)
+       echo ${UNAME_MACHINE}-pc-pw32
+       exit ;;
+    *:Interix*:[3456]*)
+       case ${UNAME_MACHINE} in
+           x86)
+               echo i586-pc-interix${UNAME_RELEASE}
+               exit ;;
+           EM64T | authenticamd)
+               echo x86_64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+           IA64)
+               echo ia64-unknown-interix${UNAME_RELEASE}
+               exit ;;
+       esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+       # How do we know it's Interix rather than the generic POSIX subsystem?
+       # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+       # UNAME_MACHINE based on the output of uname instead of i386?
+       echo i586-pc-interix
+       exit ;;
+    i*:UWIN*:*)
+       echo ${UNAME_MACHINE}-pc-uwin
+       exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit ;;
+    p*:CYGWIN*:*)
+       echo powerpcle-unknown-cygwin
+       exit ;;
+    prep*:SunOS:5.*:*)
+       echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+       exit ;;
+    *:GNU:*:*)
+       # the GNU system
+       echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+       exit ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+       exit ;;
+    i*86:Minix:*:*)
+       echo ${UNAME_MACHINE}-pc-minix
+       exit ;;
+    arm*:Linux:*:*)
+       eval $set_cc_for_build
+       if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+           | grep -q __ARM_EABI__
+       then
+           echo ${UNAME_MACHINE}-unknown-linux-gnu
+       else
+           echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+       fi
+       exit ;;
+    avr32*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    cris:Linux:*:*)
+       echo cris-axis-linux-gnu
+       exit ;;
+    crisv32:Linux:*:*)
+       echo crisv32-axis-linux-gnu
+       exit ;;
+    frv:Linux:*:*)
+       echo frv-unknown-linux-gnu
+       exit ;;
+    ia64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    m68*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    mips:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips
+       #undef mipsel
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mipsel
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+           /^CPU/{
+               s: ::g
+               p
+           }'`"
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+       ;;
+    mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips64
+       #undef mips64el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mips64el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips64
+       #else
+       CPU=
+       #endif
+       #endif
+EOF
+       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+           /^CPU/{
+               s: ::g
+               p
+           }'`"
+       test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+       ;;
+    or32:Linux:*:*)
+       echo or32-unknown-linux-gnu
+       exit ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
+       exit ;;
+    alpha:Linux:*:*)
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+       echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+       exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+       # Look for CPU level
+       case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+         PA7*) echo hppa1.1-unknown-linux-gnu ;;
+         PA8*) echo hppa2.0-unknown-linux-gnu ;;
+         *)    echo hppa-unknown-linux-gnu ;;
+       esac
+       exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+       echo hppa64-unknown-linux-gnu
+       exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+       echo ${UNAME_MACHINE}-ibm-linux
+       exit ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sh*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    vax:Linux:*:*)
+       echo ${UNAME_MACHINE}-dec-linux-gnu
+       exit ;;
+    x86_64:Linux:*:*)
+       echo x86_64-unknown-linux-gnu
+       exit ;;
+    xtensa*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit ;;
+    i*86:Linux:*:*)
+       # The BFD linker knows what the default object file format is, so
+       # first see if it will tell us. cd to the root directory to prevent
+       # problems with other programs or directories called `ld' in the path.
+       # Set LC_ALL=C to ensure ld outputs messages in English.
+       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+                        | sed -ne '/supported targets:/!d
+                                   s/[         ][      ]*/ /g
+                                   s/.*supported targets: *//
+                                   s/ .*//
+                                   p'`
+        case "$ld_supported_targets" in
+         elf32-i386)
+               TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+               ;;
+         a.out-i386-linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit ;;
+         coff-i386)
+               echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+               exit ;;
+         "")
+               # Either a pre-BFD a.out linker (linux-gnuoldld) or
+               # one that does not give us useful --help.
+               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+               exit ;;
+       esac
+       # Determine whether the default compiler is a.out or elf
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #ifdef __ELF__
+       # ifdef __GLIBC__
+       #  if __GLIBC__ >= 2
+       LIBC=gnu
+       #  else
+       LIBC=gnulibc1
+       #  endif
+       # else
+       LIBC=gnulibc1
+       # endif
+       #else
+       #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+       LIBC=gnu
+       #else
+       LIBC=gnuaout
+       #endif
+       #endif
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
+EOF
+       eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+           /^LIBC/{
+               s: ::g
+               p
+           }'`"
+       test x"${LIBC}" != x && {
+               echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+               exit
+       }
+       test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+       ;;
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
+       echo i386-sequent-sysv4
+       exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+       # I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+       echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+       exit ;;
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit ;;
+    i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+       UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+       if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+               echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+       else
+               echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+       fi
+       exit ;;
+    i*86:*:5:[678]*)
+       # UnixWare 7.x, OpenUNIX and OpenServer 6.
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+       exit ;;
+    i*86:*:3.2:*)
+       if test -f /usr/options/cb.name; then
+               UNAME_REL=`sed -n 's/.*Version //p' </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 i386.
+       echo i386-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+       echo i386-pc-mach3
+       exit ;;
+    paragon:*:*:*)
+       echo i860-intel-osf1
+       exit ;;
+    i860:*:4.*:*) # i860-SVR4
+       if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+         echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+       else # Add other i860-SVR4 vendors below as they are discovered.
+         echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+       fi
+       exit ;;
+    mini*:CTIX:SYS*5:*)
+       # "miniframe"
+       echo m68010-convergent-sysv
+       exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit ;;
+    M68*:*:R3V[5678]*:*)
+       test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+       OS_REL=''
+       test -r /etc/.relid \
+       && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+       /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+         && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+       /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+         && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+       echo m68k-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+       echo m68k-atari-sysv4
+       exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+       echo sparc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    rs6000:LynxOS:2.*:*)
+       echo rs6000-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+       echo powerpc-unknown-lynxos${UNAME_RELEASE}
+       exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+       echo mips-dde-sysv${UNAME_RELEASE}
+       exit ;;
+    RM*:ReliantUNIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    RM*:SINIX-*:*:*)
+       echo mips-sni-sysv4
+       exit ;;
+    *:SINIX-*:*:*)
+       if uname -p 2>/dev/null >/dev/null ; then
+               UNAME_MACHINE=`(uname -p) 2>/dev/null`
+               echo ${UNAME_MACHINE}-sni-sysv4
+       else
+               echo ns32k-sni-sysv
+       fi
+       exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <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 ;;
+    SX-4:SUPER-UX:*:*)
+       echo sx4-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-5:SUPER-UX:*:*)
+       echo sx5-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-7:SUPER-UX:*:*)
+       echo sx7-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8:SUPER-UX:*:*)
+       echo sx8-nec-superux${UNAME_RELEASE}
+       exit ;;
+    SX-8R:SUPER-UX:*:*)
+       echo sx8r-nec-superux${UNAME_RELEASE}
+       exit ;;
+    Power*:Rhapsody:*:*)
+       echo powerpc-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Rhapsody:*:*)
+       echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+       exit ;;
+    *:Darwin:*:*)
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       case $UNAME_PROCESSOR in
+           unknown) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+       exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
+               UNAME_MACHINE=pc
+       fi
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+       exit ;;
+    *:QNX:*:4*)
+       echo i386-pc-qnx
+       exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+       echo nsr-tandem-nsk${UNAME_RELEASE}
+       exit ;;
+    *:NonStop-UX:*:*)
+       echo mips-compaq-nonstopux
+       exit ;;
+    BS2000:POSIX*:*:*)
+       echo bs2000-siemens-sysv
+       exit ;;
+    DS/*:UNIX_System_V:*:*)
+       echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+       exit ;;
+    *:Plan9:*:*)
+       # "uname -m" is not consistent, so use $cputype instead. 386
+       # is converted to i386 for consistency with other x86
+       # operating systems.
+       if test "$cputype" = "386"; then
+           UNAME_MACHINE=i386
+       else
+           UNAME_MACHINE="$cputype"
+       fi
+       echo ${UNAME_MACHINE}-unknown-plan9
+       exit ;;
+    *:TOPS-10:*:*)
+       echo pdp10-unknown-tops10
+       exit ;;
+    *:TENEX:*:*)
+       echo pdp10-unknown-tenex
+       exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+       echo pdp10-dec-tops20
+       exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+       echo pdp10-xkl-tops20
+       exit ;;
+    *:TOPS-20:*:*)
+       echo pdp10-unknown-tops20
+       exit ;;
+    *:ITS:*:*)
+       echo pdp10-unknown-its
+       exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+       exit ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms ; exit ;;
+           I*) echo ia64-dec-vms ; exit ;;
+           V*) echo vax-dec-vms ; exit ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit ;;
+    i*86:skyos:*:*)
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       exit ;;
+    i*86:rdos:*:*)
+       echo ${UNAME_MACHINE}-pc-rdos
+       exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+         ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+       printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+       printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+       { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+       echo c1-convex-bsd
+       exit ;;
+    c2*)
+       if getsysinfo -f scalar_acc
+       then echo c32-convex-bsd
+       else echo c2-convex-bsd
+       fi
+       exit ;;
+    c34*)
+       echo c34-convex-bsd
+       exit ;;
+    c38*)
+       echo c38-convex-bsd
+       exit ;;
+    c4*)
+       echo c4-convex-bsd
+       exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.Be b/config.h.Be
new file mode 100644 (file)
index 0000000..fe08c4d
--- /dev/null
@@ -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 (file)
index 0000000..7290c88
--- /dev/null
@@ -0,0 +1,394 @@
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define for debugging messages */
+#undef DEBUG
+
+/* Define when sys_errlist is defined in the standard include files */
+#undef DECL_SYS_ERRLIST
+
+/* Define to 1 if you have the <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 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 `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 `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `sun' library (-lsun). */
+#undef HAVE_LIBSUN
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_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 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 <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 `strnlen' function. */
+#undef HAVE_STRNLEN
+
+/* Define to 1 if you have the `strpbrk' function. */
+#undef HAVE_STRPBRK
+
+/* Define to 1 if you have the `strrchr' function. */
+#undef HAVE_STRRCHR
+
+/* Define to 1 if you have the `strspn' function. */
+#undef HAVE_STRSPN
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the <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 `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 `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 the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if the `setpgrp' function takes no argument. */
+#undef SETPGRP_VOID
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <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
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/config.sub b/config.sub
new file mode 100644 (file)
index 0000000..6759825
--- /dev/null
@@ -0,0 +1,1658 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-16'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#      CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#      CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )        # Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+       -sun*os*)
+               # Prevent following clause from handling this invalid input.
+               ;;
+       -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+       -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+       -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+       -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+       -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+       -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+       -apple | -axis | -knuth | -cray)
+               os=
+               basic_machine=$1
+               ;;
+       -sim | -cisco | -oki | -wec | -winbond)
+               os=
+               basic_machine=$1
+               ;;
+       -scout)
+               ;;
+       -wrs)
+               os=-vxworks
+               basic_machine=$1
+               ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
+       -hiux*)
+               os=-hiuxwe2
+               ;;
+       -sco6)
+               os=-sco5v6
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5)
+               os=-sco3.2v5
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco4)
+               os=-sco3.2v4
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2.[4-9]*)
+               os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco3.2v[4-9]*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco5v6*)
+               # Don't forget version if it is 3.2v4 or newer.
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -sco*)
+               os=-sco3.2v2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -udk*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -isc)
+               os=-isc2.2
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -clix*)
+               basic_machine=clipper-intergraph
+               ;;
+       -isc*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+               ;;
+       -lynx*)
+               os=-lynxos
+               ;;
+       -ptx*)
+               basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+               ;;
+       -windowsnt*)
+               os=`echo $os | sed -e 's/windowsnt/winnt/'`
+               ;;
+       -psos*)
+               os=-psos
+               ;;
+       -mint | -mint[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+       # Recognize the basic CPU types without company name.
+       # Some are omitted here because they have special meanings below.
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+       | bfin \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fido | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | m32c | m32r | m32rle | m68000 | m68k | m88k \
+       | maxq | mb | microblaze | mcore | mep \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64vr | mips64vrel \
+       | mips64orion | mips64orionel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mips64vr5900 | mips64vr5900el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | mt \
+       | msp430 \
+       | nios | nios2 \
+       | ns16k | ns32k \
+       | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | score \
+       | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+       | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+       | spu | strongarm \
+       | tahoe | thumb | tic4x | tic80 | tron \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+       | z8k)
+               basic_machine=$basic_machine-unknown
+               ;;
+       m6811 | m68hc11 | m6812 | m68hc12)
+               # Motorola 68HC11/12.
+               basic_machine=$basic_machine-unknown
+               os=-none
+               ;;
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+               ;;
+       ms1)
+               basic_machine=mt-unknown
+               ;;
+
+       # We use `pc' rather than `unknown'
+       # because (1) that's what they normally are, and
+       # (2) the word "unknown" tends to confuse beginning users.
+       i*86 | x86_64)
+         basic_machine=$basic_machine-pc
+         ;;
+       # Object if more than one company name word.
+       *-*-*)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+       # Recognize the basic CPU types with company name.
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* | avr32-* \
+       | bfin-* | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+       | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | m32c-* | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mips64vr5900-* | mips64vr5900el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | mt-* \
+       | msp430-* \
+       | nios-* | nios2-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* \
+       | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+       | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tron-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+       | xstormy16-* | xtensa*-* \
+       | ymp-* \
+       | z8k-*)
+               ;;
+       # Recognize the basic CPU types without company name, with glob match.
+       xtensa*)
+               basic_machine=$basic_machine-unknown
+               ;;
+       # Recognize the various machine names and aliases which stand
+       # for a CPU type and a company and sometimes even an OS.
+       386bsd)
+               basic_machine=i386-unknown
+               os=-bsd
+               ;;
+       3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+               basic_machine=m68000-att
+               ;;
+       3b*)
+               basic_machine=we32k-att
+               ;;
+       a29khif)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
+       adobe68k)
+               basic_machine=m68010-adobe
+               os=-scout
+               ;;
+       alliant | fx80)
+               basic_machine=fx80-alliant
+               ;;
+       altos | altos3068)
+               basic_machine=m68k-altos
+               ;;
+       am29k)
+               basic_machine=a29k-none
+               os=-bsd
+               ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       amdahl)
+               basic_machine=580-amdahl
+               os=-sysv
+               ;;
+       amiga | amiga-*)
+               basic_machine=m68k-unknown
+               ;;
+       amigaos | amigados)
+               basic_machine=m68k-unknown
+               os=-amigaos
+               ;;
+       amigaunix | amix)
+               basic_machine=m68k-unknown
+               os=-sysv4
+               ;;
+       apollo68)
+               basic_machine=m68k-apollo
+               os=-sysv
+               ;;
+       apollo68bsd)
+               basic_machine=m68k-apollo
+               os=-bsd
+               ;;
+       aux)
+               basic_machine=m68k-apple
+               os=-aux
+               ;;
+       balance)
+               basic_machine=ns32k-sequent
+               os=-dynix
+               ;;
+       blackfin)
+               basic_machine=bfin-unknown
+               os=-linux
+               ;;
+       blackfin-*)
+               basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
+       convex-c1)
+               basic_machine=c1-convex
+               os=-bsd
+               ;;
+       convex-c2)
+               basic_machine=c2-convex
+               os=-bsd
+               ;;
+       convex-c32)
+               basic_machine=c32-convex
+               os=-bsd
+               ;;
+       convex-c34)
+               basic_machine=c34-convex
+               os=-bsd
+               ;;
+       convex-c38)
+               basic_machine=c38-convex
+               os=-bsd
+               ;;
+       cray | j90)
+               basic_machine=j90-cray
+               os=-unicos
+               ;;
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
+               ;;
+       cr16)
+               basic_machine=cr16-unknown
+               os=-elf
+               ;;
+       crds | unos)
+               basic_machine=m68k-crds
+               ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
+       cris | cris-* | etrax*)
+               basic_machine=cris-axis
+               ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
+       da30 | da30-*)
+               basic_machine=m68k-da30
+               ;;
+       decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+               basic_machine=mips-dec
+               ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
+       delta | 3300 | motorola-3300 | motorola-delta \
+             | 3300-motorola | delta-motorola)
+               basic_machine=m68k-motorola
+               ;;
+       delta88)
+               basic_machine=m88k-motorola
+               os=-sysv3
+               ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
+       dpx20 | dpx20-*)
+               basic_machine=rs6000-bull
+               os=-bosx
+               ;;
+       dpx2* | dpx2*-bull)
+               basic_machine=m68k-bull
+               os=-sysv3
+               ;;
+       ebmon29k)
+               basic_machine=a29k-amd
+               os=-ebmon
+               ;;
+       elxsi)
+               basic_machine=elxsi-elxsi
+               os=-bsd
+               ;;
+       encore | umax | mmax)
+               basic_machine=ns32k-encore
+               ;;
+       es1800 | OSE68k | ose68k | ose | OSE)
+               basic_machine=m68k-ericsson
+               os=-ose
+               ;;
+       fx2800)
+               basic_machine=i860-alliant
+               ;;
+       genix)
+               basic_machine=ns32k-ns
+               ;;
+       gmicro)
+               basic_machine=tron-gmicro
+               os=-sysv
+               ;;
+       go32)
+               basic_machine=i386-pc
+               os=-go32
+               ;;
+       h3050r* | hiux*)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       h8300hms)
+               basic_machine=h8300-hitachi
+               os=-hms
+               ;;
+       h8300xray)
+               basic_machine=h8300-hitachi
+               os=-xray
+               ;;
+       h8500hms)
+               basic_machine=h8500-hitachi
+               os=-hms
+               ;;
+       harris)
+               basic_machine=m88k-harris
+               os=-sysv3
+               ;;
+       hp300-*)
+               basic_machine=m68k-hp
+               ;;
+       hp300bsd)
+               basic_machine=m68k-hp
+               os=-bsd
+               ;;
+       hp300hpux)
+               basic_machine=m68k-hp
+               os=-hpux
+               ;;
+       hp3k9[0-9][0-9] | hp9[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k2[0-9][0-9] | hp9k31[0-9])
+               basic_machine=m68000-hp
+               ;;
+       hp9k3[2-9][0-9])
+               basic_machine=m68k-hp
+               ;;
+       hp9k6[0-9][0-9] | hp6[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hp9k7[0-79][0-9] | hp7[0-79][0-9])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k78[0-9] | hp78[0-9])
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+               # FIXME: really hppa2.0-hp
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][13679] | hp8[0-9][13679])
+               basic_machine=hppa1.1-hp
+               ;;
+       hp9k8[0-9][0-9] | hp8[0-9][0-9])
+               basic_machine=hppa1.0-hp
+               ;;
+       hppa-next)
+               os=-nextstep3
+               ;;
+       hppaosf)
+               basic_machine=hppa1.1-hp
+               os=-osf
+               ;;
+       hppro)
+               basic_machine=hppa1.1-hp
+               os=-proelf
+               ;;
+       i370-ibm* | ibm*)
+               basic_machine=i370-ibm
+               ;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+       i*86v32)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv32
+               ;;
+       i*86v4*)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv4
+               ;;
+       i*86v)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-sysv
+               ;;
+       i*86sol2)
+               basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+               os=-solaris2
+               ;;
+       i386mach)
+               basic_machine=i386-mach
+               os=-mach
+               ;;
+       i386-vsta | vsta)
+               basic_machine=i386-unknown
+               os=-vsta
+               ;;
+       iris | iris4d)
+               basic_machine=mips-sgi
+               case $os in
+                   -irix*)
+                       ;;
+                   *)
+                       os=-irix4
+                       ;;
+               esac
+               ;;
+       isi68 | isi)
+               basic_machine=m68k-isi
+               os=-sysv
+               ;;
+       m68knommu)
+               basic_machine=m68k-unknown
+               os=-linux
+               ;;
+       m68knommu-*)
+               basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       m88k-omron*)
+               basic_machine=m88k-omron
+               ;;
+       magnum | m3230)
+               basic_machine=mips-mips
+               os=-sysv
+               ;;
+       merlin)
+               basic_machine=ns32k-utek
+               os=-sysv
+               ;;
+       mingw32)
+               basic_machine=i386-pc
+               os=-mingw32
+               ;;
+       mingw32ce)
+               basic_machine=arm-unknown
+               os=-mingw32ce
+               ;;
+       miniframe)
+               basic_machine=m68000-convergent
+               ;;
+       *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+               basic_machine=m68k-atari
+               os=-mint
+               ;;
+       mips3*-*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+               ;;
+       mips3*)
+               basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+               ;;
+       monitor)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
+       msdos)
+               basic_machine=i386-pc
+               os=-msdos
+               ;;
+       ms1-*)
+               basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+               ;;
+       mvs)
+               basic_machine=i370-ibm
+               os=-mvs
+               ;;
+       ncr3000)
+               basic_machine=i486-ncr
+               os=-sysv4
+               ;;
+       netbsd386)
+               basic_machine=i386-unknown
+               os=-netbsd
+               ;;
+       netwinder)
+               basic_machine=armv4l-rebel
+               os=-linux
+               ;;
+       news | news700 | news800 | news900)
+               basic_machine=m68k-sony
+               os=-newsos
+               ;;
+       news1000)
+               basic_machine=m68030-sony
+               os=-newsos
+               ;;
+       news-3600 | risc-news)
+               basic_machine=mips-sony
+               os=-newsos
+               ;;
+       necv70)
+               basic_machine=v70-nec
+               os=-sysv
+               ;;
+       next | m*-next )
+               basic_machine=m68k-next
+               case $os in
+                   -nextstep* )
+                       ;;
+                   -ns2*)
+                     os=-nextstep2
+                       ;;
+                   *)
+                     os=-nextstep3
+                       ;;
+               esac
+               ;;
+       nh3000)
+               basic_machine=m68k-harris
+               os=-cxux
+               ;;
+       nh[45]000)
+               basic_machine=m88k-harris
+               os=-cxux
+               ;;
+       nindy960)
+               basic_machine=i960-intel
+               os=-nindy
+               ;;
+       mon960)
+               basic_machine=i960-intel
+               os=-mon960
+               ;;
+       nonstopux)
+               basic_machine=mips-compaq
+               os=-nonstopux
+               ;;
+       np1)
+               basic_machine=np1-gould
+               ;;
+       nsr-tandem)
+               basic_machine=nsr-tandem
+               ;;
+       op50n-* | op60c-*)
+               basic_machine=hppa1.1-oki
+               os=-proelf
+               ;;
+       openrisc | openrisc-*)
+               basic_machine=or32-unknown
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
+       OSE68000 | ose68000)
+               basic_machine=m68000-ericsson
+               os=-ose
+               ;;
+       os68k)
+               basic_machine=m68k-none
+               os=-os68k
+               ;;
+       pa-hitachi)
+               basic_machine=hppa1.1-hitachi
+               os=-hiuxwe2
+               ;;
+       paragon)
+               basic_machine=i860-intel
+               os=-osf
+               ;;
+       parisc)
+               basic_machine=hppa-unknown
+               os=-linux
+               ;;
+       parisc-*)
+               basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+               os=-linux
+               ;;
+       pbd)
+               basic_machine=sparc-tti
+               ;;
+       pbb)
+               basic_machine=m68k-tti
+               ;;
+       pc532 | pc532-*)
+               basic_machine=ns32k-pc532
+               ;;
+       pc98)
+               basic_machine=i386-pc
+               ;;
+       pc98-*)
+               basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium | p5 | k5 | k6 | nexgen | viac3)
+               basic_machine=i586-pc
+               ;;
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
+               basic_machine=i686-pc
+               ;;
+       pentiumii | pentium2 | pentiumiii | pentium3)
+               basic_machine=i686-pc
+               ;;
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+               basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumpro-* | p6-* | 6x86-* | athlon-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+               basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       pn)
+               basic_machine=pn-gould
+               ;;
+       power)  basic_machine=power-ibm
+               ;;
+       ppc)    basic_machine=powerpc-unknown
+               ;;
+       ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppcle | powerpclittle | ppc-le | powerpc-little)
+               basic_machine=powerpcle-unknown
+               ;;
+       ppcle-* | powerpclittle-*)
+               basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ps2)
+               basic_machine=i386-ibm
+               ;;
+       pw32)
+               basic_machine=i586-unknown
+               os=-pw32
+               ;;
+       rdos)
+               basic_machine=i386-pc
+               os=-rdos
+               ;;
+       rom68k)
+               basic_machine=m68k-rom68k
+               os=-coff
+               ;;
+       rm[46]00)
+               basic_machine=mips-siemens
+               ;;
+       rtpc | rtpc-*)
+               basic_machine=romp-ibm
+               ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
+       sa29200)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sde)
+               basic_machine=mipsisa32-sde
+               os=-elf
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
+       sequent)
+               basic_machine=i386-sequent
+               ;;
+       sh)
+               basic_machine=sh-hitachi
+               os=-hms
+               ;;
+       sh5el)
+               basic_machine=sh5le-unknown
+               ;;
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
+               basic_machine=sparclite-wrs
+               os=-vxworks
+               ;;
+       sps7)
+               basic_machine=m68k-bull
+               os=-sysv2
+               ;;
+       spur)
+               basic_machine=spur-unknown
+               ;;
+       st2000)
+               basic_machine=m68k-tandem
+               ;;
+       stratus)
+               basic_machine=i860-stratus
+               os=-sysv4
+               ;;
+       sun2)
+               basic_machine=m68000-sun
+               ;;
+       sun2os3)
+               basic_machine=m68000-sun
+               os=-sunos3
+               ;;
+       sun2os4)
+               basic_machine=m68000-sun
+               os=-sunos4
+               ;;
+       sun3os3)
+               basic_machine=m68k-sun
+               os=-sunos3
+               ;;
+       sun3os4)
+               basic_machine=m68k-sun
+               os=-sunos4
+               ;;
+       sun4os3)
+               basic_machine=sparc-sun
+               os=-sunos3
+               ;;
+       sun4os4)
+               basic_machine=sparc-sun
+               os=-sunos4
+               ;;
+       sun4sol2)
+               basic_machine=sparc-sun
+               os=-solaris2
+               ;;
+       sun3 | sun3-*)
+               basic_machine=m68k-sun
+               ;;
+       sun4)
+               basic_machine=sparc-sun
+               ;;
+       sun386 | sun386i | roadrunner)
+               basic_machine=i386-sun
+               ;;
+       sv1)
+               basic_machine=sv1-cray
+               os=-unicos
+               ;;
+       symmetry)
+               basic_machine=i386-sequent
+               os=-dynix
+               ;;
+       t3e)
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
+               os=-unicos
+               ;;
+       tic54x | c54x*)
+               basic_machine=tic54x-unknown
+               os=-coff
+               ;;
+       tic55x | c55x*)
+               basic_machine=tic55x-unknown
+               os=-coff
+               ;;
+       tic6x | c6x*)
+               basic_machine=tic6x-unknown
+               os=-coff
+               ;;
+       tile*)
+               basic_machine=tile-unknown
+               os=-linux-gnu
+               ;;
+       tx39)
+               basic_machine=mipstx39-unknown
+               ;;
+       tx39el)
+               basic_machine=mipstx39el-unknown
+               ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
+       tower | tower-32)
+               basic_machine=m68k-ncr
+               ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
+       udi29k)
+               basic_machine=a29k-amd
+               os=-udi
+               ;;
+       ultra3)
+               basic_machine=a29k-nyu
+               os=-sym1
+               ;;
+       v810 | necv810)
+               basic_machine=v810-nec
+               os=-none
+               ;;
+       vaxv)
+               basic_machine=vax-dec
+               os=-sysv
+               ;;
+       vms)
+               basic_machine=vax-dec
+               os=-vms
+               ;;
+       vpp*|vx|vx-*)
+               basic_machine=f301-fujitsu
+               ;;
+       vxworks960)
+               basic_machine=i960-wrs
+               os=-vxworks
+               ;;
+       vxworks68)
+               basic_machine=m68k-wrs
+               os=-vxworks
+               ;;
+       vxworks29k)
+               basic_machine=a29k-wrs
+               os=-vxworks
+               ;;
+       w65*)
+               basic_machine=w65-wdc
+               os=-none
+               ;;
+       w89k-*)
+               basic_machine=hppa1.1-winbond
+               os=-proelf
+               ;;
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
+               ;;
+       xps | xps100)
+               basic_machine=xps100-honeywell
+               ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
+       z8k-*-coff)
+               basic_machine=z8k-unknown
+               os=-sim
+               ;;
+       none)
+               basic_machine=none-none
+               os=-none
+               ;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+       w89k)
+               basic_machine=hppa1.1-winbond
+               ;;
+       op50n)
+               basic_machine=hppa1.1-oki
+               ;;
+       op60c)
+               basic_machine=hppa1.1-oki
+               ;;
+       romp)
+               basic_machine=romp-ibm
+               ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
+       rs6000)
+               basic_machine=rs6000-ibm
+               ;;
+       vax)
+               basic_machine=vax-dec
+               ;;
+       pdp10)
+               # there are many clones, so DEC is not a safe bet
+               basic_machine=pdp10-unknown
+               ;;
+       pdp11)
+               basic_machine=pdp11-dec
+               ;;
+       we32k)
+               basic_machine=we32k-att
+               ;;
+       sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+               basic_machine=sh-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+               basic_machine=sparc-sun
+               ;;
+       cydra)
+               basic_machine=cydra-cydrome
+               ;;
+       orion)
+               basic_machine=orion-highlevel
+               ;;
+       orion105)
+               basic_machine=clipper-highlevel
+               ;;
+       mac | mpw | mac-mpw)
+               basic_machine=m68k-apple
+               ;;
+       pmac | pmac-mpw)
+               basic_machine=powerpc-apple
+               ;;
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
+               ;;
+       *)
+               echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+       *-digital*)
+               basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+               ;;
+       *-commodore*)
+               basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+               ;;
+       *)
+               ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+       # -solaris* is a basic system type, with this one exception.
+       -solaris1 | -solaris1.*)
+               os=`echo $os | sed -e 's|solaris1|sunos4|'`
+               ;;
+       -solaris)
+               os=-solaris2
+               ;;
+       -svr4*)
+               os=-sysv4
+               ;;
+       -unixware*)
+               os=-sysv4.2uw
+               ;;
+       -gnu/linux*)
+               os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+               ;;
+       # First accept the basic system types.
+       # The portable systems comes first.
+       # Each alternative MUST END IN A *, to match a version number.
+       # -sysv* is not here because it comes later, after sysvr4.
+       -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+             | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+             | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+             | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+             | -aos* \
+             | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+             | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+             | -openbsd* | -solidbsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+             | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* \
+             | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+             | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+             | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+             | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+       # Remember, each alternative MUST END IN *, to match a version number.
+               ;;
+       -qnx*)
+               case $basic_machine in
+                   x86-* | i*86-*)
+                       ;;
+                   *)
+                       os=-nto$os
+                       ;;
+               esac
+               ;;
+       -nto-qnx*)
+               ;;
+       -nto*)
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
+               ;;
+       -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+             | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+             | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+               ;;
+       -mac*)
+               os=`echo $os | sed -e 's|mac|macos|'`
+               ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
+       -linux*)
+               os=`echo $os | sed -e 's|linux|linux-gnu|'`
+               ;;
+       -sunos5*)
+               os=`echo $os | sed -e 's|sunos5|solaris2|'`
+               ;;
+       -sunos6*)
+               os=`echo $os | sed -e 's|sunos6|solaris3|'`
+               ;;
+       -opened*)
+               os=-openedition
+               ;;
+        -os400*)
+               os=-os400
+               ;;
+       -wince*)
+               os=-wince
+               ;;
+       -osfrose*)
+               os=-osfrose
+               ;;
+       -osf*)
+               os=-osf
+               ;;
+       -utek*)
+               os=-bsd
+               ;;
+       -dynix*)
+               os=-bsd
+               ;;
+       -acis*)
+               os=-aos
+               ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
+       -386bsd)
+               os=-bsd
+               ;;
+       -ctix* | -uts*)
+               os=-sysv
+               ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
+       -ns2 )
+               os=-nextstep2
+               ;;
+       -nsk*)
+               os=-nsk
+               ;;
+       # Preserve the version number of sinix5.
+       -sinix5.*)
+               os=`echo $os | sed -e 's|sinix|sysv|'`
+               ;;
+       -sinix*)
+               os=-sysv4
+               ;;
+        -tpf*)
+               os=-tpf
+               ;;
+       -triton*)
+               os=-sysv3
+               ;;
+       -oss*)
+               os=-sysv3
+               ;;
+       -svr4)
+               os=-sysv4
+               ;;
+       -svr3)
+               os=-sysv3
+               ;;
+       -sysvr4)
+               os=-sysv4
+               ;;
+       # This must come after -sysvr4.
+       -sysv*)
+               ;;
+       -ose*)
+               os=-ose
+               ;;
+       -es1800*)
+               os=-ose
+               ;;
+       -xenix)
+               os=-xenix
+               ;;
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -kaos*)
+               os=-kaos
+               ;;
+       -zvmoe)
+               os=-zvmoe
+               ;;
+       -none)
+               ;;
+       *)
+               # Get rid of the `-' at the beginning of $os.
+               os=`echo $os | sed 's/[^-]*-//'`
+               echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+               exit 1
+               ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+               os=-elf
+               ;;
+        spu-*)
+               os=-elf
+               ;;
+       *-acorn)
+               os=-riscix1.2
+               ;;
+       arm*-rebel)
+               os=-linux
+               ;;
+       arm*-semi)
+               os=-aout
+               ;;
+        c4x-* | tic4x-*)
+               os=-coff
+               ;;
+       # This must come before the *-dec entry.
+       pdp10-*)
+               os=-tops20
+               ;;
+       pdp11-*)
+               os=-none
+               ;;
+       *-dec | vax-*)
+               os=-ultrix4.2
+               ;;
+       m68*-apollo)
+               os=-domain
+               ;;
+       i386-sun)
+               os=-sunos4.0.2
+               ;;
+       m68000-sun)
+               os=-sunos3
+               # This also exists in the configure program, but was not the
+               # default.
+               # os=-sunos4
+               ;;
+       m68*-cisco)
+               os=-aout
+               ;;
+        mep-*)
+               os=-elf
+               ;;
+       mips*-cisco)
+               os=-elf
+               ;;
+       mips*-*)
+               os=-elf
+               ;;
+       or32-*)
+               os=-coff
+               ;;
+       *-tti)  # must be before sparc entry or we get the wrong os.
+               os=-sysv3
+               ;;
+       sparc-* | *-sun)
+               os=-sunos4.1.1
+               ;;
+       *-be)
+               os=-beos
+               ;;
+       *-haiku)
+               os=-haiku
+               ;;
+       *-ibm)
+               os=-aix
+               ;;
+       *-knuth)
+               os=-mmixware
+               ;;
+       *-wec)
+               os=-proelf
+               ;;
+       *-winbond)
+               os=-proelf
+               ;;
+       *-oki)
+               os=-proelf
+               ;;
+       *-hp)
+               os=-hpux
+               ;;
+       *-hitachi)
+               os=-hiux
+               ;;
+       i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+               os=-sysv
+               ;;
+       *-cbm)
+               os=-amigaos
+               ;;
+       *-dg)
+               os=-dgux
+               ;;
+       *-dolphin)
+               os=-sysv3
+               ;;
+       m68k-ccur)
+               os=-rtu
+               ;;
+       m88k-omron*)
+               os=-luna
+               ;;
+       *-next )
+               os=-nextstep
+               ;;
+       *-sequent)
+               os=-ptx
+               ;;
+       *-crds)
+               os=-unos
+               ;;
+       *-ns)
+               os=-genix
+               ;;
+       i370-*)
+               os=-mvs
+               ;;
+       *-next)
+               os=-nextstep3
+               ;;
+       *-gould)
+               os=-sysv
+               ;;
+       *-highlevel)
+               os=-bsd
+               ;;
+       *-encore)
+               os=-bsd
+               ;;
+       *-sgi)
+               os=-irix
+               ;;
+       *-siemens)
+               os=-sysv4
+               ;;
+       *-masscomp)
+               os=-rtu
+               ;;
+       f30[01]-fujitsu | f700-fujitsu)
+               os=-uxpv
+               ;;
+       *-rom68k)
+               os=-coff
+               ;;
+       *-*bug)
+               os=-coff
+               ;;
+       *-apple)
+               os=-macos
+               ;;
+       *-atari*)
+               os=-mint
+               ;;
+       *)
+               os=-none
+               ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+       *-unknown)
+               case $os in
+                       -riscix*)
+                               vendor=acorn
+                               ;;
+                       -sunos*)
+                               vendor=sun
+                               ;;
+                       -aix*)
+                               vendor=ibm
+                               ;;
+                       -beos*)
+                               vendor=be
+                               ;;
+                       -hpux*)
+                               vendor=hp
+                               ;;
+                       -mpeix*)
+                               vendor=hp
+                               ;;
+                       -hiux*)
+                               vendor=hitachi
+                               ;;
+                       -unos*)
+                               vendor=crds
+                               ;;
+                       -dgux*)
+                               vendor=dg
+                               ;;
+                       -luna*)
+                               vendor=omron
+                               ;;
+                       -genix*)
+                               vendor=ns
+                               ;;
+                       -mvs* | -opened*)
+                               vendor=ibm
+                               ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
+                       -ptx*)
+                               vendor=sequent
+                               ;;
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
+                               vendor=wrs
+                               ;;
+                       -aux*)
+                               vendor=apple
+                               ;;
+                       -hms*)
+                               vendor=hitachi
+                               ;;
+                       -mpw* | -macos*)
+                               vendor=apple
+                               ;;
+                       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+                               vendor=atari
+                               ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
+               esac
+               basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+               ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755 (executable)
index 0000000..e3b2eef
--- /dev/null
+++ b/configure
@@ -0,0 +1,9650 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.63.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&    (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+        /*)
+          for as_base in sh bash ksh sh5; do
+            as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+          done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+        # Try only shells that exist, to save several forks.
+        if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+               { ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+              as_have_required=yes
+              if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+       do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+       done
+       export CONFIG_SHELL
+       exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell bug-autoconf@gnu.org about your system,
+  echo including any error possibly output before this message.
+  echo This can help us improve future autoconf versions.
+  echo Configuration will now proceed without shell functions.
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="buffer.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <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
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_xdf
+enable_vold
+enable_new_vold
+enable_debug
+enable_raw_term
+with_x
+enable_floppyd
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+XMKMF'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)   ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+        ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { $as_echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { $as_echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+   { (exit 1); exit 1; }; } ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in  exec_prefix prefix bindir sbindir libexecdir datarootdir \
+               datadir sysconfdir sharedstatedir localstatedir includedir \
+               oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+               libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { $as_echo "$as_me: error: working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_myself" : 'X\(//\)[^/]' \| \
+        X"$as_myself" : 'X\(//\)$' \| \
+        X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+       cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+       pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+X features:
+  --x-includes=DIR    X include files are in DIR
+  --x-libraries=DIR   X library files are in DIR
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-xdf           support for OS/2 extended density format disks
+  --enable-vold          compatibility with Solaris' vold
+  --enable-new-vold          compatibility with Solaris' vold, new version
+  --enable-debug         debuging messages
+  --enable-raw-term      raw terminal (readkey behaviour, default)
+  --enable-floppyd       floppy daemon support
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-x                use the X Window System
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective 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.
+
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.63
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  $as_echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+       ac_must_keep_next=false # Got value, back to normal.
+      else
+       case $ac_arg in
+         *=* | --config-cache | -C | -disable-* | --disable-* \
+         | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+         | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+         | -with-* | --with-* | -without-* | --without-* | --x)
+           case "$ac_configure_args0 " in
+             "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+           esac
+           ;;
+         -* ) ac_must_keep_next=true ;;
+       esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+       "s/'\''/'\''\\\\'\'''\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+       eval ac_val=\$$ac_var
+       case $ac_val in
+       *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+       esac
+       $as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test -r "$ac_site_file"; then
+    { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+       # differences in whitespace do not lead to failure.
+       ac_old_val_w=`echo x $ac_old_val`
+       ac_new_val_w=`echo x $ac_new_val`
+       if test "$ac_old_val_w" != "$ac_new_val_w"; then
+         { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+         ac_cache_corrupted=:
+       else
+         { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+         eval $ac_var=\$ac_old_val
+       fi
+       { $as_echo "$as_me:$LINENO:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+       { $as_echo "$as_me:$LINENO:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+       ;;
+    [ab].out )
+       # We found the default executable, but exeext='' is most
+       # certainly right.
+       break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+       then :; else
+          ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+       fi
+       # We set ac_cv_exeext here because the later test for it is not
+       # safe: cross compilers may not add the suffix if given an `-o'
+       # argument, so we may need to know it at that point already.
+       # Even if this section looks crufty: it has the advantage of
+       # actually working.
+       break;;
+    * )
+       break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+       cross_compiling=yes
+    else
+       { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+         break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:$LINENO: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+    { $as_echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
+$as_echo_n "checking whether $CC needs -traditional... " >&6; }
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+    ac_pattern="Autoconf.*'x'"
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
+$as_echo "$ac_cv_prog_gcc_traditional" >&6; }
+  if test $ac_cv_prog_gcc_traditional = yes; then
+    CC="$CC -traditional"
+  fi
+fi
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+       if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+         if test $ac_prog = install &&
+           grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # AIX install.  It has an incompatible calling convention.
+           :
+         elif test $ac_prog = install &&
+           grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+           # program-specific install script used by HP pwplus--don't use.
+           :
+         else
+           rm -rf conftest.one conftest.two conftest.dir
+           echo one > conftest.one
+           echo two > conftest.two
+           mkdir conftest.dir
+           if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+             test -s conftest.one && test -s conftest.two &&
+             test -s conftest.dir/conftest.one &&
+             test -s conftest.dir/conftest.two
+           then
+             ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+             break 3
+           fi
+         fi
+       fi
+      done
+    done
+    ;;
+esac
+
+done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+
+# Extract the first word of "install-info", so it can be a program name with args.
+set dummy install-info; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_INSTALL_INFO+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  case $INSTALL_INFO in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_INSTALL_INFO="$INSTALL_INFO" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_INSTALL_INFO="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_INSTALL_INFO" && ac_cv_path_INSTALL_INFO=""""
+  ;;
+esac
+fi
+INSTALL_INFO=$ac_cv_path_INSTALL_INFO
+if test -n "$INSTALL_INFO"; then
+  { $as_echo "$as_me:$LINENO: result: $INSTALL_INFO" >&5
+$as_echo "$INSTALL_INFO" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+  if test "${ac_cv_header_minix_config_h+set}" = set; then
+  { $as_echo "$as_me:$LINENO: checking for minix/config.h" >&5
+$as_echo_n "checking for minix/config.h... " >&6; }
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5
+$as_echo "$ac_cv_header_minix_config_h" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking minix/config.h usability" >&5
+$as_echo_n "checking minix/config.h usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <minix/config.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking minix/config.h presence" >&5
+$as_echo_n "checking minix/config.h presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <minix/config.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: minix/config.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: minix/config.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: minix/config.h: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: minix/config.h:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: minix/config.h: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: minix/config.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: minix/config.h: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: minix/config.h: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: minix/config.h: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for minix/config.h" >&5
+$as_echo_n "checking for minix/config.h... " >&6; }
+if test "${ac_cv_header_minix_config_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_header_minix_config_h=$ac_header_preproc
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_minix_config_h" >&5
+$as_echo "$ac_cv_header_minix_config_h" >&6; }
+
+fi
+if test "x$ac_cv_header_minix_config_h" = x""yes; then
+  MINIX=yes
+else
+  MINIX=
+fi
+
+
+  if test "$MINIX" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define _POSIX_SOURCE 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _POSIX_1_SOURCE 2
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define _MINIX 1
+_ACEOF
+
+  fi
+
+
+
+  { $as_echo "$as_me:$LINENO: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if test "${ac_cv_safe_to_define___extensions__+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#        define __EXTENSIONS__ 1
+         $ac_includes_default
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_safe_to_define___extensions__=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_safe_to_define___extensions__=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+  test $ac_cv_safe_to_define___extensions__ = yes &&
+    cat >>confdefs.h <<\_ACEOF
+#define __EXTENSIONS__ 1
+_ACEOF
+
+  cat >>confdefs.h <<\_ACEOF
+#define _ALL_SOURCE 1
+_ACEOF
+
+  cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+  cat >>confdefs.h <<\_ACEOF
+#define _POSIX_PTHREAD_SEMANTICS 1
+_ACEOF
+
+  cat >>confdefs.h <<\_ACEOF
+#define _TANDEM_SOURCE 1
+_ACEOF
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ $as_echo "$as_me:$LINENO: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+$as_echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:$LINENO: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+$as_echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:$LINENO: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if test "${ac_cv_target+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $target_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical target" >&5
+$as_echo "$as_me: error: invalid value of canonical target" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
+
+{ $as_echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if test "${ac_cv_c_const+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset cs;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_const=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_const=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const /**/
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if test "${ac_cv_c_inline+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_inline=$ac_kw
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+
+
+# Check whether --enable-xdf was given.
+if test "${enable_xdf+set}" = set; then
+  enableval=$enable_xdf; if test x$enableval = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_XDF 1
+_ACEOF
+
+fi
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_XDF 1
+_ACEOF
+
+fi
+
+
+
+# Check whether --enable-vold was given.
+if test "${enable_vold+set}" = set; then
+  enableval=$enable_vold; if test x$enableval = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USING_VOLD 1
+_ACEOF
+
+fi
+fi
+
+
+
+# Check whether --enable-new-vold was given.
+if test "${enable_new_vold+set}" = set; then
+  enableval=$enable_new_vold; newVold=x$enableval
+if test x$enableval = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USING_NEW_VOLD 1
+_ACEOF
+
+fi
+fi
+
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then
+  enableval=$enable_debug; if test x$enableval = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DEBUG 1
+_ACEOF
+
+fi
+fi
+
+
+
+# Check whether --enable-raw_term was given.
+if test "${enable_raw_term+set}" = set; then
+  enableval=$enable_raw_term; if test x$enableval = xyes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_RAWTERM 1
+_ACEOF
+
+fi
+else
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_RAWTERM 1
+_ACEOF
+
+fi
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for getpwnam in -lsun" >&5
+$as_echo_n "checking for getpwnam in -lsun... " >&6; }
+if test "${ac_cv_lib_sun_getpwnam+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsun  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getpwnam ();
+int
+main ()
+{
+return getpwnam ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_sun_getpwnam=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_sun_getpwnam=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_sun_getpwnam" >&5
+$as_echo "$ac_cv_lib_sun_getpwnam" >&6; }
+if test "x$ac_cv_lib_sun_getpwnam" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSUN 1
+_ACEOF
+
+  LIBS="-lsun $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for cam_open_device in -lcam" >&5
+$as_echo_n "checking for cam_open_device in -lcam... " >&6; }
+if test "${ac_cv_lib_cam_cam_open_device+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcam  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cam_open_device ();
+int
+main ()
+{
+return cam_open_device ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_cam_cam_open_device=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_cam_cam_open_device=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cam_cam_open_device" >&5
+$as_echo "$ac_cv_lib_cam_cam_open_device" >&6; }
+if test "x$ac_cv_lib_cam_cam_open_device" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCAM 1
+_ACEOF
+
+  LIBS="-lcam $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if test "${ac_cv_header_sys_wait_h+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <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
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_sys_wait_h=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_sys_wait_h=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_SYS_WAIT_H 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_header in getopt.h sys/stat.h stdlib.h unistd.h linux/unistd.h \
+libc.h fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h strings.h string.h \
+sys/param.h memory.h malloc.h signal.h sys/signal.h utime.h sgtty.h \
+sys/floppy.h mntent.h sys/sysmacros.h netinet/in.h assert.h \
+iconv.h wctype.h wchar.h locale.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in termio.h sys/termio.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+
+done
+
+
+
+for ac_header in termios.h sys/termios.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+
+done
+
+
+
+{ $as_echo "$as_me:$LINENO: checking whether llseek declared in unistd.h" >&5
+$as_echo_n "checking whether llseek declared in unistd.h... " >&6; }
+if test "${mtools_cv_have_llseek_prototype+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <unistd.h>
+int
+main ()
+{
+extern int llseek(int);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  mtools_cv_have_llseek_prototype=no
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       mtools_cv_have_llseek_prototype=yes
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $mtools_cv_have_llseek_prototype" >&5
+$as_echo "$mtools_cv_have_llseek_prototype" >&6; }
+if test "$mtools_cv_have_llseek_prototype" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LLSEEK_PROTOTYPE 1
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking whether lseek64 declared in unistd.h" >&5
+$as_echo_n "checking whether lseek64 declared in unistd.h... " >&6; }
+if test "${mtools_cv_have_lseek64_prototype+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include "sysincludes.h"
+#include <unistd.h>
+
+int
+main ()
+{
+extern int lseek64(int);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  mtools_cv_have_lseek64_prototype=no
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       mtools_cv_have_lseek64_prototype=yes
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $mtools_cv_have_lseek64_prototype" >&5
+$as_echo "$mtools_cv_have_lseek64_prototype" >&6; }
+if test "$mtools_cv_have_lseek64_prototype" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LSEEK64_PROTOTYPE 1
+_ACEOF
+
+fi
+
+
+
+for ac_func in htons
+do
+as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <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 $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  eval "$as_ac_var=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if test "${ac_cv_c_const+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+  /* Ultrix mips cc rejects this.  */
+  typedef int charset[2];
+  const charset cs;
+  /* SunOS 4.1.1 cc rejects this.  */
+  char const *const *pcpcc;
+  char **ppc;
+  /* NEC SVR4.0.2 mips cc rejects this.  */
+  struct point {int x, y;};
+  static struct point const zero = {0,0};
+  /* AIX XL C 1.02.0.0 rejects this.
+     It does not let you subtract one const X* pointer from another in
+     an arm of an if-expression whose if-part is not a constant
+     expression */
+  const char *g = "string";
+  pcpcc = &g + (g ? g-g : 0);
+  /* HPUX 7.0 cc rejects these. */
+  ++pcpcc;
+  ppc = (char**) pcpcc;
+  pcpcc = (char const *const *) ppc;
+  { /* SCO 3.2v4 cc rejects this.  */
+    char *t;
+    char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+    *t++ = 0;
+    if (s) return 0;
+  }
+  { /* Someone thinks the Sun supposedly-ANSI compiler will reject this.  */
+    int x[] = {25, 17};
+    const int *foo = &x[0];
+    ++foo;
+  }
+  { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+    typedef const int *iptr;
+    iptr p = 0;
+    ++p;
+  }
+  { /* AIX XL C 1.02.0.0 rejects this saying
+       "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+    struct s { int j; const int *ap[3]; };
+    struct s *b; b->j = 5;
+  }
+  { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+    const int foo = 10;
+    if (!foo) return 0;
+  }
+  return !cs[0] && !zero.x;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_const=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_c_const=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\_ACEOF
+#define const /**/
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if test "${ac_cv_c_inline+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_c_inline=$ac_kw
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
+{ $as_echo "$as_me:$LINENO: checking for size_t" >&5
+$as_echo_n "checking for size_t... " >&6; }
+if test "${ac_cv_type_size_t+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_type_size_t=no
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if (sizeof (size_t))
+       return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+if (sizeof ((size_t)))
+         return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_size_t=yes
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+$as_echo "$ac_cv_type_size_t" >&6; }
+if test "x$ac_cv_type_size_t" = x""yes; then
+  :
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if test "${ac_cv_header_time+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_time=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_header_time=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TIME_WITH_SYS_TIME 1
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if test "${ac_cv_struct_tm+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+                                    int *p = &tm.tm_sec;
+                                    return !p;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_struct_tm=time.h
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_struct_tm=sys/time.h
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+cat >>confdefs.h <<\_ACEOF
+#define TM_IN_SYS_TIME 1
+_ACEOF
+
+fi
+
+
+
+{ $as_echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if test "${ac_cv_type_signal+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_type_signal=int
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_type_signal=void
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+$as_echo "$ac_cv_type_signal" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+for ac_func in strerror random srandom strchr strrchr lockf flock \
+strcasecmp strncasecmp strnlen atexit on_exit getpass memmove \
+strdup strcspn strspn strtoul strtol memcpy strpbrk memset setenv \
+seteuid setresuid setpgrp \
+tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \
+snprintf stat64 setlocale \
+wcsdup wcscasecmp wcsnlen putwc \
+getuserid getgroupid
+do
+as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <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 $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  eval "$as_ac_var=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:$LINENO: checking whether setpgrp takes no argument" >&5
+$as_echo_n "checking whether setpgrp takes no argument... " >&6; }
+if test "${ac_cv_func_setpgrp_void+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then
+  { { $as_echo "$as_me:$LINENO: error: cannot check setpgrp when cross compiling" >&5
+$as_echo "$as_me: error: cannot check setpgrp when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+/* If this system has a BSD-style setpgrp which takes arguments,
+  setpgrp(1, 1) will fail with ESRCH and return -1, in that case
+  exit successfully. */
+  return setpgrp (1,1) != -1;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_func_setpgrp_void=no
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_func_setpgrp_void=yes
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_setpgrp_void" >&5
+$as_echo "$ac_cv_func_setpgrp_void" >&6; }
+if test $ac_cv_func_setpgrp_void = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define SETPGRP_VOID 1
+_ACEOF
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for 64-bit off_t" >&5
+$as_echo_n "checking for 64-bit off_t... " >&6; }
+if test "${sfs_cv_off_t_64+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+switch (0) case 0: case (sizeof (off_t) <= 4):;
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  sfs_cv_off_t_64=no
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       sfs_cv_off_t_64=yes
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $sfs_cv_off_t_64" >&5
+$as_echo "$sfs_cv_off_t_64" >&6; }
+if test $sfs_cv_off_t_64 = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OFF_T_64 1
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:$LINENO: checking whether ${CC} supports loff_t type" >&5
+$as_echo_n "checking whether ${CC} supports loff_t type... " >&6; }
+if test "${ice_cv_have_loff_t+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+int
+main ()
+{
+loff_t a;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ice_cv_have_loff_t=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ice_cv_have_loff_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ice_cv_have_loff_t" >&5
+$as_echo "$ice_cv_have_loff_t" >&6; }
+if test "$ice_cv_have_loff_t" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LOFF_T 1
+_ACEOF
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking whether ${CC} supports offset_t type" >&5
+$as_echo_n "checking whether ${CC} supports offset_t type... " >&6; }
+if test "${ice_cv_have_offset_t+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <sys/types.h>
+int
+main ()
+{
+offset_t a;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ice_cv_have_offset_t=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ice_cv_have_offset_t=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ice_cv_have_offset_t" >&5
+$as_echo "$ice_cv_have_offset_t" >&6; }
+if test "$ice_cv_have_offset_t" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OFFSET_T 1
+_ACEOF
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking whether ${CC} supports long long type" >&5
+$as_echo_n "checking whether ${CC} supports long long type... " >&6; }
+if test "${ice_cv_have_long_long+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+long long a;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ice_cv_have_long_long=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ice_cv_have_long_long=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ice_cv_have_long_long" >&5
+$as_echo "$ice_cv_have_long_long" >&6; }
+if test "$ice_cv_have_long_long" = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LONG_LONG 1
+_ACEOF
+
+fi
+
+
+
+
+
+for ac_func in utimes utime
+do
+as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <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 $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  eval "$as_ac_var=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+done
+
+
+
+for ac_func in tzset gettimeofday
+do
+as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_func" >&5
+$as_echo_n "checking for $ac_func... " >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <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 $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  eval "$as_ac_var=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       eval "$as_ac_var=no"
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_var'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:$LINENO: checking declaration of sys_errlist" >&5
+$as_echo_n "checking declaration of sys_errlist... " >&6; }
+if test "${cf_cv_dcl_sys_errlist+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+int
+main ()
+{
+char *c = (char *) *sys_errlist
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  cf_cv_dcl_sys_errlist=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       cf_cv_dcl_sys_errlist=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $cf_cv_dcl_sys_errlist" >&5
+$as_echo "$cf_cv_dcl_sys_errlist" >&6; }
+test $cf_cv_dcl_sys_errlist = no ||
+cat >>confdefs.h <<\_ACEOF
+#define DECL_SYS_ERRLIST 1
+_ACEOF
+
+
+
+
+host_os0=`echo $host_os | sed 's/-/_/g'`
+host_os1=`echo $host_os0 | sed 's/\./_/g'`
+host_os2=`echo $host_os0 | sed 's/^\([^.]*\)\..*$/\1/g'`
+host_os3=`echo $host_os2 | sed 's/^\([^0-9]*\)[0-9]*$/\1/g'`
+host_cpu1=`echo $host_cpu | sed 's/\./_/g'`
+host_vendor1=`echo $host_vendor | sed 's/\./_/g'`
+HOST_ID="-DCPU_$host_cpu1 -DVENDOR_$host_vendor1 -DOS_$host_os1"
+if [ $host_os1 != $host_os2 ] ; then
+       HOST_ID="$HOST_ID -DOS_$host_os2"
+fi
+if [ $host_os1 != $host_os3 ] && [ $host_os2 != $host_os3 ] ; then
+       HOST_ID="$HOST_ID -DOS_$host_os3"
+fi
+
+my_host_os=`echo $host_os1 $host_os2 $host_os3 | sort -u`
+objs=`echo $srcdir/*.c | sed 's/\.c$/.o/' `
+if [ "X$GCC" = "Xyes" ] ; then
+    if [ "$host_cpu" = i486 ] ; then
+           CFLAGS="$CFLAGS -m486"
+    fi
+    Wall=-Wall
+    if [ "$host_os3" = sunos ] ; then
+           Wall=""
+    fi
+    if [ "$host_os3" = ultrix ] ; then
+           Wall=""
+    fi
+    if [ "$host_os3" = linux ] ; then
+           CFLAGS="$CFLAGS -fno-strength-reduce"
+    fi
+    if [ "$host_os3" = aux ] ; then
+           CFLAGS="$CFLAGS -ZP"
+           MACHDEPLIBS="-lposix -UTIL"
+    fi
+    case "${host}" in
+       arm*-*-linux) CFLAGS="$CFLAGS -mstructure-size-boundary=8";;
+    esac
+    CFLAGS="$CFLAGS $Wall"
+else
+    if [ $host_os3 = hpux ] ; then
+           CPPFLAGS="$CPPFLAGS -Ae"
+    fi
+
+    if [ $host_os3 = xenix ] ; then
+           CFLAGS="$CFLAGS -M2e"
+    fi
+fi
+
+if [ $host_os3 = hpux ] ; then
+           LDFLAGS="$LDFLAGS -z"
+fi
+
+
+if [ $host_vendor = linux ] ; then
+    LDFLAGS="$LDFLAGS -z"
+fi
+
+if [ $host_os3 = xenix ] ; then
+    LDFLAGS="$LDFLAGS -M2e -i -f 5000"
+fi
+
+if [ $host_os2 = sysv4 ] ; then
+    SHLIB="-lc -L/usr/ucblib -lucb"
+else
+    SHLIB=""
+fi
+
+if [ $host_os3 = isc ] ; then
+    CFLAGS="$CFLAGS -D_SYSV3"
+    SHLIB="-lc_s"
+fi
+
+if [ $host_os3 = solaris -a x$newVold = xxyes ] ; then
+    SHLIB="$SHLIB -s -lvolmgt"
+fi
+
+if [ $host_os3 = nextstep ] ; then
+    CFLAGS="$CFLAGS -DBSD"
+    SHLIB=""
+fi
+
+if [ -d /usr/5lib ] ; then
+       extralibdir=-L/usr/5lib
+fi
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for X" >&5
+$as_echo_n "checking for X... " >&6; }
+
+
+# Check whether --with-x was given.
+if test "${with_x+set}" = set; then
+  withval=$with_x;
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+  # The user explicitly disabled X.
+  have_x=disabled
+else
+  case $x_includes,$x_libraries in #(
+    *\'*) { { $as_echo "$as_me:$LINENO: error: cannot use X directory names containing '" >&5
+$as_echo "$as_me: error: cannot use X directory names containing '" >&2;}
+   { (exit 1); exit 1; }; };; #(
+    *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=no ac_x_libraries=no
+rm -f -r conftest.dir
+if mkdir conftest.dir; then
+  cd conftest.dir
+  cat >Imakefile <<'_ACEOF'
+incroot:
+       @echo incroot='${INCROOT}'
+usrlibdir:
+       @echo usrlibdir='${USRLIBDIR}'
+libdir:
+       @echo libdir='${LIBDIR}'
+_ACEOF
+  if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
+    # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+    for ac_var in incroot usrlibdir libdir; do
+      eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
+    done
+    # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+    for ac_extension in a so sl dylib la dll; do
+      if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" &&
+        test -f "$ac_im_libdir/libX11.$ac_extension"; then
+       ac_im_usrlibdir=$ac_im_libdir; break
+      fi
+    done
+    # Screen out bogus values from the imake configuration.  They are
+    # bogus both because they are the default anyway, and because
+    # using them would break gcc on systems where it needs fixed includes.
+    case $ac_im_incroot in
+       /usr/include) ac_x_includes= ;;
+       *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
+    esac
+    case $ac_im_usrlibdir in
+       /usr/lib | /usr/lib64 | /lib | /lib64) ;;
+       *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
+    esac
+  fi
+  cd ..
+  rm -f -r conftest.dir
+fi
+
+# Standard set of common directories for X headers.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ac_x_header_dirs='
+/usr/X11/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R6
+/usr/local/include/X11R5
+/usr/local/include/X11R4
+
+/usr/X386/include
+/usr/x386/include
+/usr/XFree86/include/X11
+
+/usr/include
+/usr/local/include
+/usr/unsupported/include
+/usr/athena/include
+/usr/local/x11r5/include
+/usr/lpp/Xamples/include
+
+/usr/openwin/include
+/usr/openwin/share/include'
+
+if test "$ac_x_includes" = no; then
+  # Guess where to find include files, by looking for Xlib.h.
+  # First, try using that file with no special directory specified.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <X11/Xlib.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  for ac_dir in $ac_x_header_dirs; do
+  if test -r "$ac_dir/X11/Xlib.h"; then
+    ac_x_includes=$ac_dir
+    break
+  fi
+done
+fi
+
+rm -f conftest.err conftest.$ac_ext
+fi # $ac_x_includes = no
+
+if test "$ac_x_libraries" = no; then
+  # Check for the libraries.
+  # See if we find them without any special options.
+  # Don't add to $LIBS permanently.
+  ac_save_LIBS=$LIBS
+  LIBS="-lX11 $LIBS"
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <X11/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       LIBS=$ac_save_LIBS
+for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
+do
+  # Don't even attempt the hair of trying to link an X program!
+  for ac_extension in a so sl dylib la dll; do
+    if test -r "$ac_dir/libX11.$ac_extension"; then
+      ac_x_libraries=$ac_dir
+      break 2
+    fi
+  done
+done
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
+
+case $ac_x_includes,$ac_x_libraries in #(
+  no,* | *,no | *\'*)
+    # Didn't find X, or a directory has "'" in its name.
+    ac_cv_have_x="have_x=no";; #(
+  *)
+    # Record where we found X for the cache.
+    ac_cv_have_x="have_x=yes\
+       ac_x_includes='$ac_x_includes'\
+       ac_x_libraries='$ac_x_libraries'"
+esac
+fi
+;; #(
+    *) have_x=yes;;
+  esac
+  eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+  { $as_echo "$as_me:$LINENO: result: $have_x" >&5
+$as_echo "$have_x" >&6; }
+  no_x=yes
+else
+  # If each of the values was on the command line, it overrides each guess.
+  test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+  test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+  # Update the cache value to reflect the command line values.
+  ac_cv_have_x="have_x=yes\
+       ac_x_includes='$x_includes'\
+       ac_x_libraries='$x_libraries'"
+  { $as_echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5
+$as_echo "libraries $x_libraries, headers $x_includes" >&6; }
+fi
+
+if test "$no_x" = yes; then
+  # Not all programs may use this symbol, but it does not hurt to define it.
+
+cat >>confdefs.h <<\_ACEOF
+#define X_DISPLAY_MISSING 1
+_ACEOF
+
+  X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+  if test -n "$x_includes"; then
+    X_CFLAGS="$X_CFLAGS -I$x_includes"
+  fi
+
+  # It would also be nice to do this for all -L options, not just this one.
+  if test -n "$x_libraries"; then
+    X_LIBS="$X_LIBS -L$x_libraries"
+    # For Solaris; some versions of Sun CC require a space after -R and
+    # others require no space.  Words are not sufficient . . . .
+    { $as_echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5
+$as_echo_n "checking whether -R must be followed by a space... " >&6; }
+    ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+    ac_xsave_c_werror_flag=$ac_c_werror_flag
+    ac_c_werror_flag=yes
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+       X_LIBS="$X_LIBS -R$x_libraries"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       LIBS="$ac_xsave_LIBS -R $x_libraries"
+       cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+         X_LIBS="$X_LIBS -R $x_libraries"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { $as_echo "$as_me:$LINENO: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+    ac_c_werror_flag=$ac_xsave_c_werror_flag
+    LIBS=$ac_xsave_LIBS
+  fi
+
+  # Check for system-dependent libraries X programs must link with.
+  # Do this before checking for the system-independent R6 libraries
+  # (-lICE), since we may need -lsocket or whatever for X linking.
+
+  if test "$ISC" = yes; then
+    X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+  else
+    # Martyn Johnson says this is needed for Ultrix, if the X
+    # libraries were built with DECnet support.  And Karl Berry says
+    # the Alpha needs dnet_stub (dnet does not exist).
+    ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11"
+    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dnet_dnet_ntoa=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_dnet_dnet_ntoa=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+    if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+      { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet_stub  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+    fi
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+    LIBS="$ac_xsave_LIBS"
+
+    # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+    # to get the SysV transport functions.
+    # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4)
+    # needs -lnsl.
+    # The nsl library prevents programs from opening the X display
+    # on Irix 5.2, according to T.E. Dickey.
+    # The functions gethostbyname, getservbyname, and inet_addr are
+    # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking.
+    { $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5
+$as_echo_n "checking for gethostbyname... " >&6; }
+if test "${ac_cv_func_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define gethostbyname to an innocuous variant, in case <limits.h> declares gethostbyname.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define gethostbyname innocuous_gethostbyname
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char gethostbyname (); 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 gethostbyname
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_gethostbyname || defined __stub___gethostbyname
+choke me
+#endif
+
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5
+$as_echo "$ac_cv_func_gethostbyname" >&6; }
+
+    if test $ac_cv_func_gethostbyname = no; then
+      { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_nsl_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+      if test $ac_cv_lib_nsl_gethostbyname = no; then
+       { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_bsd_gethostbyname=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_bsd_gethostbyname=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd"
+fi
+
+      fi
+    fi
+
+    # lieder@skyler.mavd.honeywell.com says without -lsocket,
+    # socket/setsockopt and other routines are undefined under SCO ODT
+    # 2.0.  But -lsocket is broken on IRIX 5.2 (and is not necessary
+    # on later versions), says Simon Leinen: it contains gethostby*
+    # variants that don't use the name server (or something).  -lsocket
+    # must be given before -lnsl if both are needed.  We assume that
+    # if connect needs -lnsl, so does gethostbyname.
+    { $as_echo "$as_me:$LINENO: checking for connect" >&5
+$as_echo_n "checking for connect... " >&6; }
+if test "${ac_cv_func_connect+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define connect to an innocuous variant, in case <limits.h> declares connect.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define connect innocuous_connect
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char connect (); 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 connect
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_connect || defined __stub___connect
+choke me
+#endif
+
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_connect=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_connect=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5
+$as_echo "$ac_cv_func_connect" >&6; }
+
+    if test $ac_cv_func_connect = no; then
+      { $as_echo "$as_me:$LINENO: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if test "${ac_cv_lib_socket_connect+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_socket_connect=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_connect=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = x""yes; then
+  X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+    fi
+
+    # Guillermo Gomez says -lposix is necessary on A/UX.
+    { $as_echo "$as_me:$LINENO: checking for remove" >&5
+$as_echo_n "checking for remove... " >&6; }
+if test "${ac_cv_func_remove+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define remove to an innocuous variant, in case <limits.h> declares remove.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define remove innocuous_remove
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char remove (); 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 remove
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_remove || defined __stub___remove
+choke me
+#endif
+
+int
+main ()
+{
+return remove ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_remove=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_remove=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_remove" >&5
+$as_echo "$ac_cv_func_remove" >&6; }
+
+    if test $ac_cv_func_remove = no; then
+      { $as_echo "$as_me:$LINENO: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if test "${ac_cv_lib_posix_remove+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+int
+main ()
+{
+return remove ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_posix_remove=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_posix_remove=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+    fi
+
+    # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+    { $as_echo "$as_me:$LINENO: checking for shmat" >&5
+$as_echo_n "checking for shmat... " >&6; }
+if test "${ac_cv_func_shmat+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define shmat to an innocuous variant, in case <limits.h> declares shmat.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define shmat innocuous_shmat
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shmat (); 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 shmat
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_shmat || defined __stub___shmat
+choke me
+#endif
+
+int
+main ()
+{
+return shmat ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_shmat=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_func_shmat=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shmat" >&5
+$as_echo "$ac_cv_func_shmat" >&6; }
+
+    if test $ac_cv_func_shmat = no; then
+      { $as_echo "$as_me:$LINENO: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if test "${ac_cv_lib_ipc_shmat+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lipc  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+int
+main ()
+{
+return shmat ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_ipc_shmat=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ipc_shmat=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = x""yes; then
+  X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+fi
+
+    fi
+  fi
+
+  # Check for libraries that X11R6 Xt/Xaw programs need.
+  ac_save_LDFLAGS=$LDFLAGS
+  test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+  # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+  # check for ICE first), but we must link in the order -lSM -lICE or
+  # we get undefined symbols.  So assume we have SM if we have ICE.
+  # These have to be linked with before -lX11, unlike the other
+  # libraries we check for below, so use a different variable.
+  # John Interrante, Karl Berry
+  { $as_echo "$as_me:$LINENO: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceConnectionNumber ();
+int
+main ()
+{
+return IceConnectionNumber ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then
+  X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+fi
+
+  LDFLAGS=$ac_save_LDFLAGS
+
+fi
+
+
+# Check whether --enable-floppyd was given.
+if test "${enable_floppyd+set}" = set; then
+  enableval=$enable_floppyd; if test x$enableval != x; then
+  use_floppyd=$enableval
+fi
+fi
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lsocket" >&5
+$as_echo_n "checking for main in -lsocket... " >&6; }
+if test "${ac_cv_lib_socket_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_socket_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_socket_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_main" >&5
+$as_echo "$ac_cv_lib_socket_main" >&6; }
+if test "x$ac_cv_lib_socket_main" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+  LIBS="-lsocket $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lnsl" >&5
+$as_echo_n "checking for main in -lnsl... " >&6; }
+if test "${ac_cv_lib_nsl_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_nsl_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_nsl_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_main" >&5
+$as_echo "$ac_cv_lib_nsl_main" >&6; }
+if test "x$ac_cv_lib_nsl_main" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBNSL 1
+_ACEOF
+
+  LIBS="-lnsl $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lbsd" >&5
+$as_echo_n "checking for main in -lbsd... " >&6; }
+if test "${ac_cv_lib_bsd_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_bsd_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_cv_lib_bsd_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_main" >&5
+$as_echo "$ac_cv_lib_bsd_main" >&6; }
+if test "x$ac_cv_lib_bsd_main" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBSD 1
+_ACEOF
+
+  LIBS="-lbsd $LIBS"
+
+fi
+
+
+
+
+for ac_header in sys/socket.h arpa/inet.h netdb.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5
+$as_echo_n "checking $ac_header usability... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5
+$as_echo_n "checking $ac_header presence... " >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+$as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+$as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+              { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+
+fi
+as_val=`eval 'as_val=${'$as_ac_Header'}
+                $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+if test X$use_floppyd = X -a X$no_x = X ; then
+    use_floppyd="yes"
+fi
+
+if test X$use_floppyd = Xyes; then
+    if test X$no_x = Xyes ; then
+       echo "Floppyd needs X support" >&2
+       echo "To compile without floppyd, use ./configure --disable-floppyd" >&2
+       exit 1
+    fi
+    FLOPPYD="floppyd floppyd_installtest"
+    BINFLOPPYD="\$(DESTDIR)\$(bindir)/floppyd \$(DESTDIR)\$(bindir)/floppyd_installtest"
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_FLOPPYD 1
+_ACEOF
+
+else
+    FLOPPYD=
+    BINFLOPPYD=
+fi
+
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+       "s/'/'\\\\''/g;
+         s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+       expr "X$arg" : "X\\(.*\\)$as_nl";
+       arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""       $as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+        X"$0" : 'X\(//\)$' \| \
+        X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\/\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='        ';;     # ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+       test -d "$1/.";
+      else
+       case $1 in
+       -*)set "./$1";;
+       esac;
+       case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+       ???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTION]... [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.63,
+  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { $as_echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { $as_echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   $as_echo "$as_me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr='\r'
+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 {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\).*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\).*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <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 >>"\$tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = "\a"
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
+$as_echo "$as_me: error: could not setup config files machinery" >&2;}
+   { (exit 1); exit 1; }; }
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[         ]*VPATH[        ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[    ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[      ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[    ]*#[    ]*define[       ][      ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[    ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[        ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <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 = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5
+$as_echo "$as_me: error: could not setup config headers machinery" >&2;}
+   { (exit 1); exit 1; }; }
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
+$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+        # (if the path is not absolute).  The absolute path cannot be DOS-style,
+        # because $ac_f cannot contain `:'.
+        test -f "$ac_f" ||
+          case $ac_f in
+          [\\/$]*) false;;
+          *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+          esac ||
+          { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      ac_file_inputs="$ac_file_inputs '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+         $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+       `' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; } ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$ac_file" : 'X\(//\)[^/]' \| \
+        X"$ac_file" : 'X\(//\)$' \| \
+        X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+        X"$as_dir" : 'X\(//\)[^/]' \| \
+        X"$as_dir" : 'X\(//\)$' \| \
+        X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)[^/].*/{
+           s//\1/
+           q
+         }
+         /^X\(\/\/\)$/{
+           s//\1/
+           q
+         }
+         /^X\(\/\).*/{
+           s//\1/
+           q
+         }
+         s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[         ]*datarootdir[  ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+  esac \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$tmp/config.h" "$ac_file" \
+       || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5
+$as_echo "$as_me: error: could not create -" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..52fa860
--- /dev/null
@@ -0,0 +1,400 @@
+dnl Copyright 1996-2003,2005,2006,2008,2009 Alain Knaff.
+dnl This file is part of mtools.
+dnl
+dnl Mtools is free software: you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation, either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl Mtools is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with Mtools.  If not, see <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         debuging messages],
+[if test x$enableval = xyes; then
+  AC_DEFINE([DEBUG],1,[Define for debugging messages])
+fi])
+
+
+dnl Check for configuration options
+dnl Raw terminal code (enabled by default)
+AC_ARG_ENABLE(raw_term,
+[  --enable-raw-term      raw terminal (readkey behaviour, default)],
+[if test x$enableval = xyes; then
+  AC_DEFINE([USE_RAWTERM],1,[Define on non Unix OS'es which don't have the concept of tty's])
+fi],
+AC_DEFINE([USE_RAWTERM],1,[Define on non Unix OS'es which don't have the concept of tty's]))
+
+
+dnl Checks for libraries.
+
+dnl AC_IRIX_SUN
+AC_CHECK_LIB(sun, getpwnam)
+AC_CHECK_LIB(cam, cam_open_device)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(getopt.h sys/stat.h stdlib.h unistd.h linux/unistd.h \
+libc.h fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h strings.h string.h \
+sys/param.h memory.h malloc.h signal.h sys/signal.h utime.h sgtty.h \
+sys/floppy.h mntent.h sys/sysmacros.h netinet/in.h assert.h \
+iconv.h wctype.h wchar.h locale.h)
+AC_CHECK_HEADERS(termio.h sys/termio.h, [break])
+AC_CHECK_HEADERS(termios.h sys/termios.h, [break])
+
+
+dnl
+dnl Check to see if llseek() is declared in unistd.h.  On some libc's
+dnl it is, and on others it isn't..... Thank you glibc developers....
+dnl
+dnl Warning!  Use of --enable-gcc-wall may throw off this test.
+dnl
+dnl
+AC_MSG_CHECKING(whether llseek declared in unistd.h)
+AC_CACHE_VAL(mtools_cv_have_llseek_prototype,
+        AC_TRY_COMPILE(
+[#include <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 strcspn strspn strtoul strtol memcpy strpbrk memset setenv \
+seteuid setresuid setpgrp \
+tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \
+snprintf stat64 setlocale \
+wcsdup wcscasecmp wcsnlen putwc \
+getuserid getgroupid)
+AC_FUNC_SETPGRP
+
+dnl
+dnl Check for 64-bit off_t
+dnl
+AC_DEFUN(SFS_CHECK_OFF_T_64,
+[AC_CACHE_CHECK(for 64-bit off_t, sfs_cv_off_t_64,
+AC_TRY_COMPILE([
+#include <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
+    if [ "$host_cpu" = i486 ] ; then
+           CFLAGS="$CFLAGS -m486"
+    fi
+    Wall=-Wall
+    if [ "$host_os3" = sunos ] ; then
+           Wall=""
+    fi
+    if [ "$host_os3" = ultrix ] ; then
+           Wall=""
+    fi
+    if [ "$host_os3" = linux ] ; then
+           CFLAGS="$CFLAGS -fno-strength-reduce"
+    fi
+    if [ "$host_os3" = aux ] ; then
+           CFLAGS="$CFLAGS -ZP"
+           MACHDEPLIBS="-lposix -UTIL"
+    fi
+    case "${host}" in
+       arm*-*-linux) CFLAGS="$CFLAGS -mstructure-size-boundary=8";;
+    esac
+    CFLAGS="$CFLAGS $Wall"
+else
+    if [ $host_os3 = hpux ] ; then
+           CPPFLAGS="$CPPFLAGS -Ae"
+    fi
+
+    if [ $host_os3 = xenix ] ; then
+           CFLAGS="$CFLAGS -M2e"
+    fi
+fi
+
+if [ $host_os3 = hpux ] ; then
+           LDFLAGS="$LDFLAGS -z"
+fi
+
+
+if [ $host_vendor = linux ] ; then
+    LDFLAGS="$LDFLAGS -z"
+fi
+
+if [ $host_os3 = xenix ] ; then
+    LDFLAGS="$LDFLAGS -M2e -i -f 5000"
+fi
+
+if [ $host_os2 = sysv4 ] ; then
+    SHLIB="-lc -L/usr/ucblib -lucb"
+else
+    SHLIB=""
+fi
+
+if [ $host_os3 = isc ] ; then
+    CFLAGS="$CFLAGS -D_SYSV3"
+    SHLIB="-lc_s"
+fi
+
+if [ $host_os3 = solaris -a x$newVold = xxyes ] ; then
+    SHLIB="$SHLIB -s -lvolmgt"
+fi
+
+if [ $host_os3 = nextstep ] ; then
+    CFLAGS="$CFLAGS -DBSD"
+    SHLIB=""
+fi
+
+if [ -d /usr/5lib ] ; then
+       extralibdir=-L/usr/5lib
+fi
+
+]
+
+AC_PATH_X
+AC_PATH_XTRA
+
+dnl Floppyd
+AC_ARG_ENABLE(floppyd,
+[  --enable-floppyd       floppy daemon support],
+[if test x$enableval != x; then
+  use_floppyd=$enableval
+fi])
+
+AC_CHECK_LIB(socket,main)
+AC_CHECK_LIB(nsl,main)
+AC_CHECK_LIB(bsd,main)
+AC_CHECK_HEADERS(sys/socket.h arpa/inet.h netdb.h)
+
+if test X$use_floppyd = X -a X$no_x = X ; then
+    use_floppyd="yes"
+fi
+
+if test X$use_floppyd = Xyes; then
+    if test X$no_x = Xyes ; then
+       echo "Floppyd needs X support" >&2
+       echo "To compile without floppyd, use ./configure --disable-floppyd" >&2
+       exit 1
+    fi
+    FLOPPYD="floppyd floppyd_installtest"
+    BINFLOPPYD="\$(DESTDIR)\$(bindir)/floppyd \$(DESTDIR)\$(bindir)/floppyd_installtest"
+    AC_DEFINE([USE_FLOPPYD],1,[Define when you want to include floppyd support])
+else
+    FLOPPYD=
+    BINFLOPPYD=
+fi
+
+
+AC_SUBST(FLOPPYD)
+AC_SUBST(BINFLOPPYD)
+AC_SUBST(extraincludedir)
+AC_SUBST(extralibdir)
+AC_SUBST(MACHDEPLIBS)
+AC_SUBST(SHLIB)
+AC_SUBST(host_cpu)
+AC_SUBST(HOST_ID)
+AC_OUTPUT(Makefile)
diff --git a/copyfile.c b/copyfile.c
new file mode 100644 (file)
index 0000000..282c649
--- /dev/null
@@ -0,0 +1,73 @@
+/*  Copyright 1996-1999,2001,2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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, retw;
+/*     size_t len;*/
+       mt_size_t mt_len;
+
+       if (!Source){
+               fprintf(stderr,"Couldn't open source file\n");
+               return -1;
+       }
+
+       if (!Target){
+               fprintf(stderr,"Couldn't open target file\n");
+               return -1;
+       }
+
+       pos = 0;
+       GET_DATA(Source, 0, &mt_len, 0, 0);
+       while(1){
+               ret = READS(Source, buffer, (mt_off_t) pos, 8*16384);
+               if (ret < 0 ){
+                       perror("file read");
+                       return -1;
+               }
+               if(!ret)
+                       break;
+               if(got_signal)
+                       return -1;
+               if (ret == 0)
+                       break;
+               if ((retw = force_write(Target, buffer, (mt_off_t) pos, ret)) != ret){
+                       if(retw < 0 )
+                               perror("write in copy");
+                       else
+                               fprintf(stderr,
+                                       "Short write %d instead of %d\n", retw,
+                                       ret);
+                       if(errno == ENOSPC)
+                               got_signal = 1;
+                       return ret;
+               }
+               pos += ret;
+       }
+       return 0;
+}
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..2f3bc51
--- /dev/null
@@ -0,0 +1,95 @@
+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 (file)
index 0000000..b8626c4
--- /dev/null
@@ -0,0 +1 @@
+4
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..a8bf5b0
--- /dev/null
@@ -0,0 +1,23 @@
+Source: mtools
+Build-Depends-Indep: fakeroot, devscripts, debhelper, texinfo
+Section: otherosfs
+Priority: optional
+Maintainer: Alain Knaff <alain@knaff.lu>
+
+Package: mtools
+Section: otherosfs
+Priority: optional
+Architecture: any
+Depends: libc6 (>= 2.4-1)
+Essential: no
+Provides: mtools
+Description: Tools for manipulating MSDOS files
+ Mtools is a collection of utilities to access MS-DOS disks
+ from Unix without mounting them. It supports Win'95 style
+ long file names, OS/2 Xdf disks, ZIP/JAZ disks and 2m
+ disks (store up to 1992k on a high density 3 1/2 disk).
+ .
+ Also included in this package are commands to eject and manipulate
+ the write/password protection control of Zip disks.
+ .
+ Homepage: http://www.mtools.linux.lu/
diff --git a/debian/mtools.postinst b/debian/mtools.postinst
new file mode 100755 (executable)
index 0000000..5b9fc17
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Copyright 2007 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+
+infodir=/usr/share/info
+INSTALL_INFO=/usr/sbin/install-info
+
+if [ -f $INSTALL_INFO ] ; then
+       $INSTALL_INFO --info-dir=$infodir $infodir/mtools.info
+fi
+
diff --git a/debian/mtools.prerm b/debian/mtools.prerm
new file mode 100755 (executable)
index 0000000..94667cb
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# Copyright 2007 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+
+infodir=/usr/share/info
+INSTALL_INFO=/usr/sbin/install-info
+
+if [ -f $INSTALL_INFO ] ; then
+       $INSTALL_INFO --info-dir=$infodir --remove $infodir/mtools.info
+fi
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..8b3a760
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/make -f
+
+# Copyright 2007 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# Sample debian/rules that uses debhelper.
+# This file is public domain software, originally written by Joey Hess. 
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+buildroot=`pwd`/debian/mtools
+_prefix=/usr
+_infodir=/usr/share/info
+_mandir=/usr/share/man
+
+
+build: build-stamp
+build-stamp:
+       dh_testdir
+
+       # Add here commands to compile the package.
+       #$(MAKE)
+       ./configure --prefix=$(buildroot)$(_prefix) --sysconfdir=/etc --infodir=$(buildroot)$(_infodir) --mandir=$(buildroot)$(_mandir)
+       $(MAKE)
+
+       touch build-stamp
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp
+
+       # Add here commands to clean up after the build process.
+       #-$(MAKE) clean
+       #-$(MAKE) distclean
+       if [ -f Makefile ] ; then $(MAKE) clean ; fi
+       if [ -f Makefile ] ; then $(MAKE) distclean ; fi
+       rm -f config.status Makefile config.log config.h build-stamp
+
+       dh_clean
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k
+       dh_installdirs
+
+       # Add here commands to install the package into debian/<packagename>
+       #$(MAKE) prefix=`pwd`/debian/`dh_listpackages`/usr install
+       $(MAKE) install
+       rm -f $(buildroot)$(_infodir)/dir.gz
+       rm -f $(buildroot)$(_infodir)/dir.old.gz
+       rm -f $(buildroot)$(_infodir)/dir
+       rm -f $(buildroot)$(_infodir)/dir.old
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+       dh_installchangelogs
+       dh_installdocs
+       dh_installexamples
+#      dh_install
+#      dh_installmenu
+#      dh_installdebconf       
+#      dh_installlogrotate
+#      dh_installemacsen
+#      dh_installcatalogs
+#      dh_installpam
+#      dh_installmime
+#      dh_installinit
+#      dh_installcron
+#      dh_installinfo
+#      dh_installwm
+#      dh_installudev
+#      dh_undocumented
+       dh_installman
+       dh_link
+       dh_strip
+       dh_compress
+       dh_fixperms
+#      dh_perl
+#      dh_python
+#      dh_makeshlibs
+       dh_installdeb
+       dh_shlibdeps
+       dh_gencontrol
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/devices.c b/devices.c
new file mode 100644 (file)
index 0000000..9838a95
--- /dev/null
+++ b/devices.c
@@ -0,0 +1,1109 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-2003,2006,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)}
+
+
+
+#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
+
+const char *error_msg[22]={
+"Missing Data Address Mark",
+"Bad cylinder",
+"Scan not satisfied",
+"Scan equal hit",
+"Wrong cylinder",
+"CRC error in data field",
+"Control Mark = deleted",
+0,
+
+"Missing Address Mark",
+"Write Protect",
+"No Data - unreadable",
+0,
+"OverRun",
+"CRC error in data or address",
+0,
+"End Of Cylinder",
+
+0,
+0,
+0,
+"Not ready",
+"Equipment check error",
+"Seek end" };
+
+
+static __inline__ void print_message(RawRequest_t *raw_cmd,const char *message)
+{
+       int i, code;
+       if(!message)
+               return;
+
+       fprintf(stderr,"   ");
+       for (i=0; i< raw_cmd->cmd_count; i++)
+               fprintf(stderr,"%2.2x ", 
+                       (int)raw_cmd->cmd[i] );
+       fprintf(stderr,"\n");
+       for (i=0; i< raw_cmd->reply_count; i++)
+               fprintf(stderr,"%2.2x ",
+                       (int)raw_cmd->reply[i] );
+       fprintf(stderr,"\n");
+       code = (raw_cmd->reply[0] <<16) + 
+               (raw_cmd->reply[1] << 8) + 
+               raw_cmd->reply[2];
+       for(i=0; i<22; i++){
+               if ((code & (1 << i)) && error_msg[i])
+                       fprintf(stderr,"%s\n",
+                               error_msg[i]);
+       }
+}
+
+
+/* return values:
+ *  -1: Fatal error, don't bother retrying.
+ *   0: OK
+ *   1: minor error, retry
+ */
+
+int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message)
+{
+       if (ioctl( fd, FDRAWCMD, raw_cmd) >= 0) {
+               if (raw_cmd->reply_count < 7) {
+                       fprintf(stderr,"Short reply from FDC\n");
+                       return -1;
+               }               
+               return 0;
+       }
+
+       switch(errno) {
+               case EBUSY:
+                       fprintf(stderr, "FDC busy, sleeping for a second\n");
+                       sleep(1);
+                       return 1;
+               case EIO:
+                       fprintf(stderr,"resetting controller\n");
+                       if(ioctl(fd, FDRESET, 2)  < 0){
+                               perror("reset");
+                               return -1;
+                       }
+                       return 1;
+               default:
+                       perror(message);
+                       return -1;
+       }
+}
+
+
+/*
+ * return values
+ *  -1: error
+ *   0: OK, last sector
+ *   1: more raw commands follow
+ */
+
+int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print)
+{
+       
+       if(raw_cmd->reply_count == 7) {
+               int end;
+               
+               if (raw_cmd->reply[3] != raw_cmd->cmd[2]) {
+                       /* end of cylinder */
+                       end = raw_cmd->cmd[6] + 1;
+               } else {
+                       end = raw_cmd->reply[5];
+               }
+
+               *bytes = end - raw_cmd->cmd[4];
+               /* FIXME: over/under run */
+               *bytes = *bytes << (7 + raw_cmd->cmd[5]);
+       } else
+               *bytes = 0;       
+
+       switch(raw_cmd->reply[0] & 0xc0){
+               case 0x40:
+                       if ((raw_cmd->reply[0] & 0x38) == 0 &&
+                           (raw_cmd->reply[1]) == 0x80 &&
+                           (raw_cmd->reply[2]) == 0) {
+                               *bytes += 1 << (7 + raw_cmd->cmd[5]);
+                               break;
+                       }
+
+                       if ( raw_cmd->reply[1] & ST1_WP ){
+                               *bytes = 0;
+                               fprintf(stderr,
+                                       "This disk is write protected\n");
+                               return -1;
+                       }
+                       if(!*bytes && do_print)
+                               print_message(raw_cmd, "");
+                       return -1;
+               case 0x80:
+                       *bytes = 0;
+                       fprintf(stderr,
+                               "invalid command given\n");
+                       return -1;
+               case 0xc0:
+                       *bytes = 0;
+                       fprintf(stderr,
+                               "abnormal termination caused by polling\n");
+                       return -1;
+               default:
+                       break;
+       }       
+#ifdef FD_RAW_MORE
+       if(raw_cmd->flags & FD_RAW_MORE)
+               return 1;
+#endif
+       return 0;
+}
+
+#define predefined_devices
+struct device devices[] = {
+       {"/dev/fd0", 'A', 0, 0, 80,2, 18,0, MDEF_ARG},
+       {"/dev/fd1", 'B', 0, 0, 0,0, 0,0, FDEF_ARG},
+       /* we assume that the Zip or Jaz drive is the second on the SCSI bus */
+       {"/dev/sdb4",'J', GENHD },
+       {"/dev/sdb4",'Z', GENHD },
+       /*      {"/dev/sda4",'D', GENHD },*/
+       REMOTE
+};
+
+/*
+ * Stuffing back the floppy parameters into the driver allows for gems
+ * like 21 sector or single sided floppies from Atari ST systems.
+ * 
+ * Alain Knaff, Université Joseph Fourier, France, November 12, 1993.
+ */
+
+
+#define INIT_GENERIC
+#define generic_floppy_struct floppy_struct
+#define BLOCK_MAJOR 2
+#define SECTORS(floppy) floppy.sect
+#define TRACKS(floppy) floppy.track
+#define HEADS(floppy) floppy.head
+#define SECTORS_PER_DISK(floppy) floppy.size
+#define STRETCH(floppy) floppy.stretch
+#define USE_2M(floppy) ((floppy.rate & FD_2M) ? 0xff : 0x80 )
+#define SSIZE(floppy) ((((floppy.rate & 0x38) >> 3 ) + 2) % 8)
+
+static __inline__ void set_2m(struct floppy_struct *floppy, int value)
+{
+       if (value & 0x7f)
+               value = FD_2M;
+       else
+               value = 0;
+       floppy->rate = (floppy->rate & ~FD_2M) | value;       
+}
+#define SET_2M set_2m
+
+static __inline__ void set_ssize(struct floppy_struct *floppy, int value)
+{
+       value = (( (value & 7) + 6 ) % 8) << 3;
+
+       floppy->rate = (floppy->rate & ~0x38) | value;  
+}
+
+#define SET_SSIZE set_ssize
+
+static __inline__ int set_parameters(int fd, struct floppy_struct *floppy, 
+                                    struct MT_STAT *buf)
+{
+       if ( ( MINOR(buf->st_rdev ) & 0x7f ) > 3 )
+               return 1;
+       
+       return ioctl(fd, FDSETPRM, floppy);
+}
+
+static __inline__ int get_parameters(int fd, struct floppy_struct *floppy)
+{
+       return ioctl(fd, FDGETPRM, floppy);
+}
+
+#endif /* linux */
+
+
+/* OS/2, gcc+emx */
+#ifdef __EMX__
+#define predefined_devices
+struct device devices[] = {
+  {"A:", 'A', GENFD},
+  {"B:", 'B', GENFD},
+};
+#define INIT_NOOP
+#endif
+
+
+
+/*** /jes -- for D.O.S. 486 BL DX2/80 ***/
+/*** Jean-Marc Zucconi <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 int nr_const_devices = sizeof(const_devices) / sizeof(*const_devices);
+#else
+struct device devices[]={
+       {"/dev/fd0", 'A', 0, O_EXCL, 0,0, 0,0, MDEF_ARG},
+       /* to shut up Ultrix's native compiler, we can't make this empty :( */
+};
+const int nr_const_devices = 0;
+#endif
diff --git a/devices.h b/devices.h
new file mode 100644 (file)
index 0000000..1d0e236
--- /dev/null
+++ b/devices.h
@@ -0,0 +1,187 @@
+#ifdef OS_linux
+
+/*  Copyright 1996-2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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, int rate))
+{
+       request->rate = rate;
+}
+
+UNUSED(static __inline__ void RR_SETDRIVE(struct floppy_raw_cmd *request,int drive))
+{
+       request->cmd[1] = (request->cmd[1] & ~3) | (drive & 3);
+}
+
+UNUSED(static __inline__ void RR_SETTRACK(struct floppy_raw_cmd *request,int track))
+{
+       request->cmd[2] = track;
+}
+
+UNUSED(static __inline__ void RR_SETPTRACK(struct floppy_raw_cmd *request,
+                                      int track))
+{
+       request->track = track;
+}
+
+UNUSED(static __inline__ void RR_SETHEAD(struct floppy_raw_cmd *request, int head))
+{
+       if(head)
+               request->cmd[1] |= 4;
+       else
+               request->cmd[1] &= ~4;
+       request->cmd[3] = head;
+}
+
+UNUSED(static __inline__ void RR_SETSECTOR(struct floppy_raw_cmd *request, 
+                                          int sector))
+{
+       request->cmd[4] = sector;
+       request->cmd[6] = sector-1;
+}
+
+UNUSED(static __inline__ void RR_SETSIZECODE(struct floppy_raw_cmd *request, 
+                                            int sizecode))
+{
+       request->cmd[5] = sizecode;
+       request->cmd[6]++;
+       request->length += 128 << sizecode;
+}
+
+#if 0
+static inline void RR_SETEND(struct floppy_raw_cmd *request, int end)
+{
+       request->cmd[6] = end;
+}
+#endif
+
+UNUSED(static __inline__ void RR_SETDIRECTION(struct floppy_raw_cmd *request, 
+                                             int direction))
+{
+       if(direction == MT_READ) {
+               request->flags |= FD_RAW_READ;
+               request->cmd[0] = FD_READ & ~0x80;
+       } else {
+               request->flags |= FD_RAW_WRITE;
+               request->cmd[0] = FD_WRITE & ~0x80;
+       }
+}
+
+
+UNUSED(static __inline__ void RR_SETDATA(struct floppy_raw_cmd *request, 
+                                        caddr_t data))
+{
+       request->data = data;
+}
+
+
+#if 0
+static inline void RR_SETLENGTH(struct floppy_raw_cmd *request, int length)
+{
+       request->length += length;
+}
+#endif
+
+UNUSED(static __inline__ void RR_SETCONT(struct floppy_raw_cmd *request))
+{
+#ifdef FD_RAW_MORE
+       request->flags |= FD_RAW_MORE;
+#endif
+}
+
+
+UNUSED(static __inline__ int RR_SIZECODE(struct floppy_raw_cmd *request))
+{
+       return request->cmd[5];
+}
+
+
+
+UNUSED(static __inline__ int RR_TRACK(struct floppy_raw_cmd *request))
+{
+       return request->cmd[2];
+}
+
+
+UNUSED(static __inline__ int GET_DRIVE(int fd))
+{
+       struct MT_STAT statbuf;
+
+       if (MT_FSTAT(fd, &statbuf) < 0 ){
+               perror("stat");
+               return -1;
+       }
+         
+       if (!S_ISBLK(statbuf.st_mode) ||
+           MAJOR(statbuf.st_rdev) != FLOPPY_MAJOR)
+               return -1;
+       
+       return MINOR( statbuf.st_rdev );
+}
+
+
+
+/* void print_message(RawRequest_t *raw_cmd,char *message);*/
+int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message);
+int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print);
+
+
+#endif
diff --git a/dirCache.c b/dirCache.c
new file mode 100644 (file)
index 0000000..dea0a02
--- /dev/null
@@ -0,0 +1,336 @@
+/*  Copyright 1998,2001-2003,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "sysincludes.h"
+#include "vfat.h"
+#include "dirCache.h"
+
+
+
+
+#define BITS_PER_INT (sizeof(unsigned int) * 8)
+
+
+static __inline__ unsigned int rol(unsigned int arg, int shift)
+{
+       arg &= 0xffffffff; /* for 64 bit machines */
+       return (arg << shift) | (arg >> (32 - shift));
+}
+
+
+static int calcHash(wchar_t *name)
+{
+       unsigned long hash;
+       int i;
+       wchar_t c;
+
+       hash = 0;
+       i = 0;
+       while(*name) {
+               /* rotate it */
+               hash = rol(hash,5); /* a shift of 5 makes sure we spread quickly
+                                    * over the whole width, moreover, 5 is
+                                    * prime with 32, which makes sure that
+                                    * successive letters cannot cover each
+                                    * other easily */
+               c = towupper(*name);            
+               hash ^=  (c * (c+2)) ^ (i * (i+2));
+               hash &= 0xffffffff;
+               i++, name++;
+       }
+       hash = hash * (hash + 2);
+       /* the following two xors make sure all info is spread evenly over all
+        * bytes. Important if we only keep the low order bits later on */
+       hash ^= (hash & 0xfff) << 12;
+       hash ^= (hash & 0xff000) << 24;
+       return hash;
+}
+
+static int addBit(unsigned int *bitmap, int hash, int checkOnly)
+{
+       int bit, entry;
+
+       bit = 1 << (hash % BITS_PER_INT);
+       entry = (hash / BITS_PER_INT) % DC_BITMAP_SIZE;
+       
+       if(checkOnly)
+               return bitmap[entry] & bit;
+       else {
+               bitmap[entry] |= bit;
+               return 1;
+       }
+}
+
+static int _addHash(dirCache_t *cache, unsigned int hash, int checkOnly)
+{
+       return
+               addBit(cache->bm0, hash, checkOnly) &&
+               addBit(cache->bm1, rol(hash,12), checkOnly) &&
+               addBit(cache->bm2, rol(hash,24), checkOnly);
+}
+
+
+static void addNameToHash(dirCache_t *cache, wchar_t *name)
+{      
+       _addHash(cache, calcHash(name), 0);
+}
+
+static void hashDce(dirCache_t *cache, dirCacheEntry_t *dce)
+{
+       if(dce->beginSlot != cache->nrHashed)
+               return;
+       cache->nrHashed = dce->endSlot;
+       if(dce->longName)
+               addNameToHash(cache, dce->longName);
+       addNameToHash(cache, dce->shortName);
+}
+
+int isHashed(dirCache_t *cache, wchar_t *name)
+{
+       int ret;
+
+       ret =  _addHash(cache, calcHash(name), 1);
+       return ret;
+}
+
+int growDirCache(dirCache_t *cache, int slot)
+{
+       if(slot < 0) {
+               fprintf(stderr, "Bad slot %d\n", slot);
+               exit(1);
+       }
+
+       if( cache->nr_entries <= slot) {
+               int i;
+               
+               cache->entries = realloc(cache->entries,
+                                        (slot+1) * 2 *
+                                        sizeof(dirCacheEntry_t *));
+               if(!cache->entries)
+                       return -1;
+               for(i= cache->nr_entries; i < (slot+1) * 2; i++) {
+                       cache->entries[i] = 0;
+               }
+               cache->nr_entries = (slot+1) * 2;
+       }
+       return 0;
+}
+
+dirCache_t *allocDirCache(Stream_t *Stream, int slot)
+{
+       dirCache_t **dcp;
+
+       if(slot < 0) {
+               fprintf(stderr, "Bad slot %d\n", slot);
+               exit(1);
+       }
+
+       dcp = getDirCacheP(Stream);
+       if(!*dcp) {
+               *dcp = New(dirCache_t);
+               if(!*dcp)
+                       return 0;
+               (*dcp)->entries = NewArray((slot+1)*2+5, dirCacheEntry_t *);
+               if(!(*dcp)->entries) {
+                       free(*dcp);
+                       return 0;
+               }
+               (*dcp)->nr_entries = (slot+1) * 2;
+               memset( (*dcp)->bm0, 0, DC_BITMAP_SIZE);
+               memset( (*dcp)->bm1, 0, DC_BITMAP_SIZE);
+               memset( (*dcp)->bm2, 0, DC_BITMAP_SIZE);
+               (*dcp)->nrHashed = 0;
+       } else
+               if(growDirCache(*dcp, slot) < 0)
+                       return 0;
+       return *dcp;
+}
+
+static void freeDirCacheRange(dirCache_t *cache,
+                             unsigned int beginSlot,
+                             unsigned int endSlot)
+{
+       dirCacheEntry_t *entry;
+       unsigned int clearBegin;
+       unsigned int clearEnd;
+       unsigned int i;
+
+       if(endSlot < beginSlot) {
+               fprintf(stderr, "Bad slots %d %d in free range\n",
+                       beginSlot, endSlot);
+               exit(1);
+       }
+
+       while(beginSlot < endSlot) {
+               entry = cache->entries[beginSlot];
+               if(!entry) {
+                       beginSlot++;
+                       continue;
+               }
+               
+               clearEnd = entry->endSlot;
+               if(clearEnd > endSlot)
+                       clearEnd = endSlot;
+               clearBegin = beginSlot;
+               
+               for(i = clearBegin; i <clearEnd; i++)
+                       cache->entries[i] = 0;
+
+               if(entry->endSlot == endSlot)
+                       entry->endSlot = beginSlot;
+               else if(entry->beginSlot == beginSlot)
+                       entry->beginSlot = endSlot;
+               else {
+                       fprintf(stderr,
+                               "Internal error, non contiguous de-allocation\n");
+                       fprintf(stderr, "%d %d\n", beginSlot, endSlot);
+                       fprintf(stderr, "%d %d\n", entry->beginSlot,
+                               entry->endSlot);
+                       exit(1);                        
+               }
+
+               if(entry->beginSlot == entry->endSlot) {
+                       if(entry->longName)
+                               free(entry->longName);
+                       if(entry->shortName)
+                               free(entry->shortName);
+                       free(entry);
+               }
+
+               beginSlot = clearEnd;
+       }
+}
+
+static dirCacheEntry_t *allocDirCacheEntry(dirCache_t *cache, int beginSlot,
+                                          int endSlot,
+                                          dirCacheEntryType_t type)
+{
+       dirCacheEntry_t *entry;
+       int i;
+
+       if(growDirCache(cache, endSlot) < 0)
+               return 0;
+
+       entry = New(dirCacheEntry_t);
+       if(!entry)
+               return 0;
+       entry->type = type;
+       entry->longName = 0;
+       entry->shortName = 0;
+       entry->beginSlot = beginSlot;
+       entry->endSlot = endSlot;
+
+       freeDirCacheRange(cache, beginSlot, endSlot);
+       for(i=beginSlot; i<endSlot; i++) {
+               cache->entries[i] = entry;
+       }
+       return entry;
+}
+
+dirCacheEntry_t *addUsedEntry(dirCache_t *cache, int beginSlot, int endSlot,
+                             wchar_t *longName, wchar_t *shortName,
+                             struct directory *dir)
+{
+       dirCacheEntry_t *entry;
+
+       if(endSlot < beginSlot) {
+               fprintf(stderr,
+                       "Bad slots %d %d in add used entry\n",
+                       beginSlot, endSlot);
+               exit(1);
+       }
+
+
+       entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_USED);
+       if(!entry)
+               return 0;
+       
+       entry->beginSlot = beginSlot;
+       entry->endSlot = endSlot;
+       if(longName)
+               entry->longName = wcsdup(longName);
+       entry->shortName = wcsdup(shortName);
+       entry->dir = *dir;
+       hashDce(cache, entry);
+       return entry;
+}
+
+static void mergeFreeSlots(dirCache_t *cache, int slot)
+{
+       dirCacheEntry_t *previous, *next;
+       unsigned int i;
+
+       if(slot == 0)
+               return;
+       previous = cache->entries[slot-1];
+       next = cache->entries[slot];
+       if(next && next->type == DCET_FREE &&
+          previous && previous->type == DCET_FREE) {
+               for(i=next->beginSlot; i < next->endSlot; i++)
+                       cache->entries[i] = previous;
+               previous->endSlot = next->endSlot;
+               free(next);             
+       }
+}
+
+dirCacheEntry_t *addFreeEntry(dirCache_t *cache,
+                             unsigned int beginSlot,
+                             unsigned int endSlot)
+{
+       dirCacheEntry_t *entry;
+
+       if(beginSlot < cache->nrHashed)
+               cache->nrHashed = beginSlot;
+
+       if(endSlot < beginSlot) {
+               fprintf(stderr, "Bad slots %d %d in add free entry\n",
+                       beginSlot, endSlot);
+               exit(1);
+       }
+
+       if(endSlot == beginSlot)
+               return 0;
+       entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_FREE);
+       mergeFreeSlots(cache, beginSlot);
+       mergeFreeSlots(cache, endSlot);
+       return cache->entries[beginSlot];
+}
+
+
+dirCacheEntry_t *addEndEntry(dirCache_t *cache, int pos)
+{
+       return allocDirCacheEntry(cache, pos, pos+1, DCET_END);
+}
+
+dirCacheEntry_t *lookupInDircache(dirCache_t *cache, int pos)
+{
+       if(growDirCache(cache, pos+1) < 0)
+               return 0;
+       return cache->entries[pos];     
+}
+
+void freeDirCache(Stream_t *Stream)
+{
+       dirCache_t *cache, **dcp;
+
+       dcp = getDirCacheP(Stream);
+       cache = *dcp;
+       if(cache) {
+               freeDirCacheRange(cache, 0, cache->nr_entries);
+               free(cache);
+               *dcp = 0;
+       }
+}
diff --git a/dirCache.h b/dirCache.h
new file mode 100644 (file)
index 0000000..808f428
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef MTOOLS_DIRCACHE_H
+#define MTOOLS_DIRCACHE_H
+
+/*  Copyright 1997,1999,2001-2003,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+typedef enum {
+       DCET_FREE,
+       DCET_USED,
+       DCET_END
+} dirCacheEntryType_t;
+
+#define DC_BITMAP_SIZE 128
+
+typedef struct dirCacheEntry_t {
+       dirCacheEntryType_t type;
+       unsigned int beginSlot;
+       unsigned int endSlot;
+       wchar_t *shortName;
+       wchar_t *longName;
+       struct directory dir;
+} dirCacheEntry_t;
+
+typedef struct dirCache_t {
+       struct dirCacheEntry_t **entries;
+       int nr_entries;
+       unsigned int nrHashed;
+       unsigned int bm0[DC_BITMAP_SIZE];
+       unsigned int bm1[DC_BITMAP_SIZE];
+       unsigned int bm2[DC_BITMAP_SIZE];
+} dirCache_t;
+
+int isHashed(dirCache_t *cache, wchar_t *name);
+int growDirCache(dirCache_t *cache, int slot);
+dirCache_t *allocDirCache(Stream_t *Stream, int slot);
+dirCacheEntry_t *addUsedEntry(dirCache_t *Stream, int begin, int end,
+                             wchar_t *longName, wchar_t *shortName,
+                             struct directory *dir);
+void freeDirCache(Stream_t *Stream);
+dirCacheEntry_t *addFreeEntry(dirCache_t *Stream, 
+                             unsigned int begin, unsigned int end);
+dirCacheEntry_t *addEndEntry(dirCache_t *Stream, int pos);
+dirCacheEntry_t *lookupInDircache(dirCache_t *Stream, int pos);
+#endif
diff --git a/directory.c b/directory.c
new file mode 100644 (file)
index 0000000..9c8cb9c
--- /dev/null
@@ -0,0 +1,138 @@
+/*  Copyright 1995 David C. Niemi
+ *  Copyright 1996-2002,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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;
+       int buflen;
+       char *buffer;
+       
+       if (!getfreeMinClusters(Dir, 1))
+               return -1;
+
+       buflen = This->cluster_size * This->sector_size;
+
+       if(! (buffer=malloc(buflen)) ){
+               perror("dir_grow: malloc");
+               return -1;
+       }
+               
+       memset((char *) buffer, '\0', buflen);
+       ret = force_write(Dir, buffer, (mt_off_t) size * MDIR_SIZE, buflen);
+       free(buffer);
+       if(ret < buflen)
+               return -1;
+       return 0;
+}
+
+
+void low_level_dir_write(direntry_t *entry)
+{
+       force_write(entry->Dir, 
+                   (char *) (&entry->dir), 
+                   (mt_off_t) entry->entry * MDIR_SIZE, MDIR_SIZE);
+}
+
+
+/*
+ * Make a directory entry.  Builds a directory entry based on the
+ * name, attribute, starting cluster number, and size.  Returns a pointer
+ * to a static directory structure.
+ */
+
+struct directory *mk_entry(const dos_name_t *dn, char attr,
+                          unsigned int fat, size_t size, time_t date,
+                          struct directory *ndir)
+{
+       struct tm *now;
+       time_t date2 = date;
+       unsigned char hour, min_hi, min_low, sec;
+       unsigned char year, month_hi, month_low, day;
+
+       now = localtime(&date2);
+       dosnameToDirentry(dn, ndir);
+       ndir->attr = attr;
+       ndir->ctime_ms = 0;
+       hour = now->tm_hour << 3;
+       min_hi = now->tm_min >> 3;
+       min_low = now->tm_min << 5;
+       sec = now->tm_sec / 2;
+       ndir->ctime[1] = ndir->time[1] = hour + min_hi;
+       ndir->ctime[0] = ndir->time[0] = min_low + sec;
+       year = (now->tm_year - 80) << 1;
+       month_hi = (now->tm_mon + 1) >> 3;
+       month_low = (now->tm_mon + 1) << 5;
+       day = now->tm_mday;
+       ndir -> adate[1] = ndir->cdate[1] = ndir->date[1] = year + month_hi;
+       ndir -> adate[0] = ndir->cdate[0] = ndir->date[0] = month_low + day;
+
+       set_word(ndir->start, fat & 0xffff);
+       set_word(ndir->startHi, fat >> 16);
+       set_dword(ndir->size, size);
+       return ndir;
+}
+
+/*
+ * Make a directory entry from base name. This is supposed to be used
+ * from places such as mmd for making special entries (".", "..", "/", ...)
+ * Thus it doesn't bother with character set conversions
+ */
+struct directory *mk_entry_from_base(const char *base, char attr,
+                                    unsigned int fat, size_t size, time_t date,
+                                    struct directory *ndir)
+{
+       struct dos_name_t dn;
+       strncpy(dn.base, base, 8);
+       strncpy(dn.ext, "   ", 3);
+       return mk_entry(&dn, attr, fat, size, date, ndir);
+}
diff --git a/direntry.c b/direntry.c
new file mode 100644 (file)
index 0000000..07a1f0b
--- /dev/null
@@ -0,0 +1,139 @@
+/*  Copyright 1997,2000-2003,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+       entry->entry = -1;
+/*     entry->parent = getDirentry(Dir);*/
+       entry->Dir = Dir;
+       entry->beginSlot = 0;
+       entry->endSlot = 0;
+}
+
+int isNotFound(direntry_t *entry)
+{
+       return entry->entry == -2;
+}
+
+direntry_t *getParent(direntry_t *entry)
+{
+       return getDirentry(entry->Dir);
+}
+
+
+static int getPathLen(direntry_t *entry)
+{
+       int length=0;
+
+       while(1) {
+               if(entry->entry == -3) /* rootDir */
+                       return length + 3;
+               
+               length += 1 + wcslen(entry->name);
+               entry = getDirentry(entry->Dir);
+       }
+}
+
+static char *sprintPwd(direntry_t *entry, char *ptr)
+{
+       if(entry->entry == -3) {
+               *ptr++ = getDrive(entry->Dir);
+               *ptr++ = ':';
+               *ptr++ = '/';
+       } else {
+               ptr = sprintPwd(getDirentry(entry->Dir), ptr);
+               if(ptr[-1] != '/')
+                       *ptr++ = '/';
+               ptr += wchar_to_native(entry->name, ptr, MAX_VNAMELEN);
+       }
+       return ptr;             
+}
+
+
+#ifdef HAVE_WCHAR_H
+#define NEED_ESCAPE L"\"$\\"
+#else
+#define NEED_ESCAPE "\"$\\"
+#endif
+
+static void _fprintPwd(FILE *f, direntry_t *entry, int recurs, int escape)
+{
+       if(entry->entry == -3) {
+               putc(getDrive(entry->Dir), f);
+               putc(':', f);
+               if(!recurs)
+                       putc('/', f);
+       } else {
+               _fprintPwd(f, getDirentry(entry->Dir), 1, escape);
+               if (escape && wcspbrk(entry->name, NEED_ESCAPE)) {
+                       wchar_t *ptr;
+                       putc('/', f);
+                       for(ptr = entry->name; *ptr; ptr++) {
+                               if (wcschr(NEED_ESCAPE, *ptr))
+                                       putc('\\', f);
+                               putwc(*ptr, f);
+                       }
+               } else {
+                       char tmp[4*MAX_VNAMELEN+1];
+                       wchar_to_native(entry->name,tmp,MAX_VNAMELEN);
+                       fprintf(f, "/%s", tmp);
+               }
+       }
+}
+
+void fprintPwd(FILE *f, direntry_t *entry, int escape)
+{
+       if (escape)
+               putc('"', f);
+       _fprintPwd(f, entry, 0, escape);
+       if(escape)
+               putc('"', f);
+}
+
+char *getPwd(direntry_t *entry)
+{
+       int size;
+       char *ret;
+       char *end;
+
+       size = getPathLen(entry);
+       ret = malloc(size+1);
+       if(!ret)
+               return 0;
+       end = sprintPwd(entry, ret);
+       *end = '\0';
+       return ret;
+}
+
+int isSubdirOf(Stream_t *inside, Stream_t *outside)
+{
+       while(1) {
+               if(inside == outside) /* both are the same */
+                       return 1;
+               if(getDirentry(inside)->entry == -3) /* root directory */
+                       return 0;
+               /* look further up */
+               inside = getDirentry(inside)->Dir;
+       }                       
+}
diff --git a/expand.c b/expand.c
new file mode 100644 (file)
index 0000000..6b11f09
--- /dev/null
+++ b/expand.c
@@ -0,0 +1,108 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Do filename expansion with the shell.
+ */
+
+#define EXPAND_BUF     2048
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+#ifndef OS_mingw32msvc
+int safePopenOut(const char **command, char *output, int len)
+{
+       int pipefd[2];
+       pid_t pid;
+       int status;
+       int last;
+
+       if(pipe(pipefd)) {
+               return -2;
+       }
+       switch((pid=fork())){
+               case -1:
+                       return -2;
+               case 0: /* the son */
+                       close(pipefd[0]);
+                       destroy_privs();
+                       close(1);
+                       close(2); /* avoid nasty error messages on stderr */
+                       if(dup(pipefd[1]) < 0) {
+                               perror("Dup error");
+                               exit(1);
+                       }
+                       close(pipefd[1]);
+                       execvp(command[0], (char**)(command+1));
+                       exit(1);
+               default:
+                       close(pipefd[1]);
+                       break;
+       }
+       last=read(pipefd[0], output, len);
+       kill(pid,9);
+       wait(&status);
+       if(last<0) {
+               return -1;
+       }
+       return last;
+}
+#endif
+
+
+const char *expand(const char *input, char *ans)
+{
+#ifndef OS_mingw32msvc
+       int last;
+       char buf[256];
+       const char *command[] = { "/bin/sh", "sh", "-c", 0, 0 };
+
+       ans[EXPAND_BUF-1]='\0';
+
+       if (input == NULL)
+               return(NULL);
+       if (*input == '\0')
+               return("");
+                                       /* any thing to expand? */
+       if (!strpbrk(input, "$*(){}[]\\?`~")) {
+               strncpy(ans, input, EXPAND_BUF-1);
+               return(ans);
+       }
+                                       /* popen an echo */
+#ifdef HAVE_SNPRINTF
+       snprintf(buf, 255, "echo %s", input);
+#else
+       sprintf(buf, "echo %s", input);
+#endif
+
+       command[3]=buf;
+       last=safePopenOut(command, ans, EXPAND_BUF-1);
+       if(last<0) {
+               perror("Pipe read error");
+               exit(1);
+       }
+       if(last)
+               ans[last-1] = '\0';
+       else
+               strncpy(ans, input, EXPAND_BUF-1);
+       return ans;
+#else
+       strncpy(ans, input, EXPAND_BUF-1);
+       ans[EXPAND_BUF-1]='\0';
+       return ans;
+#endif
+}
diff --git a/fat.c b/fat.c
new file mode 100644 (file)
index 0000000..c9463f2
--- /dev/null
+++ b/fat.c
@@ -0,0 +1,1000 @@
+/*  Copyright 1996-2006,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 writeSector(Fs_t *This, char *buf, unsigned int off,
+                                 size_t size)
+{
+       return WRITES(This->Next, buf, sectorsToBytes((Stream_t*)This, off), 
+                                 size << This->sectorShift);
+}
+
+static __inline__ int forceWriteSector(Fs_t *This, char *buf, unsigned int off,
+                                      size_t size)
+{
+       return force_write(This->Next, buf, sectorsToBytes((Stream_t*)This, off), 
+                                          size << This->sectorShift);
+}
+
+
+static FatMap_t *GetFatMap(Fs_t *Stream)
+{
+       int nr_entries,i;
+       FatMap_t *map;
+
+       Stream->fat_error = 0;
+       nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
+       map = NewArray(nr_entries, FatMap_t);
+       if(!map)
+               return 0;
+
+       for(i=0; i< nr_entries; i++) {
+               map[i].data = 0;
+               map[i].valid = 0;
+               map[i].dirty = 0;
+       }
+
+       return map;
+}
+
+static __inline__ int locate(Fs_t *Stream, size_t offset, int *slot, int *bit)
+{
+       if(offset >= Stream->fat_len)
+               return -1;
+       *slot = offset / SECT_PER_ENTRY;
+       *bit = offset % SECT_PER_ENTRY;
+       return 0;
+}
+
+static __inline__ int fatReadSector(Fs_t *This, int sector, int slot, 
+                                   int bit, int dupe, fatBitMask bitmap)
+{
+       int fat_start, ret;
+       int nr_sectors;
+
+       dupe = (dupe + This->primaryFat) % This->num_fat;
+       fat_start = This->fat_start + This->fat_len * dupe;
+       
+       if(bitmap == 0) {
+           nr_sectors = SECT_PER_ENTRY - bit%SECT_PER_ENTRY;
+       } else {
+           nr_sectors = 1;
+       }
+
+       /* first, read as much as the buffer can give us */
+       ret = readSector(This,
+                        (char *)(This->FatMap[slot].data+(bit<<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;
+       int fat_start;
+
+       /*fprintf(stderr, "Fat write\n");*/
+
+       if (!This->fat_dirty)
+               return;
+
+       dups = This->num_fat;
+       if (This->fat_error)
+               dups = 1;
+
+
+       for(i=0; i<dups; i++){
+               j = 0;
+               fat_start = This->fat_start + i*This->fat_len;
+               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);
+               set_dword(infoSector->signature1, INFOSECT_SIGNATURE1);
+               memset(infoSector->filler1, 0, sizeof(infoSector->filler1));
+               memset(infoSector->filler2, 0, sizeof(infoSector->filler2));
+               set_dword(infoSector->signature2, INFOSECT_SIGNATURE2);
+               set_dword(infoSector->pos, This->last);
+               set_dword(infoSector->count, This->freeSpace);
+               set_dword(infoSector->signature3, 0xaa55);
+               if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) !=
+                  (signed int) This->sector_size)
+                       fprintf(stderr,"Trouble writing the info sector\n");
+               free(infoSector);
+       }
+       This->fat_dirty = 0;
+       This->lastFatAccessMode = FAT_ACCESS_READ;
+}
+
+
+
+/*
+ * Zero-Fat
+ * Used by mformat.
+ */
+int zero_fat(Fs_t *Stream, int media_descriptor)
+{
+       unsigned int i, j;
+       unsigned int fat_start;
+       unsigned char *buf;
+
+       buf = malloc(Stream->sector_size);
+       if(!buf) {
+               perror("alloc fat sector buffer");
+               return -1;
+       }
+       for(i=0; i< Stream->num_fat; i++) {
+               fat_start = Stream->fat_start + i*Stream->fat_len;
+               for(j = 0; j < Stream->fat_len; j++) {
+                       if(j <= 1)
+                               memset(buf, 0, Stream->sector_size);
+                       if(!j) {
+                               buf[0] = media_descriptor;
+                               buf[2] = buf[1] = 0xff;
+                               if(Stream->fat_bits > 12)
+                                       buf[3] = 0xff;
+                               if(Stream->fat_bits > 16) {
+                                       buf[4] = 0xff;
+                                       buf[5] = 0xff;
+                                       buf[6] = 0xff;
+                                       buf[7] = 0x0f;
+                               }
+                       }
+
+                       if(forceWriteSector(Stream, (char *)buf,
+                                           fat_start + j, 1) !=
+                          (signed int) Stream->sector_size) {
+                               fprintf(stderr,
+                                       "Trouble initializing a FAT sector\n");
+                               free(buf);
+                               return -1;
+                       }
+               }
+       }
+       
+       free(buf);
+       Stream->FatMap = GetFatMap(Stream);
+       if (Stream->FatMap == NULL) {
+               perror("alloc fat map");
+               return -1;
+       }
+       return 0;
+}
+
+
+void set_fat12(Fs_t *This)
+{
+       This->fat_bits = 12;
+       This->end_fat = 0xfff;
+       This->last_fat = 0xff6;
+       This->fat_decode = fat12_decode;
+       This->fat_encode = fat12_encode;
+}
+
+static char word_endian_test[] = { 0x34, 0x12 };
+
+void set_fat16(Fs_t *This)
+{
+       This->fat_bits = 16;
+       This->end_fat = 0xffff;
+       This->last_fat = 0xfff6;
+
+       if(sizeof(unsigned short) == 2 &&  
+          * (unsigned short *) word_endian_test == 0x1234) {
+               This->fat_decode = fast_fat16_decode;
+               This->fat_encode = fast_fat16_encode;
+       } else {
+               This->fat_decode = fat16_decode;
+               This->fat_encode = fat16_encode;
+       }
+}
+
+static char dword_endian_test[] = { 0x78, 0x56, 0x34, 0x12 };
+
+void set_fat32(Fs_t *This)
+{
+       This->fat_bits = 32;
+       This->end_fat = 0xfffffff;
+       This->last_fat = 0xffffff6;
+       
+       if(sizeof(unsigned int) == 4 &&  
+          * (unsigned int *) dword_endian_test == 0x12345678) {
+               This->fat_decode = fast_fat32_decode;
+               This->fat_encode = fast_fat32_encode;
+       } else {
+               This->fat_decode = fat32_decode;
+               This->fat_encode = fat32_encode;
+       }
+}
+
+
+static int check_fat(Fs_t *This)
+{
+       /* 
+        * This is only a sanity check.  For disks with really big FATs,
+        * there is no point in checking the whole FAT.
+        */
+
+       unsigned int i, f;
+       unsigned int tocheck;
+       if(mtools_skip_check)
+               return 0;
+
+       /* too few sectors in the FAT */
+       if(This->fat_len < NEEDED_FAT_SIZE(This))
+               return -1;
+       /* we do not warn about too much sectors in FAT, which may
+        * happen when a partition has been shrunk using FIPS, or on
+        * other occurrences */
+       
+       tocheck = This->num_clus;
+       if (tocheck + 1 >= This->last_fat) {
+               fprintf(stderr, "Too many clusters in FAT\n");
+               return -1;
+       }
+
+       if(tocheck > 4096)
+               tocheck = 4096;
+
+       for ( i= 3 ; i < tocheck; i++){
+               f = This->fat_decode(This,i);
+               if (f == 1 || (f < This->last_fat && f > This->num_clus)){
+                       fprintf(stderr,
+                               "Cluster # at %d too big(%#x)\n", i,f);
+                       fprintf(stderr,"Probably non MS-DOS disk\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+
+/*
+ * Read the first sector of FAT table into memory.  Crude error detection on
+ * wrong FAT encoding scheme.
+ */
+static int check_media_type(Fs_t *This, union bootsector *boot, 
+                           unsigned int tot_sectors)
+{
+       unsigned char *address;
+
+       This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size;
+
+       This->FatMap = GetFatMap(This);
+       if (This->FatMap == NULL) {
+               perror("alloc fat map");
+               return -1;
+       }
+
+       address = getAddress(This, 0, FAT_ACCESS_READ);
+       if(!address) {
+               fprintf(stderr,
+                       "Could not read first FAT sector\n");
+               return -1;
+       }
+
+       if(mtools_skip_check)
+               return 0;
+
+       if(!address[0] && !address[1] && !address[2])
+               /* Some Atari disks have zeroes where Dos has media descriptor
+                * and 0xff.  Do not consider this as an error */
+               return 0;
+       
+       if((address[0] != boot->boot.descr && boot->boot.descr >= 0xf0 &&
+           ((address[0] != 0xf9 && address[0] != 0xf7) 
+            || boot->boot.descr != 0xf0)) || address[0] < 0xf0) {
+               fprintf(stderr,
+                       "Bad media types %02x/%02x, probably non-MSDOS disk\n", 
+                               address[0],
+                               boot->boot.descr);
+               return -1;
+       }
+
+       if(address[1] != 0xff || address[2] != 0xff){
+               fprintf(stderr,"Initial byte of fat is not 0xff\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int fat_32_read(Fs_t *This, union bootsector *boot, 
+                      unsigned int tot_sectors)
+{
+       int size;
+
+       This->fat_len = DWORD(ext.fat32.bigFat);
+       This->writeAllFats = !(boot->boot.ext.fat32.extFlags[0] & 0x80);
+       This->primaryFat = boot->boot.ext.fat32.extFlags[0] & 0xf;
+       This->rootCluster = DWORD(ext.fat32.rootCluster);
+       This->clus_start = This->fat_start + This->num_fat * This->fat_len;
+
+       /* read the info sector */
+       size = This->sector_size;
+       This->infoSectorLoc = WORD(ext.fat32.infoSector);
+       if(This->sector_size >= 512 &&
+          This->infoSectorLoc && This->infoSectorLoc != MAX32) {
+               InfoSector_t *infoSector;
+               infoSector = (InfoSector_t *) safe_malloc(size);
+               if(forceReadSector(This, (char *)infoSector,
+                                  This->infoSectorLoc, 1) == 
+                  (signed int) This->sector_size &&
+                  _DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1 &&
+                  _DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2) {
+                       This->freeSpace = _DWORD(infoSector->count);
+                       This->last = _DWORD(infoSector->pos);
+               }
+               free(infoSector);
+       }
+       
+       set_fat32(This);
+       return(check_media_type(This, boot, tot_sectors) ||
+              check_fat(This));
+}
+
+
+static int old_fat_read(Fs_t *This, union bootsector *boot, 
+                                               int config_fat_bits,
+                                               size_t tot_sectors, int nodups)
+{
+       This->writeAllFats = 1;
+       This->primaryFat = 0;
+       This->dir_start = This->fat_start + This->num_fat * This->fat_len;
+       This->clus_start = This->dir_start + This->dir_len;
+       This->infoSectorLoc = MAX32;
+
+       if(nodups)
+               This->num_fat = 1;
+
+       if(check_media_type(This,boot, tot_sectors))
+               return -1;
+
+       if(This->num_clus >= FAT12) {
+               set_fat16(This);
+               /* third FAT byte must be 0xff */
+               if(!mtools_skip_check && readByte(This, 3) != 0xff)
+                       return -1;
+       } else
+               set_fat12(This);
+
+       return check_fat(This);
+}
+
+/*
+ * Read the first sector of the  FAT table into memory and initialize 
+ * structures.
+ */
+int fat_read(Fs_t *This, union bootsector *boot, int fat_bits,
+          size_t tot_sectors, int nodups)
+{
+       This->fat_error = 0;
+       This->fat_dirty = 0;
+       This->last = MAX32;
+       This->freeSpace = MAX32;
+       This->lastFatSectorNr = 0;
+       This->lastFatSectorData = 0;
+
+       if(This->fat_len)
+               return old_fat_read(This, boot, fat_bits, tot_sectors, nodups);
+       else
+               return fat_32_read(This, boot, tot_sectors);
+}
+
+
+unsigned int fatDecode(Fs_t *This, unsigned int pos)
+{
+       unsigned int ret;
+
+       ret = This->fat_decode(This, pos);
+       if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) {
+               fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos);
+               This->fat_error++;
+       }
+       return ret;
+}
+
+/* append a new cluster */
+void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos)
+{
+       This->fat_encode(This, pos, newpos);
+       This->fat_encode(This, newpos, This->end_fat);
+       if(This->freeSpace != MAX32)
+               This->freeSpace--;
+}
+
+/* de-allocates the given cluster */
+void fatDeallocate(Fs_t *This, unsigned int pos)
+{
+       This->fat_encode(This, pos, 0);
+       if(This->freeSpace != MAX32)
+               This->freeSpace++;
+}
+
+/* allocate a new cluster */
+void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value)
+{
+       This->fat_encode(This, pos, value);
+       if(This->freeSpace != MAX32)
+               This->freeSpace--;
+}
+
+void fatEncode(Fs_t *This, unsigned int pos, unsigned int value)
+{
+       unsigned int oldvalue = This->fat_decode(This, pos);
+       This->fat_encode(This, pos, value);
+       if(This->freeSpace != MAX32) {
+               if(oldvalue)
+                       This->freeSpace++;
+               if(value)
+                       This->freeSpace--;
+       }
+}
+
+unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
+{
+       unsigned int i;
+
+       if(This->last != MAX32)
+               last = This->last;
+
+       if (last < 2 ||
+           last >= This->num_clus+1)
+               last = 1;
+
+       for (i=last+1; i< This->num_clus+2; i++) {
+               unsigned int r = fatDecode(This, i);
+               if(r == 1)
+                       goto exit_0;
+               if (!r) {
+                       This->last = i;
+                       return i;
+               }
+       }
+
+       for(i=2; i < last+1; i++) {
+               unsigned int r = fatDecode(This, i);
+               if(r == 1)
+                       goto exit_0;
+               if (!r) {
+                       This->last = i;
+                       return i;
+               }
+       }
+
+
+       fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters,
+               This->last);
+       return 1;
+ exit_0:
+       fprintf(stderr, "FAT error\n");
+       return 1;
+}
+
+int fat_error(Stream_t *Dir)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+
+       if(This->fat_error)
+               fprintf(stderr,"Fat error detected\n");
+
+       return This->fat_error;
+}
+
+int fat32RootCluster(Stream_t *Dir)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+       
+       if(This->fat_bits == 32)
+               return This->rootCluster;
+       else
+               return 0;
+}
+
+
+/*
+ * Get the amount of free space on the diskette
+ */
+
+mt_size_t getfree(Stream_t *Dir)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+
+       if(This->freeSpace == MAX32 || This->freeSpace == 0) {
+               register unsigned int i;
+               size_t total;
+
+               total = 0L;
+               for (i = 2; i < This->num_clus + 2; i++) {
+                       unsigned int r = fatDecode(This,i);
+                       if(r == 1) {
+                               return -1;
+                       }
+                       if (!r)
+                               total++;
+               }
+               This->freeSpace = total;
+       }
+       return sectorsToBytes((Stream_t*)This, 
+                                                 This->freeSpace * This->cluster_size);
+}
+
+
+/*
+ * Ensure that there is a minimum of total sectors free
+ */
+int getfreeMinClusters(Stream_t *Dir, size_t size)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+       register unsigned int i, last;
+       size_t total;
+
+       if(batchmode && This->freeSpace == MAX32)
+               getfree(Stream);
+
+       if(This->freeSpace != MAX32) {
+               if(This->freeSpace >= size)
+                       return 1;
+               else {
+                       fprintf(stderr, "Disk full\n");
+                       got_signal = 1;
+                       return 0;
+               }
+       }
+
+       total = 0L;
+
+       /* we start at the same place where we'll start later to actually
+        * allocate the sectors.  That way, the same sectors of the FAT, which
+        * are already loaded during getfreeMin will be able to be reused 
+        * during get_next_free_cluster */
+       last = This->last;
+       
+       if ( last < 2 || last >= This->num_clus + 2)
+               last = 1;
+       for (i=last+1; i< This->num_clus+2; i++){
+               unsigned int r = fatDecode(This, i);
+               if(r == 1) {
+                       goto exit_0;
+               }
+               if (!r)
+                       total++;
+               if(total >= size)
+                       return 1;                               
+       }
+       for(i=2; i < last+1; i++){
+               unsigned int r = fatDecode(This, i);            
+               if(r == 1) {
+                       goto exit_0;
+               }
+               if (!r)
+                       total++;
+               if(total >= size)
+                       return 1;
+       }
+       fprintf(stderr, "Disk full\n");
+       got_signal = 1;
+       return 0;
+ exit_0:
+       fprintf(stderr, "FAT error\n");
+       return 0;
+}
+
+
+int getfreeMinBytes(Stream_t *Dir, mt_size_t size)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+       size_t size2;
+
+       size2 = size  / (This->sector_size * This->cluster_size);
+       if(size % (This->sector_size * This->cluster_size))
+               size2++;
+       return getfreeMinClusters(Dir, size2);
+}
+
+
+unsigned int getStart(Stream_t *Dir, struct directory *dir)
+{
+       Stream_t *Stream = GetFs(Dir);
+       unsigned int first;
+
+       first = START(dir);
+       if(fat32RootCluster(Stream))
+               first |= STARTHI(dir) << 16;
+       return first;
+}
+
+int fs_free(Stream_t *Stream)
+{
+       DeclareThis(Fs_t);
+
+       if(This->FatMap) {
+               int i, nr_entries;
+               nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) / 
+                       SECT_PER_ENTRY;
+               for(i=0; i< nr_entries; i++)
+                       if(This->FatMap[i].data)
+                               free(This->FatMap[i].data);             
+               free(This->FatMap);
+       }
+       if(This->cp)
+               cp_close(This->cp);
+       return 0;
+}
diff --git a/fat_free.c b/fat_free.c
new file mode 100644 (file)
index 0000000..6d49018
--- /dev/null
@@ -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 (file)
index 0000000..55b6884
--- /dev/null
@@ -0,0 +1,227 @@
+%  Copyright 2003,2005,2007 Alain Knaff.
+
+% This documentation is for Mtools which is a collection of tools to
+% allow Unix systems to manipulate MS-DOS files.
+
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.3 or
+% any later version published by the Free Software Foundation; with no
+% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+%Texts.  A copy of the license is included in the section entitled
+% ``GNU Free Documentation License''.
+
+\documentclass[a4paper,12pt]{article}
+
+\usepackage[T1]{fontenc}
+\usepackage[latin1]{inputenc}
+\usepackage{pslatex}
+\usepackage[pdfpagemode=None,colorlinks]{hyperref}
+
+\author{Alain Knaff}
+\title{How mformat-3.9.10 and above calculates needed FAT size}
+
+\begin{document}
+
+\maketitle
+
+This small document explains the formula used by {\tt mformat.c} to
+figure out fat size and number of clusters. Due to the way that
+filesystem parameters are stored in the boot sector, we can afford to
+have a FAT that is larger than need to be to accomodate the clusters
+present on disk, but under no circumstances can we have one that is
+too small.
+
+In this discussion, we use the following variable names:
+
+\begin{tabular}{|r|p{12cm}|}
+
+\hline
+
+$fatNybls$&
+Number of nubbles (4 bit unit per FAT). This is 3 for FAT12, 4 for
+FAT16, and 8 for FAT16\\
+
+\hline
+
+$numClus$&
+Number of clusters on the disk\\
+
+\hline
+
+$clusSiz$&
+Size of a cluster, expressed in sectors\\
+
+\hline
+
+$secSiz$&
+Size of a sector, in bytes. Size of a sector in nybbles is $secSiz$ * 2\\
+
+\hline
+
+$nfats$&
+Number of FAT copies, usually two\\
+
+\hline
+
+$remSects$&
+``Remaining sectors'', after number of boot sectors and root directory
+have been accounted for\\
+
+\hline
+
+$fatLen$&
+Length of the FAT, in sectors\\
+
+\hline
+
+
+\end{tabular}
+
+
+Taking into account both data and fat, each cluster takes up the
+following number of nybbles (units of 4 bytes):
+
+
+$$clusSiz * (2*secSiz)  + nfats * fatNybls$$
+       
+This accounts for the data of the cluster ($clusSiz * secSiz$),
+as well as for the space taken up by its descriptor.
+
+The space taken up by all clusters together, plus the space taken by
+descriptors for clusters 0 and 1 ($2*nfats*fatNybls$) should be less
+than what is available.
+
+Additional sectors may be lost due to slack (you have to use a full
+FAT sector, you also have to use a full cluster in the data
+area). Thus, an {\em upper bound} for the number of clusters is as
+follows:
+
+$$
+numClus \le  {2*remSect*secSiz - 2*nfats*fatNybls \over
+2*clusSiz*secSiz + nfats*fatNybls}
+$$
+
+                               
+$$
+numClus \le {(remSect+2*clusSiz)*2*secSiz \over
+2*clusSiz*secSiz + nfats*fatNybls} - 2
+$$
+
+          
+These will take up at most the following space in one copy of the FAT
+(we have to round up, because even a half-full fat sector must be
+taken in its entirety)
+
+$$
+fatLen \le \left\lceil {  (numClus+2)*fatNybls \over secSiz * 2 } \right\rceil
+$$
+
+
+$$
+fatLen \le \left\lceil {
+\left( { 2*(remSect+2*clusSiz)*secSiz \over
+2*clusSiz*secSiz + nfats*fatNybls} \right) * fatNybls \over
+2*secSiz 
+} \right\rceil
+$$
+
+
+$$
+fatLen \le \left\lceil {
+(remSect+2*clusSiz)* fatNybls \over
+2*clusSiz*secSiz + nfats*fatNybls
+} \right\rceil
+$$
+
+The space left after FAT sector has been deduced is now {\em less than
+or equal} to what would be needed for the data area of the clusters
+(including fractional clusters), which is good, as we may have under
+no circumstances {\em more} clusters in the data area than in the FAT.
+An important point in this calculation is that we based the needed FAT
+size on a {\em fractional} number of clusters, rather than a rounded
+down amount of clusters. Indeed, using a rounded down number could
+have exposed us to a situation where we had an {\em almost enough}
+space for one more cluster (i.e. not enough space for data + FAT, but
+enough for data alone). This situation, combined with a situation
+where the last FAT sector was flush full could have lead to a
+situation where $numClus$ would become too large for the FAT to
+accomodate. I think this is clearer with an example:
+\begin{itemize}
+\item $remSect=4127$, $clusSiz=1$, $nfats=1$
+\item (Non rounded down) $numClus={(4127+2)*(1024) \over 1032} -
+2 =4094.992$
+\item Rounded down: 4094 clusters
+\item These fit into 16 FAT sectors, exactly
+\item ... leaving us 4095 clusters, which is one to many (because
+these 4095 clusters would now need 17 FAT clusters)
+\end{itemize}
+
+Keeping the fractional part (0.992) allows us to round {\em up} the
+needed number of FAT sectors to 17, nicely solving this problem.
+
+The downside of counting the fractional part however is that we quite
+often waste a sector in the really common situation where both $nfats$
+and $clusSiz$ are even, while $remSect$ is odd. An easy way to address
+this is to substract one from $remSect$ before application of the
+formula, if this case is detected. Such operation carries no risk, as
+the odd final sector cannot be used to make a full cluster.
+
+There is still a case however, where fatLen must be grown manually
+after application of the formula: If numClus exceeds the maximum
+number of clusters allowable for FAT12 or FAT16), we need to shrink
+$numClus$ after application of the formula, and manually make the FAT
+larger in order to take up any excess space.
+
+Also note that as we used upper bounds, we may waste a certain number
+of sectors, which an exact calculation may not have wasted. However,
+normally, we should not lose more than one sector per FAT copy.
+
+N.B. In its document at \url{http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf},
+Microsoft proposes a much simpler formula. However, this formula is
+both wrong (i.e. occasionally it produces a smaller FAT than is
+needed for the clusters on disk), less generic (only works for sector
+sizes equal to 512), and less efficient (in case of FAT32, it may
+waste up to 8 sectors!)
+
+The formula is the following (for FAT16):
+$$
+fatLen \le \left\lceil { remSect \over 256 * clusSiz + nfats} \right\rceil
+$$
+
+Note that it doesn't account for the dummy clusters 0 and 1. Thus, if
+we have 258 sectors remaining, with a cluster size of 1, and two FAT
+copies, the Microsoft formula mistakenly assumes fatLen = 1. This
+leaves 258 - 2 = 256 sectors for clusters, which yields 256 clusters.
+However, those clusters do not fit into the FAT, as two clusters are
+lost (0 and 1). However, to Micro\$ofts' credit, this is not actually
+the formula they're using (tested with $remsect=160056$ and
+$clusSize=4$), so this seems to be a documentation issue rather than a
+genuine bug.
+
+In case of FAT32, Microsoft just halves the denominator. This is
+wasteful, as only the $256*clusSiz$ part would need to be halved.
+
+If we assume 16777000, and a cluster size of 8, our formula would give
+us:
+$$fatLen = \left\lceil (16777000 + 16) * 8 \over 2 * 8 * 512 + 16
+\right\rceil = 16352$$
+This would leave $16777000-2*16352=16744296$ sectors for the clusters,
+i.e. 2093037 clusters. The FAT descriptors for those 2093037 clusters
+do indeed fit into our 16352 fat sectors.
+
+Microsoft, on the other hand, would get: $$fatLen = \left\lceil{
+16777000 \over (256 * 8 + 2)/2} \right\rceil = 16368$$ This would only
+leave $16777000-2*16368=16744264$, i.e. 2093033 clusters, thus wasting
+4 clusters. The FAT would be 28 sectors too big, i.e. more than the
+mere 8 sectors announced by Microsoft! Unfortunately, I currently
+don't have access to any sufficiently recent Windows to check out
+whether this really happens in the code, or whether it is only a
+documentation issue as well.
+
+Oh, and before somebody points it out: the formula in this document
+occassionnally wastes sectors too, although not as much (Example: With
+$remsect=685$, $clusSiz=1$ and $nfats=2$ our formula gives $fatLen=3$,
+which leaves 679 clusters. However, we could use $fatLen=2$, leaving
+681 clusters,
+
+\end{document}
diff --git a/file.c b/file.c
new file mode 100644 (file)
index 0000000..cba4c89
--- /dev/null
+++ b/file.c
@@ -0,0 +1,694 @@
+/*  Copyright 1996-1999,2001-2003,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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;
+       int hint;
+       struct dirCache_t *dcp;
+
+       unsigned int loopDetectRel;
+       unsigned int loopDetectAbs;
+} File_t;
+
+static Class_t FileClass;
+T_HashTable *filehash;
+
+static File_t *getUnbufferedFile(Stream_t *Stream)
+{
+       while(Stream->Class != &FileClass)
+               Stream = Stream->Next;
+       return (File_t *) Stream;
+}
+
+Fs_t *getFs(Stream_t *Stream)
+{
+       return getUnbufferedFile(Stream)->Fs;
+}
+
+struct dirCache_t **getDirCacheP(Stream_t *Stream)
+{
+       return &getUnbufferedFile(Stream)->dcp;
+}
+
+direntry_t *getDirentry(Stream_t *Stream)
+{
+       return &getUnbufferedFile(Stream)->direntry;
+}
+
+
+static int recalcPreallocSize(File_t *This)
+{
+       size_t currentClusters, neededClusters;
+       int clus_size;
+       int neededPrealloc;
+       Fs_t *Fs = This->Fs;
+       int r;
+
+#if 0
+       if(This->FileSize & 0xc0000000) {
+               fprintf(stderr, "Bad filesize\n");
+       }
+       if(This->preallocatedSize & 0xc0000000) {
+               fprintf(stderr, "Bad preallocated size %x\n",
+                               (int) This->preallocatedSize);
+       }
+#endif
+       clus_size = Fs->cluster_size * Fs->sector_size;
+
+       currentClusters = (This->FileSize + clus_size - 1) / clus_size;
+       neededClusters = (This->preallocatedSize + clus_size - 1) / clus_size;
+       neededPrealloc = neededClusters - currentClusters;
+       if(neededPrealloc < 0)
+               neededPrealloc = 0;
+       r = fsPreallocateClusters(Fs, neededPrealloc - This->preallocatedClusters);
+       if(r)
+               return r;
+       This->preallocatedClusters = neededPrealloc;
+       return 0;
+}
+
+static int _loopDetect(unsigned int *oldrel, unsigned int rel,
+                      unsigned int *oldabs, unsigned int absol)
+{
+       if(*oldrel && rel > *oldrel && absol == *oldabs) {
+               fprintf(stderr, "loop detected! oldrel=%d newrel=%d abs=%d\n",
+                               *oldrel, rel, absol);
+               return -1;
+       }
+
+       if(rel >= 2 * *oldrel + 1) {
+               *oldrel = rel;
+               *oldabs = absol;
+       }
+       return 0;
+}
+
+
+static int loopDetect(File_t *This, unsigned int rel, unsigned int absol)
+{
+       return _loopDetect(&This->loopDetectRel, rel, &This->loopDetectAbs, absol);
+}
+
+static unsigned int _countBlocks(Fs_t *This, unsigned int block)
+{
+       unsigned int blocks;
+       unsigned int rel, oldabs, oldrel;
+
+       blocks = 0;
+       
+       oldabs = oldrel = rel = 0;
+
+       while (block <= This->last_fat && block != 1 && block) {
+               blocks++;
+               block = fatDecode(This, block);
+               rel++;
+               if(_loopDetect(&oldrel, rel, &oldabs, block) < 0)
+                       block = -1;
+       }
+       return blocks;
+}
+
+unsigned int countBlocks(Stream_t *Dir, unsigned int block)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+
+       return _countBlocks(This, block);
+}
+
+/* returns number of bytes in a directory.  Represents a file size, and
+ * can hence be not bigger than 2^32
+ */
+static size_t countBytes(Stream_t *Dir, unsigned int block)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+
+       return _countBlocks(This, block) *
+               This->sector_size * This->cluster_size;
+}
+
+void printFat(Stream_t *Stream)
+{
+       File_t *This = getUnbufferedFile(Stream);
+       unsigned long n;
+       int rel;
+       unsigned long begin, end;
+       int first;
+
+       n = This->FirstAbsCluNr;
+       if(!n) {
+               printf("Root directory or empty file\n");
+               return;
+       }
+
+       rel = 0;
+       first = 1;
+       begin = end = 0;
+       do {
+               if (first || n != end+1) {
+                       if (!first) {
+                               if (begin != end)
+                                       printf("-%lu", end);
+                               printf("> ");
+                       }
+                       begin = end = n;
+                       printf("<%lu", begin);
+               } else {
+                       end++;
+               }
+               first = 0;
+               n = fatDecode(This->Fs, n);
+               rel++;
+               if(loopDetect(This, rel, n) < 0)
+                       n = 1;
+       } while (n <= This->Fs->last_fat && n != 1);
+       if(!first) {
+               if (begin != end)
+                       printf("-%lu", end);
+               printf(">");
+       }
+}
+
+static int normal_map(File_t *This, off_t where, size_t *len, int mode,
+                                                  mt_off_t *res)
+{
+       int offset;
+       size_t end;
+       int NrClu; /* number of clusters to read */
+       unsigned int RelCluNr;
+       unsigned int CurCluNr;
+       unsigned int NewCluNr;
+       unsigned int AbsCluNr;
+       int clus_size;
+       Fs_t *Fs = This->Fs;
+
+       *res = 0;
+       clus_size = Fs->cluster_size * Fs->sector_size;
+       offset = where % clus_size;
+
+       if (mode == MT_READ)
+               maximize(*len, This->FileSize - where);
+       if (*len == 0 )
+               return 0;
+
+       if (This->FirstAbsCluNr < 2){
+               if( mode == MT_READ || *len == 0){
+                       *len = 0;
+                       return 0;
+               }
+               NewCluNr = get_next_free_cluster(This->Fs, 1);
+               if (NewCluNr == 1 ){
+                       errno = ENOSPC;
+                       return -2;
+               }
+               hash_remove(filehash, (void *) This, This->hint);
+               This->FirstAbsCluNr = NewCluNr;
+               hash_add(filehash, (void *) This, &This->hint);
+               fatAllocate(This->Fs, NewCluNr, Fs->end_fat);
+       }
+
+       RelCluNr = where / clus_size;
+       
+       if (RelCluNr >= This->PreviousRelCluNr){
+               CurCluNr = This->PreviousRelCluNr;
+               AbsCluNr = This->PreviousAbsCluNr;
+       } else {
+               CurCluNr = 0;
+               AbsCluNr = This->FirstAbsCluNr;
+       }
+
+
+       NrClu = (offset + *len - 1) / clus_size;
+       while (CurCluNr <= RelCluNr + NrClu){
+               if (CurCluNr == RelCluNr){
+                       /* we have reached the beginning of our zone. Save
+                        * coordinates */
+                       This->PreviousRelCluNr = RelCluNr;
+                       This->PreviousAbsCluNr = AbsCluNr;
+               }
+               NewCluNr = fatDecode(This->Fs, AbsCluNr);
+               if (NewCluNr == 1 || NewCluNr == 0){
+                       fprintf(stderr,"Fat problem while decoding %d %x\n",
+                               AbsCluNr, NewCluNr);
+                       exit(1);
+               }
+               if(CurCluNr == RelCluNr + NrClu)                        
+                       break;
+               if (NewCluNr > Fs->last_fat && mode == MT_WRITE){
+                       /* if at end, and writing, extend it */
+                       NewCluNr = get_next_free_cluster(This->Fs, AbsCluNr);
+                       if (NewCluNr == 1 ){ /* no more space */
+                               errno = ENOSPC;
+                               return -2;
+                       }
+                       fatAppend(This->Fs, AbsCluNr, NewCluNr);
+               }
+
+               if (CurCluNr < RelCluNr && NewCluNr > Fs->last_fat){
+                       *len = 0;
+                       return 0;
+               }
+
+               if (CurCluNr >= RelCluNr && NewCluNr != AbsCluNr + 1)
+                       break;
+               CurCluNr++;
+               AbsCluNr = NewCluNr;
+               if(loopDetect(This, CurCluNr, AbsCluNr)) {
+                       errno = EIO;
+                       return -2;
+               }
+       }
+
+       maximize(*len, (1 + CurCluNr - RelCluNr) * clus_size - offset);
+       
+       end = where + *len;
+       if(batchmode &&
+          mode == MT_WRITE &&
+          end >= This->FileSize) {
+               *len += ROUND_UP(end, clus_size) - end;
+       }
+
+       if((*len + offset) / clus_size + This->PreviousAbsCluNr-2 >
+               Fs->num_clus) {
+               fprintf(stderr, "cluster too big\n");
+               exit(1);
+       }
+
+       *res = sectorsToBytes((Stream_t*)Fs,
+                                                 (This->PreviousAbsCluNr-2) * Fs->cluster_size +
+                                                 Fs->clus_start) + offset;
+       return 1;
+}
+
+
+static int root_map(File_t *This, off_t where, size_t *len, int mode,
+                                       mt_off_t *res)
+{
+       Fs_t *Fs = This->Fs;
+
+       if(Fs->dir_len * Fs->sector_size < (size_t) where) {
+               *len = 0;
+               errno = ENOSPC;
+               return -2;
+       }
+
+       maximize(*len, Fs->dir_len * Fs->sector_size - where);
+        if (*len == 0)
+            return 0;
+       
+       *res = sectorsToBytes((Stream_t*)Fs, Fs->dir_start) + where;
+       return 1;
+}
+       
+
+static int read_file(Stream_t *Stream, char *buf, mt_off_t iwhere,
+                                        size_t len)
+{
+       DeclareThis(File_t);
+       mt_off_t pos;
+       int err;
+       off_t where = truncBytes32(iwhere);
+
+       Stream_t *Disk = This->Fs->Next;
+       
+       err = This->map(This, where, &len, MT_READ, &pos);
+       if(err <= 0)
+               return err;
+       return READS(Disk, buf, pos, len);
+}
+
+static int write_file(Stream_t *Stream, char *buf, mt_off_t iwhere, size_t len)
+{
+       DeclareThis(File_t);
+       mt_off_t pos;
+       int ret;
+       size_t requestedLen;
+       Stream_t *Disk = This->Fs->Next;
+       off_t where = truncBytes32(iwhere);
+       int err;
+
+       requestedLen = len;
+       err = This->map(This, where, &len, MT_WRITE, &pos);
+       if( err <= 0)
+               return err;
+       if(batchmode)
+               ret = force_write(Disk, buf, pos, len);
+       else
+               ret = WRITES(Disk, buf, pos, len);
+       if(ret > (signed int) requestedLen)
+               ret = requestedLen;
+       if (ret > 0 &&
+           where + ret > (off_t) This->FileSize )
+               This->FileSize = where + ret;
+       recalcPreallocSize(This);
+       return ret;
+}
+
+
+/*
+ * Convert an MSDOS time & date stamp to the Unix time() format
+ */
+
+static int month[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
+                                         0, 0, 0 };
+static __inline__ time_t conv_stamp(struct directory *dir)
+{
+       struct tm *tmbuf;
+       long tzone, dst;
+       time_t accum, tmp;
+
+       accum = DOS_YEAR(dir) - 1970; /* years past */
+
+       /* days passed */
+       accum = accum * 365L + month[DOS_MONTH(dir)-1] + DOS_DAY(dir);
+
+       /* leap years */
+       accum += (DOS_YEAR(dir) - 1972) / 4L;
+
+       /* back off 1 day if before 29 Feb */
+       if (!(DOS_YEAR(dir) % 4) && DOS_MONTH(dir) < 3)
+               accum--;
+       accum = accum * 24L + DOS_HOUR(dir); /* hours passed */
+       accum = accum * 60L + DOS_MINUTE(dir); /* minutes passed */
+       accum = accum * 60L + DOS_SEC(dir); /* seconds passed */
+
+       /* correct for Time Zone */
+#ifdef HAVE_GETTIMEOFDAY
+       {
+               struct timeval tv;
+               struct timezone tz;
+               
+               gettimeofday(&tv, &tz);
+               tzone = tz.tz_minuteswest * 60L;
+       }
+#else
+#if defined HAVE_TZSET && !defined OS_mingw32msvc
+       {
+#if !defined OS_ultrix && !defined OS_cygwin
+               /* Ultrix defines this to be a different type */
+               extern long timezone;
+#endif
+               tzset();
+               tzone = (long) timezone;
+       }
+#else
+       tzone = 0;
+#endif /* HAVE_TZSET */
+#endif /* HAVE_GETTIMEOFDAY */
+
+       accum += tzone;
+
+       /* correct for Daylight Saving Time */
+       tmp = accum;
+       tmbuf = localtime(&tmp);
+       dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
+       accum += dst;
+       
+       return accum;
+}
+
+
+static int get_file_data(Stream_t *Stream, time_t *date, mt_size_t *size,
+                        int *type, int *address)
+{
+       DeclareThis(File_t);
+
+       if(date)
+               *date = conv_stamp(& This->direntry.dir);
+       if(size)
+               *size = (mt_size_t) This->FileSize;
+       if(type)
+               *type = This->direntry.dir.attr & ATTR_DIR;
+       if(address)
+               *address = This->FirstAbsCluNr;
+       return 0;
+}
+
+
+static int free_file(Stream_t *Stream)
+{
+       DeclareThis(File_t);
+       Fs_t *Fs = This->Fs;
+       fsPreallocateClusters(Fs, -This->preallocatedClusters);
+       FREE(&This->direntry.Dir);
+       freeDirCache(Stream);
+       return hash_remove(filehash, (void *) Stream, This->hint);
+}
+
+
+static int flush_file(Stream_t *Stream)
+{
+       DeclareThis(File_t);
+       direntry_t *entry = &This->direntry;
+
+       if(isRootDir(Stream)) {
+               return 0;
+       }
+
+       if(This->FirstAbsCluNr != getStart(entry->Dir, &entry->dir)) {
+               set_word(entry->dir.start, This->FirstAbsCluNr & 0xffff);
+               set_word(entry->dir.startHi, This->FirstAbsCluNr >> 16);
+               dir_write(entry);
+       }
+       return 0;
+}
+
+
+static int pre_allocate_file(Stream_t *Stream, mt_size_t isize)
+{
+       DeclareThis(File_t);
+
+       size_t size = truncBytes32(isize);
+
+       if(size > This->FileSize &&
+          size > This->preallocatedSize) {
+               This->preallocatedSize = size;
+               return recalcPreallocSize(This);
+       } else
+               return 0;
+}
+
+static Class_t FileClass = {
+       read_file,
+       write_file,
+       flush_file, /* flush */
+       free_file, /* free */
+       0, /* get_geom */
+       get_file_data,
+       pre_allocate_file,
+       get_dosConvert_pass_through
+};
+
+static unsigned int getAbsCluNr(File_t *This)
+{
+       if(This->FirstAbsCluNr)
+               return This->FirstAbsCluNr;
+       if(isRootDir((Stream_t *) This))
+               return 0;
+       return 1;
+}
+
+static unsigned int func1(void *Stream)
+{
+       DeclareThis(File_t);
+
+       return getAbsCluNr(This) ^ (long) This->Fs;
+}
+
+static unsigned int func2(void *Stream)
+{
+       DeclareThis(File_t);
+
+       return getAbsCluNr(This);
+}
+
+static int comp(void *Stream, void *Stream2)
+{
+       DeclareThis(File_t);
+
+       File_t *This2 = (File_t *) Stream2;
+
+       return This->Fs != This2->Fs ||
+               getAbsCluNr(This) != getAbsCluNr(This2);
+}
+
+static void init_hash(void)
+{
+       static int is_initialised=0;
+       
+       if(!is_initialised){
+               make_ht(func1, func2, comp, 20, &filehash);
+               is_initialised = 1;
+       }
+}
+
+
+static Stream_t *_internalFileOpen(Stream_t *Dir, unsigned int first,
+                                  size_t size, direntry_t *entry)
+{
+       Stream_t *Stream = GetFs(Dir);
+       DeclareThis(Fs_t);
+       File_t Pattern;
+       File_t *File;
+
+       init_hash();
+       This->refs++;
+
+       if(first != 1){
+               /* we use the illegal cluster 1 to mark newly created files.
+                * do not manage those by hashtable */
+               Pattern.Fs = This;
+               Pattern.Class = &FileClass;
+               if(first || (entry && !IS_DIR(entry)))
+                       Pattern.map = normal_map;
+               else
+                       Pattern.map = root_map;
+               Pattern.FirstAbsCluNr = first;
+               Pattern.loopDetectRel = 0;
+               Pattern.loopDetectAbs = first;
+               if(!hash_lookup(filehash, (T_HashTableEl) &Pattern,
+                               (T_HashTableEl **)&File, 0)){
+                       File->refs++;
+                       This->refs--;
+                       return (Stream_t *) File;
+               }
+       }
+
+       File = New(File_t);
+       if (!File)
+               return NULL;
+       File->dcp = 0;
+       File->preallocatedClusters = 0;
+       File->preallocatedSize = 0;
+       /* memorize dir for date and attrib */
+       File->direntry = *entry;
+       if(entry->entry == -3)
+               File->direntry.Dir = (Stream_t *) File; /* root directory */
+       else
+               COPY(File->direntry.Dir);
+
+       File->Class = &FileClass;
+       File->Fs = This;
+       if(first || (entry && !IS_DIR(entry)))
+               File->map = normal_map;
+       else
+               File->map = root_map; /* FAT 12/16 root directory */
+       if(first == 1)
+               File->FirstAbsCluNr = 0;
+       else
+               File->FirstAbsCluNr = first;
+
+       File->loopDetectRel = 0;
+       File->loopDetectAbs = 0;
+
+       File->PreviousRelCluNr = 0xffff;
+       File->FileSize = size;
+       File->refs = 1;
+       File->Buffer = 0;
+       hash_add(filehash, (void *) File, &File->hint);
+       return (Stream_t *) File;
+}
+
+Stream_t *OpenRoot(Stream_t *Dir)
+{
+       unsigned int num;
+       direntry_t entry;
+       size_t size;
+       Stream_t *file;
+
+       memset(&entry, 0, sizeof(direntry_t));
+
+       num = fat32RootCluster(Dir);
+
+       /* make the directory entry */
+       entry.entry = -3;
+       entry.name[0] = '\0';
+       mk_entry_from_base("/", ATTR_DIR, num, 0, 0, &entry.dir);
+
+       if(num)
+               size = countBytes(Dir, num);
+       else {
+               Fs_t *Fs = (Fs_t *) GetFs(Dir);
+               size = Fs->dir_len * Fs->sector_size;
+       }
+       file = _internalFileOpen(Dir, num, size, &entry);
+       bufferize(&file);
+       return file;
+}
+
+
+Stream_t *OpenFileByDirentry(direntry_t *entry)
+{
+       Stream_t *file;
+       unsigned int first;
+       size_t size;
+
+       first = getStart(entry->Dir, &entry->dir);
+
+       if(!first && IS_DIR(entry))
+               return OpenRoot(entry->Dir);
+       if (IS_DIR(entry))
+               size = countBytes(entry->Dir, first);
+       else
+               size = FILE_SIZE(&entry->dir);
+       file = _internalFileOpen(entry->Dir, first, size, entry);
+       if(IS_DIR(entry)) {
+               bufferize(&file);
+               if(first == 1)
+                       dir_grow(file, 0);
+       }
+
+       return file;
+}
+
+
+int isRootDir(Stream_t *Stream)
+{
+       File_t *This = getUnbufferedFile(Stream);
+
+       return This->map == root_map;
+}
diff --git a/file.h b/file.h
new file mode 100644 (file)
index 0000000..a2e0244
--- /dev/null
+++ b/file.h
@@ -0,0 +1,27 @@
+#ifndef MTOOLS_FILE_H
+#define MTOOLS_FILE_H
+/*  Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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);
+direntry_t *getDirentry(Stream_t *Stream);
+#endif
diff --git a/file_name.c b/file_name.c
new file mode 100644 (file)
index 0000000..e38bbe3
--- /dev/null
@@ -0,0 +1,229 @@
+/*  Copyright 1995 David C. Niemi
+ *  Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+       char buffer[13];
+       wchar_t wbuffer[13];
+       char *a;
+       int j;
+       
+       for (a=buffer,j=0; (j<8) && (dn->base[j] > ' '); ++j,++a)
+               *a = dn->base[j];
+       if(dn->ext[0] > ' ') {
+               *a++ = '.';
+               for (j=0; j<3 && dn->ext[j] > ' '; ++j,++a)
+                       *a = dn->ext[j];
+       }
+       *a++ = '\0';
+       dos_to_wchar(cp, buffer, wbuffer, 13);
+       wchar_to_native(wbuffer, ans, 13);
+       return ans;
+}
+
+typedef enum Case_l {
+       NONE,
+       UPPER,
+       LOWER
+} Case_t;
+
+static void TranslateToDos(doscp_t *toDos, const char *in, char *out, int count,
+                          char *end, Case_t *Case, int *mangled)
+{
+       wchar_t buffer[12];
+       wchar_t *s=buffer;
+       wchar_t *t=buffer;
+
+       /* first convert to wchar, so we get to use towupper etc. */
+       native_to_wchar(in, buffer, count, end, mangled);
+       buffer[count]='\0';
+
+       *Case = NONE;
+       for( ;  *s ; s++) {
+               if(!count) {
+                       *mangled |= 3;
+                       break;
+               }
+               /* skip spaces & dots */
+               if(*s == ' ' || *s == '.') {
+                       *mangled |= 3;
+                       continue;
+               }
+
+               if (iswcntrl(*s)) {
+                       /* "control" characters */
+                       *mangled |= 3;
+                       *t = '_';
+               } else if (iswlower(*s)) {
+                       *t = towupper(*s);
+                       if(*Case == UPPER && !mtools_no_vfat)
+                               *mangled |= 1;
+                       else
+                               *Case = LOWER;
+               } else if (iswupper(*s)) {
+                       *t = *s;
+                       if(*Case == LOWER && !mtools_no_vfat)
+                               *mangled |= 1;
+                       else
+                               *Case = UPPER;
+               } else
+                       *t = *s;
+               count--;
+               t++;
+       }
+       wchar_to_dos(toDos, buffer, out, t - buffer, mangled);
+}
+
+/* dos_name
+ *
+ * Convert a Unix-style filename to a legal MSDOS name and extension.
+ * Will truncate file and extension names, will substitute
+ * the character '~' for any illegal character(s) in the name.
+ */
+void dos_name(doscp_t *toDos, const char *name, int verbose, int *mangled,
+             dos_name_t *dn)
+{
+       char *s, *ext;
+       register int i;
+       Case_t BaseCase, ExtCase;
+
+       *mangled = 0;
+
+       /* skip drive letter */
+       if (name[0] && name[1] == ':')
+               name = &name[2];
+
+       /* zap the leading path */
+       name = (char *) _basename(name);
+       if ((s = strrchr(name, '\\')))
+               name = s + 1;
+       
+       memset(dn, ' ', 11);
+
+       /* skip leading dots and spaces */
+       i = strspn(name, ". ");
+       if(i) {
+               name += i;
+               *mangled = 3;
+       }
+
+       ext = strrchr(name, '.');
+
+       /* main name */
+       TranslateToDos(toDos, name, dn->base, 8, ext, &BaseCase, mangled);
+       if(ext)
+               TranslateToDos(toDos, ext+1, dn->ext, 3, 0, &ExtCase,  mangled);
+
+       if(*mangled & 2)
+               autorename_short(dn, 0);
+
+       if(!*mangled) {
+               if(BaseCase == LOWER)
+                       *mangled |= BASECASE;
+               if(ExtCase == LOWER)
+                       *mangled |= EXTCASE;
+               if((BaseCase == LOWER || ExtCase == LOWER) &&
+                  !mtools_no_vfat) {
+                       *mangled |= 1;
+               }
+       }
+}
+
+
+/*
+ * Get rid of spaces in an MSDOS 'raw' name (one that has come from the
+ * directory structure) so that it can be used for regular expression
+ * matching with a Unix filename.  Also used to 'unfix' a name that has
+ * been altered by dos_name().
+ */
+
+wchar_t *unix_name(doscp_t *dosCp,
+                  const char *base, const char *ext, char Case, wchar_t *ret)
+{
+       char *s, tname[9], text[4], ans[13];
+       int i;
+
+       strncpy(tname, base, 8);
+       tname[8] = '\0';
+       if ((s = strchr(tname, ' ')))
+               *s = '\0';
+
+       if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case)
+               Case |= BASECASE | EXTCASE;
+
+       if(Case & BASECASE)
+               for(i=0;i<8 && tname[i];i++)
+                       tname[i] = tolower(tname[i]);
+
+       strncpy(text, ext, 3);
+       text[3] = '\0';
+       if ((s = strchr(text, ' ')))
+               *s = '\0';
+
+       if(Case & EXTCASE)
+               for(i=0;i<3 && text[i];i++)
+                       text[i] = tolower(text[i]);
+
+       if (*text) {
+               strcpy(ans, tname);
+               strcat(ans, ".");
+               strcat(ans, text);
+       } else
+               strcpy(ans, tname);
+
+       /* fix special characters (above 0x80) */
+       dos_to_wchar(dosCp, ans, ret, 12);
+       return ret;
+}
+
+/* If null encountered, set *end to 0x40 and write nulls rest of way
+ * 950820: Win95 does not like this!  It complains about bad characters.
+ * So, instead: If null encountered, set *end to 0x40, write the null, and
+ * write 0xff the rest of the way (that is what Win95 seems to do; hopefully
+ * that will make it happy)
+ */
+/* Always return num */
+int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p)
+{
+       int j;
+
+       for (j=0; j<num; ++j) {
+               if (*end_p)
+                       /* Fill with 0xff */
+                       out->uchar = out->lchar = (char) 0xff;
+               else {
+                       out->uchar = *in >> 8;
+                       out->lchar = *in;
+                       if (! *in) {
+                               *end_p = VSE_LAST;
+                       }
+               }
+
+               ++out;
+               ++in;
+       }
+       return num;
+}
diff --git a/file_name.h b/file_name.h
new file mode 100644 (file)
index 0000000..0d9ac90
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef FILE_NAME_H
+#define FILE_NAME_H
+
+/*  Copyright 2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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];
+  char ext[3];
+  char sentinel;
+};
+
+int dos_to_wchar(doscp_t *fromDos, char *dos, wchar_t *wchar, size_t len);
+void wchar_to_dos(doscp_t *toDos, wchar_t *wchar, char *dos, size_t len, int *mangled);
+
+doscp_t *cp_open(int codepage);
+void cp_close(doscp_t *cp);
+
+int wchar_to_native(const wchar_t *wchar, char *native, size_t len);
+int native_to_wchar(const char *native, wchar_t *wchar, size_t len,
+                   const char *end, int *mangled);
+
+#endif
diff --git a/file_read.c b/file_read.c
new file mode 100644 (file)
index 0000000..60e336f
--- /dev/null
@@ -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 (file)
index 0000000..6a78217
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,173 @@
+/*  Copyright 1996,1997,1999,2001-2003,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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
+};
+
+Stream_t *open_filter(Stream_t *Next, int convertCharset)
+{
+       Filter_t *This;
+
+       This = New(Filter_t);
+       if (!This)
+               return NULL;
+       This->Class = &FilterClass;
+       This->dospos = This->unixpos = This->rw = 0;
+       This->Next = Next;
+       This->refs = 1;
+       This->Buffer = 0;
+       /*
+         This->convertCharset = convertCharset;
+       */
+
+       return (Stream_t *) This;
+}
diff --git a/floppyd.1 b/floppyd.1
new file mode 100644 (file)
index 0000000..7f03d14
--- /dev/null
+++ b/floppyd.1
@@ -0,0 +1,258 @@
+.TH floppyd 1 "03Nov09" mtools-4.0.12
+.SH Name
+floppyd - floppy daemon for remote access to floppy drive
+floppyd_installtest - tests whether floppyd is installed and running
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p floppyd"
+.iX "c X terminal"
+.iX "c remote floppy access"
+.PP
+\&\fR\&\f(CWFloppyd\fR is used as a server to grant access to the floppy drive
+to clients running on a remote machine, just as an X server grants
+access to the display to remote clients.  It has the following syntax:
+.PP
+\&\fR\&\f(CWfloppyd\fR [\fR\&\f(CW-d\fR] [\fR\&\f(CW-l\fR] [\fR\&\f(CW-s\fR \fIport\fR] [\fR\&\f(CW-r\fR
+\&\fIuser\fR] [\fR\&\f(CW-b\fR \fIipaddr\fR] [\fR\&\f(CW-x\fR \fIdisplay\fR] \fIdevicenames\fR
+.PP
+\&\fR\&\f(CWfloppyd\fR is always associated with an X server.  It runs on the
+same machine as its X server, and listens on port 5703 and above.
+.PP
+.SH Authentication
+.PP
+\&\fR\&\f(CWfloppyd\fR authenticates remote clients using the \fR\&\f(CWXauthority\fR
+protocol. Xhost authentication is not supported. Each floppyd is
+associated with an X server.  When a remote client attempts to connect
+to floppyd, it sends floppyd the X authority record corresponding to
+floppyd's X server.  Floppyd in turn then tries to open up a connection
+to the X server in order to verify the authenticity of the xauth record.
+If the connection to the X server succeeds, the client is granted
+access.
+\&\fR\&\f(CWDISPLAY\fR.
+.PP
+\&\fBCaution\fR: In order to make authentication work correctly, the
+local host should \fBnot\fR be listed in the \fR\&\f(CWxhost\fR list of
+allowed hosts.
+ Indeed, hosts listed in \fR\&\f(CWxhost\fR do not need a correct
+\&\fR\&\f(CWXauthority\fR cookie to connect to the X server. As \fR\&\f(CWfloppyd\fR
+runs on the same host as the X server, all its probe connection would
+succeed even for clients who supplied a bad cookie.  This means that
+your floppy drive would be open to the world, i.e. a huge security hole.
+ If your X server does not allow you to remove \fR\&\f(CWlocalhost:0\fR and
+\&\fR\&\f(CW:0\fR from the \fR\&\f(CWxhost\fR list, you can prevent floppyd from
+probing those display names with the \fR\&\f(CW-l\fR option.
+.PP
+.SH Command\ line\ options
+.TP
+\&\fR\&\f(CWd\fR\ 
+Daemon mode. Floppyd runs its own server loop.  Do not supply this if
+you start floppyd from \fR\&\f(CWinetd.conf\fR
+.TP
+\&\fR\&\f(CWs\ \ \fIport\fR\&\f(CW\fR\ 
+Port number for deamon mode.  Default is 5703 + \fIdisplaynumber\fR.
+This flag implies daemon mode.  For example, for display
+\&\fR\&\f(CWhitchhiker:5\fR, the port would be 5708.
+.TP
+\&\fR\&\f(CWb\ \ \fIipaddr\fR\&\f(CW\fR\ 
+Bind address (for multihomed hosts). This flag implies daemon mode
+.TP
+\&\fR\&\f(CWr\ \fIuser\fR\&\f(CW\fR\ 
+Run the server under as the given user
+.TP
+\&\fR\&\f(CWx\ \fIdisplay\fR\&\f(CW\fR\ 
+X display to use for authentication. By default, this is taken from the
+\&\fR\&\f(CWDISPLAY\fR variable. If neither the \fR\&\f(CWx\fR attribute is present
+nor \fR\&\f(CWDISPLAY\fR is set, floppyd uses \fR\&\f(CW:0.0\fR.
+.PP
+\&\fIdevicenames\fR is a list of device nodes to be opened.  Default
+is \fR\&\f(CW/dev/fd0\fR. Multiple devices are only supported on mtools
+versions newer than 3.9.11.
+.PP
+.SH Connecting\ to\ floppyd
+.PP
+ In order to use floppyd, add the flag \fR\&\f(CWremote\fR to the device
+description in your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR file.  If the flag \fR\&\f(CWremote\fR
+is given, the \fR\&\f(CWfile\fR parameter of the device description is taken
+to be a remote address.  It's format is the following:
+\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR[\fIbaseport\fR][\fR\&\f(CW/\fR\fIdrive\fR]]. When
+using this entry, mtools connects to port
+\&\fIbaseport\fR+\fIdisplaynumber\fR at \fIhostname\fR. By default
+\&\fIbaseport\fR is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+.PP
+.SH Examples:
+.PP
+ The following starts a floppy daemon giving access to \fR\&\f(CW\(if/dev/fd0\(is\fR,
+listening on the default port 5703, tied to the default X servers:
+.PP
+.nf
+.ft 3
+.in +0.3i
+floppyd -d /dev/fd0
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+ Each of the following starts a floppy daemon giving access to
+\&\fR\&\f(CW\(if/dev/fd1\(is\fR, tied to the :1 local X servers, and listening on port
+5704. We assume that the local host is named \fR\&\f(CWhitchhiker\fR.
+.PP
+.nf
+.ft 3
+.in +0.3i
+floppyd -d /dev/fd0
+floppyd -d -x :1 -p 5704 /dev/fd0 
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+ If you want to start floppyd by \fR\&\f(CWinetd\fR instead of running it as a 
+daemon, insert the following lines into \fR\&\f(CW\(if/etc/services\(is\fR:
+.nf
+.ft 3
+.in +0.3i
+# floppy daemon
+floppyd-0    5703/tcp    # floppy daemon for X server :0
+floppyd-1    5704/tcp    # floppy daemon for X server :1
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+ And insert the following into \fR\&\f(CW\(if/etc/inetd.conf\(is\fR (assuming that you
+have defined a user named floppy in your \fR\&\f(CW\(if/etc/passwd\(is\fR):
+.PP
+.nf
+.ft 3
+.in +0.3i
+# floppy daemon
+floppyd-0 stream  tcp  wait  floppy  /usr/sbin/floppyd floppyd /dev/fd0 
+floppyd-1 stream  tcp  wait  floppy  /usr/sbin/floppyd floppyd -x :1 /dev/fd0 
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+ Note that you need to supply the X display names for the second
+floppyd.  This is because the port is opened by inetd.conf, and hence
+floppyd cannot know its number to interfere the display number.
+.PP
+On the client side, insert the following into your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR
+to define a drive letter accessing floppy drive in your X terminal:
+.nf
+.ft 3
+.in +0.3i
+drive x: file="$DISPLAY" remote
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+If your X terminal has more than one drive, you may access the
+additional drives as follows:
+.nf
+.ft 3
+.in +0.3i
+drive y: file="$DISPLAY//1" remote
+drive z: file="$DISPLAY//2" remote
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/floppyd.c b/floppyd.c
new file mode 100644 (file)
index 0000000..69a2cf4
--- /dev/null
+++ b/floppyd.c
@@ -0,0 +1,1257 @@
+/*  Copyright 1999 Peter Schlaile.
+ *  Copyright 1999-2005,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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"
+
+#ifdef USE_FLOPPYD
+
+#define USE_FLOPPYD_BUFFERED_IO  1
+#define FLOPPYD_DEFAULT_PORT     5703
+
+#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!
+           
+*/
+
+typedef unsigned char Byte;
+typedef unsigned long Dword;
+
+
+#define MAX_XAUTHORITY_LENGTH    3000
+#define MAX_DATA_REQUEST         3000000
+#define BUFFERED_IO_SIZE         16348
+
+
+void serve_client(int sock, char **device_name, int n_dev, int close_stderr);
+
+
+#ifdef USE_FLOPPYD_BUFFERED_IO
+typedef struct io_buffer {
+       Byte out_buffer[BUFFERED_IO_SIZE];
+       Byte in_buffer[BUFFERED_IO_SIZE];
+       
+       long in_valid;
+       long in_start;
+       long out_valid;
+       
+       int handle;
+} *io_buffer;
+
+static io_buffer new_io_buffer (int _handle) {
+       io_buffer buffer;
+
+       buffer = New(struct io_buffer);
+
+       buffer->handle = _handle;
+       buffer->in_valid = buffer->in_start = 0;
+       buffer->out_valid = 0;
+       return buffer;
+}
+
+
+static void flush(io_buffer buffer) {
+       if (buffer->out_valid) {
+               if(write(buffer->handle, buffer->out_buffer, buffer->out_valid) < 0) {
+                       perror("floppyd flush");
+               }
+               buffer->out_valid = 0;
+       }
+}
+
+static void free_io_buffer(io_buffer buffer) {
+       flush(buffer);
+       free(buffer);
+}
+
+
+static size_t buf_read (io_buffer buf, Byte* buffer, size_t nbytes) {
+       size_t rval;
+       
+       if (nbytes <= buf->in_valid) {
+               memcpy(buffer, buf->in_buffer+buf->in_start, nbytes);
+               buf->in_valid -= nbytes;
+               buf->in_start += nbytes;
+               rval = nbytes;
+       } else {
+               if (buf->in_valid) 
+                       memcpy(buffer, buf->in_buffer+buf->in_start, 
+                                  buf->in_valid);
+               nbytes -= buf->in_valid;
+               buffer += buf->in_valid;
+               if (nbytes > BUFFERED_IO_SIZE) {
+                       rval = read(buf->handle, buffer, nbytes);
+                       if (rval >= 0) {
+                               rval += buf->in_valid;
+                       }
+                       buf->in_valid = buf->in_start = 0;
+               } else {
+                       rval = read(buf->handle, buf->in_buffer, 
+                                               BUFFERED_IO_SIZE);
+                       if (rval >= 0) {
+                               if (rval < nbytes) {
+                                       memcpy(buffer, buf->in_buffer, rval);
+                                       rval += buf->in_valid;
+                                       buf->in_valid = buf->in_start = 0;
+                               } else {
+                                       size_t a;
+                                       memcpy(buffer, buf->in_buffer, nbytes);
+                                       buf->in_start = nbytes;
+                                       a = buf->in_valid;
+                                       buf->in_valid = rval-nbytes;
+                                       rval = a + nbytes;
+                               }
+                       }
+               }
+       }
+       return rval;
+}
+
+static size_t buf_write(io_buffer buf, void* buffer, size_t nbytes) {
+       if (buf->out_valid + nbytes > BUFFERED_IO_SIZE) {
+               flush(buf);
+               return write(buf->handle, buffer, nbytes);
+       }
+       memcpy(buf->out_buffer+buf->out_valid, buffer, nbytes);
+       buf->out_valid += nbytes;
+       return nbytes;
+}
+
+
+
+#else
+
+typedef int io_buffer;
+
+io_buffer new_io_buffer (int handle) {
+       return handle;
+}
+
+
+size_t buf_read (io_buffer handle, Byte* buffer, size_t nbytes) {
+       return (read(handle, buffer, nbytes));
+}
+
+size_t buf_write(io_buffer handle, void* buffer, size_t nbytes) {
+       return (write(handle, buffer, nbytes));
+}
+
+
+void free_io_buffer(io_buffer buffer) { }
+
+
+void flush(io_buffer buffer) { }
+
+#endif
+
+typedef struct Packet {
+       Byte* data;
+       Dword len;
+       Dword alloc_size;
+} *Packet;
+
+#include "byte_dword.h"
+
+static Dword read_dword(io_buffer fp)
+{
+       Byte val[4];
+       if (buf_read(fp, val, 4) < 4) {
+               return 0xffffffff;
+       }
+       
+       return byte2dword(val);
+}
+
+static void write_dword(io_buffer fp, Dword parm)
+{
+       Byte val[4];
+       
+       dword2byte(parm, val);
+       
+       buf_write(fp, val,4);
+}
+
+
+static Packet newPacket(void)
+{
+       Packet packet;
+
+       packet = New(struct Packet);
+       packet->data = NULL;
+       packet->len = packet->alloc_size = 0;
+       return packet;
+}
+
+
+static void destroyPacket(Packet packet)
+{
+       if(packet->data)
+               free(packet->data);
+       free(packet);
+}
+
+static void kill_packet(Packet packet)
+{
+       if(packet->data)
+               free(packet->data);
+       packet->data = NULL;
+       packet->len = 0;
+       packet->alloc_size = 0;
+}
+
+static void make_new(Packet packet, unsigned long l)
+{
+       if (l < packet->alloc_size) {
+               packet->len = l;
+               return;
+       }
+       kill_packet(packet);
+       packet->len = packet->alloc_size = l;
+       packet->data = malloc(l);
+       memset(packet->data, 0, l);
+}
+
+static char send_packet(Packet packet, io_buffer fp)
+{
+       if (packet->data) {
+               write_dword(fp, packet->len);
+               buf_write(fp, packet->data, packet->len);
+               flush(fp);
+#if DEBUG
+               fprintf(stderr, "send_packet(): Size: %li\n", packet->len);
+#endif
+
+#if DEBUG
+               fprintf(stderr, "send_packet(): ");
+               for (int i = 0; i < packet->len; i++) {
+                       fprintf(stderr, "%d ", packet->data[i]);
+               }
+               fprintf(stderr, "\n");
+#endif         
+
+       }
+       return (packet->data != NULL);
+}
+
+static char recv_packet(Packet packet, io_buffer fp, Dword maxlength)
+{
+       int start;
+       int l;
+       Dword length = read_dword(fp);
+#if DEBUG
+       fprintf(stderr, "recv_packet(): Size: %li\n", length);
+#endif
+       if (length > maxlength || length == 0xffffffff ) {
+               return 0;
+       }
+       make_new(packet, length);
+       l = 0;
+       for (start = 0; start < length; start += l) {
+               l = buf_read(fp, packet->data+start, length-start);
+               if (l == 0) {
+                       return 0;
+               }
+       }
+       if (packet->len == 0) {
+               return 0;
+       }
+#if DEBUG
+       fprintf(stderr, "*** read: %li\n", packet->len);
+#endif
+       
+#if DEBUG
+       fprintf(stderr, "recv_packet(): ");
+       for (i = 0; i < packet->len; i++) {
+               fprintf(stderr, "%d ", packet->data[i]);
+       }
+       fprintf(stderr, "\n");
+#endif         
+       return 1;
+}
+
+static void read_packet(Packet packet, int fd, int length) {
+       make_new(packet, length);
+       packet->len = read(fd, packet->data, packet->len);
+}
+
+static int write_packet(Packet packet, int fd) {
+       return (write(fd, packet->data, packet->len));
+}
+
+static void put_dword(Packet packet, int my_index, Dword val) {
+       dword2byte(val, packet->data+my_index);
+}
+
+static Dword get_dword(Packet packet, int my_index) {
+       return byte2dword(packet->data+my_index);
+}      
+
+static Dword get_length(Packet packet) {
+       return packet->len;
+}
+
+static int eat(char **ptr, int *len, unsigned char c) {
+    /* remove length + size code + terminating 0 */
+    if (*len < c + 3)
+       return -1;
+    (*ptr) += c + 2;
+    (*len) -= c + 2;
+    return 0;
+}
+
+static const char *dispName;
+
+static char XAUTHORITY[]="XAUTHORITY";
+
+static char do_auth(io_buffer sock, int *version) 
+{
+       int fd;
+       Display* displ;
+       Packet proto_version = newPacket();
+       Packet mit_cookie;
+       char *ptr;
+       int len;
+
+       char authFile[41]="/tmp/floppyd.XXXXXX";
+       char template[4096];
+
+       Packet reply = newPacket();
+
+       make_new(reply, 4);
+
+       if (!recv_packet(proto_version, sock, 4)) {
+               put_dword(reply, 0, AUTH_PACKETOVERSIZE);
+               send_packet(reply, sock);
+               destroyPacket(reply);
+               destroyPacket(proto_version);
+               return 0;
+       }
+
+       *version = get_dword(proto_version, 0);
+       if (*version > FLOPPYD_PROTOCOL_VERSION || 
+           *version < FLOPPYD_PROTOCOL_VERSION_OLD) {
+               /* fail if client requests a newer version than us */
+               put_dword(reply, 0, AUTH_WRONGVERSION);
+               send_packet(reply, sock);
+               destroyPacket(reply);
+               destroyPacket(proto_version);
+               return 0;
+       }
+
+       if(*version == FLOPPYD_PROTOCOL_VERSION_OLD) {
+               put_dword(reply, 0, AUTH_SUCCESS);
+       } else {
+               make_new(reply, 12);
+               put_dword(reply, 0, AUTH_SUCCESS);
+               put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION);
+               put_dword(reply, 8, FLOPPYD_CAP_EXPLICIT_OPEN);
+       }
+       send_packet(reply, sock);
+       destroyPacket(proto_version);
+
+       make_new(reply, 4);
+       mit_cookie = newPacket();
+       if (!recv_packet(mit_cookie, sock, MAX_XAUTHORITY_LENGTH)) {
+               put_dword(reply, 0, AUTH_PACKETOVERSIZE);
+               send_packet(reply, sock);
+               destroyPacket(reply);
+               destroyPacket(mit_cookie);
+               return 0;
+       }
+
+       umask(077);
+       fd = mkstemp(authFile);
+       if(fd == -1) {
+               /* Different error than file exists */
+               put_dword(reply, 0, AUTH_DEVLOCKED);
+               send_packet(reply, sock);
+               close(fd);
+               destroyPacket(reply);
+               destroyPacket(mit_cookie);
+               return 0;
+       }
+#ifdef HAVE_SETENV
+       setenv(XAUTHORITY, authFile, 1);
+#else
+       {
+         char *buffer=malloc(strlen(XAUTHORITY)+strlen(authFile)+2);
+         strcpy(buffer, XAUTHORITY);
+         strcat(buffer, "=");
+         strcat(buffer, authFile);
+         putenv(buffer);
+       }
+#endif
+
+       ptr = template;
+       ptr[4095] = 0;
+       *ptr++ = 1;
+       *ptr++ = 0;
+       *ptr++ = 0;
+       gethostname(ptr+1, 4088);
+       len = strlen(ptr+1);
+       *ptr++ = len;
+       ptr += len;
+       *ptr++ = 0;
+       *ptr++ = 1;
+       *ptr++ = '0'; /* Display number */
+       *ptr++ = '\0';
+
+       if(write(fd, template, len+8) < len + 8) {
+               close(fd);
+               return 0;
+       }
+       ptr = (char *)mit_cookie->data;
+       len = mit_cookie->len;
+
+       if (eat(&ptr,&len,1) ||    /* the "type"    */
+           eat(&ptr,&len,*ptr) || /* the hostname  */
+           eat(&ptr,&len,*ptr)) { /* the display number */
+           destroyPacket(mit_cookie);
+           unlink(XauFileName());
+           put_dword(reply, 0, AUTH_BADPACKET);
+           send_packet(reply, sock);
+           destroyPacket(reply);
+           return 0;
+       }
+
+       if(write(fd, ptr, len) < len) {
+               close(fd);
+               return 0;
+       }
+       close(fd);
+
+       destroyPacket(mit_cookie);
+
+       displ = XOpenDisplay(dispName);
+       if (!displ) {
+               unlink(XauFileName());
+               put_dword(reply, 0, AUTH_AUTHFAILED);
+               send_packet(reply, sock);
+               destroyPacket(reply);
+               return 0;
+       }
+       XCloseDisplay(displ);
+
+       put_dword(reply, 0, AUTH_SUCCESS);
+       send_packet(reply, sock);
+       destroyPacket(reply);
+       unlink(XauFileName());
+       return 1;
+}
+
+/*
+ * Return the port number, in network order, of the specified service.
+ */
+static short getportnum(char *portnum)
+{
+       char                    *digits = portnum;
+       struct servent  *serv;
+       short                   port;
+
+       for (port = 0; isdigit(*digits); ++digits)
+               {
+                       port = (port * 10) + (*digits - '0');
+               }
+
+       if ((*digits != '\0') || (port <= 0))
+               {
+                       if ((serv = getservbyname(portnum, "tcp")) != NULL)
+                               {
+                                       port = ntohs(serv->s_port);
+                               }
+                       else
+                               {
+                                       port = -1;
+                               }
+                       endservent();
+               }
+
+#if DEBUG
+       fprintf(stderr, "Port lookup %s -> %hd\n", portnum, port);
+#endif
+
+       return (port);
+}
+
+/*
+ * Return the IP address of the specified host.
+ */
+static IPaddr_t getipaddress(char *ipaddr)
+{
+       struct hostent  *host;
+       IPaddr_t ip;
+
+       if (((ip = inet_addr(ipaddr)) == INADDR_NONE)
+           &&
+               (strcmp(ipaddr, "255.255.255.255") != 0))
+               {
+                       if ((host = gethostbyname(ipaddr)) != NULL)
+                               {
+                                       memcpy(&ip, host->h_addr, sizeof(ip));
+                               }
+                       endhostent();
+               }
+
+#if DEBUG
+       fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
+#endif
+
+       return (ip);
+}
+
+/*
+ * Find the userid of the specified user.
+ */
+static uid_t getuserid(char *user)
+{
+       struct passwd   *pw;
+       uid_t                   uid;
+
+       if ((pw = getpwnam(user)) != NULL)
+               {
+                       uid = pw->pw_uid;
+               }
+       else if (*user == '#')
+               {
+                       uid = (uid_t)atoi(&user[1]);
+               }
+       else
+               {
+#ifdef HAVE_GETUSERID
+                       id = getuserid("nobody");
+#else
+                       uid = 65535;
+#endif
+               }
+
+#if DEBUG
+       fprintf(stderr, "User lookup %s -> %d\n", user, uid);
+#endif
+
+       endpwent();
+
+       return (uid);
+}
+
+/*
+ * Find the groupid of the specified user.
+ */
+static uid_t getgroupid(uid_t uid)
+{
+       struct passwd   *pw;
+       gid_t                   gid;
+
+       if ((pw = getpwuid(uid)) != NULL)
+               {
+                       gid = pw->pw_gid;
+               }
+       else
+               {
+#ifdef HAVE_GETGROUPID
+                       id = getgroupid(uid);
+#else
+                       gid = 65535;
+#endif
+               }
+
+#if DEBUG
+       fprintf(stderr, "Group lookup %d -> %d\n", uid, gid);
+#endif
+
+       endpwent();
+
+       return (gid);
+}
+
+/*
+ * Bind to the specified ip and port.
+ */
+static int bind_to_port(IPaddr_t bind_ip, short bind_port)
+{
+       struct sockaddr_in      addr;
+       int                                     sock;
+
+       /*
+        * Allocate a socket.
+        */
+       if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+               {
+                       perror("socket()");
+                       exit(1);
+               }
+
+       /*
+        * Set the SO_REUSEADDR option for debugging.
+        */
+       {
+               int     on = 1;
+               if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
+                             (char *)&on, sizeof(on)) < 0) {
+                       perror("setsockopt");
+                       exit(1);
+               }
+       }
+
+       /*
+        * Set the address to listen to.
+        */
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(bind_port);
+       addr.sin_addr.s_addr = bind_ip;
+
+       /*
+        * Bind our socket to the above address.
+        */
+       if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+               {
+                       perror("bind()");
+                       exit(1);
+               }
+
+       /*
+        * Establish a large listen backlog.
+        */
+       if (listen(sock, SOMAXCONN) < 0)
+               {
+                       perror("listen()");
+                       exit(1);
+               }
+
+       return (sock);
+}
+
+static int sockethandle_now = -1;
+  
+/*
+ * Catch alarm signals and exit.
+ */
+static void alarm_signal(int a)
+{
+       if (sockethandle_now != -1) {
+               close(sockethandle_now);
+               sockethandle_now = -1;
+               unlink(XauFileName());
+       }
+       exit(1);
+}
+
+
+/*
+ * This is the main loop when running as a server.
+ */
+static void server_main_loop(int sock, char **device_name, int n_dev)
+{
+       struct sockaddr_in      addr;
+       unsigned int            len;
+
+       /*
+        * Ignore dead servers so no zombies should be left hanging.
+        */
+       signal(SIGCLD, SIG_IGN);
+
+       for (;;) {
+               int                                     new_sock;
+               /*
+                * Accept an incoming connection.
+                */
+               len = sizeof(addr);
+               while ((new_sock = accept(sock, (struct sockaddr *)&addr, &len)) < 0){}
+               
+               /*
+                * Create a new process to handle the connection.
+                */
+#if DEBUG == 0
+               switch (fork()) {
+                       case -1:
+                               /*
+                                * Under load conditions just ignore new connections.
+                                */
+                               break;
+                               
+                       case 0:
+                               /*
+                                * Start the proxy work in the new socket.
+                                */
+#endif
+                               serve_client(new_sock,device_name, n_dev, 0);
+                               exit(0);
+#if DEBUG == 0
+               }
+#endif
+               /*
+                * Close the socket as the child does the handling.
+                */
+               close(new_sock);
+               new_sock = -1;
+       }
+}
+
+/*
+ * Print some basic help information.
+ */
+static void usage(char *prog, const char *opt, int ret)
+{
+       if (opt)
+               {
+                       fprintf(stderr, "%s: %s\n", prog, opt);
+               }
+       fprintf(stderr, "usage: %s [-s port [-r user] [-b ipaddr]] devicename [Names of local host]\n", 
+                       prog);
+       fprintf(stderr, "    -d          Run as a server (default port 5703 + DISPLAY)\n");
+       fprintf(stderr, "    -s port     Run as a server bound to the specified port.\n");
+       fprintf(stderr, "    -r user     Run as the specified user in server mode.\n");
+       fprintf(stderr, "    -b ipaddr   Bind to the specified ipaddr in server mode.\n");
+       fprintf(stderr, "    -l          Do not attempt to connect to localhost:0 to validate connection\n");
+       exit(ret);
+}
+
+
+static char *makeDisplayName(int dispNr)
+{
+       char result[80];
+       sprintf(result, ":%d.0", dispNr);
+       return strdup(result);
+}
+
+int main (int argc, char** argv) 
+{
+       int sockfd = 0;
+       int                     arg;
+       int                     run_as_server = 0;
+       IPaddr_t                bind_ip = INADDR_ANY;
+       unsigned short          bind_port = 0;
+       uid_t                   run_uid = 65535;
+       gid_t                   run_gid = 65535;
+       char*                   username = strdup("nobody");
+       int                     sock;
+       int                     port_is_supplied = 0;
+
+       char *server_hostname=NULL;
+       char **device_name = NULL; 
+       const char *floppy0 = "/dev/fd0";
+       int n_dev;
+
+
+       /*
+        * Parse the command line arguments.
+        */
+       if(argc > 1 && !strcmp(argv[0], "--help"))
+               usage(argv[0], NULL, 0);
+       while ((arg = getopt(argc, argv, "ds:r:b:x:h")) != EOF)
+               {
+                       switch (arg)
+                               {
+                                       case 'd':
+                                               run_as_server = 1;
+                                               break;
+                                       case 's':
+                                               run_as_server = 1;
+                                               port_is_supplied = 1;
+                                               bind_port = getportnum(optarg);
+                                               break;
+
+                                       case 'r':
+                                               free(username); username = strdup(optarg);
+                                               run_uid = getuserid(optarg);
+                                               run_gid = getgroupid(run_uid);
+                                               break;
+
+                                       case 'b':
+                                               run_as_server = 1;
+                                               bind_ip = getipaddress(optarg);
+                                               server_hostname=optarg;
+                                               break;
+                                       case 'x':
+                                               dispName = strdup(optarg);
+                                               break;
+
+                                       case 'h':
+                                               usage(argv[0], NULL, 0);
+                                               break;
+                                       case '?':
+                                               usage(argv[0], NULL, 1);
+                                               break;
+                               }
+               }
+
+       if(optind < argc) {
+               device_name = argv + optind;
+               n_dev = argc - optind;
+       } else {
+               device_name = (char **)&floppy0;
+               n_dev = 1;
+       }
+
+       if(dispName == NULL)
+               dispName = getenv("DISPLAY");
+       if(dispName==NULL && bind_port != 0)
+               dispName=makeDisplayName((unsigned short)(bind_port - 5703));
+       if(dispName==NULL)              
+               dispName=":0";
+
+       if(bind_port == 0) {
+               char *p = strchr(dispName,':');
+               bind_port = FLOPPYD_DEFAULT_PORT;
+               if(p != NULL)
+                       bind_port += atoi(p+1);
+       }
+
+       if(!run_as_server) {
+               struct sockaddr_in      addr;
+               unsigned int len = sizeof(addr);
+               
+               /* try to find out port that we are connected to */
+               if(getsockname(0, (struct sockaddr*) &addr, &len) >= 0 && 
+                  len == sizeof(addr)) {
+                       port_is_supplied = 1;
+                       bind_port = ntohs(addr.sin_port);
+                       server_hostname = strdup(inet_ntoa(addr.sin_addr));
+               }
+       }
+
+       umask(0077);
+
+       /*
+        * Test to make sure required args were provided and are valid.
+        */
+       if (run_as_server && (bind_ip == INADDR_NONE)) {
+               usage(argv[0], "The server ipaddr is invalid.", 1);
+       }
+       if (run_as_server && (bind_port == 0))  {
+               usage(argv[0], "No server port was specified (or it was invalid).", 1);
+       }
+
+
+       /*
+        * See if we should run as a server.
+        */
+       if (run_as_server) {
+               /*
+                * Start by binding to the port, the child inherits this socket.
+                */
+               sock = bind_to_port(bind_ip, bind_port);
+               
+               /*
+                * Start a server process. When DEBUG is defined, just run
+                * in the foreground.
+                */
+#if DEBUG
+               switch (0)
+#else
+                       switch (fork())
+#endif
+                               {
+                               case -1:
+                                       perror("fork()");
+                                       exit(1);
+                                       
+                               case 0:
+                                       /*
+                                        * Ignore some signals.
+                                        */
+                                       signal(SIGHUP, SIG_IGN);
+#if DEBUG
+                                       signal(SIGINT, SIG_IGN);
+#endif
+                                       signal(SIGQUIT, SIG_IGN);
+                                       signal(SIGTSTP, SIG_IGN);
+                                       signal(SIGCONT, SIG_IGN);
+                                       signal(SIGPIPE, alarm_signal);
+                                       /*signal(SIGALRM, alarm_signal);*/
+                                       
+                                       /*
+                                        * Drop back to an untrusted user.
+                                        */
+                                       setgid(run_gid);
+                                       initgroups(username, -1);
+                                       setuid(run_uid);
+                                       
+                                       /*
+                                        * Start a new session and group.
+                                        */
+                                       setsid();
+#ifdef HAVE_SETPGRP
+#ifdef SETPGRP_VOID
+                                       setpgrp();
+#else
+                                       setpgrp(0,0);
+#endif
+#endif
+#if DEBUG
+                                       close(2);
+                                       open("/dev/null", O_WRONLY);
+#endif
+                                       /*
+                                        * Handle the server main loop.
+                                        */
+                                       server_main_loop(sock, device_name, n_dev);
+                                       
+                                       /*
+                                        * Should never exit.
+                                        */
+                                       exit(1);
+                               }
+               
+               /*
+                * Parent exits at this stage.
+                */
+               exit(0);
+       }
+
+       signal(SIGHUP, alarm_signal);
+#if DEBUG == 0
+       signal(SIGINT, alarm_signal);
+#endif
+       signal(SIGQUIT, alarm_signal);
+       signal(SIGTERM, alarm_signal);
+       signal(SIGTSTP, SIG_IGN);
+       signal(SIGCONT, SIG_IGN);
+       signal(SIGPIPE, alarm_signal);
+       /*signal(SIGALRM, alarm_signal);*/
+
+       /* Starting from inetd */
+
+       serve_client(sockfd, device_name, n_dev, 1);
+       return 0;
+}
+
+static void send_reply(int rval, io_buffer sock, int len) {
+       Packet reply = newPacket();
+
+       make_new(reply, 8);
+       put_dword(reply, 0, len);
+       if (rval == -1) {
+               put_dword(reply, 4, 0);
+       } else {
+               put_dword(reply, 4, errno);
+       }
+       send_packet(reply, sock);
+       destroyPacket(reply);
+}
+
+static void cleanup(int x) {
+       unlink(XauFileName());
+       exit(-1);
+}
+
+#include "lockdev.h"
+
+void serve_client(int sockhandle, char **device_name, int n_dev,
+                 int close_stderr) {
+       Packet opcode;
+       Packet parm;
+
+       int readOnly;
+       int devFd;
+       io_buffer sock;
+       int stopLoop;
+       int version;
+       int needSendReply=0;
+       int rval=0;
+       
+       /*
+        * Set the keepalive socket option to on.
+        */
+       {
+               int             on = 1;
+               if(setsockopt(sockhandle, SOL_SOCKET, 
+                             SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) {
+                       perror("setsockopt");
+                       exit(1);
+               }
+                       
+       }
+
+
+#if DEBUG == 0
+       if(close_stderr) {
+               close(2);
+               open("/dev/null", O_WRONLY);
+       }
+#endif
+
+       sock = new_io_buffer(sockhandle);
+       
+       /*
+        * Allow 60 seconds for any activity.
+        */
+       alarm(60);
+       
+       version = 0;
+       if (!do_auth(sock, &version)) {
+               free_io_buffer(sock);
+               return;
+       }
+       alarm(0);
+
+
+       signal(SIGTERM, cleanup);
+       signal(SIGALRM, cleanup);
+
+
+
+       sockethandle_now = sockhandle;
+
+
+       opcode = newPacket();
+       parm = newPacket();
+
+       devFd = -1;
+       readOnly = 1;
+
+       stopLoop = 0;
+       if(version == FLOPPYD_PROTOCOL_VERSION_OLD) {
+                               /* old protocol */
+               readOnly = 0;
+               devFd = open(device_name[0], O_RDWR);
+               
+               if (devFd < 0) {
+                       readOnly = 1;
+                       devFd = open(device_name[0], 
+                                    O_RDONLY);
+               }
+               if(devFd < 0) {
+                       send_reply(0, sock, devFd);
+                       stopLoop = 1;
+               }
+               lock_dev(devFd, !readOnly, NULL);
+       }
+
+
+       while(!stopLoop) {
+               int dev_nr = 0;
+               /*
+                * Allow 60 seconds for any activity.
+                */
+               /*alarm(60);*/
+
+               if (!recv_packet(opcode, sock, 1)) {
+                       break;
+               }
+/*             if(opcode->data[0] != OP_CLOSE)*/
+                   recv_packet(parm, sock, MAX_DATA_REQUEST);
+
+
+               switch(opcode->data[0]) {
+                       case OP_OPRO:
+                               if(get_length(parm) >= 4)
+                                       dev_nr = get_dword(parm,0);
+                               else
+                                       dev_nr = 0;
+                               if(dev_nr >= n_dev) {
+                                       send_reply(0, sock, -1);
+                                       break;
+                               }
+
+                               devFd = open(device_name[dev_nr], O_RDONLY);
+#if DEBUG
+                               fprintf(stderr, "Device opened\n");
+#endif
+                               if(devFd >= 0 && lock_dev(devFd, 0, NULL)) {
+                                       send_reply(0, sock, -1);
+                                       break;
+                               }
+                               send_reply(0, sock, devFd);
+                               readOnly = 1;
+                               break;
+                       case OP_OPRW:
+                               if(get_length(parm) >= 4)
+                                       dev_nr = get_dword(parm,0);
+                               else
+                                       dev_nr = 0;
+                               if(dev_nr >= n_dev) {
+                                       send_reply(0, sock, -1);
+                                       break;
+                               }
+                               devFd = open(device_name[dev_nr], O_RDWR);
+                               if(devFd >= 0 && lock_dev(devFd, 1, NULL)) {
+                                       send_reply(0, sock, -1);
+                                       break;
+                               }
+                               send_reply(0, sock, devFd);
+                               readOnly = 0;
+                               break;
+                       case OP_READ:
+#if DEBUG
+                               fprintf(stderr, "READ:\n");
+#endif
+                               read_packet(parm, devFd, get_dword(parm, 0));
+                               send_reply(devFd, sock, get_length(parm));
+                               if(get_length(parm) >= 0)
+                                       send_packet(parm, sock);
+                               break;
+                       case OP_WRITE:
+#if DEBUG
+                               fprintf(stderr, "WRITE:\n");
+#endif
+                               if(readOnly) {
+                                       errno = -EROFS;
+                                       rval = -1;
+                               } else {
+                                       rval = write_packet(parm, devFd);
+                               }
+                               send_reply(devFd, sock, rval);
+                               break;
+                       case OP_SEEK:
+#if DEBUG
+                               fprintf(stderr, "SEEK:\n");
+#endif
+
+                               lseek(devFd, 
+                                     get_dword(parm, 0), get_dword(parm, 4));
+                               send_reply(devFd, 
+                                          sock, 
+                                          lseek(devFd, 0, SEEK_CUR));
+                               break;
+                       case OP_FLUSH:
+#if DEBUG
+                               fprintf(stderr, "FLUSH:\n");
+#endif
+                               fsync(devFd);
+                               send_reply(devFd, sock, 0);
+                               break;
+                       case OP_CLOSE:
+#if DEBUG
+                               fprintf(stderr, "CLOSE:\n");
+#endif
+
+                               close(devFd);
+                               needSendReply = 1;
+                               rval = devFd;
+                               devFd = -1;
+                               stopLoop = 1;
+                               break;
+                       case OP_IOCTL:
+                               /* Unimplemented for now... */
+                               break;
+                       default:
+#if DEBUG
+                               fprintf(stderr, "Invalid Opcode!\n");
+#endif
+                               errno = EINVAL;
+                               send_reply(devFd, sock, -1);
+                               break;
+               }
+               kill_packet(parm);
+               alarm(0);
+       }
+
+       
+
+#if DEBUG
+       fprintf(stderr, "Closing down...\n");
+#endif
+
+       if (devFd >= 0) {
+               close(devFd);
+               devFd = -1;
+       }
+
+       free_io_buffer(sock);
+
+       /* remove "Lock"-File  */
+       unlink(XauFileName());
+
+       if(needSendReply)
+           send_reply(rval, sock, 0);
+       destroyPacket(opcode);
+       destroyPacket(parm);
+}
+
+#else
+#include <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 (file)
index 0000000..4dcb001
--- /dev/null
@@ -0,0 +1,96 @@
+.TH floppyd_installtest 1 "03Nov09" mtools-4.0.12
+.SH Name
+floppyd_installtest - tests whether floppyd is installed and running
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p floppyd_installtest"
+.iX "c X terminal"
+.iX "c remote floppy access"
+.PP
+\&\fR\&\f(CWFloppyd_installtest\fR is used to check for the presence of a running
+floppyd daemon. This is usefull, if you have a small frontend script to
+mtools, which decides whether to use floppyd or not.
+.PP
+\&\fR\&\f(CWfloppyd_installtest\fR [\fR\&\f(CW-f\fR]  Connect-String
+.PP
+If the \fR\&\f(CW-f\fR option is specified, \fR\&\f(CWfloppyd_installtest\fR does a
+full X-Cookie authentication and complains if this does not work.
+.PP
+The connect-String has the format described in the floppyd-section:
+\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR\fIbaseport\fR]
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/floppyd_installtest.c b/floppyd_installtest.c
new file mode 100644 (file)
index 0000000..5f44201
--- /dev/null
@@ -0,0 +1,323 @@
+/*  Copyright 1999 Peter Schlaile.
+ *  Copyright 1999-2002,2006,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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>
+
+/* ######################################################################## */
+
+typedef unsigned char Byte;
+typedef unsigned long Dword;
+
+const char* AuthErrors[] = {
+       "Auth success!",
+       "Auth failed: Packet oversized!",
+       "Auth failed: X-Cookie doesn't match!",
+       "Auth failed: Wrong transmission protocol version!",
+       "Auth failed: Device locked!"
+};
+
+#include "byte_dword.h"
+#include "read_dword.h"
+
+static int write_dword(int handle, Dword parm)
+{
+       Byte val[4];
+
+       dword2byte(parm, val);
+
+       if(write(handle, val, 4) < 4)
+               return -1;
+       return 0;
+}
+
+
+/* ######################################################################## */
+
+static int authenticate_to_floppyd(char fullauth, int sock, char *display, 
+                                  int protoversion)
+{
+       off_t filelen=0;
+       Byte buf[16];
+       const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
+       char *xcookie = NULL;
+       Dword errcode;
+       int bytesRead;
+
+       if (fullauth) {
+               command[4] = display;
+
+               filelen=strlen(display);
+               filelen += 100;
+
+               xcookie = (char *) safe_malloc(filelen+4);
+               filelen = safePopenOut(command, xcookie+4, filelen);
+               if(filelen < 1)
+                   return AUTH_AUTHFAILED;
+       }
+       dword2byte(4,buf);
+       dword2byte(protoversion,buf+4);
+       if(write(sock, buf, 8) < 8)
+               return AUTH_IO_ERROR;
+
+       bytesRead = read_dword(sock);
+
+       if (bytesRead != 4 && bytesRead != 12) {
+               return AUTH_WRONGVERSION;
+       }
+
+
+       errcode = read_dword(sock);
+
+       if (errcode != AUTH_SUCCESS) {
+               return errcode;
+       }
+
+
+       if(bytesRead == 8) {
+           protoversion = read_dword(sock);
+           read_dword(sock);
+       }
+       
+       fprintf(stderr, "Protocol Version=%d\n", protoversion);
+
+       if (fullauth) {
+               dword2byte(filelen, (Byte *) xcookie);
+               if(write(sock, xcookie, filelen+4) < filelen+4)
+                       return AUTH_IO_ERROR;
+
+               if (read_dword(sock) != 4) {
+                       return AUTH_PACKETOVERSIZE;
+               }
+
+               errcode = read_dword(sock);
+       }
+
+       return errcode;
+
+}
+
+
+/* ######################################################################## */
+
+static int get_host_and_port(const char* name, char** hostname, char **display,
+                            short* port)
+{
+       char* newname = strdup(name);
+       char* p;
+       char* p2;
+
+       p = newname;
+       while (*p != '/' && *p) p++;
+       p2 = p;
+       if (*p) p++;
+       *p2 = 0;
+       
+       *port = atoi(p);
+       if (*port == 0) {
+               *port = FLOPPYD_DEFAULT_PORT;   
+       }
+
+       *display = strdup(newname);
+
+       p = newname;
+       while (*p != ':' && *p) p++;
+       p2 = p;
+       if (*p) p++;
+       *p2 = 0;
+
+       *port += atoi(p);  /* add display number to the port */
+
+       if (!*newname || strcmp(newname, "unix") == 0) {
+               free(newname);
+               newname = strdup("localhost");
+       }
+
+       *hostname = newname;
+       return 1;
+}
+
+/*
+ *  * Return the IP address of the specified host.
+ *  */
+static IPaddr_t getipaddress(char *ipaddr)
+{
+       
+       struct hostent  *host;
+       IPaddr_t        ip;
+       
+       if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
+           (strcmp(ipaddr, "255.255.255.255") != 0)) {
+               
+               if ((host = gethostbyname(ipaddr)) != NULL) {
+                       memcpy(&ip, host->h_addr, sizeof(ip));
+               }
+               
+               endhostent();
+       }
+       
+#ifdef DEBUG
+       fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
+#endif
+         
+       return (ip);
+}
+
+/*
+ *  * Connect to the floppyd server.
+ *  */
+static int connect_to_server(IPaddr_t ip, short port)
+{
+       
+       struct sockaddr_in      addr;
+       int                     sock;
+       
+       /*
+        * Allocate a socket.
+        */
+       if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               return (-1);
+       }
+       
+       /*
+        * Set the address to connect to.
+        */
+       
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(port);
+       addr.sin_addr.s_addr = ip;
+       
+        /*
+        * Connect our socket to the above address.
+        */
+       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+               return (-1);
+       }
+
+        /*
+        * Set the keepalive socket option to on.
+        */
+       {
+               int             on = 1;
+               setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE, 
+                          (char *)&on, sizeof(on));
+
+       }
+       
+       return (sock);
+}
+
+int main (int argc, char** argv) 
+{
+       char* hostname;
+       char* display;
+       char* name;
+       short port;
+       int sock;
+       int reply;
+       int rval;
+       int protoversion;
+       char fullauth = 0;
+       Byte opcode = OP_CLOSE;
+
+        if (argc < 2) {
+              puts("Usage: floppyd_installtest [-f] Connect-String\n"
+                   "-f\tDo full X-Cookie-Authentication");
+              return -1;
+       }
+
+       name = argv[1];
+       if (strcmp(name, "-f") == 0) {
+               fullauth = 1;
+               name = argv[2];
+       }
+
+       rval = get_host_and_port(name, &hostname, &display, &port);
+       
+       if (!rval) return -1;
+
+       sock = connect_to_server(getipaddress(hostname), port);
+
+       if (sock == -1) {
+               fprintf(stderr,
+                       "Can't connect to floppyd server on %s, port %i!\n",
+                       hostname, port);
+               return -1;
+       }
+       
+       protoversion = FLOPPYD_PROTOCOL_VERSION;
+       while(1) {
+           reply = authenticate_to_floppyd(fullauth, sock, display,
+                                           protoversion);
+           if(protoversion == FLOPPYD_PROTOCOL_VERSION_OLD)
+               break;
+           if(reply == AUTH_WRONGVERSION) {
+               /* fall back on old version */
+               protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;
+               continue;
+           }
+           break;
+       }
+
+       if (reply != 0) {
+               fprintf(stderr, 
+                       "Connection to floppyd failed:\n"
+                       "%s\n", AuthErrors[reply]);
+               return -1;
+       }
+       
+       free(hostname);
+       free(display);
+
+       if(write_dword(sock, 1) < 0) {
+               fprintf(stderr,
+                       "Short write to floppyd:\n"
+                       "%s\n", strerror(errno));
+       }
+
+       if(write(sock, &opcode, 1) < 0) {
+               fprintf(stderr,
+                       "Short write to floppyd:\n"
+                       "%s\n", strerror(errno));
+       }
+
+       close(sock);
+
+       return 0;
+}
+#endif
diff --git a/floppyd_io.c b/floppyd_io.c
new file mode 100644 (file)
index 0000000..9763891
--- /dev/null
@@ -0,0 +1,636 @@
+/*  Copyright 1999 Peter Schlaile.
+ *  Copyright 1999-2002,2005-2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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
+
+/* ######################################################################## */
+
+
+typedef unsigned char Byte;
+typedef unsigned long Dword;
+
+const char* AuthErrors[] = {
+       "Auth success",
+       "Auth failed: Packet oversized",
+       "Auth failed: X-Cookie doesn't match",
+       "Auth failed: Wrong transmission protocol version",
+       "Auth failed: Device locked"
+       "Auth failed: Bad packet",
+       "Auth failed: I/O Error"
+};
+
+
+typedef struct RemoteFile_t {
+       Class_t *Class;
+       int refs;
+       Stream_t *Next;
+       Stream_t *Buffer;
+       int fd;
+       mt_off_t offset;
+       mt_off_t lastwhere;
+       mt_off_t size;
+       int version;
+       int capabilities;
+       int drive;
+} RemoteFile_t;
+
+
+#include "byte_dword.h"
+#include "read_dword.h"
+
+
+/* ######################################################################## */
+
+static int authenticate_to_floppyd(RemoteFile_t *floppyd, int sock, char *display)
+{
+       off_t filelen;
+       Byte buf[16];
+       const char *command[] = { "xauth", "xauth", "extract", "-", 0, 0 };
+       char *xcookie;
+       Dword errcode;
+       int l;
+
+       command[4] = display;
+
+       filelen=strlen(display);
+       filelen += 100;
+
+       xcookie = (char *) safe_malloc(filelen+4);
+       filelen = safePopenOut(command, xcookie+4, filelen);
+       if(filelen < 1)
+               return AUTH_AUTHFAILED;
+
+       /* Version negotiation */
+       dword2byte(4,buf);
+       dword2byte(floppyd->version,buf+4);
+       if(write(sock, buf, 8) < 8)
+               return AUTH_IO_ERROR;
+
+       if ( (l = read_dword(sock)) < 4) {
+               return AUTH_WRONGVERSION;
+       }
+
+       errcode = read_dword(sock);
+
+       if (errcode != AUTH_SUCCESS) {
+               return errcode;
+       }
+
+       if(l >= 8)
+               floppyd->version = read_dword(sock);
+       if(l >= 12)
+               floppyd->capabilities = read_dword(sock);
+
+       dword2byte(filelen, (Byte *)xcookie);
+       if(write(sock, xcookie, filelen+4) < filelen + 4)
+               return AUTH_IO_ERROR;
+
+       if (read_dword(sock) != 4) {
+               return AUTH_PACKETOVERSIZE;
+       }
+
+       errcode = read_dword(sock);
+       
+       return errcode;
+}
+
+
+static int floppyd_reader(int fd, char* buffer, int len) 
+{
+       Dword errcode;
+       Dword gotlen;
+       int l;
+       int start;
+       Byte buf[16];
+
+       dword2byte(1, buf);
+       buf[4] = OP_READ;
+       dword2byte(4, buf+5);
+       dword2byte(len, buf+9);
+       if(write(fd, buf, 13) < 13)
+               return AUTH_IO_ERROR;
+
+       if (read_dword(fd) != 8) {
+               errno = EIO;
+               return -1;
+       }
+
+       gotlen = read_dword(fd);
+       errcode = read_dword(fd);
+
+       if (gotlen != -1) {
+               if (read_dword(fd) != gotlen) {
+                       errno = EIO;
+                       return -1;
+               }
+               for (start = 0, l = 0; start < gotlen; start += l) {
+                       l = read(fd, buffer+start, gotlen-start);
+                       if (l == 0) {
+                               errno = EIO;
+                               return -1;
+                       }
+               }
+       } else {
+               errno = errcode;
+       }
+       return gotlen;
+}
+
+static int floppyd_writer(int fd, char* buffer, int len) 
+{
+       Dword errcode;
+       Dword gotlen;
+       Byte buf[16];
+
+       dword2byte(1, buf);
+       buf[4] = OP_WRITE;
+       dword2byte(len, buf+5);
+
+       if(write(fd, buf, 9) < 9)
+               return AUTH_IO_ERROR;
+       if(write(fd, buffer, len) < len)
+               return AUTH_IO_ERROR;
+       
+       if (read_dword(fd) != 8) {
+               errno = EIO;
+               return -1;
+       }
+
+       gotlen = read_dword(fd);
+       errcode = read_dword(fd);
+
+       errno = errcode;
+       if(errno != 0 && gotlen == 0) {
+           if (errno == EBADF)
+               errno = EROFS;
+           gotlen = -1;
+       }
+
+       return gotlen;
+}
+
+static int floppyd_lseek(int fd, mt_off_t offset, int whence) 
+{
+       Dword errcode;
+       Dword gotlen;
+       Byte buf[32];
+       
+       dword2byte(1, buf);
+       buf[4] = OP_SEEK;
+       
+       dword2byte(8, buf+5);
+       dword2byte(truncBytes32(offset), buf+9);
+       dword2byte(whence, buf+13);
+       
+       if(write(fd, buf, 17) < 17)
+               return AUTH_IO_ERROR;
+       
+       if (read_dword(fd) != 8) {
+               errno = EIO;
+               return -1;
+       }
+
+       gotlen = read_dword(fd);
+       errcode = read_dword(fd);
+
+       errno = errcode;
+       
+       return gotlen;
+}
+
+static int floppyd_open(RemoteFile_t *This, int mode) 
+{
+       Dword errcode;
+       Dword gotlen;
+       Byte buf[16];
+       
+       if(! (This->capabilities & FLOPPYD_CAP_EXPLICIT_OPEN) ) {
+               /* floppyd has no "explicit seek" capabilities */
+               return 0;
+       }
+
+       dword2byte(1, buf);
+       if((mode & O_ACCMODE) == O_RDONLY)
+               buf[4] = OP_OPRO;
+       else
+               buf[4] = OP_OPRW;
+       dword2byte(4, buf+5);
+       dword2byte(This->drive, buf+9);
+
+       if(write(This->fd, buf, 13) < 13)
+               return AUTH_IO_ERROR;
+       
+       if (read_dword(This->fd) != 8) {
+               errno = EIO;
+               return -1;
+       }
+
+       gotlen = read_dword(This->fd);
+       errcode = read_dword(This->fd);
+
+       errno = errcode;
+       
+       return gotlen;
+}
+
+
+/* ######################################################################## */
+
+typedef int (*iofn) (int, char *, int);
+
+static int floppyd_io(Stream_t *Stream, char *buf, mt_off_t where, int len,
+                  iofn io)
+{
+       DeclareThis(RemoteFile_t);
+       int ret;
+
+       where += This->offset;
+
+       if (where != This->lastwhere ){
+               if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){
+                       perror("floppyd_lseek");
+                       This->lastwhere = (mt_off_t) -1;
+                       return -1;
+               }
+       }
+       ret = io(This->fd, buf, len);
+       if ( ret == -1 ){
+               perror("floppyd_io");
+               This->lastwhere = (mt_off_t) -1;
+               return -1;
+       }
+       This->lastwhere = where + ret;
+       return ret;
+}
+
+static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
+{      
+       return floppyd_io(Stream, buf, where, len, (iofn) floppyd_reader);
+}
+
+static int floppyd_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
+{
+       return floppyd_io(Stream, buf, where, len, (iofn) floppyd_writer);
+}
+
+static int floppyd_flush(Stream_t *Stream)
+{
+       Byte buf[16];
+
+       DeclareThis(RemoteFile_t);
+
+       dword2byte(1, buf);
+       buf[4] = OP_FLUSH;
+       dword2byte(1, buf+5);
+       buf[9] = '\0';
+
+       if(write(This->fd, buf, 10) < 10)
+               return AUTH_IO_ERROR;
+
+       if (read_dword(This->fd) != 8) {
+               errno = EIO;
+               return -1;
+       }
+
+       read_dword(This->fd);
+       read_dword(This->fd);
+       return 0;
+}
+
+static int floppyd_free(Stream_t *Stream)
+{
+       Byte buf[16];
+       int gotlen;
+       int errcode;
+       DeclareThis(RemoteFile_t);
+
+       if (This->fd > 2) {
+               dword2byte(1, buf);
+               buf[4] = OP_CLOSE;
+               if(write(This->fd, buf, 5) < 5)
+                       return AUTH_IO_ERROR;
+               shutdown(This->fd, 1);
+               if (read_dword(This->fd) != 8) {
+                   errno = EIO;
+                   return -1;
+               }
+               
+               gotlen = read_dword(This->fd);
+               errcode = read_dword(This->fd);
+               
+               errno = errcode;
+
+               close(This->fd);
+               return gotlen;
+       } else {
+               return 0;
+       }
+}
+
+static int floppyd_geom(Stream_t *Stream, struct device *dev, 
+                    struct device *orig_dev,
+                    int media, union bootsector *boot)
+{
+       size_t tot_sectors;
+       int sect_per_track;
+       DeclareThis(RemoteFile_t);
+
+       dev->ssize = 2; /* allow for init_geom to change it */
+       dev->use_2m = 0x80; /* disable 2m mode to begin */
+
+       if(media == 0xf0 || media >= 0x100){            
+               dev->heads = WORD(nheads);
+               dev->sectors = WORD(nsect);
+               tot_sectors = DWORD(bigsect);
+               SET_INT(tot_sectors, WORD(psect));
+               sect_per_track = dev->heads * dev->sectors;
+               tot_sectors += sect_per_track - 1; /* round size up */
+               dev->tracks = tot_sectors / sect_per_track;
+
+       } else if (media >= 0xf8){
+               media &= 3;
+               dev->heads = old_dos[media].heads;
+               dev->tracks = old_dos[media].tracks;
+               dev->sectors = old_dos[media].sectors;
+               dev->ssize = 0x80;
+               dev->use_2m = ~1;
+       } else {
+               fprintf(stderr,"Unknown media type\n");
+               exit(1);
+       }
+
+       This->size = (mt_off_t) 512 * dev->sectors * dev->tracks * dev->heads;
+
+       return 0;
+}
+
+
+static int floppyd_data(Stream_t *Stream, time_t *date, mt_size_t *size,
+                    int *type, int *address)
+{
+       DeclareThis(RemoteFile_t);
+
+       if(date)
+               /* unknown, and irrelevant anyways */
+               *date = 0;
+       if(size)
+               /* the size derived from the geometry */
+               *size = (mt_size_t) This->size;
+       if(type)
+               *type = 0; /* not a directory */
+       if(address)
+               *address = 0;
+       return 0;
+}
+
+/* ######################################################################## */
+
+static Class_t FloppydFileClass = {
+       floppyd_read, 
+       floppyd_write,
+       floppyd_flush,
+       floppyd_free,
+       floppyd_geom,
+       floppyd_data
+};
+
+/* ######################################################################## */
+
+static int get_host_and_port_and_drive(const char* name, char** hostname,
+                                      char **display, short* port, int *drive)
+{
+       char* newname = strdup(name);
+       char* p;
+       char* p2;
+
+       p = newname;
+       while (*p != '/' && *p) p++;
+       p2 = p;
+       if (*p) p++;
+       *p2 = 0;
+       
+       *port = FLOPPYD_DEFAULT_PORT;   
+       if(*p >= '0' && *p <= '9')
+         *port = strtoul(p, &p, 0);
+       if(*p == '/')
+         p++;
+       *drive = 0;
+       if(*p >= '0' && *p <= '9')
+         *drive = strtoul(p, &p, 0);
+
+       *display = strdup(newname);
+
+       p = newname;
+       while (*p != ':' && *p) p++;
+       p2 = p;
+       if (*p) p++;
+       *p2 = 0;
+
+       *port += atoi(p);  /* add display number to the port */
+
+       if (!*newname || strcmp(newname, "unix") == 0) {
+               free(newname);
+               newname = strdup("localhost");
+       }
+
+       *hostname = newname;
+       return 1;
+}
+
+/*
+ *  * Return the IP address of the specified host.
+ *  */
+static IPaddr_t getipaddress(char *ipaddr)
+{
+       
+       struct hostent  *host;
+       IPaddr_t        ip;
+
+       if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
+           (strcmp(ipaddr, "255.255.255.255") != 0)) {
+               
+               if ((host = gethostbyname(ipaddr)) != NULL) {
+                       memcpy(&ip, host->h_addr, sizeof(ip));
+               }
+               
+               endhostent();
+       }
+       
+#ifdef DEBUG
+       fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
+#endif
+         
+       return (ip);
+}
+
+/*
+ *  * Connect to the floppyd server.
+ *  */
+static int connect_to_server(IPaddr_t ip, short port)
+{
+       
+       struct sockaddr_in      addr;
+       int                     sock;
+       
+       /*
+        * Allocate a socket.
+        */
+       if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+               return (-1);
+       }
+       
+       /*
+        * Set the address to connect to.
+        */
+       
+       addr.sin_family = AF_INET;
+       addr.sin_port = htons(port);
+       addr.sin_addr.s_addr = ip;
+       
+        /*
+        * Connect our socket to the above address.
+        */
+       if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+               return (-1);
+       }
+
+        /*
+        * Set the keepalive socket option to on.
+        */
+       {
+               int             on = 1;
+               setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, 
+                          (char *)&on, sizeof(on));
+       }
+       
+       return (sock);
+}
+
+static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name, 
+                           char *errmsg);
+
+Stream_t *FloppydOpen(struct device *dev, struct device *dev2,
+                     char *name, int mode, char *errmsg,
+                     int mode2, int locked)
+{
+       RemoteFile_t *This;
+
+       if (!dev ||  !(dev->misc_flags & FLOPPYD_FLAG))
+               return NULL;
+       
+       This = New(RemoteFile_t);
+       if (!This){
+               printOom();
+               return NULL;
+       }
+       This->Class = &FloppydFileClass;
+       This->Next = 0;
+       This->offset = 0;
+       This->lastwhere = 0;
+       This->refs = 1;
+       This->Buffer = 0;
+
+       This->fd = ConnectToFloppyd(This, name, errmsg);
+       if (This->fd == -1) {
+               Free(This);
+               return NULL;
+       }
+
+       if(floppyd_open(This, mode) < 0) {
+               sprintf(errmsg,
+                       "Can't open remote drive: %s", strerror(errno));
+               close(This->fd);
+               Free(This);
+               return NULL;
+       }
+
+       return (Stream_t *) This;
+}
+
+static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name, 
+                           char *errmsg) 
+{
+       char* hostname;
+       char* display;
+       short port;
+       int rval = get_host_and_port_and_drive(name, &hostname, &display, 
+                                              &port, &floppyd->drive);
+       int sock;
+       int reply;
+       
+       if (!rval) return -1;
+
+       floppyd->version = FLOPPYD_PROTOCOL_VERSION;
+       floppyd->capabilities = 0;
+       while(1) {
+               sock = connect_to_server(getipaddress(hostname), port);
+               
+               if (sock == -1) {
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg, 200,
+                                "Can't connect to floppyd server on %s, port %i (%s)!",
+                                hostname, port, strerror(errno));
+#else
+                       sprintf(errmsg,
+                                "Can't connect to floppyd server on %s, port %i!",
+                                hostname, port);
+#endif
+                       return -1;
+               }
+               
+               reply = authenticate_to_floppyd(floppyd, sock, display);
+               if(floppyd->version == FLOPPYD_PROTOCOL_VERSION_OLD)
+                       break;
+               if(reply == AUTH_WRONGVERSION) {
+                       /* fall back on old version */
+                       floppyd->version = FLOPPYD_PROTOCOL_VERSION_OLD;
+                       continue;
+               }
+               break;
+       }
+
+       if (reply != 0) {
+               fprintf(stderr, 
+                       "Permission denied, authentication failed!\n"
+                       "%s\n", AuthErrors[reply]);
+               return -1;
+       }
+
+       free(hostname);
+       free(display);
+
+       return sock;
+}
+#endif
diff --git a/floppyd_io.h b/floppyd_io.h
new file mode 100644 (file)
index 0000000..066d7b9
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef MTOOLS_FLOPPYDIO_H
+#define MTOOLS_FLOPPYDIO_H
+
+/*  Copyright 1999 Peter Schlaile.
+ *  Copyright 1998,2000-2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef USE_FLOPPYD
+
+#include "stream.h"
+
+/*extern int ConnectToFloppyd(const char* name, Class_t** ioclass);*/
+Stream_t *FloppydOpen(struct device *dev, struct device *dev2,
+                                         char *name, int mode, char *errmsg,
+                                         int mode2, int locked);
+
+#define FLOPPYD_DEFAULT_PORT 5703
+
+#define FLOPPYD_PROTOCOL_VERSION_OLD 10
+#define FLOPPYD_PROTOCOL_VERSION 11
+
+#define FLOPPYD_CAP_EXPLICIT_OPEN 1 /* explicit open. Useful for 
+                                    * clean signalling of readonly disks */
+#define FLOPPYD_CAP_LARGE_SEEK 2    /* large seeks */
+
+enum FloppydOpcodes {
+       OP_READ,
+       OP_WRITE,
+       OP_SEEK,
+       OP_FLUSH,
+       OP_CLOSE,
+       OP_IOCTL,
+       OP_OPRO,
+       OP_OPRW
+};
+
+enum AuthErrorsEnum {
+       AUTH_SUCCESS,
+       AUTH_PACKETOVERSIZE,
+       AUTH_AUTHFAILED,
+       AUTH_WRONGVERSION,
+       AUTH_DEVLOCKED,
+       AUTH_BADPACKET,
+       AUTH_IO_ERROR
+};
+
+typedef unsigned long IPaddr_t;
+
+#endif
+#endif
diff --git a/force_io.c b/force_io.c
new file mode 100644 (file)
index 0000000..006d315
--- /dev/null
@@ -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 (file)
index 0000000..65cf466
--- /dev/null
+++ b/fs.h
@@ -0,0 +1,43 @@
+#ifndef MTOOLS_FS_H
+#define MTOOLS_FS_H
+
+/*  Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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;
+       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 (file)
index 0000000..98f73bb
--- /dev/null
+++ b/fsP.h
@@ -0,0 +1,103 @@
+#ifndef MTOOLS_FSP_H
+#define MTOOLS_FSP_H
+
+/*  Copyright 1996-1999,2001-2003,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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, int fat_bits,
+                        size_t tot_sectors, int nodups);
+void fat_write(Fs_t *This);
+int zero_fat(Fs_t *Fs, int media_descriptor);
+extern Class_t FsClass;
+int fsPreallocateClusters(Fs_t *Fs, long);
+Fs_t *getFs(Stream_t *Stream);
+
+
+#endif
diff --git a/hash.c b/hash.c
new file mode 100644 (file)
index 0000000..ba56287
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,220 @@
+/*  Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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;
+  int size;  /* actual size of the array */
+  int fill;  /* number of deleted or in use slots */
+  int inuse; /* number of slots in use */
+  int max;   /* maximal number of elements to keep efficient */
+  T_HashTableEl *entries;
+};
+
+static int sizes[]={5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853,
+                   25717, 51437, 102877, 205759, 411527, 823117, 1646237,
+                   3292489, 6584983, 13169977, 26339969, 52679969, 105359939,
+                   210719881, 421439783, 842879579, 1685759167, 0 };
+static int deleted=0;
+static int unallocated=0;
+
+static int alloc_ht(T_HashTable *H, int size)
+{
+  int i;
+
+  for(i=0; sizes[i]; i++)
+    if (sizes[i] > size*4 )
+      break;
+  if (!sizes[i])
+    for(i=0; sizes[i]; i++)
+      if (sizes[i] > size*2 )
+       break;
+  if (!sizes[i])
+    for(i=0; sizes[i]; i++)
+      if (sizes[i] > size)
+       break;
+  if(!sizes[i])
+    return -1;
+  size = sizes[i];
+  if(size < H->size)
+         size = H->size; /* never shrink the table */
+  H->max = size * 4 / 5 - 2;
+  H->size = size;
+  H->fill = 0;
+  H->inuse = 0;
+  H->entries = NewArray(size, T_HashTableEl);
+  if (H->entries == NULL)
+    return -1; /* out of memory error */
+  
+  for(i=0; i < size; i++)
+    H->entries[i] = &unallocated;
+  return 0;
+}
+
+int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size,
+           T_HashTable **H)
+{
+  *H = New(T_HashTable);
+  if (*H == NULL){
+    return -1; /* out of memory error */
+  }
+  
+  (*H)->f1 = f1;
+  (*H)->f2 = f2;
+  (*H)->compar = c;
+  (*H)->size = 0;
+  if(alloc_ht(*H,size))
+    return -1;
+  return 0;
+}
+
+int free_ht(T_HashTable *H, T_HashFunc entry_free)
+{
+  int i;
+  if(entry_free)
+    for(i=0; i< H->size; i++)
+      if (H->entries[i] != &unallocated &&
+         H->entries[i] != &deleted)
+       entry_free(H->entries[i]);
+  Free(H->entries);
+  Free(H);
+  return 0;
+}
+
+/* add into hash table without checking for repeats */
+static int _hash_add(T_HashTable *H,T_HashTableEl *E, int *hint)
+{
+  int f2, pos, ctr;
+
+  pos = H->f1(E) % H->size;
+  f2 = -1;
+  ctr = 0;
+  while(H->entries[pos] != &unallocated &&
+       H->entries[pos] != &deleted){
+    if (f2 == -1)
+      f2 = H->f2(E) % (H->size - 1);
+    pos = (pos+f2+1) % H->size;
+    ctr++;
+  }
+  if(H->entries[pos] == &unallocated)
+     H->fill++; /* only increase fill if the previous element was not yet
+                * counted, i.e. unallocated */
+  H->inuse++;
+  H->entries[pos] = E;
+  if(hint)
+         *hint = pos;
+  return 0;
+}
+
+static int rehash(T_HashTable *H)
+{
+  int size,i;
+  T_HashTableEl *oldentries;
+  /* resize the table */
+  
+  size = H->size;
+  oldentries = H->entries;
+  if(alloc_ht(H,((H->inuse+1)*4+H->fill)/5))
+         return -1;
+
+  for(i=0; i < size; i++){
+    if(oldentries[i] != &unallocated && oldentries[i] != &deleted)
+      _hash_add(H, oldentries[i], 0);
+  }
+  Free(oldentries);
+  return 0;
+}
+
+int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint)
+{
+  if (H->fill >= H->max)
+    rehash(H);
+  if (H->fill == H->size)
+    return -1; /*out of memory error */
+  return _hash_add(H,E, hint);
+}
+
+
+/* add into hash table without checking for repeats */
+static int _hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2,
+                       int *hint, int isIdentity)
+{
+  int f2, pos, upos, ttl;
+
+  pos = H->f1(E) % H->size;
+  ttl = H->size;
+  f2 = -1;
+  upos = -1;
+  while(ttl &&
+       H->entries[pos] != &unallocated &&
+       (H->entries[pos] == &deleted ||
+        ((isIdentity || H->compar(H->entries[pos], E) != 0) &&
+         (!isIdentity || H->entries[pos] != E)))){
+    if (f2 == -1)
+      f2 = H->f2(E) % (H->size - 1);
+    if (upos == -1 && H->entries[pos] == &deleted)
+      upos = pos;
+    pos = (pos+f2+1) % H->size;
+    ttl--;
+  }
+  if(H->entries[pos] == &unallocated || !ttl)
+    return -1;
+  if (upos != -1){
+    H->entries[upos] = H->entries[pos];
+    H->entries[pos] = &deleted;
+    pos = upos;
+  }
+  if(hint)
+    *hint = pos;
+  *E2= H->entries[pos];
+  return 0;
+}
+
+
+int hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2,
+               int *hint)
+{
+       return _hash_lookup(H, E, E2, hint, 0);
+}
+
+/* add into hash table without checking for repeats */
+int hash_remove(T_HashTable *H,T_HashTableEl *E, int hint)
+{
+  T_HashTableEl *E2;
+
+  if (hint >=0 && hint < H->size &&
+      H->entries[hint] == E){
+    H->inuse--;
+    H->entries[hint] = &deleted;
+    return 0;
+  }
+
+  if(_hash_lookup(H, E, &E2, &hint, 1)) {
+         fprintf(stderr, "Removing non-existent entry\n");
+         exit(1);
+         return -1;
+  }
+  H->inuse--;
+  H->entries[hint] = &deleted;
+  return 0;
+}
diff --git a/htable.h b/htable.h
new file mode 100644 (file)
index 0000000..576a2b7
--- /dev/null
+++ b/htable.h
@@ -0,0 +1,32 @@
+/*  Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * hashtable
+ */
+
+typedef struct hashtable T_HashTable;
+typedef void *T_HashTableEl;
+typedef unsigned int (*T_HashFunc)(void *);
+typedef int (*T_ComparFunc)(void *, void *);
+
+
+int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, T_HashTable **H);
+int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint);
+int hash_remove(T_HashTable *H, T_HashTableEl *E, int hint);
+int hash_lookup(T_HashTable *H, T_HashTableEl *E, T_HashTableEl **E2,
+               int *hint);
+int free_ht(T_HashTable *H, T_HashFunc entry_free);
+
diff --git a/init.c b/init.c
new file mode 100644 (file)
index 0000000..b495f48
--- /dev/null
+++ b/init.c
@@ -0,0 +1,424 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-2002,2006-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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
+
+unsigned int num_clus;                 /* total number of cluster */
+
+
+/*
+ * Read the boot sector.  We glean the disk parameters from this sector.
+ */
+static int read_boot(Stream_t *Stream, union bootsector * boot, int size)
+{      
+       /* read the first sector, or part of it */
+       if(!size)
+               size = BOOTSIZE;
+       if(size > MAX_BOOT)
+               size = MAX_BOOT;
+
+       if (force_read(Stream, boot->characters, 0, size) != size)
+               return -1;
+       return 0;
+}
+
+static int fs_flush(Stream_t *Stream)
+{
+       DeclareThis(Fs_t);
+
+       fat_write(This);
+       return 0;
+}
+
+static doscp_t *get_dosConvert(Stream_t *Stream)
+{
+  DeclareThis(Fs_t);
+  return This->cp;
+}
+
+Class_t FsClass = {
+       read_pass_through, /* read */
+       write_pass_through, /* write */
+       fs_flush, 
+       fs_free, /* free */
+       0, /* set geometry */
+       get_data_pass_through,
+       0, /* pre allocate */
+       get_dosConvert, /* dosconvert */
+};
+
+static int get_media_type(Stream_t *St, union bootsector *boot)
+{
+       int media;
+
+       media = boot->boot.descr;
+       if(media < 0xf0){
+               char temp[512];
+               /* old DOS disk. Media descriptor in the first FAT byte */
+               /* old DOS disk always have 512-byte sectors */
+               if (force_read(St,temp,(mt_off_t) 512,512) == 512)
+                       media = (unsigned char) temp[0];
+               else
+                       media = 0;
+       } else
+               media += 0x100;
+       return media;
+}
+
+
+Stream_t *GetFs(Stream_t *Fs)
+{
+       while(Fs && Fs->Class != &FsClass)
+               Fs = Fs->Next;
+       return Fs;
+}
+
+Stream_t *find_device(char drive, int mode, struct device *out_dev,
+                     union bootsector *boot,
+                     char *name, int *media, mt_size_t *maxSize,
+                     int *isRop)
+{
+       char errmsg[200];
+       Stream_t *Stream;
+       struct device *dev;
+       int r;
+       int isRo=0;
+
+       Stream = NULL;
+       sprintf(errmsg, "Drive '%c:' not supported", drive);    
+                                       /* open the device */
+       for (dev=devices; dev->name; dev++) {
+               FREE(&Stream);
+               if (dev->drive != drive)
+                       continue;
+               *out_dev = *dev;
+               expand(dev->name,name);
+#ifdef USING_NEW_VOLD
+               strcpy(name, getVoldName(dev, name));
+#endif
+
+               Stream = 0;
+               if(out_dev->misc_flags & FLOPPYD_FLAG) {
+                   Stream = 0;
+#ifdef USE_FLOPPYD
+                   Stream = FloppydOpen(out_dev, dev, name, mode,
+                                        errmsg, 0, 1);
+                   if(Stream && maxSize)
+                       *maxSize = max_off_t_31;
+#endif
+               } else {
+
+#ifdef USE_XDF
+                   Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
+                   if(Stream) {
+                       out_dev->use_2m = 0x7f;
+                       if(maxSize)
+                           *maxSize = max_off_t_31;
+                   }
+#endif
+
+               
+                   if (!Stream)
+                       Stream = SimpleFileOpen(out_dev, dev, name,
+                                               isRop ? mode | O_RDWR: mode,
+                                               errmsg, 0, 1, maxSize);
+               
+                   if(Stream) {
+                       isRo=0;
+                   } else if(isRop &&
+                      (errno == EPERM || errno == EACCES || errno == EROFS)) {
+                       Stream = SimpleFileOpen(out_dev, dev, name,
+                                               mode | O_RDONLY,
+                                               errmsg, 0, 1, maxSize);
+                       if(Stream) {
+                               isRo=1;
+                       }
+                   }
+               }
+
+               if( !Stream)
+                   continue;
+
+               /* read the boot sector */
+               if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
+                       sprintf(errmsg,
+                               "init %c: could not read boot sector",
+                               drive);
+                       continue;
+               }
+
+               if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
+                       if (boot->boot.jump[2]=='L')
+                               sprintf(errmsg,
+                                       "diskette %c: is Linux LILO, not DOS",
+                                       drive);
+                       else
+                               sprintf(errmsg,"init %c: non DOS media", drive);
+                       continue;
+               }
+
+               /* set new parameters, if needed */
+               errno = 0;
+               if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
+                       if(errno)
+#ifdef HAVE_SNPRINTF
+                               snprintf(errmsg, 199,
+                                       "Can't set disk parameters for %c: %s",
+                                       drive, strerror(errno));
+#else
+                               sprintf(errmsg,
+                                       "Can't set disk parameters for %c: %s",
+                                       drive, strerror(errno));
+#endif
+                       else
+                               sprintf(errmsg,
+                                       "Can't set disk parameters for %c",
+                                       drive);
+                       continue;
+               }
+               break;
+       }
+
+       /* print error msg if needed */ 
+       if ( dev->drive == 0 ){
+               FREE(&Stream);
+               fprintf(stderr,"%s\n",errmsg);
+               return NULL;
+       }
+       if(isRop)
+               *isRop = isRo;
+       return Stream;
+}
+
+
+Stream_t *fs_init(char drive, int mode, int *isRop)
+{
+       int blocksize;
+       int media,i;
+       int nhs;
+       int disk_size = 0;      /* In case we don't happen to set this below */
+       size_t tot_sectors;
+       char name[EXPAND_BUF];
+       int cylinder_size;
+       struct device dev;
+       mt_size_t maxSize;
+
+       union bootsector boot;
+
+       Fs_t *This;
+
+       This = New(Fs_t);
+       if (!This)
+               return NULL;
+
+       This->Direct = NULL;
+       This->Next = NULL;
+       This->refs = 1;
+       This->Buffer = 0;
+       This->Class = &FsClass;
+       This->preallocatedClusters = 0;
+       This->lastFatSectorNr = 0;
+       This->lastFatAccessMode = 0;
+       This->lastFatSectorData = 0;
+       This->drive = drive;
+       This->last = 0;
+
+       This->Direct = find_device(drive, mode, &dev, &boot, name, &media,
+                                  &maxSize, isRop);
+       if(!This->Direct)
+               return NULL;
+       
+       This->sector_size = WORD_S(secsiz);
+       if(This->sector_size > MAX_SECTOR){
+               fprintf(stderr,"init %c: sector size too big\n", drive);
+               return NULL;
+       }
+
+       i = log_2(This->sector_size);
+
+       if(i == 24) {
+               fprintf(stderr,
+                       "init %c: sector size (%d) not a small power of two\n",
+                       drive, This->sector_size);
+               return NULL;
+       }
+       This->sectorShift = i;
+       This->sectorMask = This->sector_size - 1;
+
+
+       cylinder_size = dev.heads * dev.sectors;
+       This->serialized = 0;
+       if ((media & ~7) == 0xf8){
+               i = media & 3;
+               This->cluster_size = old_dos[i].cluster_size;
+               tot_sectors = cylinder_size * old_dos[i].tracks;
+               This->fat_start = 1;
+               This->fat_len = old_dos[i].fat_len;
+               This->dir_len = old_dos[i].dir_len;
+               This->num_fat = 2;
+               This->sector_size = 512;
+               This->sectorShift = 9;
+               This->sectorMask = 511;
+               This->fat_bits = 12;
+               nhs = 0;
+       } else {
+               struct label_blk_t *labelBlock;
+               /*
+                * all numbers are in sectors, except num_clus
+                * (which is in clusters)
+                */
+               tot_sectors = WORD_S(psect);
+               if(!tot_sectors) {
+                       tot_sectors = DWORD_S(bigsect);                 
+                       nhs = DWORD_S(nhs);
+               } else
+                       nhs = WORD_S(nhs);
+
+
+               This->cluster_size = boot.boot.clsiz;           
+               This->fat_start = WORD_S(nrsvsect);
+               This->fat_len = WORD_S(fatlen);
+               This->dir_len = WORD_S(dirents) * MDIR_SIZE / This->sector_size;
+               This->num_fat = boot.boot.nfat;
+
+               if (This->fat_len) {
+                       labelBlock = &boot.boot.ext.old.labelBlock;
+               } else {
+                       labelBlock = &boot.boot.ext.fat32.labelBlock;
+               }
+
+               if(labelBlock->dos4 == 0x29) {
+                       This->serialized = 1;
+                       This->serial_number = _DWORD(labelBlock->serial);
+               }
+       }
+
+       if (tot_sectors >= (maxSize >> This->sectorShift)) {
+               fprintf(stderr, "Big disks not supported on this architecture\n");
+               exit(1);
+       }
+
+       if(!mtools_skip_check && (tot_sectors % dev.sectors)){
+               fprintf(stderr,
+                       "Total number of sectors (%d) not a multiple of"
+                       " sectors per track (%d)!\n", (int) tot_sectors,
+                       dev.sectors);
+               fprintf(stderr,
+                       "Add mtools_skip_check=1 to your .mtoolsrc file "
+                       "to skip this test\n");
+               exit(1);
+       }
+
+       /* full cylinder buffering */
+#ifdef FULL_CYL
+       disk_size = (dev.tracks) ? cylinder_size : 512;
+#else /* FULL_CYL */
+       disk_size = (dev.tracks) ? dev.sectors : 512;
+#endif /* FULL_CYL */
+
+#if (defined OS_sysv4 && !defined OS_solaris)
+       /*
+        * The driver in Dell's SVR4 v2.01 is unreliable with large writes.
+        */
+        disk_size = 0;
+#endif /* (defined sysv4 && !defined(solaris)) */
+
+#ifdef OS_linux
+       disk_size = cylinder_size;
+#endif
+
+#if 1
+       if(disk_size > 256) {
+               disk_size = dev.sectors;
+               if(dev.sectors % 2)
+                       disk_size <<= 1;
+       }
+#endif
+       if (disk_size % 2)
+               disk_size *= 2;
+
+       if(!dev.blocksize || dev.blocksize < This->sector_size)
+               blocksize = This->sector_size;
+       else
+               blocksize = dev.blocksize;
+       if (disk_size)
+               This->Next = buf_init(This->Direct,
+                                     8 * disk_size * blocksize,
+                                     disk_size * blocksize,
+                                     This->sector_size);
+       else
+               This->Next = This->Direct;
+
+       if (This->Next == NULL) {
+               perror("init: allocate buffer");
+               This->Next = This->Direct;
+       }
+
+       /* read the FAT sectors */
+       if(fat_read(This, &boot, dev.fat_bits, tot_sectors, dev.use_2m&0x7f)){
+               This->num_fat = 1;
+               FREE(&This->Next);
+               Free(This->Next);
+               return NULL;
+       }
+
+       /* Set the codepage */
+       This->cp = cp_open(dev.codepage);
+       if(This->cp == NULL) {
+               fs_free((Stream_t *)This);
+               FREE(&This->Next);
+               Free(This->Next);
+               return NULL;
+       }
+
+       return (Stream_t *) This;
+}
+
+char getDrive(Stream_t *Stream)
+{
+       DeclareThis(Fs_t);
+
+       if(This->Class != &FsClass)
+               return getDrive(GetFs(Stream));
+       else
+               return This->drive;
+}
+
+int fsPreallocateClusters(Fs_t *Fs, long size)
+{
+       if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
+               return -1;
+
+       Fs->preallocatedClusters += size;
+       return 0;
+}
diff --git a/install-sh b/install-sh
new file mode 100755 (executable)
index 0000000..89fc9b0
--- /dev/null
@@ -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 (file)
index 0000000..a1eaeec
--- /dev/null
+++ b/llong.c
@@ -0,0 +1,96 @@
+/*  Copyright 1999-2003,2006,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 */
+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 (file)
index 0000000..6be3e9d
--- /dev/null
+++ b/llong.h
@@ -0,0 +1,115 @@
+#ifndef MTOOLS_LLONG_H
+#define MTOOLS_LLONG_H
+
+/*  Copyright 1999,2001-2004,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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
+#define MT_SIZE_T size_t
+#endif
+
+#ifndef MT_OFF_T
+# if defined(HAVE_LLSEEK) || defined(HAVE_LSEEK64)
+/* we have llseek. Now, what's its type called? loff_t or offset_t ? */
+#  ifdef HAVE_LOFF_T
+#   define MT_OFF_T loff_t
+/* use the same type for size. Better to get signedness wrong than width */
+#   define MT_SIZE_T loff_t
+#  else
+#   ifdef HAVE_OFFSET_T
+#    define MT_OFF_T offset_t
+/* use the same type for size. Better to get signedness wrong than width */
+#    define MT_SIZE_T offset_t
+#   endif
+#  endif
+# endif
+#endif
+
+#ifndef MT_OFF_T
+/* we still don't have a suitable mt_off_t type...*/
+# ifdef HAVE_LONG_LONG
+/* ... first try long long ... */
+#  define MT_OFF_T long long
+#  define MT_SIZE_T unsigned long long
+# else
+#  ifdef HAVE_OFF64_T
+#   define MT_OFF_T off64_t
+#   define MT_SIZE_T off64_t
+#  else
+/* ... and if that fails, fall back on good ole' off_t */
+#   define MT_OFF_T off_t
+#   define MT_SIZE_T size_t
+#  endif
+# endif
+#endif
+
+typedef MT_OFF_T mt_off_t;
+typedef MT_SIZE_T mt_size_t;
+
+#else
+/* testing: meant to flag dubious assignments between 32 bit length types
+ * and 64 bit ones */
+typedef struct {
+       unsigned int lo;
+       int high;
+} *mt_off_t;
+
+typedef struct {
+       unsigned int lo;
+       unsigned int high;
+} *mt_size_t;
+
+#endif
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define MAX_OFF_T_B(bits) \
+       ((((mt_off_t) 1 << min(bits-1, sizeof(mt_off_t)*8 - 2)) -1) << 1 | 1)
+
+#if defined(HAVE_LLSEEK) || defined(HAVE_LSEEK64)
+# define SEEK_BITS 63
+#else
+# define SEEK_BITS (sizeof(off_t) * 8 - 1)
+#endif
+
+extern const mt_off_t max_off_t_31;
+extern const mt_off_t max_off_t_41;
+extern const mt_off_t max_off_t_seek;
+
+extern off_t truncBytes32(mt_off_t off);
+extern int fileTooBig(mt_off_t off);
+mt_off_t sectorsToBytes(Stream_t *This, off_t off);
+
+mt_size_t getfree(Stream_t *Stream);
+int getfreeMinBytes(Stream_t *Stream, mt_size_t ref);
+
+Stream_t *find_device(char drive, int mode, struct device *out_dev,
+                     union bootsector *boot,
+                     char *name, int *media, mt_size_t *maxSize,
+                     int *isRop);
+
+int mt_lseek(int fd, mt_off_t where, int whence);
+
+
+unsigned int log_2(int);
+
+#endif
diff --git a/lockdev.h b/lockdev.h
new file mode 100644 (file)
index 0000000..4467bc2
--- /dev/null
+++ b/lockdev.h
@@ -0,0 +1,77 @@
+#ifndef LOCK_DEV
+#define LOCK_DEV
+
+/*  Copyright 2005,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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.
+ */
+
+int lock_dev(int fd, int mode, struct device *dev)
+{
+#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
+       /**/
+#else /* FLOCK */
+
+#if (defined(HAVE_LOCKF) && defined(F_TLOCK))
+       /**/
+#else /* LOCKF */
+
+#if (defined(F_SETLK) && defined(F_WRLCK))
+       struct flock flk;
+
+#endif /* FCNTL */
+#endif /* LOCKF */
+#endif /* FLOCK */
+
+       if(IS_NOLOCK(dev))
+               return 0;
+
+#if (defined(HAVE_FLOCK) && defined (LOCK_EX) && defined(LOCK_NB))
+       if (flock(fd, (mode ? LOCK_EX : LOCK_SH)|LOCK_NB) < 0)
+#else /* FLOCK */
+
+#if (defined(HAVE_LOCKF) && defined(F_TLOCK))
+       if (mode && lockf(fd, F_TLOCK, 0) < 0)
+#else /* LOCKF */
+
+#if (defined(F_SETLK) && defined(F_WRLCK))
+       flk.l_type = mode ? F_WRLCK : F_RDLCK;
+       flk.l_whence = 0;
+       flk.l_start = 0L;
+       flk.l_len = 0L;
+
+       if (fcntl(fd, F_SETLK, &flk) < 0)
+#endif /* FCNTL */
+#endif /* LOCKF */
+#endif /* FLOCK */
+       {
+               if(errno == EINVAL
+#ifdef  EOPNOTSUPP 
+                  || errno ==  EOPNOTSUPP
+#endif
+                 )
+                       return 0;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+
+#endif
diff --git a/mainloop.c b/mainloop.c
new file mode 100644 (file)
index 0000000..4218edd
--- /dev/null
@@ -0,0 +1,669 @@
+/*  Copyright 1997-2002,2005-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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] == ':') {
+               strncpy(ans, buf, 2);
+               ans[2] = '\0';
+               s = &buf[2];
+       } else {
+               ans[0] = get_default_drive();
+               strcpy(ans+1, ":");
+       }
+                       /* add a leading separator */
+       if (*s != '/' && *s != '\\') {
+               strcat(ans, "/");
+               strcat(ans, s);
+       } else
+               strcat(ans, s);
+
+#if 0
+                                       /* translate to upper case */
+       for (s = ans; *s; ++s) {
+               *s = toupper(*s);
+               if (*s == '\\')
+                       *s = '/';
+       }
+#endif
+                                       /* if only drive, colon, & separator */
+       if (strlen(ans) == 3)
+               return(ans);
+                                       /* zap the trailing separator */
+       if (*--s == '/')
+               *s = '\0';
+       return ans;
+}
+
+int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); 
+int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg,
+             int follow_dir_link);
+
+static int _unix_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
+{
+       return unix_dir_loop(Dir, mp);
+}
+
+int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, int follow_dir_link)
+{
+       int ret;
+       int isdir;
+       int unixNameLength;
+
+       mp->File = NULL;
+       mp->direntry = NULL;
+       unixNameLength = strlen(arg);
+       if(unixNameLength > 1 && arg[unixNameLength-1] == '/') {
+           /* names ending in slash, and having at least two characters */
+           char *name = strdup(arg);
+           name[unixNameLength-1]='\0';
+           mp->unixSourceName = name;
+       } else {
+           mp->unixSourceName = arg;
+       }
+       /*      mp->dir.attr = ATTR_ARCHIVE;*/
+       mp->loop = _unix_loop;
+       if((mp->lookupflags & DO_OPEN)){
+               mp->File = SimpleFileOpen(0, 0, arg, O_RDONLY, 0, 0, 0, 0);
+               if(!mp->File){
+                       perror(arg);
+#if 0
+                       tmp = _basename(arg);
+                       strncpy(mp->filename, tmp, VBUFSIZE);
+                       mp->filename[VBUFSIZE-1] = '\0';
+#endif
+                       return ERROR_ONE;
+               }
+               GET_DATA(mp->File, 0, 0, &isdir, 0);
+               if(isdir) {
+#if !defined(__EMX__) && !defined(OS_mingw32msvc)
+                       struct MT_STAT buf;
+#endif
+
+                       FREE(&mp->File);
+#if !defined(__EMX__) && !defined(OS_mingw32msvc)
+                       if(!follow_dir_link &&
+                          MT_LSTAT(arg, &buf) == 0 &&
+                          S_ISLNK(buf.st_mode)) {
+                               /* skip links to directories in order to avoid
+                                * infinite loops */
+                               fprintf(stderr,
+                                       "skipping directory symlink %s\n",
+                                       arg);
+                               return 0;                               
+                       }
+#endif
+                       if(! (mp->lookupflags & ACCEPT_DIR))
+                               return 0;
+                       mp->File = OpenDir(Stream, arg);
+               }
+       }
+
+       if(isdir)
+               ret = mp->dirCallback(0, mp);
+       else
+               ret = mp->unixcallback(mp);
+       FREE(&mp->File);
+       return ret;
+}
+
+
+int isSpecial(const char *name)
+{
+       if(name[0] == '\0')
+               return 1;
+       if(!strcmp(name,"."))
+               return 1;
+       if(!strcmp(name,".."))
+               return 1;
+       return 0;                       
+}
+
+#ifdef HAVE_WCHAR_H
+int isSpecialW(const wchar_t *name)
+{
+       if(name[0] == '\0')
+               return 1;
+       if(!wcscmp(name,L"."))
+               return 1;
+       if(!wcscmp(name,L".."))
+               return 1;
+       return 0;                       
+}
+#endif
+
+static int checkForDot(int lookupflags, const wchar_t *name)
+{
+       return (lookupflags & NO_DOTS) && isSpecialW(name);
+}
+
+
+typedef struct lookupState_t {
+       Stream_t *container;
+       int nbContainers;
+       Stream_t *Dir;
+       int nbDirs;
+       const char *filename;
+} lookupState_t;
+
+static int isUniqueTarget(const char *name)
+{
+       return name && strcmp(name, "-");
+}
+
+static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
+                      lookupState_t *lookupState)
+{
+       Stream_t *MyFile=0;
+       int ret;
+
+       if(got_signal)
+               return ERROR_ONE;
+       if(lookupState) {
+               /* we are looking for a "target" file */
+               switch(lookupState->nbDirs) {
+                       case 0: /* no directory yet, open it */
+                               lookupState->Dir = OpenFileByDirentry(direntry);
+                               lookupState->nbDirs++;
+                               /* dump the container, we have
+                                * better now */
+                               FREE(&lookupState->container);
+                               return 0;
+                       case 1: /* we have already a directory */
+                               FREE(&lookupState->Dir);
+                               fprintf(stderr,"Ambigous\n");
+                               return STOP_NOW | ERROR_ONE;
+                       default:
+                               return STOP_NOW | ERROR_ONE;
+               }
+       }
+
+       mp->direntry = direntry;
+       if(IS_DIR(direntry)) {
+               if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
+                       MyFile = mp->File = OpenFileByDirentry(direntry);
+               ret = mp->dirCallback(direntry, mp);
+       } else {
+               if(mp->lookupflags & DO_OPEN)
+                       MyFile = mp->File = OpenFileByDirentry(direntry);
+               ret = mp->callback(direntry, mp);
+       }
+       FREE(&MyFile);
+       if(isUniqueTarget(mp->targetName))
+               ret |= STOP_NOW;
+       return ret;
+}
+
+static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
+{      
+       Stream_t *MyFile=0;
+       direntry_t entry;
+       int ret;
+       int r;
+
+       ret = 0;
+       r=0;
+       initializeDirentry(&entry, Dir);
+       while(!got_signal &&
+             (r=vfat_lookup(&entry, filename, -1,
+                            mp->lookupflags, mp->shortname,
+                            mp->longname)) == 0 ){
+               mp->File = NULL;
+               if(!checkForDot(mp->lookupflags,entry.name)) {
+                       MyFile = 0;
+                       if((mp->lookupflags & DO_OPEN) ||
+                          (IS_DIR(&entry) &&
+                           (mp->lookupflags & DO_OPEN_DIRS))) {
+                               MyFile = mp->File = OpenFileByDirentry(&entry);
+                       }
+                       if(got_signal)
+                               break;
+                       mp->direntry = &entry;
+                       if(IS_DIR(&entry))
+                               ret |= mp->dirCallback(&entry,mp);
+                       else
+                               ret |= mp->callback(&entry, mp);
+                       FREE(&MyFile);
+               }
+               if (fat_error(Dir))
+                       ret |= ERROR_ONE;
+               if(mp->fast_quit && (ret & ERROR_ONE))
+                       break;
+       }
+       if (r == -2)
+           return ERROR_ONE;
+       if(got_signal)
+               ret |= ERROR_ONE;
+       return ret;
+}
+
+static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
+                          const char *filename1,
+                          lookupState_t *lookupState)
+{
+       /* Dir is de-allocated by the same entity which allocated it */
+       const char *ptr;
+       direntry_t entry;
+       int length;
+       int lookupflags;
+       int ret;
+       int have_one;
+       int doing_mcwd;
+       int r;
+
+       while(1) {
+               /* strip dots and / */
+               if(!strncmp(filename0,"./", 2)) {
+                       filename0 += 2;
+                       continue;
+               }
+               if(!strcmp(filename0,".") && filename1) {
+                       filename0 ++;
+                       continue;
+               }
+               if(filename0[0] == '/') {
+                       filename0++;
+                       continue;
+               }
+               if(!filename0[0]) {
+                       if(!filename1)
+                               break;
+                       filename0 = filename1;
+                       filename1 = 0;
+                       continue;
+               }
+               break;
+       }
+
+       if(!strncmp(filename0,"../", 3) ||
+          (!strcmp(filename0, "..") && filename1)) {
+               /* up one level */
+               mp->File = getDirentry(mp->File)->Dir;
+               return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
+       }
+
+       doing_mcwd = !!filename1;
+
+       ptr = strchr(filename0, '/');
+       if(!ptr) {                      
+               length = strlen(filename0);             
+               ptr = filename1;
+               filename1 = 0;
+       } else {
+               length = ptr - filename0;
+               ptr++;
+       }
+       if(!ptr) {
+               if(mp->lookupflags & OPEN_PARENT) {
+                       mp->targetName = filename0;
+                       ret = handle_leaf(getDirentry(mp->File), mp,
+                                         lookupState);
+                       mp->targetName = 0;
+                       return ret;
+               }
+               
+               if(!strcmp(filename0, ".") || !filename0[0]) {
+                       return handle_leaf(getDirentry(mp->File),
+                                          mp, lookupState);
+               }
+
+               if(!strcmp(filename0, "..")) {
+                       return handle_leaf(getParent(getDirentry(mp->File)), mp,
+                                          lookupState);
+               }
+
+               lookupflags = mp->lookupflags;
+               
+               if(lookupState) {
+                       lookupState->filename = filename0;
+                       if(lookupState->nbContainers + lookupState->nbDirs > 0){
+                               /* we have already one target, don't bother
+                                * with this one. */
+                               FREE(&lookupState->container);
+                       } else {
+                               /* no match yet.  Remember this container for
+                                * later use */
+                               lookupState->container = COPY(mp->File);
+                       }
+                       lookupState->nbContainers++;
+               }
+       } else
+               lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
+
+       ret = 0;
+       r = 0;
+       have_one = 0;
+       initializeDirentry(&entry, mp->File);
+       while(!(ret & STOP_NOW) &&
+             !got_signal &&
+             (r=vfat_lookup(&entry, filename0, length,
+                            lookupflags | NO_MSG,
+                            mp->shortname, mp->longname)) == 0 ){
+               if(checkForDot(lookupflags, entry.name))
+                       /* while following the path, ignore the
+                        * special entries if they were not
+                        * explicitly given */
+                       continue;
+               have_one = 1;
+               if(ptr) {
+                       Stream_t *SubDir;
+                       SubDir = mp->File = OpenFileByDirentry(&entry);
+                       ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
+                       FREE(&SubDir);
+               } else {
+                       ret |= handle_leaf(&entry, mp, lookupState);
+                       if(isUniqueTarget(mp->targetName))
+                               return ret | STOP_NOW;
+               }
+               if(doing_mcwd)
+                       break;
+       }
+       if (r == -2)
+               return ERROR_ONE;
+       if(got_signal)
+               return ret | ERROR_ONE;
+       if(doing_mcwd && !have_one)
+               return NO_CWD;
+       return ret;
+}
+
+static int common_dos_loop(MainParam_t *mp, const char *pathname,
+                          lookupState_t *lookupState, int open_mode)
+
+{
+       Stream_t *RootDir;
+       const char *cwd;
+       char drive;
+
+       int ret;
+       mp->loop = _dos_loop;
+       
+       drive='\0';
+       cwd = "";
+       if(*pathname && pathname[1] == ':') {
+               drive = toupper(*pathname);
+               pathname += 2;
+               if(mp->mcwd[0] == drive)
+                       cwd = mp->mcwd+2;
+       } else if(mp->mcwd[0]) {
+               drive = mp->mcwd[0];
+               cwd = mp->mcwd+2;
+       } else {
+               drive = get_default_drive();
+       }
+
+       if(*pathname=='/') /* absolute path name */
+               cwd = "";
+
+       RootDir = mp->File = open_root_dir(drive, open_mode, NULL);
+       if(!mp->File)
+               return ERROR_ONE;
+
+       ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
+       if(ret & NO_CWD) {
+               /* no CWD */
+               *mp->mcwd = '\0';
+               unlink_mcwd();
+               ret = recurs_dos_loop(mp, "", pathname, lookupState);
+       }
+       FREE(&RootDir);
+       return ret;
+}
+
+static int dos_loop(MainParam_t *mp, const char *arg)
+{
+       return common_dos_loop(mp, arg, 0, mp->openflags);
+}
+
+
+static int dos_target_lookup(MainParam_t *mp, const char *arg)
+{
+       lookupState_t lookupState;
+       int ret;
+       int lookupflags;
+
+       lookupState.nbDirs = 0;
+       lookupState.Dir = 0;
+       lookupState.nbContainers = 0;
+       lookupState.container = 0;
+
+       lookupflags = mp->lookupflags;
+       mp->lookupflags = DO_OPEN | ACCEPT_DIR;
+       ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
+       mp->lookupflags = lookupflags;
+       if(ret & ERROR_ONE)
+               return ret;
+
+       if(lookupState.nbDirs) {
+               mp->targetName = 0;
+               mp->targetDir = lookupState.Dir;
+               FREE(&lookupState.container); /* container no longer needed */
+               return ret;
+       }
+
+       switch(lookupState.nbContainers) {
+               case 0:
+                       /* no match */
+                       fprintf(stderr,"%s: no match for target\n", arg);
+                       return MISSED_ONE;
+               case 1:
+                       mp->targetName = strdup(lookupState.filename);
+                       mp->targetDir = lookupState.container;
+                       return ret;
+               default:
+                       /* too much */
+                       fprintf(stderr, "Ambigous %s\n", arg);
+                       return ERROR_ONE;                       
+       }
+}
+
+static int unix_target_lookup(MainParam_t *mp, const char *arg)
+{
+       char *ptr;
+       mp->unixTarget = strdup(arg);
+       /* try complete filename */
+       if(access(mp->unixTarget, F_OK) == 0)
+               return GOT_ONE;
+       ptr = strrchr(mp->unixTarget, '/');
+       if(!ptr) {
+               mp->targetName = mp->unixTarget;
+               mp->unixTarget = strdup(".");
+               return GOT_ONE;
+       } else {
+               *ptr = '\0';
+               mp->targetName = ptr+1;
+               return GOT_ONE;
+       }
+}
+
+int target_lookup(MainParam_t *mp, const char *arg)
+{
+       if((mp->lookupflags & NO_UNIX) || (arg[0] && arg[1] == ':' ))
+               return dos_target_lookup(mp, arg);
+       else
+               return unix_target_lookup(mp, arg);
+}
+
+int main_loop(MainParam_t *mp, char **argv, int argc)
+{
+       int i;
+       int ret, Bret;
+       
+       Bret = 0;
+
+       if(argc != 1 && mp->targetName) {
+               fprintf(stderr,
+                       "Several file names given, but last argument (%s) not a directory\n", mp->targetName);
+       }
+
+       for (i = 0; i < argc; i++) {
+               if ( got_signal )
+                       break;
+               mp->originalArg = argv[i];
+               mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg),
+                                                 "*[?") != 0;
+               if (mp->unixcallback && (!argv[i][0]
+#ifdef OS_mingw32msvc
+/* On Windows, support only the command-line image drive. */
+                                         || argv[i][0] != ':'
+#endif
+                                         || argv[i][1] != ':' ))
+                       ret = unix_loop(0, mp, argv[i], 1);
+               else
+                       ret = dos_loop(mp, argv[i]);
+               
+               if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
+                       /* one argument was unmatched */
+                       fprintf(stderr, "%s: File \"%s\" not found\n",
+                               progname, argv[i]);
+                       ret |= ERROR_ONE;
+               }
+               Bret |= ret;
+               if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
+                       break;
+       }
+       FREE(&mp->targetDir);
+       if(Bret & ERROR_ONE)
+               return 1;
+       if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
+               return 2;
+       if (Bret & MISSED_ONE)
+               return 1;
+       return 0;
+}
+
+static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
+{
+       if(entry)
+               return mp->callback(entry, mp);
+       else
+               return mp->unixcallback(mp);
+}
+
+
+void init_mp(MainParam_t *mp)
+{
+       fix_mcwd(mp->mcwd);
+       mp->openflags = O_RDONLY;
+       mp->targetName = 0;
+       mp->targetDir = 0;
+       mp->unixTarget = 0;
+       mp->dirCallback = dispatchToFile;
+       mp->unixcallback = NULL;
+       mp->shortname = mp->longname = 0;
+       mp->File = 0;
+       mp->fast_quit = 0;
+}
+
+const char *mpGetBasename(MainParam_t *mp)
+{
+       if(mp->direntry) {
+               wchar_to_native(mp->direntry->name, mp->targetBuffer,
+                               MAX_VNAMELEN+1);
+               return mp->targetBuffer;
+       } else
+               return _basename(mp->unixSourceName);
+}
+
+void mpPrintFilename(FILE *fp, MainParam_t *mp)
+{
+       if(mp->direntry)
+               fprintPwd(fp, mp->direntry, 0);
+       else
+               fprintf(fp,"%s",mp->originalArg);
+}
+
+const char *mpPickTargetName(MainParam_t *mp)
+{
+       /* picks the target name: either the one explicitly given by the
+        * user, or the same as the source */
+       if(mp->targetName)
+               return mp->targetName;
+       else
+               return mpGetBasename(mp);
+}
+
+char *mpBuildUnixFilename(MainParam_t *mp)
+{
+       const char *target;
+       char *ret;
+       char *tmp;
+
+       target = mpPickTargetName(mp);
+       ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
+       if(!ret)
+               return 0;
+       strcpy(ret, mp->unixTarget);
+       if(*target) {
+#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
+               if(!mp->targetName && !mp->targetDir) {
+                       struct MT_STAT buf;
+                       if (!MT_STAT(ret, &buf) && !S_ISDIR(buf.st_mode))
+                               return ret;
+               }
+#endif
+               strcat(ret, "/");
+               if(!strcmp(target, ".")) {
+                 target="DOT";
+               } else if(!strcmp(target, "..")) {
+                 target="DOTDOT";
+               }
+               while( (tmp=strchr(target, '/')) ) {
+                 strncat(ret, target, tmp-target);
+                 strcat(ret, "\\");
+                 target=tmp+1;
+               }
+               strcat(ret, target);
+       }
+       return ret;
+}
diff --git a/mainloop.h b/mainloop.h
new file mode 100644 (file)
index 0000000..940c853
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef MTOOLS_MAINLOOP_H
+#define MTOOLS_MAINLOOP_H
+
+/*  Copyright 1997,2001,2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/param.h>
+#include "vfat.h"
+#include "mtoolsDirentry.h"
+
+typedef struct MainParam_t {
+       /* stuff needing to be initialised by the caller */
+       int (*loop)(Stream_t *Dir, struct MainParam_t *mp, 
+                   const char *filename);
+       int (*dirCallback)(direntry_t *, struct MainParam_t *);
+       int (*callback)(direntry_t *, struct MainParam_t *);
+       int (*unixcallback)(struct MainParam_t *mp);
+
+       void *arg; /* command-specific parameters
+                   * to be passed to callback */
+
+               int openflags; /* flags used to open disk */
+       int lookupflags; /* flags used to lookup up using vfat_lookup */
+       int fast_quit; /* for commands manipulating multiple files, quit
+                       * as soon as even _one_ file has a problem */
+
+       char *shortname; /* where to put the short name of the matched file */
+       char *longname; /* where to put the long name of the matched file */
+
+       /* out parameters */
+       Stream_t *File;
+
+       direntry_t *direntry;  /* dir of this entry */
+       char *unixSourceName;  /* filename of the last opened Unix source
+                               * file (Unix equiv of Dos direntry) */
+
+       Stream_t *targetDir; /* directory where to place files */
+       char *unixTarget; /* directory on Unix where to put files */
+
+       const char *targetName; /* basename of target file, or NULL if same
+                                * basename as source should be conserved */
+
+       char *originalArg; /* original argument, complete with wildcards */
+       int basenameHasWildcard; /* true if there are wildcards in the
+                                 * basename */
+
+
+       /* internal data */
+       char mcwd[MAX_PATH+4];
+
+       char *fileName; /* resolved Unix filename */
+
+       char targetBuffer[4*MAX_VNAMELEN+1]; /* buffer for target name */
+} MainParam_t;
+
+void init_mp(MainParam_t *MainParam);
+int main_loop(MainParam_t *MainParam, char **argv, int argc);
+
+int target_lookup(MainParam_t *mp, const char *arg);
+
+Stream_t *open_root_dir(unsigned char drivename, int flags, int *isRop);
+
+const char *mpGetBasename(MainParam_t *mp); /* statically allocated
+                                            * string */
+
+void mpPrintFilename(FILE *file, MainParam_t *mp);
+const char *mpPickTargetName(MainParam_t *mp); /* statically allocated string */
+
+char *mpBuildUnixFilename(MainParam_t *mp); /* dynamically allocated, must
+                                            * be freed */
+
+int isSpecial(const char *name);
+#ifdef HAVE_WCHAR_H
+int isSpecialW(const wchar_t *name);
+#else
+#define isSpecialW isSpecial
+#endif
+
+#define MISSED_ONE 2  /* set if one cmd line argument didn't match any files */
+#define GOT_ONE 4     /* set if a match was found, used for exit status */
+#define NO_CWD 8     /* file not found while looking for current working
+                     * directory */
+#define ERROR_ONE 16 /* flat out error, such as problems with target file,
+                       interrupt by user, etc. */
+#define STOP_NOW 32 /* stop as soon as possible, not necessarily an error */
+
+#endif
diff --git a/man-warning-end.texi b/man-warning-end.texi
new file mode 100644 (file)
index 0000000..12bb530
--- /dev/null
@@ -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 (file)
index 0000000..4e3ab61
--- /dev/null
@@ -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 (file)
index 0000000..da3a497
--- /dev/null
+++ b/match.c
@@ -0,0 +1,158 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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(a) == towupper(b);
+}
+
+static int exactcmp(wchar_t a,wchar_t b)
+{
+       return a == b;
+}
+
+
+static int parse_range(const wchar_t **p, const wchar_t *s, wchar_t *out,
+                      int (*compfn)(wchar_t a, wchar_t b))
+{
+       wchar_t table[256];
+       int reverse;
+       int i;
+       short first, last;
+
+       if (**p == '^') {
+               reverse = 1;
+               (*p)++;
+       } else
+               reverse=0;      
+       for(i=0; i<256; i++)
+               table[i]=0;
+       while(**p != ']') {
+               if(!**p)
+                       return 0;
+               if((*p)[1] == '-') {
+                       first = **p;
+                       (*p)+=2;
+                       if(**p == ']')
+                               last = 256;
+                       else
+                               last = *((*p)++);                               
+                       for(i=first; i<=last; i++)
+                               table[i] = 1;
+               } else
+                       table[(int) *((*p)++)] = 1;
+       }
+       if(out)
+               *out = *s;
+       if(table[(int) *s])
+               return 1 ^ reverse;
+       if(compfn == exactcmp)
+               return reverse;
+       if(table[tolower(*s)]) {
+               if(out)
+                       *out = tolower(*s);
+               return 1 ^ reverse;
+       }
+       if(table[toupper(*s)]) {
+               if(out)
+                       *out = toupper(*s);
+               return 1 ^ reverse;
+       }
+       return reverse;
+}
+
+
+static int _match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case,
+                 int length,
+                 int (*compfn) (wchar_t a, wchar_t b))
+{
+       for (; *p != '\0' && length; ) {
+               switch (*p) {
+                       case '?':       /* match any one character */
+                               if (*s == '\0')
+                                       return(0);
+                               if(out)
+                                       *(out++) = *s;
+                               break;
+                       case '*':       /* match everything */
+                               while (*p == '*' && length) {
+                                       p++;
+                                       length--;
+                               }
+
+                                       /* search for next char in pattern */
+                               while(*s) {
+                                       if(_match(s, p, out, Case, length,
+                                                 compfn))
+                                               return 1;
+                                       if(out)
+                                               *out++ = *s;
+                                       s++;
+                               }
+                               continue;
+                       case '[':        /* match range of characters */
+                               p++;
+                               length--;
+                               if(!parse_range(&p, s, out++, compfn))
+                                       return 0;
+                               break;
+                       case '\\':      /* Literal match with next character */
+                               p++;
+                               length--;
+                               /* fall thru */
+                       default:
+                               if (!compfn(*s,*p))
+                                       return(0);
+                               if(out)
+                                       *(out++) = *p;
+                               break;
+               }
+               p++;
+               length--;
+               s++;
+       }
+       if(out)
+               *out = '\0';
+
+                                       /* string ended prematurely ? */
+       if (*s != '\0')
+               return(0);
+       else
+               return(1);
+}
+
+
+int match(const wchar_t *s, const wchar_t *p, wchar_t *out, int Case, int length)
+{
+       int (*compfn)(wchar_t a, wchar_t b);
+
+       if(Case)
+               compfn = casecmp;
+       else
+               /*compfn = exactcmp;*/
+               compfn = casecmp;
+       return _match(s, p, out, Case, length, compfn);
+}
+
diff --git a/mattrib.1 b/mattrib.1
new file mode 100644 (file)
index 0000000..1695521
--- /dev/null
+++ b/mattrib.1
@@ -0,0 +1,133 @@
+.TH mattrib 1 "03Nov09" mtools-4.0.12
+.SH Name
+mattrib - change MSDOS file attribute flags
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mattrib"
+.iX "c Changing file attributes"
+.iX "c Hidden files"
+.iX "c Read-only files (changing the attribute)"
+.iX "c System files"
+.iX "c Archive bit"
+.PP
+\&\fR\&\f(CWMattrib\fR is used to change MS-DOS file attribute flags. It has the
+following syntax:
+.PP
+\&\fR\&\f(CWmattrib\fR [\fR\&\f(CW-a|+a\fR] [\fR\&\f(CW-h|+h\fR] [\fR\&\f(CW-r|+r\fR]
+[\fR\&\f(CW-s|+s\fR] [\fR\&\f(CW-/\fR]  [\fR\&\f(CW-p\fR] [\fR\&\f(CW-X\fR] \fImsdosfile\fR [ \fImsdosfiles\fR \&... ]
+.PP
+\&\fR\&\f(CWMattrib\fR adds attribute flags to an MS-DOS file (with the
+`\fR\&\f(CW+\fR' operator) or remove attribute flags (with the `\fR\&\f(CW-\fR'
+operator).
+.PP
+\&\fR\&\f(CWMattrib\fR supports the following attribute bits:
+.TP
+\&\fR\&\f(CWa\fR\ 
+Archive bit.  Used by some backup programs to indicate a new file.
+.TP
+\&\fR\&\f(CWr\fR\ 
+Read-only bit.  Used to indicate a read-only file.  Files with this bit
+set cannot be erased by \fR\&\f(CWDEL\fR nor modified.
+.TP
+\&\fR\&\f(CWs\fR\ 
+System bit.  Used by MS-DOS to indicate a operating system file.
+.TP
+\&\fR\&\f(CWh\fR\ 
+Hidden bit.  Used to make files hidden from \fR\&\f(CWDIR\fR.
+.PP
+\&\fR\&\f(CWMattrib\fR supports the following command line flags:
+.TP
+\&\fR\&\f(CW/\fR\ 
+Recursive.  Recursively list the attributes of the files in the subdirectories.
+.TP
+\&\fR\&\f(CWX\fR\ 
+Concise. Prints the attributes whithout any whitespace padding.  If
+neither the "/" option is given, nor the \fImsdosfile\fR contains a
+wildcard, and there is only one Msdos file parameter on the command
+line, only the attribute is printed, and not the filename.  This option
+is convenient for scripts
+.TP
+\&\fR\&\f(CWp\fR\ 
+Replay mode.  Outputs a series of mformat commands that will reproduce
+the current situation, starting from a situation as left by untarring
+the Dos filesystem.  Commands are only output for attribute settings
+that differ from the default (archive bit set for files, unset for
+directories).  This option is intended to be used in addition to
+tar. The \fR\&\f(CWreadonly\fR attribute is not taken into account, as tar can
+set that one itself.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mattrib.c b/mattrib.c
new file mode 100644 (file)
index 0000000..dd6ca20
--- /dev/null
+++ b/mattrib.c
@@ -0,0 +1,258 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-1998,2000-2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 {
+       char add;
+       unsigned char remove;
+       struct MainParam_t mp;
+       int recursive;
+       int doPrintName;
+} Arg_t;
+
+static int attrib_file(direntry_t *entry, MainParam_t *mp)
+{
+       Arg_t *arg=(Arg_t *) mp->arg;
+
+       if(entry->entry != -3) {
+               /* if not root directory, change it */
+               entry->dir.attr = (entry->dir.attr & arg->remove) | arg->add;
+               dir_write(entry);
+       }
+       return GOT_ONE;
+}
+
+static int replay_attrib(direntry_t *entry, MainParam_t *mp)
+{
+       if ( (IS_ARCHIVE(entry) && IS_DIR(entry)) ||
+                (!IS_ARCHIVE(entry) && !IS_DIR(entry)) ||
+                IS_SYSTEM(entry) || IS_HIDDEN(entry)) {
+
+               printf("mattrib ");
+
+               if (IS_ARCHIVE(entry) && IS_DIR(entry)) {
+                       printf("+a ");
+               }
+
+               if (!IS_ARCHIVE(entry) && !IS_DIR(entry)) {
+                       printf("-a ");
+               }
+
+               if (IS_SYSTEM(entry)) {
+                       printf("+s ");
+               }
+
+               if (IS_HIDDEN(entry)) {
+                       printf("+h ");
+               }
+
+               fprintPwd(stdout, entry, 1);
+               printf("\n");
+       }
+       return GOT_ONE;
+}
+
+
+
+static int view_attrib(direntry_t *entry, MainParam_t *mp)
+{
+       printf("  ");
+       if(IS_ARCHIVE(entry))
+               putchar('A');
+       else
+               putchar(' ');
+       fputs("  ",stdout);
+       if(IS_SYSTEM(entry))
+               putchar('S');
+       else
+               putchar(' ');
+       if(IS_HIDDEN(entry))
+               putchar('H');
+       else
+               putchar(' ');
+       if(IS_READONLY(entry))
+               putchar('R');
+       else
+               putchar(' ');
+       printf("     ");
+       fprintPwd(stdout, entry, 0);
+       printf("\n");
+       return GOT_ONE;
+}
+
+
+static int concise_view_attrib(direntry_t *entry, MainParam_t *mp)
+{
+       Arg_t *arg=(Arg_t *) mp->arg;
+
+       if(IS_ARCHIVE(entry))
+               putchar('A');
+       if(IS_DIR(entry))
+               putchar('D');   
+       if(IS_SYSTEM(entry))
+               putchar('S');
+       if(IS_HIDDEN(entry))
+               putchar('H');
+       if(IS_READONLY(entry))
+               putchar('R');
+       if(arg->doPrintName) {
+               putchar(' ');
+               fprintPwd(stdout, entry, 0);
+       }
+       putchar('\n');
+       return GOT_ONE;
+}
+
+static int recursive_attrib(direntry_t *entry, MainParam_t *mp)
+{
+       mp->callback(entry, mp);
+       return mp->loop(mp->File, mp, "*");
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr, "Mtools version %s, dated %s\n", 
+               mversion, mdate);
+       fprintf(stderr, 
+               "Usage: %s [-p] [-a|+a] [-h|+h] [-r|+r] [-s|+s] msdosfile [msdosfiles...]\n",
+               progname);
+       exit(ret);
+}
+
+static int letterToCode(int letter)
+{
+       switch (toupper(letter)) {
+               case 'A':
+                       return ATTR_ARCHIVE;
+               case 'H':
+                       return ATTR_HIDDEN;
+               case 'R':
+                       return ATTR_READONLY;
+               case 'S':
+                       return ATTR_SYSTEM;
+               default:
+                       usage(1);
+       }
+}
+
+
+void mattrib(int argc, char **argv, int type)
+{
+       Arg_t arg;
+       int view;
+       int c;
+       int concise;
+       int replay;
+       char *ptr;
+       int wantUsage;
+
+       arg.add = 0;
+       arg.remove = 0xff;
+       arg.recursive = 0;
+       arg.doPrintName = 1;
+       view = 0;
+       concise = 0;
+       replay = 0;
+       wantUsage = 0;
+
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:/ahrsAHRSXp")) != EOF) {
+               switch (c) {
+                       case 'h':
+                               wantUsage = 1;
+                               /* FALL THROUGH */
+                       default:
+                               arg.remove &= ~letterToCode(c);
+                               break;
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'p':
+                               replay = 1;
+                               break;
+                       case '/':
+                               arg.recursive = 1;
+                               break;
+                       case 'X':
+                               concise = 1;
+                               break;
+                       case '?':
+                               usage(1);
+               }
+       }
+
+       if(optind == argc && wantUsage) {
+               usage(0);
+       }
+
+       for(;optind < argc;optind++) {
+               switch(argv[optind][0]) {
+                       case '+':
+                               for(ptr = argv[optind] + 1; *ptr; ptr++)
+                                       arg.add |= letterToCode(*ptr);
+                               continue;
+                       case '-':
+                               for(ptr = argv[optind] + 1; *ptr; ptr++)
+                                       arg.remove &= ~letterToCode(*ptr);
+                               continue;
+               }
+               break;
+       }
+
+       if(arg.remove == 0xff && !arg.add)
+               view = 1;
+
+       if (optind >= argc)
+               usage(1);
+
+       init_mp(&arg.mp);
+       if(view){
+               if(concise) {
+                       arg.mp.callback = concise_view_attrib;
+                       arg.doPrintName = (argc - optind > 1 ||
+                                          arg.recursive ||
+                                          strpbrk(argv[optind], "*[?") != 0);
+               } else if (replay) {
+                       arg.mp.callback = replay_attrib;
+               } else
+                       arg.mp.callback = view_attrib;
+               arg.mp.openflags = O_RDONLY;
+       } else {
+               arg.mp.callback = attrib_file;
+               arg.mp.openflags = O_RDWR;
+       }
+
+       if(arg.recursive)
+               arg.mp.dirCallback = recursive_attrib;
+
+       arg.mp.arg = (void *) &arg;
+       arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR;
+       if(arg.recursive)
+               arg.mp.lookupflags |= DO_OPEN_DIRS | NO_DOTS;
+       exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mbadblocks.1 b/mbadblocks.1
new file mode 100644 (file)
index 0000000..ffae70c
--- /dev/null
@@ -0,0 +1,98 @@
+.TH mbadblocks 1 "03Nov09" mtools-4.0.12
+.SH Name
+mbadblocks - tests a floppy disk, and marks the bad blocks in the FAT
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmbadblocks\fR command is used to scan an MS-DOS floppy and mark
+its unused bad blocks as bad. It uses the following syntax:
+.PP
+\&\fR\&\f(CWmbadblocks\fR \fIdrive\fR\fR\&\f(CW:\fR
+.iX "p mbadblocks"
+.iX "c Marking blocks as bad"
+.iX "c Bad blocks"
+.iX "c Read errors"
+.PP
+\&\fR\&\f(CWMbadblocks\fR scans an MS-DOS floppy for bad blocks. All unused bad
+blocks are marked as such in the FAT. This is intended to be used right
+after \fR\&\f(CWmformat\fR.  It is not intended to salvage bad disks.
+.SH Bugs
+\&\fR\&\f(CWMbadblocks\fR should (but doesn't yet :-( ) also try to salvage bad
+blocks which are in use by reading them repeatedly, and then mark them
+bad.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mbadblocks.c b/mbadblocks.c
new file mode 100644 (file)
index 0000000..1ac35a2
--- /dev/null
@@ -0,0 +1,92 @@
+/*  Copyright 1995-1999,2001-2003,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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"
+
+void mbadblocks(int argc, char **argv, int type)
+{
+       unsigned int i;
+       char *in_buf;
+       int in_len;
+       off_t start;
+       struct MainParam_t mp;
+       Fs_t *Fs;
+       Stream_t *Dir;
+       int ret;
+
+       if (argc != 2 || !argv[1][0] || argv[1][1] != ':' || argv[1][2]) {
+               fprintf(stderr, "Mtools version %s, dated %s\n", 
+                       mversion, mdate);
+               fprintf(stderr, "Usage: %s [-V] device\n", argv[0]);
+               exit(1);
+       }
+
+       init_mp(&mp);
+
+       Dir = open_root_dir(argv[1][0], O_RDWR, NULL);
+       if (!Dir) {
+               fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
+               exit(1);
+       }
+
+       Fs = (Fs_t *)GetFs(Dir);
+       in_len = Fs->cluster_size * Fs->sector_size;
+       in_buf = malloc(in_len);
+       if(!in_buf) {
+               FREE(&Dir);
+               printOom();
+               exit(1);
+       }
+       for(i=0; i < Fs->clus_start; i++ ){
+               ret = READS(Fs->Next, in_buf, 
+                           sectorsToBytes((Stream_t*)Fs, i), Fs->sector_size);
+               if( ret < 0 ){
+                       perror("early error");
+                       exit(1);
+               }
+               if(ret < (signed int) Fs->sector_size){
+                       fprintf(stderr,"end of file in file_read\n");
+                       exit(1);
+               }
+       }
+               
+       in_len = Fs->cluster_size * Fs->sector_size;
+       for(i=2; i< Fs->num_clus + 2; i++){
+               if(got_signal)
+                       break;
+               if(Fs->fat_decode((Fs_t*)Fs,i))
+                       continue;
+               start = (i - 2) * Fs->cluster_size + Fs->clus_start;
+               ret = force_read(Fs->Next, in_buf, 
+                                                sectorsToBytes((Stream_t*)Fs, start), in_len);
+               if(ret < in_len ){
+                       printf("Bad cluster %d found\n", i);
+                       fatEncode((Fs_t*)Fs, i, 0xfff7);
+                       continue;
+               }
+       }
+       FREE(&Dir);
+       exit(0);
+}
diff --git a/mcat.1 b/mcat.1
new file mode 100644 (file)
index 0000000..0fb7dff
--- /dev/null
+++ b/mcat.1
@@ -0,0 +1,103 @@
+.TH mcat 1 "03Nov09" mtools-4.0.12
+.SH Name
+mcat - dump raw disk image
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmcat\fR command is used to copy an entire disk image from or
+to the floppy device. It uses the following syntax:
+.PP
+\&\fR\&\f(CWmcat\fR [\fR\&\f(CW-w\fR] \fIdrive\fR\fR\&\f(CW:\fR
+.iX "p mcat"
+.iX "c Copying an entire disk image"
+.iX "c Disk image"
+.iX "c Floppyd cat"
+.PP
+\&\fR\&\f(CWMcat\fR performs the same task as the unix \fR\&\f(CWcat\fR command. It
+is included into the mtools package, since \fR\&\f(CWcat\fR cannot access
+remote floppy devices offered by the mtools floppy daemon.
+Now it is possible to create boot floppies remotely.
+.PP
+The default operation is reading. The output is written to stdout.
+.PP
+If the \fR\&\f(CW-w\fR option is specified, mcat reads a disk-image from 
+stdin and writes it to the given device. 
+\&\fBUse this carefully!\fR Because of the lowlevel nature of this 
+command, it will happily destroy any data written before on the
+disk without warning!
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mcat.c b/mcat.c
new file mode 100644 (file)
index 0000000..1adead5
--- /dev/null
+++ b/mcat.c
@@ -0,0 +1,162 @@
+/*  Copyright 1999-2003,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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) 
+{
+       fprintf(stderr, "Mtools version %s, dated %s\n", 
+               mversion, mdate);
+       fprintf(stderr, "Usage: mcat [-V] [-w] device\n");
+       fprintf(stderr, "       -w write on device else read\n");
+       exit(1);
+}
+
+#ifdef __CYGWIN__
+#define BUF_SIZE 512
+#else
+#define BUF_SIZE 16000
+#endif
+
+static size_t bufLen(size_t blocksize, mt_size_t totalSize, mt_off_t address)
+{
+       if(totalSize == 0)
+               return blocksize;
+       if(address + blocksize > totalSize)
+               return totalSize - address;
+       return blocksize;
+}
+
+void mcat(int argc, char **argv, int type)
+{
+       struct device *dev;
+       struct device out_dev;
+       char drive, name[EXPAND_BUF];
+        char errmsg[200];
+        Stream_t *Stream;
+       char buf[BUF_SIZE];
+
+       mt_off_t address = 0;
+
+       char mode = O_RDONLY;
+       int optindex = 1;
+       size_t len;
+
+       noPrivileges = 1;
+
+       if (argc < 2) {
+               usage();
+       }
+
+       if (argv[1][0] == '-') {
+               if (argv[1][1] != 'w') {
+                       usage();
+               }
+               mode = O_WRONLY;
+               optindex++;
+       }
+
+       if (argc - optindex < 1)
+               usage();
+
+
+       if (!argv[optindex][0] || argv[optindex][1] != ':' 
+           || argv[optindex][2]) {
+               usage();
+       }
+
+        drive = toupper(argv[optindex][0]);
+
+        /* check out a drive whose letter and parameters match */       
+        sprintf(errmsg, "Drive '%c:' not supported", drive);    
+        Stream = NULL;
+        for (dev=devices; dev->name; dev++) {
+                FREE(&Stream);
+                if (dev->drive != drive)
+                        continue;
+                out_dev = *dev;
+                expand(dev->name,name);
+#ifdef USING_NEW_VOLD
+                strcpy(name, getVoldName(dev, name));
+#endif
+
+                Stream = 0;
+#ifdef USE_XDF
+                Stream = XdfOpen(&out_dev, name, mode, errmsg, 0);
+                               if(Stream)
+                        out_dev.use_2m = 0x7f;
+
+#endif
+
+#ifdef USE_FLOPPYD
+                if(!Stream)
+                        Stream = FloppydOpen(&out_dev, dev, name, 
+                                            mode, errmsg, 0, 1);
+#endif
+
+
+                if (!Stream)
+                        Stream = SimpleFileOpen(&out_dev, dev, name, mode,
+                                               errmsg, 0, 1, 0);
+
+                if( !Stream)
+                        continue;
+                break;
+        }
+
+        /* print error msg if needed */ 
+        if ( dev->drive == 0 ){
+                FREE(&Stream);
+                fprintf(stderr,"%s\n",errmsg);
+                exit(1);
+        }
+
+
+       if (mode == O_WRONLY) {
+               mt_size_t size=0;
+               size = out_dev.sectors * out_dev.heads * out_dev.tracks;
+               size *= 512;
+               while ((len = fread(buf, 1,
+                                   bufLen(BUF_SIZE, size, address),
+                                   stdin)) > 0) {                      
+                       int r = WRITES(Stream, buf, address, len);
+                       fprintf(stderr, "Wrote to %d\n", (int) address);
+                       if(r < 0)
+                               break;
+                       address += len;
+               }
+       } else {
+               while ((len = READS(Stream, buf, address, BUF_SIZE)) > 0) {
+                       fwrite(buf, 1, len, stdout);
+                       address += len;
+               }
+       }
+
+       FREE(&Stream);
+       exit(0);
+}
diff --git a/mcd.1 b/mcd.1
new file mode 100644 (file)
index 0000000..a0cc7ba
--- /dev/null
+++ b/mcd.1
@@ -0,0 +1,116 @@
+.TH mcd 1 "03Nov09" mtools-4.0.12
+.SH Name
+mcd - change MSDOS directory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mcd"
+.iX "c Directory (changing)"
+.iX "c Working directory"
+.iX "c Current working directory (changing the)"
+.iX "c Default directory (changing the)"
+.iX "c Mcwd file"
+.PP
+The \fR\&\f(CWmcd\fR command is used to change the mtools working directory
+on the MS-DOS disk. It uses the following syntax:
+.PP
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWmcd [\fImsdosdirectory\fR\&\f(CW]
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+Without arguments, \fR\&\f(CWmcd\fR reports the current device and working
+directory.  Otherwise, \fR\&\f(CWmcd\fR changes the current device and current
+working directory relative to an MS-DOS filesystem.
+.PP
+The environmental variable \fR\&\f(CWMCWD\fR may be used to locate the file
+where the device and current working directory information is stored.
+The default is \fR\&\f(CW\(if$HOME/.mcwd\(is\fR.  Information in this file is ignored
+if the file is more than 6 hours old.
+.PP
+\&\fR\&\f(CWMcd\fR returns 0 on success or 1 on failure.
+.PP
+Unlike MS-DOS versions of \fR\&\f(CWCD\fR, \fR\&\f(CWmcd\fR can be used to change to
+another device. It may be wise to remove old \fR\&\f(CW\(if.mcwd\(is\fR files at logout.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mcd.c b/mcd.c
new file mode 100644 (file)
index 0000000..21f5e44
--- /dev/null
+++ b/mcd.c
@@ -0,0 +1,62 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996,1997,2000-2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+       FILE *fp;
+
+       if (!(fp = open_mcwd("w"))){
+               fprintf(stderr,"mcd: Can't open mcwd .file for writing\n");
+               return ERROR_ONE;
+       }
+       
+       fprintPwd(fp, entry,0);
+       fprintf(fp, "\n");
+       fclose(fp);
+       return GOT_ONE | STOP_NOW;
+}
+
+
+void mcd(int argc, char **argv, int type)
+{
+       struct MainParam_t mp;
+
+       if (argc > 2) {
+               fprintf(stderr, "Mtools version %s, dated %s\n", 
+                       mversion, mdate);
+               fprintf(stderr, "Usage: %s: [-V] msdosdirectory\n", argv[0]);
+               exit(1);
+       }
+
+       init_mp(&mp);
+       mp.lookupflags = ACCEPT_DIR | NO_DOTS;
+       mp.dirCallback = mcd_callback;
+       if (argc == 1) {
+               printf("%s\n", mp.mcwd);
+               exit(0);
+       } else 
+               exit(main_loop(&mp, argv + 1, 1));
+}
diff --git a/mclasserase.1 b/mclasserase.1
new file mode 100644 (file)
index 0000000..9a7675c
--- /dev/null
@@ -0,0 +1,115 @@
+.TH mclasserase 1 "03Nov09" mtools-4.0.12
+.SH Name
+mclasserase - erase memory cards
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mclasserase"
+.iX "c Memory Card"
+.iX "c Physically erase"
+.PP
+The \fR\&\f(CWmclasserase\fR command is used to wipe memory cards by
+overwriting it three times: first with \fR\&\f(CW0xff\fR, then with
+\&\fR\&\f(CW0x00\fR, then with \fR\&\f(CW0xff\fR again. The command uses the following
+syntax:
+.PP
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWmclasserase [\fR\&\f(CW-d] \fImsdosdrive\fR\&\f(CW
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+Dos drive is optional, if none is specified, use \fR\&\f(CWA:\fR. If more than
+one drive are specified, all but the last are ignored.
+.PP
+\&\fR\&\f(CWMclasserase\fR accepts the following command line options:
+.TP
+\&\fR\&\f(CWd\fR\ 
+Stop after each erase cycle, for testing purposes
+.TP
+\&\fR\&\f(CWp\fR\ 
+Not yet implemented
+.PP
+\&\fR\&\f(CWMclasserase\fR returns 0 on success or -1 on failure.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
+mclasserase
diff --git a/mclasserase.c b/mclasserase.c
new file mode 100644 (file)
index 0000000..1cbe023
--- /dev/null
@@ -0,0 +1,351 @@
+/*  Copyright 2003 Stefan Feuz, Lukas Meyer, Thomas Locher
+ *  Copyright 2004,2006,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+  struct device dev;           /* Device information structure */
+  union bootsector boot;
+
+  int media;                   /* Just used to enter some in find_device */
+  char name[EXPAND_BUF];
+  Stream_t *Stream;
+  struct label_blk_t *labelBlock;
+  
+  FILE * fDevice;              /* Stores device's file descriptor */
+  
+  char cCardType[12];
+  
+  char drivel[2];              /* Stores the drive letter */
+
+
+  int i = 0;
+
+  /* FILE *forf; */
+
+  char dummy[2];       /* dummy input for debugging purposes.. */
+  int icount=0;
+  int iTotalErase = 0;
+
+  const int cycles = 3;                /* How many times we'll overwrite the media */
+  char odat[cycles];           /* Data for each overwrite procedure */
+
+  /* Creating values for overwrite  */
+  odat[0]=0xff;
+  odat[1]=0x00;
+  odat[2]=0xff;
+  
+
+  if (debug == 1)
+     printf("cycles: %i, odats: %i,%i,%i\n",cycles,odat[0],odat[1],odat[2]);
+  
+  
+
+  /* Reading parameters from card. Exit with -1 if failed. */
+  if(! (Stream = find_device(drive, O_RDONLY, &dev, &boot,
+                                          name, &media, 0, NULL)))
+       exit(1);
+
+  FREE(&Stream);
+
+  /* Determine the FAT - type */
+#if 0
+  if(WORD(fatlen)) {
+    labelBlock = &bbelBlock = &boot->ext.old.labelBlock;
+  } else {
+    labelBlock = &boot->ext.fat32.labelBlock;
+  }
+#endif
+
+  /* we use only FAT12/16 ...*/
+  labelBlock = &boot.boot.ext.old.labelBlock;
+   
+  /* store card type */
+  sprintf(cCardType, "%11.11s", labelBlock->label);
+
+  if (debug == 1)
+  {
+     printf("Using Device: %s\n",name);
+     printf("Card-Type detected: %s\n",cCardType);
+  }
+      
+  /* Forming cat command to overwrite the medias content. */
+  sprintf( drivel, "%c:", tolower(drive) );
+
+#if 0
+  media_sectors = dev.tracks * dev.sectors;
+  sector_size = WORD(secsiz) * dev.heads; 
+  
+
+       printf(mcat);
+       printf("\n%d\n", media_sectors);
+       printf("%d\n", sector_size);
+#endif
+  /*
+   * Overwrite device
+   */
+  for( i=0; i < cycles; i++){
+
+     if (debug==1)
+     {
+        printf("Erase Cycle %i, writing data: 0x%2.2x...\n",i+1,odat[i]);
+     }
+
+     fDevice = fopen(name,"ab+");
+          
+     if (fDevice == 0)
+     {
+        perror("Error opening device");
+       exit(-1);
+     }
+
+
+     if (debug==1)
+     {
+        printf("Open successful...\n");
+       printf("Flushing device after 32 kBytes of data...\n");
+       printf("Erasing:");
+       fflush( stdout );
+     }
+
+     /* iTotalErase = 0; */
+      
+     /*
+      * overwrite the whole device
+      */
+     while ((feof(fDevice)==0) && (ferror(fDevice)==0))
+     {
+                       
+       fputc(odat[i],fDevice);
+
+       icount++;
+       if (icount > (32 * 1024))
+       {
+          /* flush device every 32KB of data...*/
+          fflush( fDevice );
+           
+          iTotalErase += icount;
+          if (debug == 1)
+          {
+             printf(".");         
+             fflush( stdout );
+          }
+          icount=0;
+       }
+     }
+     
+     if (debug==1)
+     {
+        printf("\nPress <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 wont
+ * 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)
+{
+  /* declaration of all variables */
+  int c;
+  int debug=0;
+  /* char* tempFilePath=NULL; */
+  char drive='a';
+
+  int extern optind;
+
+  destroy_privs();
+
+  /* check and read command line arguments */
+#ifdef DEBUG
+  printf("mclasserase: argc = %i\n",argc);
+#endif
+  /* check num of arguments */
+  if(helpFlag(argc, argv))
+    usage(0);
+  if ( (argc != 2) & (argc != 3) & (argc != 4))
+    { /* wrong num of arguments */
+    printf ("mclasserase: wrong num of args\n");
+    usage(1);
+  }
+  else
+  { /* correct num of arguments */
+    while ((c = getopt(argc, argv, "+p:dh")) != EOF)
+    {
+      switch (c)
+      {
+       
+       case 'd':
+           
+          printf("=============\n");
+          printf("Debug Mode...\n");
+          printf("=============\n");
+           debug = 1;
+          break;
+       case 'p':
+           printf("option -p not implemented yet\n"); 
+           break;
+       case 'h':
+         usage(0);
+        case '?':
+           usage(1);
+        default:
+           break;
+       }
+     }
+#ifdef DEBUG
+     printf("mclasserase: optind = %i\n",optind);
+   /* look for the drive to erase */
+   printf("mclasserase: searching drive\n");
+#endif
+   for(; optind < argc; optind++)
+   {
+     if(!argv[optind][0] || argv[optind][1] != ':')
+     {
+       usage(1);
+     }
+     drive = toupper(argv[optind][0]);
+   }
+  }
+#ifdef DEBUG
+  printf("mclasserase: found drive %c\n", drive);
+#endif 
+  /* remove all data on drive, you never come back if drive does
+   * not exist */
+  
+  do_mclasserase(drive,debug);
+  
+  exit (0);
+}
diff --git a/mcopy.1 b/mcopy.1
new file mode 100644 (file)
index 0000000..3aa488b
--- /dev/null
+++ b/mcopy.1
@@ -0,0 +1,183 @@
+.TH mcopy 1 "03Nov09" mtools-4.0.12
+.SH Name
+mcopy - copy MSDOS files to/from Unix
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mcopy"
+.iX "c Reading MS-DOS files"
+.iX "c Writing MS-DOS files"
+.iX "c Copying MS-DOS files"
+.iX "c Concatenating MS-DOS files"
+.iX "c Text files"
+.iX "c CR/LF conversions"
+.PP
+The \fR\&\f(CWmcopy\fR command is used to copy MS-DOS files to and from
+Unix. It uses the following syntax:
+.PP
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWmcopy [\fR\&\f(CW-bspanvmQT] [\fR\&\f(CW-D \fIclash_option\fR\&\f(CW] \fIsourcefile\fR\&\f(CW \fItargetfile\fR\&\f(CW
+\&\fR\&\f(CWmcopy [\fR\&\f(CW-bspanvmQT] [\fR\&\f(CW-D \fIclash_option\fR\&\f(CW] \fIsourcefile\fR\&\f(CW [ \fIsourcefiles\fR\&\f(CW\&... ] \fItargetdirectory\fR\&\f(CW
+\&\fR\&\f(CWmcopy [\fR\&\f(CW-tnvm] \fIMSDOSsourcefile\fR\&\f(CW
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+\&\fR\&\f(CWMcopy\fR copies the specified file to the named file, or copies
+multiple files to the named directory.  The source and target can be
+either MS-DOS or Unix files.
+.PP
+The use of a drive letter designation on the MS-DOS files, 'a:' for
+example, determines the direction of the transfer.  A missing drive
+designation implies a Unix file whose path starts in the current
+directory.  If a source drive letter is specified with no attached file
+name (e.g. \fR\&\f(CWmcopy a: .\fR), all files are copied from that drive.
+.PP
+If only a single, MS-DOS source parameter is provided (e.g. "mcopy
+a:foo.exe"), an implied destination of the current directory
+(`\fR\&\f(CW.\fR') is assumed.
+.PP
+A filename of `\fR\&\f(CW-\fR' means standard input or standard output, depending
+on its position on the command line.
+.PP
+\&\fR\&\f(CWMcopy\fR accepts the following command line options:
+.TP
+\&\fR\&\f(CWt\fR\ 
+Text file transfer.  Mcopy translates incoming carriage return/line
+feeds to line feeds when copying from Dos to Unix, and vice-versa when
+copying from Unix to Dos.
+.TP
+\&\fR\&\f(CWb\fR\ 
+Batch mode. Optimized for huge recursive copies, but less secure if a
+crash happens during the copy.
+.TP
+\&\fR\&\f(CWs\fR\ 
+Recursive copy.  Also copies directories and their contents
+.TP
+\&\fR\&\f(CWp\fR\ 
+Preserves the attributes of the copied files
+.TP
+\&\fR\&\f(CWQ\fR\ 
+When mcopying multiple files, quits as soon as one copy fails (for
+example due to lacking storage space on the target disk)
+.TP
+\&\fR\&\f(CWa\fR\ 
+Text (Ascii) file transfer.  \fR\&\f(CWMcopy\fR translates incoming carriage
+return/line feeds to line feeds.
+.TP
+\&\fR\&\f(CWT\fR\ 
+Text (Ascii) file transfer with charset conversion.  Differs from
+\&\fR\&\f(CW-a\fR in the \fR\&\f(CWMcopy\fR also translates incoming PC-8 characters
+to ISO-8859-1 equivalents as far as possible.  When reading DOS files,
+untranslatable characters are replaced by '\fR\&\f(CW#\fR'; when writing DOS files,
+untranslatable characters are replaced by '\fR\&\f(CW.\fR'.
+.TP
+\&\fR\&\f(CWn\fR\ 
+No confirmation when overwriting Unix files.  \fR\&\f(CWMcopy\fR doesn't warn
+the user when overwriting an existing Unix file. If the target file already exists,
+and the \fR\&\f(CW-n\fR option is not in effect, \fR\&\f(CWmcopy\fR asks whether to
+overwrite the file or to rename the new file (\(ifname clashes\(is) for
+details).  In order to switch off confirmation for DOS files, use \fR\&\f(CW-o\fR.
+.TP
+\&\fR\&\f(CWm\fR\ 
+Preserve the file modification time.
+.TP
+\&\fR\&\f(CWv\fR\ 
+Verbose. Displays the name of each file as it is copied.
+.PP
+.SH Bugs
+Unlike MS-DOS, the '+' operator (append) from MS-DOS is not
+supported. However, you may use \fR\&\f(CWmtype\fR to produce the same effect:
+.nf
+.ft 3
+.in +0.3i
+mtype a:file1 a:file2 a:file3 >unixfile
+mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mcopy.c b/mcopy.c
new file mode 100644 (file)
index 0000000..0074489
--- /dev/null
+++ b/mcopy.c
@@ -0,0 +1,635 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1994,1996-2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mcopy.c
+ * Copy an MSDOS files to and from Unix
+ *
+ */
+
+
+#define LOWERCASE
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "mainloop.h"
+#include "plain_io.h"
+#include "nameclash.h"
+#include "file.h"
+#include "fs.h"
+
+
+/*
+ * Preserve the file modification times after the fclose()
+ */
+
+static void set_mtime(const char *target, time_t mtime)
+{
+       if (target && strcmp(target, "-") && mtime != 0L) {
+#ifdef HAVE_UTIMES
+               struct timeval tv[2];   
+               tv[0].tv_sec = mtime;
+               tv[0].tv_usec = 0;
+               tv[1].tv_sec = mtime;
+               tv[1].tv_usec = 0;
+               utimes((char *)target, tv);
+#else
+#ifdef HAVE_UTIME
+               struct utimbuf utbuf;
+
+               utbuf.actime = mtime;
+               utbuf.modtime = mtime;
+               utime(target, &utbuf);
+#endif
+#endif
+       }
+       return;
+}
+
+typedef struct Arg_t {
+       int recursive;
+       int preserveAttributes;
+       int preserveTime;
+       unsigned char attr;
+       char *path;
+       int textmode;
+       int needfilter;
+       int nowarn;
+       int verbose;
+       int type;
+       int convertCharset;
+       MainParam_t mp;
+       ClashHandling_t ch;
+       int noClobber;
+} Arg_t;
+
+static int _unix_write(direntry_t *entry, MainParam_t *mp, int needfilter,
+                      const char *unixFile);
+
+/* Write the Unix file */
+static int unix_write(direntry_t *entry, MainParam_t *mp, int needfilter)
+{
+       Arg_t *arg=(Arg_t *) mp->arg;
+
+       if(arg->type)
+               return _unix_write(entry, mp, needfilter, "-");
+       else {
+               char *unixFile = mpBuildUnixFilename(mp);
+               int ret;
+               if(!unixFile) {
+                       printOom();
+                       return ERROR_ONE;
+               }
+               ret = _unix_write(entry, mp, needfilter, unixFile);
+               free(unixFile);
+               return ret;
+       }
+}
+
+
+/* Write the Unix file */
+static int _unix_write(direntry_t *entry, MainParam_t *mp, int needfilter,
+                      const char *unixFile)
+{
+       Arg_t *arg=(Arg_t *) mp->arg;
+       time_t mtime;
+       Stream_t *File=mp->File;
+       Stream_t *Target, *Source;
+       struct MT_STAT stbuf;
+       int ret;
+       char errmsg[80];
+
+       File->Class->get_data(File, &mtime, 0, 0, 0);
+
+       if (!arg->preserveTime)
+               mtime = 0L;
+
+       /* if we are creating a file, check whether it already exists */
+       if(!arg->type) {
+               if (!arg->nowarn && &arg->type && !access(unixFile, 0)){
+                       if(arg->noClobber) {
+                               fprintf(stderr, "File \"%s\" exists. To overwrite, try again, and explicitly specify target directory\n",unixFile);
+                               return ERROR_ONE;
+                       }
+
+                       /* sanity checking */
+                       if (!MT_STAT(unixFile, &stbuf)) {
+                               struct MT_STAT srcStbuf;
+                               int sFd; /* Source file descriptor */
+                               if(!S_ISREG(stbuf.st_mode)) {
+                                       fprintf(stderr,"\"%s\" is not a regular file\n",
+                                               unixFile);
+                               
+                                       return ERROR_ONE;
+                               }
+                               sFd = get_fd(File);
+                               if(sFd == -1) {
+                                       fprintf(stderr, "Not ok Unix file ==> good\n");
+                               }
+                               if((!MT_FSTAT(sFd, &srcStbuf)) &&
+                                  stbuf.st_dev == srcStbuf.st_dev &&
+                                  stbuf.st_ino == srcStbuf.st_ino) {
+                                       fprintf(stderr, "Attempt to copy file on itself\n");
+                                       return ERROR_ONE;
+                               }
+                       }
+
+                       if( ask_confirmation("File \"%s\" exists, overwrite (y/n) ? ",
+                                            unixFile)) {
+                               return ERROR_ONE;
+                       }
+                       
+               }
+       }
+
+       if(!arg->type && arg->verbose) {
+               fprintf(stderr,"Copying ");
+               mpPrintFilename(stderr,mp);
+               fprintf(stderr,"\n");
+       }
+       
+       if(got_signal) {
+               return ERROR_ONE;
+       }
+
+       if ((Target = SimpleFileOpen(0, 0, unixFile,
+                                    O_WRONLY | O_CREAT | O_TRUNC,
+                                    errmsg, 0, 0, 0))) {
+               ret = 0;
+               if(needfilter && arg->textmode){
+                       Source = open_filter(COPY(File),arg->convertCharset);
+                       if (!Source)
+                               ret = -1;
+               } else
+                       Source = COPY(File);
+
+               if (ret == 0 )
+                       ret = copyfile(Source, Target);
+               FREE(&Source);
+               FREE(&Target);
+               if(ret <= -1){
+                       if(!arg->type)
+                               unlink(unixFile);
+                       return ERROR_ONE;
+               }
+               if(!arg->type)
+                       set_mtime(unixFile, mtime);
+               return GOT_ONE;
+       } else {
+               fprintf(stderr,"%s\n", errmsg);
+               return ERROR_ONE;
+       }
+}
+
+static int makeUnixDir(char *filename)
+{
+       if(!mkdir(filename
+#ifndef OS_mingw32msvc
+                 , 0777
+#endif
+                ))
+               return 0;
+       if(errno == EEXIST) {
+               struct MT_STAT buf;
+               if(MT_STAT(filename, &buf) < 0)
+                       return -1;
+               if(S_ISDIR(buf.st_mode))
+                       return 0;
+               errno = ENOTDIR;
+       }
+       return -1;
+}
+
+/* Copy a directory to Unix */
+static int unix_copydir(direntry_t *entry, MainParam_t *mp)
+{
+       Arg_t *arg=(Arg_t *) mp->arg;
+       time_t mtime;
+       Stream_t *File=mp->File;
+       int ret;
+       char *unixFile;
+
+       if (!arg->recursive && mp->basenameHasWildcard)
+               return 0;
+
+       File->Class->get_data(File, &mtime, 0, 0, 0);   
+       if (!arg->preserveTime)
+               mtime = 0L;
+       if(!arg->type && arg->verbose) {
+               fprintf(stderr,"Copying ");
+               fprintPwd(stderr, entry,0);
+               fprintf(stderr, "\n");
+       }
+       if(got_signal)
+               return ERROR_ONE;
+       unixFile = mpBuildUnixFilename(mp);
+       if(!unixFile) {
+               printOom();
+               return ERROR_ONE;
+       }
+       if(arg->type || !*mpPickTargetName(mp) || !makeUnixDir(unixFile)) {
+               Arg_t newArg;
+
+               newArg = *arg;
+               newArg.mp.arg = (void *) &newArg;
+               newArg.mp.unixTarget = unixFile;
+               newArg.mp.targetName = 0;
+               newArg.mp.basenameHasWildcard = 1;
+
+               ret = mp->loop(File, &newArg.mp, "*");
+               set_mtime(unixFile, mtime);
+               free(unixFile);
+               return ret | GOT_ONE;           
+       } else {
+               perror("mkdir");
+               fprintf(stderr, 
+                       "Failure to make directory %s\n", 
+                       unixFile);
+               free(unixFile);
+               return ERROR_ONE;
+       }
+}
+
+static  int dos_to_unix(direntry_t *entry, MainParam_t *mp)
+{
+       return unix_write(entry, mp, 1);
+}
+
+
+static  int unix_to_unix(MainParam_t *mp)
+{
+       return unix_write(0, mp, 0);
+}
+
+
+static int directory_dos_to_unix(direntry_t *entry, MainParam_t *mp)
+{
+       return unix_copydir(entry, mp);
+}
+
+/*
+ * Open the named file for read, create the cluster chain, return the
+ * directory structure or NULL on error.
+ */
+static int writeit(struct dos_name_t *dosname,
+                  char *longname,
+                  void *arg0,
+                  direntry_t *entry)
+{
+       Stream_t *Target;
+       time_t now;
+       int type, fat, ret;
+       time_t date;
+       mt_size_t filesize, newsize;
+       Arg_t *arg = (Arg_t *) arg0;
+
+
+
+       if (arg->mp.File->Class->get_data(arg->mp.File,
+                                                                         & date, &filesize, &type, 0) < 0 ){
+               fprintf(stderr, "Can't stat source file\n");
+               return -1;
+       }
+
+       if(fileTooBig(filesize)) {
+               fprintf(stderr, "File \"%s\" too big\n", longname);
+               return 1;
+       }
+
+       if (type){
+               if (arg->verbose)
+                       fprintf(stderr, "\"%s\" is a directory\n", longname);
+               return -1;
+       }
+
+       /*if (!arg->single || arg->recursive)*/
+       if(arg->verbose)
+               fprintf(stderr,"Copying %s\n", longname);
+       if(got_signal)
+               return -1;
+
+       /* will it fit? */
+       if (!getfreeMinBytes(arg->mp.targetDir, filesize))
+               return -1;
+       
+       /* preserve mod time? */
+       if (arg->preserveTime)
+               now = date;
+       else
+               getTimeNow(&now);
+
+       mk_entry(dosname, arg->attr, 1, 0, now, &entry->dir);
+
+       Target = OpenFileByDirentry(entry);
+       if(!Target){
+               fprintf(stderr,"Could not open Target\n");
+               exit(1);
+       }
+       if (arg->needfilter & arg->textmode)
+               Target = open_filter(Target,arg->convertCharset);
+
+
+
+       ret = copyfile(arg->mp.File, Target);
+       GET_DATA(Target, 0, &newsize, 0, &fat);
+       FREE(&Target);
+       if (arg->needfilter & arg->textmode)
+           newsize++; /* ugly hack: we gathered the size before the Ctrl-Z
+                       * was written.  Increment it manually */
+       if(ret < 0 ){
+               fat_free(arg->mp.targetDir, fat);
+               return -1;
+       } else {
+               mk_entry(dosname, arg->attr, fat, truncBytes32(newsize),
+                                now, &entry->dir);
+               return 0;
+       }
+}
+
+
+
+static int dos_write(direntry_t *entry, MainParam_t *mp, int needfilter)
+/* write a messy dos file to another messy dos file */
+{
+       int result;
+       Arg_t * arg = (Arg_t *) (mp->arg);
+       const char *targetName = mpPickTargetName(mp);
+
+       if(entry && arg->preserveAttributes)
+               arg->attr = entry->dir.attr;
+       else
+               arg->attr = ATTR_ARCHIVE;
+
+       arg->needfilter = needfilter;
+       if (entry && mp->targetDir == entry->Dir){
+               arg->ch.ignore_entry = -1;
+               arg->ch.source = entry->entry;
+       } else {
+               arg->ch.ignore_entry = -1;
+               arg->ch.source = -2;
+       }
+       result = mwrite_one(mp->targetDir, targetName, 0,
+                           writeit, (void *)arg, &arg->ch);
+       if(result == 1)
+               return GOT_ONE;
+       else
+               return ERROR_ONE;
+}
+
+static Stream_t *subDir(Stream_t *parent, const char *filename)
+{
+       direntry_t entry;
+       initializeDirentry(&entry, parent);
+
+       switch(vfat_lookup(&entry, filename, -1, ACCEPT_DIR, 0, 0)) {
+           case 0:
+               return OpenFileByDirentry(&entry);
+           case -1:
+               return NULL;
+           default: /* IO Error */
+               return NULL;
+       }
+}
+
+static int dos_copydir(direntry_t *entry, MainParam_t *mp)
+/* copyes a directory to Dos */
+{
+       Arg_t * arg = (Arg_t *) (mp->arg);
+       Arg_t newArg;
+       time_t now;
+       time_t date;
+       int ret;
+       const char *targetName = mpPickTargetName(mp);
+
+       if (!arg->recursive && mp->basenameHasWildcard)
+               return 0;
+
+       if(entry && isSubdirOf(mp->targetDir, mp->File)) {
+               fprintf(stderr, "Cannot recursively copy directory ");
+               fprintPwd(stderr, entry,0);
+               fprintf(stderr, " into one of its own subdirectories ");
+               fprintPwd(stderr, getDirentry(mp->targetDir),0);
+               fprintf(stderr, "\n");
+               return ERROR_ONE;
+       }
+
+       if (arg->mp.File->Class->get_data(arg->mp.File,
+                                         & date, 0, 0, 0) < 0 ){
+               fprintf(stderr, "Can't stat source file\n");
+               return ERROR_ONE;
+       }
+
+       if(!arg->type && arg->verbose)
+               fprintf(stderr,"Copying %s\n", mpGetBasename(mp));
+
+       if(entry && arg->preserveAttributes)
+               arg->attr = entry->dir.attr;
+       else
+               arg->attr = 0;
+
+       if (entry && (mp->targetDir == entry->Dir)){
+               arg->ch.ignore_entry = -1;
+               arg->ch.source = entry->entry;
+       } else {
+               arg->ch.ignore_entry = -1;
+               arg->ch.source = -2;
+       }
+
+       /* preserve mod time? */
+       if (arg->preserveTime)
+               now = date;
+       else
+               getTimeNow(&now);
+
+       newArg = *arg;
+       newArg.mp.arg = &newArg;
+       newArg.mp.targetName = 0;
+       newArg.mp.basenameHasWildcard = 1;
+       if(*targetName) {
+               /* maybe the directory already exist. Use it */
+               newArg.mp.targetDir = subDir(mp->targetDir, targetName);
+               if(!newArg.mp.targetDir)
+                       newArg.mp.targetDir = createDir(mp->targetDir, 
+                                                       targetName,
+                                                       &arg->ch, arg->attr, 
+                                                       now);
+       } else
+               newArg.mp.targetDir = mp->targetDir;
+
+       if(!newArg.mp.targetDir)
+               return ERROR_ONE;
+
+       ret = mp->loop(mp->File, &newArg.mp, "*");
+       if(*targetName)
+               FREE(&newArg.mp.targetDir);
+       return ret | GOT_ONE;
+}
+
+
+static int dos_to_dos(direntry_t *entry, MainParam_t *mp)
+{
+       return dos_write(entry, mp, 0);
+}
+
+static int unix_to_dos(MainParam_t *mp)
+{
+       return dos_write(0, mp, 1);
+}
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr,
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr,
+               "Usage: %s [-spatnmQVBT] [-D clash_option] sourcefile targetfile\n", progname);
+       fprintf(stderr,
+               "       %s [-spatnmQVBT] [-D clash_option] sourcefile [sourcefiles...] targetdirectory\n", 
+               progname);
+       exit(ret);
+}
+
+void mcopy(int argc, char **argv, int mtype)
+{
+       Arg_t arg;
+       int c, ret, fastquit;
+       int todir;
+       
+
+       /* get command line options */
+
+       init_clash_handling(& arg.ch);
+
+       /* get command line options */
+       todir = 0;
+       arg.recursive = 0;
+       arg.preserveTime = 0;
+       arg.preserveAttributes = 0;
+       arg.nowarn = 0;
+       arg.textmode = 0;
+       arg.verbose = 0;
+       arg.convertCharset = 0;
+       arg.type = mtype;
+       fastquit = 0;
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:abB/sptTnmvQD:oh")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 's':
+                       case '/':
+                               arg.recursive = 1;
+                               break;
+                       case 'p':
+                               arg.preserveAttributes = 1;
+                               break;
+                       case 'T':
+                               arg.convertCharset = 1;
+                       case 'a':
+                       case 't':
+                               arg.textmode = 1;
+                               break;
+                       case 'n':
+                               arg.nowarn = 1;
+                               break;
+                       case 'm':
+                               arg.preserveTime = 1;
+                               break;
+                       case 'v':
+                               arg.verbose = 1;
+                               break;
+                       case 'Q':
+                               fastquit = 1;
+                               break;
+                       case 'B':
+                       case 'b':
+                               batchmode = 1;
+                               break;
+                       case 'o':
+                               handle_clash_options(&arg.ch, c);
+                               break;
+                       case 'D':
+                               if(handle_clash_options(&arg.ch, *optarg))
+                                       usage(1);
+                               break;
+                       case 'h':
+                               usage(0);
+                       case '?':
+                               usage(1);
+                       default:
+                               break;
+               }
+       }
+
+       if (argc - optind < 1)
+               usage(1);
+
+       init_mp(&arg.mp);
+       arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN | NO_DOTS;
+       arg.mp.fast_quit = fastquit;
+       arg.mp.arg = (void *) &arg;
+       arg.mp.openflags = O_RDONLY;
+       arg.noClobber = 0;
+
+       /* last parameter is "-", use mtype mode */
+       if(!mtype && !strcmp(argv[argc-1], "-")) {
+               arg.type = mtype = 1;
+               argc--;
+       }
+
+       if(mtype){
+               /* Mtype = copying to stdout */
+               arg.mp.targetName = strdup("-");
+               arg.mp.unixTarget = strdup("");
+               arg.mp.callback = dos_to_unix;
+               arg.mp.dirCallback = unix_copydir;
+               arg.mp.unixcallback = unix_to_unix;             
+       } else {
+               const char *target;
+               if (argc - optind == 1) {
+                       /* copying to the current directory */
+                       target = ".";
+                       arg.noClobber = 1;
+               } else {
+                       /* target is the last item mentioned */
+                       argc--;
+                       target = argv[argc];
+               }
+
+               ret = target_lookup(&arg.mp, target);
+               if(!arg.mp.targetDir && !arg.mp.unixTarget) {
+                       fprintf(stderr,"Bad target %s\n", target);
+                       exit(1);
+               }
+
+               /* callback functions */
+               if(arg.mp.unixTarget) {
+                       arg.mp.callback = dos_to_unix;
+                       arg.mp.dirCallback = directory_dos_to_unix;
+                       arg.mp.unixcallback = unix_to_unix;
+               } else {
+                       arg.mp.dirCallback = dos_copydir;
+                       arg.mp.callback = dos_to_dos;
+                       arg.mp.unixcallback = unix_to_dos;
+               }
+       }
+
+       exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mdel.1 b/mdel.1
new file mode 100644 (file)
index 0000000..b2391c7
--- /dev/null
+++ b/mdel.1
@@ -0,0 +1,100 @@
+.TH mdel 1 "03Nov09" mtools-4.0.12
+.SH Name
+mdel - delete an MSDOS file
+mdeltree - recursively delete an MSDOS directory and its contents
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mdel"
+.iX "c removing MS-DOS files"
+.iX "c erasing MS-DOS files"
+.iX "c deleting MS-DOS files"
+.PP
+The \fR\&\f(CWmdel\fR command is used to delete an MS-DOS file. Its syntax
+is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmdel\fR [\fR\&\f(CW-v\fR] \fImsdosfile\fR [ \fImsdosfiles\fR \&...  ]
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMdel\fR deletes files on an MS-DOS filesystem.
+.PP
+\&\fR\&\f(CWMdel\fR asks for verification prior to removing a read-only file.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdel.c b/mdel.c
new file mode 100644 (file)
index 0000000..e59a2cd
--- /dev/null
+++ b/mdel.c
@@ -0,0 +1,208 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-2002,2005,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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, NULL)) == 0 ){
+                       if(shortname[0] != DELMARK &&
+                          shortname[0] &&
+                          shortname[0] != '.' ){
+                               if(arg->deltype != 2){
+                                       fprintf(stderr,
+                                               "Directory ");
+                                       fprintPwd(stderr, entry,0);
+                                       fprintf(stderr," non empty\n");
+                                       ret = ERROR_ONE;
+                                       break;
+                               }
+                               if(got_signal) {
+                                       ret = ERROR_ONE;
+                                       break;
+                               }
+                               ret = del_file(&subEntry, &sonmp);
+                               if( ret & ERROR_ONE)
+                                       break;
+                               ret = 0;
+                       }
+               }
+               FREE(&SubDir);
+               if (r == -2)
+                       return ERROR_ONE;
+               if(ret)
+                       return ret;
+       }
+       return del_entry(entry, mp);
+}
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr, 
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr, 
+               "Usage: %s [-v] msdosfile [msdosfiles...]\n", progname);
+       exit(ret);
+}
+
+void mdel(int argc, char **argv, int deltype)
+{
+       Arg_t arg;
+       MainParam_t mp;
+       int c,i;
+
+       arg.verbose = 0;
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:vh")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'v':
+                               arg.verbose = 1;
+                               break;
+                       case 'h':
+                               usage(0);
+                       default:
+                               usage(1);
+               }
+       }
+
+       if(argc == optind)
+               usage(1);
+
+       init_mp(&mp);
+       mp.callback = del_file;
+       mp.arg = (void *) &arg;
+       mp.openflags = O_RDWR;
+       arg.deltype = deltype;
+       switch(deltype){
+       case 0:
+               mp.lookupflags = ACCEPT_PLAIN; /* mdel */
+               break;
+       case 1:
+               mp.lookupflags = ACCEPT_DIR; /* mrd */
+               break;
+       case 2:
+               mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN; /* mdeltree */
+               break;
+       }
+       mp.lookupflags |= NO_DOTS;
+       for(i=optind;i<argc;i++) {
+               int 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 (file)
index 0000000..f8dd5e8
--- /dev/null
@@ -0,0 +1,100 @@
+.TH mdeltree 1 "03Nov09" mtools-4.0.12
+.SH Name
+mdeltree - recursively delete an MSDOS directory and its contents
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mdeltree"
+.iX "c removing an MS-DOS directory recursively"
+.iX "c erasing an MS-DOS directory recursively"
+.iX "c deleting an MS-DOS directory recursively"
+.iX "c recursively removing an MS-DOS directory"
+.PP
+The \fR\&\f(CWmdeltree\fR command is used to delete an MS-DOS file. Its syntax
+is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmdeltree\fR [\fR\&\f(CW-v\fR] \fImsdosdirectory\fR [\fImsdosdirectories\fR\&...]
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMdeltree\fR removes a directory and all the files and subdirectories
+it contains from an MS-DOS filesystem. An error occurs if the directory
+to be removed does not exist.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdir.1 b/mdir.1
new file mode 100644 (file)
index 0000000..e08a751
--- /dev/null
+++ b/mdir.1
@@ -0,0 +1,121 @@
+.TH mdir 1 "03Nov09" mtools-4.0.12
+.SH Name
+mdir - display an MSDOS directory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mdir"
+.iX "c Read-only files (listing them)"
+.iX "c Listing a directory"
+.iX "c Directory listing"
+.PP
+The \fR\&\f(CWmdir\fR command is used to display an MS-DOS directory. Its
+syntax is:
+.PP
+\&\fR\&\f(CWmdir\fR [\fR\&\f(CW-/\fR] [\fR\&\f(CW-f\fR] [\fR\&\f(CW-w\fR] [\fR\&\f(CW-a\fR] [\fR\&\f(CW-b\fR] \fImsdosfile\fR [ \fImsdosfiles\fR\&...] 
+.PP
+\&\fR\&\f(CWMdir\fR
+displays the contents of MS-DOS directories, or the entries for some
+MS-DOS files.
+.PP
+\&\fR\&\f(CWMdir\fR supports the following command line options:
+.TP
+\&\fR\&\f(CW/\fR\ 
+Recursive output, just like Dos' \fR\&\f(CW-s\fR option
+.TP
+\&\fR\&\f(CWw\fR\ 
+Wide output.  With this option, \fR\&\f(CWmdir\fR prints the filenames across
+the page without displaying the file size or creation date.
+.TP
+\&\fR\&\f(CWa\fR\ 
+Also list hidden files.
+.TP
+\&\fR\&\f(CWf\fR\ 
+Fast.  Do not try to find out free space.  On larger disks, finding out
+the amount of free space takes up some non trivial amount of time, as
+the whole FAT must be read in and scanned.  The \fR\&\f(CW-f\fR flag bypasses
+this step.  This flag is not needed on FAT32 filesystems, which store
+the size explicitely.
+.TP
+\&\fR\&\f(CWb\fR\ 
+Concise listing. Lists each directory name or filename, one per line
+(including the filename extension). This switch displays no heading
+information and no summary. Only a newline separated list of pathnames
+is displayed.
+.PP
+An error occurs if a component of the path is not a directory.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdir.c b/mdir.c
new file mode 100644 (file)
index 0000000..0bd2aed
--- /dev/null
+++ b/mdir.c
@@ -0,0 +1,618 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-2002,2004,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 global_shortname[13];
+static char global_longname[VBUFSIZE];
+
+
+/*
+ * Print an MSDOS directory date stamp.
+ */
+static __inline__ void print_date(struct directory *dir)
+{
+       char year[5];
+       char day[3];
+       char month[3];
+       const char *p;
+
+       sprintf(year, "%04d", DOS_YEAR(dir));
+       sprintf(day, "%02d", DOS_DAY(dir));
+       sprintf(month, "%02d", DOS_MONTH(dir));
+
+       for(p=mtools_date_string; *p; p++) {
+               if(!strncasecmp(p, "yyyy", 4)) {
+                       printf("%04d", DOS_YEAR(dir));
+                       p+= 3;
+                       continue;
+               } else if(!strncasecmp(p, "yy", 2)) {
+                       printf("%02d", DOS_YEAR(dir) % 100);
+                       p++;
+                       continue;
+               } else if(!strncasecmp(p, "dd", 2)) {
+                       printf("%02d", DOS_DAY(dir));
+                       p++;
+                       continue;
+               } else if(!strncasecmp(p, "mm", 2)) {
+                       printf("%02d", DOS_MONTH(dir));
+                       p++;
+                       continue;
+               }
+               putchar(*p);
+       }
+}
+
+/*
+ * Print an MSDOS directory time stamp.
+ */
+static __inline__ void print_time(struct directory *dir)
+{
+       char am_pm;
+       int hour = DOS_HOUR(dir);
+       
+       if(!mtools_twenty_four_hour_clock) {
+               am_pm = (hour >= 12) ? 'p' : 'a';
+               if (hour > 12)
+                       hour = hour - 12;
+               if (hour == 0)
+                       hour = 12;
+       } else
+               am_pm = ' ';
+
+       printf("%2d:%02d%c", hour, DOS_MINUTE(dir), am_pm);
+}
+
+/*
+ * Return a number in dotted notation
+ */
+static const char *dotted_num(mt_size_t num, int width, char **buf)
+{
+       int      len;
+       register char *srcp, *dstp;
+       int size;
+
+       unsigned long numlo;
+       unsigned long numhi;
+
+       if (num < 0) {
+           /* warn about negative numbers here.  They should not occur */
+           fprintf(stderr, "Invalid negative number\n");
+       }
+
+       size = width + width;
+       *buf = malloc(size+1);
+
+       if (*buf == NULL)
+               return "";
+       
+       /* Create the number in maximum width; make sure that the string
+        * length is not exceeded (in %6ld, the result can be longer than 6!)
+        */
+
+       numlo = num % 1000000000;
+       numhi = num / 1000000000;
+
+       if(numhi && size > 9) {
+               sprintf(*buf, "%.*lu%09lu", size-9, numhi, numlo);
+       } else {
+               sprintf(*buf, "%.*lu", size, numlo);
+       }
+
+       for (srcp=*buf; srcp[1] != '\0'; ++srcp)
+               if (srcp[0] == '0')
+                       srcp[0] = ' ';
+               else
+                       break;
+       
+       len = strlen(*buf);
+       srcp = (*buf)+len;
+       dstp = (*buf)+len+1;
+
+       for ( ; dstp >= (*buf)+4 && isdigit (srcp[-1]); ) {
+               srcp -= 3;  /* from here we copy three digits */
+               dstp -= 4;  /* that's where we put these 3 digits */
+       }
+
+       /* now finally copy the 3-byte blocks to their new place */
+       while (dstp < (*buf) + len) {
+               dstp[0] = srcp[0];
+               dstp[1] = srcp[1];
+               dstp[2] = srcp[2];
+               if (dstp + 3 < (*buf) + len)
+                       /* use spaces instead of dots: they please both
+                        * Americans and Europeans */
+                       dstp[3] = ' ';          
+               srcp += 3;
+               dstp += 4;
+       }
+
+       return (*buf) + len-width;
+}
+
+static __inline__ int print_volume_label(Stream_t *Dir, char drive)
+{
+       Stream_t *Stream = GetFs(Dir);
+       direntry_t entry;
+       DeclareThis(FsPublic_t);
+       char shortname[13];
+       char longname[VBUFSIZE];
+       int r;
+
+       RootDir = OpenRoot(Stream);
+       if(concise)
+               return 0;
+       
+       /* find the volume label */
+
+       initializeDirentry(&entry, RootDir);
+       if((r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
+                         shortname, longname)) ) {
+               if (r == -2) {
+                       /* I/O Error */
+                       return -1;
+               }
+               printf(" Volume in drive %c has no label", drive);
+       } else if (*longname)
+               printf(" Volume in drive %c is %s (abbr=%s)",
+                      drive, longname, shortname);
+       else
+               printf(" Volume in drive %c is %s",
+                      drive, shortname);
+       if(This->serialized)
+               printf("\n Volume Serial Number is %04lX-%04lX",
+                      (This->serial_number >> 16) & 0xffff, 
+                      This->serial_number & 0xffff);
+       return 0;
+}
+
+
+static void printSummary(int files, mt_size_t bytes)
+{
+       if(!filesInDir)
+               printf("No files\n");
+       else {          
+               char *s1 = NULL;
+               printf("      %3d file", files);
+               if(files == 1)
+                       putchar(' ');
+               else
+                       putchar('s');
+               printf("       %s bytes\n",
+                      dotted_num(bytes, 13, &s1));
+               if(s1)
+                       free(s1);
+       }
+}
+
+static void leaveDirectory(int haveError);
+
+static void leaveDrive(int haveError)
+{
+       if(!currentDrive)
+               return;
+       leaveDirectory(haveError);
+       if(!concise && !haveError) {
+
+               if(dirsOnDrive > 1) {
+                       printf("\nTotal files listed:\n");
+                       printSummary(filesOnDrive, bytesOnDrive);
+               }
+               if(RootDir && !fast) {
+                       char *s1 = NULL;
+                       mt_off_t bytes = getfree(RootDir);
+                       if(bytes == -1) {
+                               fprintf(stderr, "Fat error\n");
+                               goto exit_1;
+                       }
+                       printf("                  %s bytes free\n\n",
+                              dotted_num(bytes,17, &s1));
+#ifdef TEST_SIZE
+                       ((Fs_t*)GetFs(RootDir))->freeSpace = 0;
+                       bytes = getfree(RootDir);
+                       printf("                  %s bytes free\n\n",
+                              dotted_num(bytes,17, &s1));
+#endif
+                       if(s1)
+                               free(s1);
+               }
+       }
+ exit_1:
+       FREE(&RootDir);
+       currentDrive = '\0';
+}
+
+
+static int enterDrive(Stream_t *Dir, char drive)
+{
+       int r;
+       if(currentDrive == drive)
+               return 0; /* still the same */
+       
+       leaveDrive(0);
+       currentDrive = drive;
+       
+       r = print_volume_label(Dir, drive);
+       if (r)
+               return r;
+
+
+       bytesOnDrive = 0;
+       filesOnDrive = 0;
+       dirsOnDrive = 0;
+       return 0;
+}
+
+static const char *emptyString="<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)
+{
+       unsigned long size;
+       int i;
+       int Case;
+       int r;
+
+       wchar_t ext[4];
+       wchar_t name[9];
+       doscp_t *cp;
+
+       if(!all && (entry->dir.attr & 0x6))
+               return 0;
+
+       if(concise && isSpecialW(entry->name))
+               return 0;
+
+       r=enterDirectory(entry->Dir);
+       if (r)
+               return ERROR_ONE;
+       if (wide) {
+               if(filesInDir % 5)
+                       putchar(' ');                           
+               else
+                       putchar('\n');
+       }
+       
+       if(IS_DIR(entry)){
+               size = 0;
+       } else
+               size = FILE_SIZE(&entry->dir);
+       
+       Case = entry->dir.Case;
+       if(!(Case & (BASECASE | EXTCASE)) && 
+          mtools_ignore_short_case)
+               Case |= BASECASE | EXTCASE;
+       
+       cp = GET_DOSCONVERT(entry->Dir);
+       dos_to_wchar(cp, entry->dir.ext, ext, 3);
+       if(Case & EXTCASE){
+               for(i=0; i<3;i++)
+                       ext[i] = towlower(ext[i]);
+       }
+       ext[3] = '\0';
+       dos_to_wchar(cp, entry->dir.name, name, 8);
+       if(Case & BASECASE){
+               for(i=0; i<8;i++)
+                       name[i] = towlower(name[i]);
+       }
+       name[8]='\0';
+       if(wide){
+               if(IS_DIR(entry))
+                       printf("[%s]%*s", global_shortname,
+                              (int) (15 - 2 - strlen(global_shortname)), "");
+               else
+                       printf("%-15s", global_shortname);
+       } else if(!concise) {                           
+               char tmpBasename[4*8+1];
+               char tmpExt[4*8+1];
+               wchar_to_native(name,tmpBasename,8);
+               wchar_to_native(ext,tmpExt,3);
+
+               if (name[0] == ' ') 
+                       printf("             ");
+               else if(mtools_dotted_dir)
+                       printf("%s", global_shortname);
+               else
+                       printf("%s %s ", tmpBasename, tmpExt);
+               /* is a subdirectory */
+               if(IS_DIR(entry))
+                       printf("<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(*global_longname)
+                       printf(" %s", global_longname);
+               printf("\n");
+       } else {
+               char tmp[4*MAX_VNAMELEN+1];
+               wchar_to_native(entry->name,tmp,MAX_VNAMELEN);
+
+               printf("%s/%s", dirPath, tmp);
+               if(IS_DIR(entry))
+                       putchar('/');
+               putchar('\n');
+       }
+
+       filesOnDrive++;
+       filesInDir++;
+
+       bytesOnDrive += (mt_size_t) size;
+       bytesInDir += (mt_size_t) size;
+       return GOT_ONE;
+}
+
+static int list_non_recurs_directory(direntry_t *entry, MainParam_t *mp)
+{
+       int r;
+       /* list top-level directory
+        *   If this was matched by wildcard in the basename, list it as
+        *   file, otherwise, list it as directory */
+       if (mp->basenameHasWildcard) {
+               /* wildcard, list it as file */
+               return list_file(entry, mp);
+       } else {
+               /* no wildcard, list it as directory */
+               MainParam_t subMp;
+
+               r=enterDirectory(mp->File);
+               if(r)
+                       return ERROR_ONE;
+
+               subMp = *mp;
+               subMp.dirCallback = subMp.callback;
+               return mp->loop(mp->File, &subMp, "*") | GOT_ONE;
+       }
+}
+
+
+static int list_recurs_directory(direntry_t *entry, MainParam_t *mp)
+{
+       MainParam_t subMp;
+       int ret;
+
+       /* first list the files */
+       subMp = *mp;
+       subMp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN;
+       subMp.dirCallback = list_file;
+       subMp.callback = list_file;
+
+       ret = mp->loop(mp->File, &subMp, "*");
+
+       /* then list subdirectories */
+       subMp = *mp;
+       subMp.lookupflags = ACCEPT_DIR | NO_DOTS | NO_MSG | DO_OPEN;
+       return ret | mp->loop(mp->File, &subMp, "*");
+}
+
+#if 0
+static int test_directory(direntry_t *entry, MainParam_t *mp)
+{
+       Stream_t *File=mp->File;
+       Stream_t *Target;
+       char errmsg[80];
+
+       if ((Target = SimpleFileOpen(0, 0, "-",
+                                    O_WRONLY,
+                                    errmsg, 0, 0, 0))) {
+               copyfile(File, Target);
+               FREE(&Target);
+       }
+       return GOT_ONE;
+}
+#endif
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+               fprintf(stderr, "Mtools version %s, dated %s\n",
+                       mversion, mdate);
+               fprintf(stderr, "Usage: %s: [-V] [-w] [-a] [-b] [-s] [-f] msdosdirectory\n",
+                       progname);
+               fprintf(stderr,
+                       "       %s: [-V] [-w] [-a] [-b] [-s] [-f] msdosfile [msdosfiles...]\n",
+                       progname);
+               exit(ret);
+}
+
+
+void mdir(int argc, char **argv, int type)
+{
+       int ret;
+       MainParam_t mp;
+       int faked;
+       int c;
+       const char *fakedArgv[] = { "." };
+
+       concise = 0;
+       recursive = 0;
+       wide = all = 0;
+                                       /* first argument */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:waXbfds/h")) != EOF) {
+               switch(c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'w':
+                               wide = 1;
+                               break;
+                       case 'a':
+                               all = 1;
+                               break;
+                       case 'b':
+                       case 'X':
+                               concise = 1;
+                               /*recursive = 1;*/
+                               break;
+                       case 's':
+                       case '/':
+                               recursive = 1;
+                               break;
+                       case 'f':
+                               fast = 1;
+                               break;
+                       case 'd':
+                               debug = 1;
+                               break;
+#if 0
+                       case 't': /* test mode */
+                               testmode = 1;
+                               break;
+#endif
+                       case 'h':
+                               usage(0);
+                       default:
+                               usage(1);
+               }
+       }
+
+       /* fake an argument */
+       faked = 0;
+       if (optind == argc) {
+               argv = (char **)fakedArgv;
+               argc = 1;
+               optind = 0;
+       }
+
+       init_mp(&mp);
+       currentDrive = '\0';
+       currentDir = 0;
+       RootDir = 0;
+       dirPath = 0;
+#if 0
+       if (testmode) {
+               mp.lookupflags = ACCEPT_DIR | NO_DOTS;
+               mp.dirCallback = test_directory;
+       } else 
+#endif
+               if(recursive) {
+               mp.lookupflags = ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
+               mp.dirCallback = list_recurs_directory;
+       } else {
+               mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN | DO_OPEN_DIRS;
+               mp.dirCallback = list_non_recurs_directory;
+               mp.callback = list_file;
+       }
+       mp.longname = global_longname;
+       mp.shortname = global_shortname;
+       ret=main_loop(&mp, argv + optind, argc - optind);
+       leaveDirectory(ret);
+       leaveDrive(ret);
+       exit(ret);
+}
diff --git a/mdoctorfat.c b/mdoctorfat.c
new file mode 100644 (file)
index 0000000..7f5c5f1
--- /dev/null
@@ -0,0 +1,183 @@
+/*  Copyright 1999,2001,2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Test program for doctoring the fat
+ */
+
+
+#define LOWERCASE
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "mainloop.h"
+#include "plain_io.h"
+#include "nameclash.h"
+#include "file.h"
+#include "fs.h"
+#include "fsP.h"
+
+typedef struct Arg_t {
+       char *target;
+       MainParam_t mp;
+       ClashHandling_t ch;
+       Stream_t *sourcefile;
+       unsigned long fat;
+       int markbad;
+       int setsize;
+       unsigned long size;
+       Fs_t *Fs;
+} Arg_t;
+
+static int dos_doctorfat(direntry_t *entry, MainParam_t *mp)
+{
+       Fs_t *Fs = getFs(mp->File);
+       Arg_t *arg=(Arg_t *) mp->arg;
+       
+       if(!arg->markbad && entry->entry != -3) {
+               /* if not root directory, change it */
+               set_word(entry->dir.start, arg->fat & 0xffff);
+               set_word(entry->dir.startHi, arg->fat >> 16);
+               if(arg->setsize)
+                       set_dword(entry->dir.size, arg->size);
+               dir_write(entry);               
+       }
+       arg->Fs = Fs; 
+       return GOT_ONE;
+}
+
+static int unix_doctorfat(MainParam_t *mp)
+{
+       fprintf(stderr,"File does not reside on a Dos fs\n");
+       return ERROR_ONE;
+}
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr,
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr,
+               "Usage: [-b] %s file fat\n", progname);
+       exit(ret);
+}
+
+void mdoctorfat(int argc, char **argv, int mtype)
+{
+       Arg_t arg;
+       int c, ret;
+       long address, begin, end;
+       char *number, *eptr;
+       int i, j;
+       long offset;
+       
+       /* get command line options */
+
+       init_clash_handling(& arg.ch);
+
+       offset = 0;
+
+       arg.markbad = 0;
+       arg.setsize = 0;
+
+       /* get command line options */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:bo:s:h")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'b':
+                               arg.markbad = 1;
+                               break;
+                       case 'o':
+                               offset = strtoul(optarg,0,0);
+                               break;
+                       case 's':
+                               arg.setsize=1;
+                               arg.size = strtoul(optarg,0,0);
+                               break;
+                       case 'h':
+                               usage(0);
+                       case '?':
+                               usage(1);
+                               break;
+               }
+       }
+
+       if (argc - optind < 2)
+               usage(1);
+
+
+       /* only 1 file to copy... */
+       init_mp(&arg.mp);
+       arg.mp.arg = (void *) &arg;
+               
+       arg.mp.callback = dos_doctorfat;
+       arg.mp.unixcallback = unix_doctorfat;
+       
+       arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
+       arg.mp.openflags = O_RDWR;
+       arg.fat = strtoul(argv[optind+1], 0, 0) + offset;
+       ret=main_loop(&arg.mp, argv + optind, 1);
+       if(ret)
+               exit(ret);
+       address = 0;
+       for(i=optind+1; i < argc; i++) {
+               number = argv[i];
+               if (*number == '<') {
+                       number++;
+               }
+               begin = strtoul(number, &eptr, 0);
+               if (eptr && *eptr == '-') {
+                       number = eptr+1;
+                       end = strtoul(number, &eptr, 0);
+               } else {
+                       end = begin;
+               }
+               if (eptr == number) {
+                       fprintf(stderr, "Not a number: %s\n", number);
+                       exit(-1);
+               }
+
+               if (eptr && *eptr == '>') {
+                       eptr++;
+               }
+               if (eptr && *eptr) {
+                       fprintf(stderr, "Not a number: %s\n", eptr);
+                       exit(-1);
+               }
+
+               for (j=begin; j <= end; j++) {
+                       if(arg.markbad) {
+                               arg.Fs->fat_encode(arg.Fs, j+offset, arg.Fs->last_fat ^ 6 ^ 8);
+                       } else {
+                               if(address) {
+                                       arg.Fs->fat_encode(arg.Fs, address, j+offset);
+                               }
+                               address = j+offset;
+                       }
+               }
+       }
+
+       if (address && !arg.markbad) {
+               arg.Fs->fat_encode(arg.Fs, address, arg.Fs->end_fat);
+       }
+
+       exit(ret);
+}
diff --git a/mdu.1 b/mdu.1
new file mode 100644 (file)
index 0000000..1641297
--- /dev/null
+++ b/mdu.1
@@ -0,0 +1,99 @@
+.TH mdu 1 "03Nov09" mtools-4.0.12
+.SH Name
+mdu - display the amount of space occupied by an MSDOS directory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mdu"
+.iX "c Space occupied by directories and files"
+.iX "c du"
+.iX "c Listing space occupied by directories and files"
+.iX "c Occupation of space by directories and files"
+.PP
+\&\fR\&\f(CWMdu\fR is used to list the space occupied by a directory, its
+subdirectories and its files. It is similar to the \fR\&\f(CWdu\fR command on
+Unix.  The unit used are clusters.  Use the minfo command to find out
+the cluster size.
+.PP
+\&\fR\&\f(CWmdu\fR [\fR\&\f(CW-a\fR] [ \fImsdosfiles\fR \&... ]
+.TP
+\&\fR\&\f(CWa\fR\ 
+All files.  List also the space occupied for individual files.
+.TP
+\&\fR\&\f(CWs\fR\ 
+Only list the total space, don't give details for each subdirectory.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdu.c b/mdu.c
new file mode 100644 (file)
index 0000000..87ddeaf
--- /dev/null
+++ b/mdu.c
@@ -0,0 +1,140 @@
+/*  Copyright 1997,2000-2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+       Arg_t arg;
+       int c;
+
+       arg.all = 0;
+       arg.inDir = 0;
+       arg.summary = 0;
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:ash")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'a':
+                               arg.all = 1;
+                               break;
+                       case 's':
+                               arg.summary = 1;
+                               break;
+                       case 'h':
+                               usage(0);
+                       case '?':
+                               usage(1);
+               }
+       }
+
+       if (optind >= argc)
+               usage(1);
+
+       if(arg.summary && arg.all) {
+               fprintf(stderr,"-a and -s options are mutually exclusive\n");
+               usage(1);
+       }
+
+       init_mp(&arg.mp);
+       arg.mp.callback = file_mdu;
+       arg.mp.openflags = O_RDONLY;
+       arg.mp.dirCallback = dir_mdu;
+
+       arg.mp.arg = (void *) &arg;
+       arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
+       exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mformat.1 b/mformat.1
new file mode 100644 (file)
index 0000000..7184486
--- /dev/null
+++ b/mformat.1
@@ -0,0 +1,282 @@
+.TH mformat 1 "03Nov09" mtools-4.0.12
+.SH Name
+mformat - add an MSDOS filesystem to a low-level formatted floppy disk
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mformat"
+.iX "c Initializing disks"
+.iX "c Formatting disks"
+.iX "c Filesystem creation"
+.PP
+The \fR\&\f(CWmformat\fR command is used to add an MS-DOS filesystem to a
+low-level formatted diskette. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmformat\fR [\fR\&\f(CW-t\fR \fIcylinders\fR] [\fR\&\f(CW-h\fR \fIheads\fR] [\fR\&\f(CW-s\fR \fIsectors\fR]
+  [\fR\&\f(CW-f\fR \fIsize\fR] [\fR\&\f(CW-1\fR] [\fR\&\f(CW-4\fR] [\fR\&\f(CW-8\fR]
+  [\fR\&\f(CW-v\fR \fIvolume_label\fR]
+  [\fR\&\f(CW-F\fR] [\fR\&\f(CW-S\fR \fIsizecode\fR] [\fR\&\f(CW-X\fR]
+  [\fR\&\f(CW-2\fR \fIsectors_on_track_0\fR] [\fR\&\f(CW-3\fR]
+  [\fR\&\f(CW-0\fR \fIrate_on_track_0\fR] [\fR\&\f(CW-A\fR \fIrate_on_other_tracks\fR]
+  [\fR\&\f(CW-M\fR \fIsoftware_sector_size\fR]
+  [\fR\&\f(CW-N\fR \fIserial_number\fR] [\fR\&\f(CW-a\fR]
+  [\fR\&\f(CW-C\fR] [\fR\&\f(CW-H\fR \fIhidden_sectors\fR] [\fR\&\f(CW-I\fR \fIfsVersion\fR]
+  [\fR\&\f(CW-r\fR \fIroot_sectors\fR] [\fR\&\f(CW-L\fR \fIfat_len\fR] 
+  [\fR\&\f(CW-B\fR \fIboot_sector\fR] [\fR\&\f(CW-k\fR]
+  [\fR\&\f(CW-m\fR \fImedia_descriptor\fR]
+  \fIdrive:\fR
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMformat\fR adds a minimal MS-DOS filesystem (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+.PP
+The following options are supported: (The S, 2, 1 and M options may not
+exist if this copy of mtools has been compiled without the USE_2M
+option)
+.PP
+The following options are the same as for Dos's format command:
+.PP
+.SH Options
+.TP
+\&\fR\&\f(CWv\fR\ 
+Specifies the volume label. A volume label identifies the disk and can
+be a maximum of 11 characters. If you omit the -v switch, mlabel will
+assign no label to the disk.
+.TP
+\&\fR\&\f(CWf\fR\ 
+Specifies the size of the DOS filesystem to format. Only a certain
+number of predefined sizes are supported by this flag; for others use
+the -h/-t/-s flags. The following sizes are supported:
+.RS
+.TP
+160\ 
+160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+180\ 
+160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+320\ 
+320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+360\ 
+360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+720\ 
+720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD)
+.TP
+1200\ 
+1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD)
+.TP
+1440\ 
+1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD)
+.TP
+2880\ 
+2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED)
+.RE
+.TP
+\&\fR\&\f(CWt\fR\ 
+Specifies the number of tracks on the disk.
+.TP
+\&\fR\&\f(CWh\fR\ 
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWn\fR\ 
+Specifies the number of sectors per track. If the 2m option is given,
+number of 512-byte sector equivalents on generic tracks (i.e. not head 0
+track 0).  If the 2m option is not given, number of physical sectors per
+track (which may be bigger than 512 bytes).
+.TP
+\&\fR\&\f(CW1\fR\ 
+Formats a single side (equivalent to -h 1)
+.TP
+\&\fR\&\f(CW4\fR\ 
+Formats a 360K double-sided disk (equivalent to -f 360). When used
+together with -the 1 switch, this switch formats a 180K disk
+.TP
+\&\fR\&\f(CW8\fR\ 
+Formats a disk with 8 sectors per track.
+.PP
+MSDOS format's \fR\&\f(CWq\fR, \fR\&\f(CWu\fR and \fR\&\f(CWb\fR options are not
+supported, and \fR\&\f(CWs\fR has a different meaning.
+.PP
+The following options are specific to mtools:
+.IP
+.TP
+\&\fR\&\f(CWF\fR\ 
+Format the partition as FAT32.
+.TP
+\&\fR\&\f(CWS\fR\ 
+The sizecode. The size of the sector is 2 ^ (sizecode + 7).
+.TP
+\&\fR\&\f(CWX\fR\ 
+formats the disk as an XDF disk. See section XDF, for more details. The disk
+has first to be low-level formatted using the xdfcopy utility included
+in the fdutils package. XDF disks are used for instance for OS/2 install
+disks.
+.TP
+\&\fR\&\f(CW2\fR\ 
+2m format. The parameter to this option describes the number of
+sectors on track 0, head 0. This option is recommended for sectors
+bigger than normal.
+.TP
+\&\fR\&\f(CW3\fR\ 
+don't use a 2m format, even if the current geometry of the disk is a 2m 
+geometry.
+.TP
+\&\fR\&\f(CW0\fR\ 
+Data transfer rate on track 0
+.TP
+\&\fR\&\f(CWA\fR\ 
+Data transfer rate on tracks other than 0
+.TP
+\&\fR\&\f(CWM\fR\ 
+software sector size. This parameter describes the sector size in bytes used
+by the MS-DOS filesystem. By default it is the physical sector size.
+.TP
+\&\fR\&\f(CWN\fR\ 
+Uses the requested serial number, instead of generating one
+automatically
+.TP
+\&\fR\&\f(CWa\fR\ 
+If this option is given, an Atari style serial number is generated.
+Ataris store their serial number in the OEM label.
+.TP
+\&\fR\&\f(CWC\fR\ 
+creates the disk image file to install the MS-DOS filesystem on
+it. Obviously, this is useless on physical devices such as floppies
+and hard disk partitions, but is interesting for image files.
+.TP
+\&\fR\&\f(CWH\fR\ 
+number of hidden sectors. This parameter is useful for formatting hard
+disk partition, which are not aligned on track boundaries (i.e. first
+head of first track doesn't belong to the partition, but contains a
+partition table). In that case the number of hidden sectors is in
+general the number of sectors per cylinder. This is untested.
+.TP
+\&\fR\&\f(CWI\fR\ 
+Sets the fsVersion id when formatting a FAT32 drive.  In order to find
+this out, run minfo on an existing FAT32 drive, and mail me about it, so
+I can include the correct value in future versions of mtools.
+.TP
+\&\fR\&\f(CWc\fR\ 
+Sets the size of a cluster (in sectors).  If this cluster size would
+generate a FAT that too big for its number of bits, mtools automatically
+increases the cluster size, until the FAT is small enough.
+.TP
+\&\fR\&\f(CWd\fR\ 
+Sets the number of FAT copies. Default is 2. This setting can also be
+specified using the \fR\&\f(CWMTOOLS_NFATS\fR environment variable.
+.TP
+\&\fR\&\f(CWr\fR\ 
+Sets the size of the root directory (in sectors).  Only applicable to 12
+and 16 bit FATs. This setting can also be specified using the
+\&\fR\&\f(CWMTOOLS_DIR_LEN\fR environment variable.
+.TP
+\&\fR\&\f(CWL\fR\ 
+Sets the length of the FAT.
+.TP
+\&\fR\&\f(CWB\fR\ 
+Use the bootsector stored in the given file or device, instead of using
+its own.  Only the geometry fields are updated to match the target disks
+parameters.
+.TP
+\&\fR\&\f(CWk\fR\ 
+Keep the existing boot sector as much as possible.  Only the geometry
+fields and other similar filesystem data are updated to match the target
+disks parameters.
+.TP
+\&\fR\&\f(CWm\fR\ 
+Use a non-standard media descriptor byte for this disk. The media
+descriptor is stored at position 21 of the boot sector, and as first
+byte in each FAT copy. Using this option may confuse DOS or older mtools
+version, and may make the disk unreadable. Only use if you know what you
+are doing.
+.PP
+To format a diskette at a density other than the default, you must supply
+(at least) those command line parameters that are different from the
+default.
+.PP
+\&\fR\&\f(CWMformat\fR returns 0 on success or 1 on failure.
+.PP
+It doesn't record bad block information to the Fat, use
+\&\fR\&\f(CWmbadblocks\fR for that.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mformat.c b/mformat.c
new file mode 100644 (file)
index 0000000..c60f65d
--- /dev/null
+++ b/mformat.c
@@ -0,0 +1,1324 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1994,1996-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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,
+                              int sectors0, int rate_0, int rate_any,
+                              unsigned long *tot_sectors, int keepBoot)
+{
+       int i;
+       int nb_renum;
+       int sector2;
+       int size2;
+       int j;
+       int sum;
+
+       set_word(boot->boot.nsect, dev->sectors);
+       set_word(boot->boot.nheads, dev->heads);
+
+       *tot_sectors = dev->heads * dev->sectors * dev->tracks - DWORD(nhs);
+
+       if (*tot_sectors < 0x10000){
+               set_word(boot->boot.psect, *tot_sectors);
+               set_dword(boot->boot.bigsect, 0);
+       } else {
+               set_word(boot->boot.psect, 0);
+               set_dword(boot->boot.bigsect, *tot_sectors);
+       }
+
+       if (dev->use_2m & 0x7f){
+               int bootOffset;
+               strncpy(boot->boot.banner, "2M-STV04", 8);
+               boot->boot.ext.old.res_2m = 0;
+               boot->boot.ext.old.fmt_2mf = 6;
+               if ( dev->sectors % ( ((1 << dev->ssize) + 3) >> 2 ))
+                       boot->boot.ext.old.wt = 1;
+               else
+                       boot->boot.ext.old.wt = 0;
+               boot->boot.ext.old.rate_0= rate_0;
+               boot->boot.ext.old.rate_any= rate_any;
+               if (boot->boot.ext.old.rate_any== 2 )
+                       boot->boot.ext.old.rate_any= 1;
+               i=76;
+
+               /* Infp0 */
+               set_word(boot->boot.ext.old.Infp0, i);
+               boot->bytes[i++] = sectors0;
+               boot->bytes[i++] = 108;
+               for(j=1; j<= sectors0; j++)
+                       boot->bytes[i++] = j;
+
+               set_word(boot->boot.ext.old.InfpX, i);
+               
+               boot->bytes[i++] = 64;
+               boot->bytes[i++] = 3;
+               nb_renum = i++;
+               sector2 = dev->sectors;
+               size2 = dev->ssize;
+               j=1;
+               while( sector2 ){
+                       while ( sector2 < (1 << size2) >> 2 )
+                               size2--;
+                       boot->bytes[i++] = 128 + j;
+                       boot->bytes[i++] = j++;
+                       boot->bytes[i++] = size2;
+                       sector2 -= (1 << size2) >> 2;
+               }
+               boot->bytes[nb_renum] = ( i - nb_renum - 1 ) / 3;
+
+               set_word(boot->boot.ext.old.InfTm, i);
+
+               sector2 = dev->sectors;
+               size2= dev->ssize;
+               while(sector2){
+                       while ( sector2 < 1 << ( size2 - 2) )
+                               size2--;
+                       boot->bytes[i++] = size2;
+                       sector2 -= 1 << (size2 - 2 );
+               }
+               
+               set_word(boot->boot.ext.old.BootP,i);
+               bootOffset = i;
+
+               /* checksum */          
+               for (sum=0, j=64; 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(tot_sectors >= 2* min_fat16_size)
+                       return 16; /* heuristics */
+       }
+
+       return estimate;
+}
+
+
+/*
+ * According to Microsoft "Hardware White Paper", "Microsoft
+ * Extensible Formware Initiative", "FAT32 File System Specification",
+ * Version 1.03, December 6, 2000:
+ * If (CountofClusters < 4085) { 
+ *  // Volume is FAT12  
+ * } else if (CountofClusters < 65525) { 
+ *  // Volume is FAT16
+ * } else { 
+ *  //Volume is FAT32
+ * }
+ *
+ * This document can be found at the following URL
+ * http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf
+ * The relevant passus is on page 15.
+ *
+ * Actually, experimentations with Windows NT 4 show that the
+ * cutoff is 4087 rather than 4085... This is Microsoft after all.
+ * Not sure what the other Microsoft OS'es do though...
+ */
+static void calc_fat_bits2(Fs_t *Fs, unsigned long tot_sectors, int fat_bits,
+                          int may_change_cluster_size, 
+                          int may_change_root_size)
+{
+       unsigned long rem_sect;
+
+       /*
+        * the "remaining sectors" after directory and boot
+        * hasve been accounted for.
+        */
+       rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
+       switch(abs(fat_bits)) {
+               case 0:
+
+#define MY_DISK_SIZE(bits,clusters) \
+                       DISK_SIZE( (bits), Fs->sector_size, (clusters), \
+                                  Fs->num_fat, Fs->cluster_size)
+
+                       if(rem_sect >= MY_DISK_SIZE(16, FAT12+2))
+                               /* big enough for FAT16 
+                                * We take a margin of 2, because NT4 
+                                * misbehaves, and starts considering a disk
+                                * as FAT16 only if it is larger than 4086
+                                * sectors, rather than 4084 as it should
+                                */
+                               set_fat16(Fs);
+                       else if(rem_sect <= MY_DISK_SIZE(12, FAT12-1))
+                                /* small enough for FAT12 */
+                                set_fat12(Fs);
+                       else {
+                               /* "between two chairs",
+                                * augment cluster size, and
+                                * settle it */
+                               if(may_change_cluster_size && 
+                                  Fs->cluster_size * Fs->sector_size * 2 
+                                  <= MAX_BYTES_PER_CLUSTER)
+                                       Fs->cluster_size <<= 1;
+                               else if(may_change_root_size) {
+                                       Fs->dir_len +=
+                                               rem_sect - MY_DISK_SIZE(12, FAT12-1);
+                               }
+                               set_fat12(Fs);
+                       }
+                       break;
+#undef MY_DISK_SIZE
+
+               case 12:
+                       set_fat12(Fs);
+                       break;
+               case 16:
+                       set_fat16(Fs);
+                       break;
+               case 32:
+                       set_fat32(Fs);
+                       break;
+       }
+}
+
+static __inline__ void format_root(Fs_t *Fs, char *label, union bootsector *boot)
+{
+       Stream_t *RootDir;
+       char *buf;
+       int i;
+       struct ClashHandling_t ch;
+       int dirlen;
+
+       init_clash_handling(&ch);
+       ch.name_converter = label_name;
+       ch.ignore_entry = -2;
+
+       buf = safe_malloc(Fs->sector_size);
+       RootDir = OpenRoot((Stream_t *)Fs);
+       if(!RootDir){
+               fprintf(stderr,"Could not open root directory\n");
+               exit(1);
+       }
+
+       memset(buf, '\0', Fs->sector_size);
+
+       if(Fs->fat_bits == 32) {
+               /* on a FAT32 system, we only write one sector,
+                * as the directory can be extended at will...*/
+               dirlen = Fs->cluster_size;
+               fatAllocate(Fs, Fs->rootCluster, Fs->end_fat);
+       } else
+               dirlen = Fs->dir_len;
+       for (i = 0; i < dirlen; i++)
+               WRITES(RootDir, buf, sectorsToBytes((Stream_t*)Fs, i),
+                          Fs->sector_size);
+
+       ch.ignore_entry = 1;
+       if(label[0])
+               mwrite_one(RootDir,label, 0, labelit, NULL,&ch);
+
+       FREE(&RootDir);
+       if(Fs->fat_bits == 32)
+               set_word(boot->boot.dirents, 0);
+       else
+               set_word(boot->boot.dirents, Fs->dir_len * (Fs->sector_size / 32));
+       free(buf);
+}
+
+
+static void xdf_calc_fat_size(Fs_t *Fs, unsigned long tot_sectors,
+                             int fat_bits)
+{
+       unsigned int rem_sect;
+
+       rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start - 2 * Fs->fat_len;
+
+       if(Fs->fat_len) {
+               /* an XDF disk, we know the fat_size and have to find
+                * out the rest. We start with a cluster size of 1 and
+                * keep doubling until everything fits into the
+                * FAT. This will occur eventually, as our FAT has a
+                * minimal size of 1 */
+               for(Fs->cluster_size = 1; 1 ; Fs->cluster_size <<= 1) {
+                       Fs->num_clus = rem_sect / Fs->cluster_size;
+                       if(abs(fat_bits) == 16 || Fs->num_clus >= FAT12)
+                               set_fat16(Fs);
+                       else
+                               set_fat12(Fs);
+                       if (Fs->fat_len >= NEEDED_FAT_SIZE(Fs))
+                               return;
+               }
+       }
+       fprintf(stderr,"Internal error while calculating Xdf fat size\n");
+       exit(1);
+}
+
+
+static void calc_fat_size(Fs_t *Fs, unsigned long tot_sectors)
+{
+       unsigned long rem_sect;
+       unsigned long real_rem_sect;
+       unsigned long numerator;
+       unsigned long denominator;
+       int fat_nybbles;
+       unsigned int slack;
+       int printGrowMsg=1; /* Should we print "growing FAT" messages ?*/
+       
+#ifdef DEBUG
+       fprintf(stderr, "Fat start=%d\n", Fs->fat_start);
+       fprintf(stderr, "tot_sectors=%lu\n", tot_sectors);
+       fprintf(stderr, "dir_len=%d\n", Fs->dir_len);
+#endif
+       real_rem_sect = rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
+
+       /* Cheat a little bit to address the _really_ common case of
+          odd number of remaining sectors while both nfat and cluster size
+          are even... */
+       if(rem_sect         %2 == 1 &&
+          Fs->num_fat      %2 == 0 &&
+          Fs->cluster_size %2 == 0)
+               rem_sect--;
+
+#ifdef DEBUG
+       fprintf(stderr, "Rem sect=%lu\n", rem_sect);
+#endif
+
+       if(Fs->fat_bits == 0) {
+               fprintf(stderr, "Weird, fat bits = 0\n");
+               exit(1);                
+       }
+
+
+       /* See fat_size_calculation.tex or
+          (http://ftp.gnu.org/software/mtools/manual/fat_size_calculation.pdf)
+          for an explantation about why the stuff below works...
+       */
+
+       fat_nybbles = Fs->fat_bits / 4;
+       numerator   = rem_sect+2*Fs->cluster_size;
+       denominator =
+         Fs->cluster_size * Fs->sector_size * 2 +
+         Fs->num_fat * fat_nybbles;
+
+       if(fat_nybbles == 3)
+               numerator *= fat_nybbles;
+       else
+               /* Avoid numerical overflows, divide the denominator
+                * rather than multiplying the numerator */
+               denominator = denominator / fat_nybbles;
+
+#ifdef DEBUG
+       fprintf(stderr, "Numerator=%lu denominator=%lu\n",
+               numerator, denominator);
+#endif
+
+       Fs->fat_len = (numerator-1)/denominator+1;
+       Fs->num_clus = (rem_sect-(Fs->fat_len*Fs->num_fat))/Fs->cluster_size;
+
+       /* Apply upper bounds for FAT bits */
+       if(Fs->fat_bits == 16 && Fs->num_clus >= FAT16)
+               Fs->num_clus = FAT16-1;
+       if(Fs->fat_bits == 12 && Fs->num_clus >= FAT12)
+               Fs->num_clus = FAT12-1;
+       
+       /* A safety, if above math is correct, this should not be happen...*/
+       if(Fs->num_clus > (Fs->fat_len * Fs->sector_size * 2 /
+                          fat_nybbles - 2)) {
+               fprintf(stderr,
+                       "Fat size miscalculation, shrinking num_clus from %d ",
+                       Fs->num_clus);
+               Fs->num_clus = (Fs->fat_len * Fs->sector_size * 2 /
+                               fat_nybbles - 2);
+               fprintf(stderr, " to %d\n", Fs->num_clus);
+       }
+#ifdef DEBUG
+       fprintf(stderr, "Num_clus=%d fat_len=%d nybbles=%d\n",
+               Fs->num_clus, Fs->fat_len, fat_nybbles);
+#endif
+
+       if ( Fs->num_clus < FAT16 && Fs->fat_bits > 16 ){
+               fprintf(stderr,"Too few clusters for this fat size."
+                       " Please choose a 16-bit fat in your /etc/mtools.conf"
+                       " or .mtoolsrc file\n");
+               exit(1);
+       }
+
+       /* As the number of clusters is specified nowhere in the boot sector,
+        * it will be calculated by removing everything else from total number
+        * of sectors. This means that if we reduced the number of clusters
+        * above, we will have to grow the FAT in order to take up any excess
+        * sectors... */
+#ifdef HAVE_ASSERT_H
+       assert(rem_sect >= Fs->num_clus * Fs->cluster_size +
+              Fs->fat_len * Fs->num_fat);
+#endif
+       slack = rem_sect -
+               Fs->num_clus * Fs->cluster_size -
+               Fs->fat_len * Fs->num_fat;
+       if(slack >= Fs->cluster_size) {
+               /* This can happen under two circumstances:
+                  1. We had to reduce num_clus because we reached maximum
+                  number of cluster for FAT12 or FAT16
+               */
+               if(printGrowMsg) {
+                       fprintf(stderr, "Slack=%d\n", slack);
+                       fprintf(stderr, "Growing fat size from %d",
+                               Fs->fat_len);
+               }
+               Fs->fat_len +=
+                       (slack - Fs->cluster_size) / Fs->num_fat + 1;
+               if(printGrowMsg) {
+                       fprintf(stderr,
+                               " to %d in order to take up excess cluster area\n",
+                               Fs->fat_len);
+               }
+               Fs->num_clus = (rem_sect-(Fs->fat_len*Fs->num_fat))/
+                       Fs->cluster_size;
+
+       }
+
+#ifdef HAVE_ASSERT_H
+       /* Fat must be big enough for all clusters */
+       assert( ((Fs->num_clus+2) * fat_nybbles) <=
+               (Fs->fat_len*Fs->sector_size*2));
+
+       /* num_clus must be big enough to cover rest of disk, or else further
+        * users of the filesystem will assume a bigger num_clus, which might
+        * be too big for fat_len */
+       assert(Fs->num_clus ==
+              (real_rem_sect - Fs->num_fat * Fs->fat_len) / Fs->cluster_size);
+#endif
+}
+
+
+static unsigned char bootprog[]=
+{0xfa, 0x31, 0xc0, 0x8e, 0xd8, 0x8e, 0xc0, 0xfc, 0xb9, 0x00, 0x01,
+ 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x80, 0xf3, 0xa5, 0xea, 0x00, 0x00,
+ 0x00, 0x08, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c, 0xba, 0x80, 0x00,
+ 0xb9, 0x01, 0x00, 0xcd, 0x13, 0x72, 0x05, 0xea, 0x00, 0x7c, 0x00,
+ 0x00, 0xcd, 0x19};
+
+static __inline__ void inst_boot_prg(union bootsector *boot, int offset)
+{
+       memcpy((char *) boot->boot.jump + offset,
+              (char *) bootprog, sizeof(bootprog) /sizeof(bootprog[0]));
+       if(offset - 2 < 0x80) {
+         /* short jump */
+         boot->boot.jump[0] = 0xeb;
+         boot->boot.jump[1] = offset -2;
+         boot->boot.jump[2] = 0x90;
+       } else {
+         /* long jump, if offset is too large */
+         boot->boot.jump[0] = 0xe9;
+         boot->boot.jump[1] = offset -3;
+         boot->boot.jump[2] = 0x00;
+       }
+       set_word(boot->boot.jump + offset + 20, offset + 24);
+}
+
+static void calc_cluster_size(struct Fs_t *Fs, unsigned long tot_sectors,
+                             int fat_bits)
+                       
+{
+       unsigned int max_clusters; /* maximal possible number of sectors for
+                                  * this FAT entry length (12/16/32) */
+       unsigned int max_fat_size; /* maximal size of the FAT for this FAT
+                                   * entry length (12/16/32) */
+       unsigned int rem_sect; /* remaining sectors after we accounted for
+                               * the root directory and boot sector(s) */
+
+       switch(abs(fat_bits)) {
+               case 12:                        
+                       max_clusters = FAT12-1;
+                       max_fat_size = Fs->num_fat *
+                               FAT_SIZE(12, Fs->sector_size, max_clusters);
+                       break;
+               case 16:
+               case 0: /* still hesititating between 12 and 16 */
+                       max_clusters = FAT16-1;
+                       max_fat_size = Fs->num_fat *
+                               FAT_SIZE(16, Fs->sector_size, max_clusters);
+                       break;
+               case 32:                
+                       Fs->cluster_size = 8;
+                       /* According to
+                        * http://support.microsoft.com/support/kb/articles/q154/9/97.asp
+                        * Micro$oft does not support FAT32 with less than 4K
+                        */
+                       return;
+               default:
+                       fprintf(stderr,"Bad fat size\n");
+                       exit(1);
+       }
+
+       rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
+
+       /* double the cluster size until we can fill up the disk with
+        * the maximal number of sectors of this size */
+       while(Fs->cluster_size * max_clusters  + max_fat_size < rem_sect) {
+               if(Fs->cluster_size > 64) {
+                       /* bigger than 64. Should fit */
+                       fprintf(stderr,
+                               "Internal error while calculating cluster size\n");
+                       exit(1);
+               }
+               Fs->cluster_size <<= 1;
+       }
+}
+
+
+struct OldDos_t old_dos[]={
+{   40,  9,  1, 4, 1, 2, 0xfc },
+{   40,  9,  2, 7, 2, 2, 0xfd },
+{   40,  8,  1, 4, 1, 1, 0xfe },
+{   40,  8,  2, 7, 2, 1, 0xff },
+{   80,  9,  2, 7, 2, 3, 0xf9 },
+{   80, 15,  2,14, 1, 7, 0xf9 },
+{   80, 18,  2,14, 1, 9, 0xf0 },
+{   80, 36,  2,15, 2, 9, 0xf0 },
+{    1,  8,  1, 1, 1, 1, 0xf0 },
+};
+
+static int old_dos_size_to_geom(size_t size, int *cyls, int *heads, int *sects)
+{
+       unsigned int i;
+       size = size * 2;
+       for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
+               if (old_dos[i].sectors *
+                   old_dos[i].tracks *
+                   old_dos[i].heads == size) {
+                       *cyls = old_dos[i].tracks;
+                       *heads = old_dos[i].heads;
+                       *sects = old_dos[i].sectors;
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+
+static void calc_fs_parameters(struct device *dev, unsigned long tot_sectors,
+                              struct Fs_t *Fs, union bootsector *boot)
+{
+       unsigned int i;
+
+       for(i=0; i < sizeof(old_dos) / sizeof(old_dos[0]); i++){
+               if (dev->sectors == old_dos[i].sectors &&
+                   dev->tracks == old_dos[i].tracks &&
+                   dev->heads == old_dos[i].heads &&
+                   (dev->fat_bits == 0 || abs(dev->fat_bits) == 12) &&
+                   (Fs->dir_len == 0 || Fs->dir_len == old_dos[i].dir_len) &&
+                   (Fs->cluster_size == 0 ||
+                    Fs->cluster_size == old_dos[i].cluster_size)) {
+                       boot->boot.descr = old_dos[i].media;
+                       Fs->cluster_size = old_dos[i].cluster_size;
+                       Fs->dir_len = old_dos[i].dir_len;
+                       Fs->fat_len = old_dos[i].fat_len;
+                       Fs->fat_bits = 12;
+                       break;
+               }
+       }
+       if (i == sizeof(old_dos) / sizeof(old_dos[0]) ){
+               int may_change_cluster_size = (Fs->cluster_size == 0);
+               int may_change_root_size = (Fs->dir_len == 0);
+
+               /* a non-standard format */
+               if(DWORD(nhs))
+                       boot->boot.descr = 0xf8;
+                 else
+                       boot->boot.descr = 0xf0;
+
+
+               if(!Fs->cluster_size) {
+                       if (dev->heads == 1)
+                               Fs->cluster_size = 1;
+                       else {
+                               Fs->cluster_size = (tot_sectors > 2000 ) ? 1:2;
+                               if (dev->use_2m & 0x7f)
+                                       Fs->cluster_size = 1;
+                       }
+               }
+               
+               if(!Fs->dir_len) {
+                       if (dev->heads == 1)
+                               Fs->dir_len = 4;
+                       else
+                               Fs->dir_len = (tot_sectors > 2000) ? 32 : 7;
+               }                       
+
+               calc_cluster_size(Fs, tot_sectors, dev->fat_bits);
+               if(Fs->fat_len)
+                       xdf_calc_fat_size(Fs, tot_sectors, dev->fat_bits);
+               else {
+                       calc_fat_bits2(Fs, tot_sectors, dev->fat_bits,
+                                      may_change_cluster_size,
+                                      may_change_root_size);
+                       calc_fat_size(Fs, tot_sectors);
+               }
+       }
+
+       set_word(boot->boot.fatlen, Fs->fat_len);
+}
+
+
+
+static void calc_fs_parameters_32(unsigned long tot_sectors,
+                                 struct Fs_t *Fs, union bootsector *boot)
+{
+       if(DWORD(nhs))
+               boot->boot.descr = 0xf8;
+       else
+               boot->boot.descr = 0xf0;
+       if(!Fs->cluster_size)
+               /* According to
+                * http://www.microsoft.com/kb/articles/q154/9/97.htm,
+                * Micro$oft does not support FAT32 with less than 4K
+                */
+               Fs->cluster_size = 8;
+       
+       Fs->dir_len = 0;
+       Fs->num_clus = tot_sectors / Fs->cluster_size;
+       set_fat32(Fs);
+       calc_fat_size(Fs, tot_sectors);
+       set_word(boot->boot.fatlen, 0);
+       set_dword(boot->boot.ext.fat32.bigFat, Fs->fat_len);
+}
+
+
+
+
+static void usage(int ret)
+{
+       fprintf(stderr,
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr,
+               "Usage: %s [-V] [-t tracks] [-h heads] [-n sectors] "
+               "[-v label] [-1] [-4] [-8] [-f size] "
+               "[-N serialnumber] "
+               "[-k] [-B bootsector] [-r root_dir_len] [-L fat_len] "
+               "[-F] [-I fsVersion] [-C] [-c cluster_size] "
+               "[-H hidden_sectors] "
+#ifdef USE_XDF
+               "[-X] "
+#endif
+               "[-S hardsectorsize] [-M softsectorsize] [-3] "
+               "[-2 track0sectors] [-0 rate0] [-A rateany] [-a]"
+               "device\n", progname);
+       exit(ret);
+}
+
+#ifdef OS_linux
+static int get_block_geom(int fd, struct MT_STAT *buf, struct device *dev,
+                         char *errmsg) {
+       struct hd_geometry geom;
+       long size;
+       int heads=dev->heads;
+       int sectors=dev->sectors;
+       int sect_per_track;
+
+       if (ioctl(fd, HDIO_GETGEO, &geom) < 0) {
+               sprintf(errmsg, "Could not get geometry of device (%s)",
+                       strerror(errno));
+               return -1;
+       }
+       
+       if (ioctl(fd, BLKGETSIZE, &size) < 0) {
+               sprintf(errmsg, "Could not get size of device (%s)",
+                       strerror(errno));
+               return -1;
+       }
+       
+       if(!heads)
+               heads = geom.heads;
+       if(!sectors)
+               sectors = geom.sectors;
+
+       sect_per_track = heads * sectors;
+       if(!dev->hidden) {
+               int hidden;
+               hidden = geom.start % sect_per_track;
+               if(hidden && hidden != sectors) {
+                       sprintf(errmsg,
+                               "Hidden (%d) does not match sectors (%d)\n",
+                               hidden, sectors);
+                       return -1;
+               }
+               dev->hidden = hidden;
+       }
+       dev->heads = heads;
+       dev->sectors = sectors;
+       if(!dev->tracks)
+               dev->tracks = (size + dev->hidden) / sect_per_track;
+       size = dev->tracks * dev->heads * dev->sectors + dev->hidden;
+       return 0;
+}
+#endif
+
+void mformat(int argc, char **argv, int dummy)
+{
+       int r; /* generic return value */
+       Fs_t Fs;
+       int hs, hs_set;
+       int arguse_2m = 0;
+       int sectors0=18; /* number of sectors on track 0 */
+       int create = 0;
+       int rate_0, rate_any;
+       int mangled;
+       int argssize=0; /* sector size */
+       int msize=0;
+       int fat32 = 0;
+       struct label_blk_t *labelBlock;
+       int bootOffset;
+
+#ifdef USE_XDF
+       unsigned int i;
+       int format_xdf = 0;
+       struct xdf_info info;
+#endif
+       union bootsector boot;
+       char *bootSector=0;
+       int c;
+       int keepBoot = 0;
+       struct device used_dev;
+       int argtracks, argheads, argsectors;
+       unsigned long tot_sectors;
+       int blocksize;
+
+       char drive, name[EXPAND_BUF];
+
+       char label[VBUFSIZE];
+
+       dos_name_t shortlabel;
+       struct device *dev;
+       char errmsg[200];
+
+       unsigned long serial;
+       int serial_set;
+       int fsVersion;
+       int mediaDesc=-1;
+
+       mt_size_t maxSize;
+
+       int Atari = 0; /* should we add an Atari-style serial number ? */
+
+       hs = hs_set = 0;
+       argtracks = 0;
+       argheads = 0;
+       argsectors = 0;
+       arguse_2m = 0;
+       argssize = 0x2;
+       label[0] = '\0';
+       serial_set = 0;
+       serial = 0;
+       fsVersion = 0;
+       
+       Fs.cluster_size = 0;
+       Fs.refs = 1;
+       Fs.dir_len = 0;
+       if(getenv("MTOOLS_DIR_LEN")) {
+         Fs.dir_len = atoi(getenv("MTOOLS_DIR_LEN"));
+         if(Fs.dir_len <= 0)
+           Fs.dir_len=0;
+       }
+       Fs.fat_len = 0;
+       Fs.num_fat = 2;
+       if(getenv("MTOOLS_NFATS")) {
+         Fs.num_fat = atoi(getenv("MTOOLS_NFATS"));
+         if(Fs.num_fat <= 0)
+           Fs.num_fat=2;
+       }
+       Fs.Class = &FsClass;    
+       rate_0 = mtools_rate_0;
+       rate_any = mtools_rate_any;
+
+       /* get command line options */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc,argv,
+                          "i:148f:t:n:v:qub"
+                          "kB:r:L:I:FCc:Xh:s:l:N:H:M:S:2:30:Aad:m:"))!= EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+
+                       /* standard DOS flags */
+                       case '1':
+                               argheads = 1;
+                               break;
+                       case '4':
+                               argsectors = 9;
+                               argtracks = 40;
+                               break;
+                       case '8':
+                               argsectors = 8;
+                               argtracks = 40;
+                               break;
+                       case 'f':
+                               r=old_dos_size_to_geom(atoi(optarg),
+                                                      &argtracks, &argheads,
+                                                      &argsectors);
+                               if(r) {
+                                       fprintf(stderr,
+                                               "Bad size %s\n", optarg);
+                                       exit(1);
+                               }
+                               break;
+                       case 't':
+                               argtracks = atoi(optarg);
+                               break;
+
+                       case 'n': /*non-standard*/
+                       case 's':
+                               argsectors = atoi(optarg);
+                               break;
+
+                       case 'l': /* non-standard */
+                       case 'v':
+                               strncpy(label, optarg, VBUFSIZE-1);
+                               label[VBUFSIZE-1] = '\0';
+                               break;
+
+                       /* flags supported by Dos but not mtools */
+                       case 'q':
+                       case 'u':
+                       case 'b':
+                       /*case 's': leave this for compatibility */
+                               fprintf(stderr,
+                                       "Flag %c not supported by mtools\n",c);
+                               exit(1);
+                               
+
+
+                       /* flags added by mtools */
+                       case 'F':
+                               fat32 = 1;
+                               break;
+
+
+                       case 'S':
+                               argssize = atoi(optarg) | 0x80;
+                               if(argssize < 0x81)
+                                       usage(1);
+                               if(argssize >= 0x87) {
+                                       fprintf(stderr, "argssize must be less than 6\n");
+                                       usage(1);
+                               }
+                               break;
+
+#ifdef USE_XDF
+                       case 'X':
+                               format_xdf = 1;
+                               break;
+#endif
+
+                       case '2':
+                               arguse_2m = 0xff;
+                               sectors0 = atoi(optarg);
+                               break;
+                       case '3':
+                               arguse_2m = 0x80;
+                               break;
+
+                       case '0': /* rate on track 0 */
+                               rate_0 = atoi(optarg);
+                               break;
+                       case 'A': /* rate on other tracks */
+                               rate_any = atoi(optarg);
+                               break;
+
+                       case 'M':
+                               msize = atoi(optarg);
+                               if(msize != 512 &&
+                                  msize != 1024 &&
+                                  msize != 2048 &&
+                                  msize != 4096) {
+                                 fprintf(stderr, "Only sector sizes of 512, 1024, 2048 or 4096 bytes are allowed\n");
+                                 usage(1);
+                               }
+                               break;
+
+                       case 'N':
+                               serial = strtoul(optarg,0,16);
+                               serial_set = 1;
+                               break;
+                       case 'a': /* Atari style serial number */
+                               Atari = 1;
+                               break;
+
+                       case 'C':
+                               create = O_CREAT | O_TRUNC;
+                               break;
+
+                       case 'H':
+                               hs = atoi(optarg);
+                               hs_set = 1;
+                               break;
+
+                       case 'I':
+                               fsVersion = strtoul(optarg,0,0);
+                               break;
+
+                       case 'c':
+                               Fs.cluster_size = atoi(optarg);
+                               break;
+
+                       case 'r':
+                               Fs.dir_len = strtoul(optarg,0,0);
+                               break;
+                       case 'L':
+                               Fs.fat_len = strtoul(optarg,0,0);
+                               break;
+
+
+                       case 'B':
+                               bootSector = optarg;
+                               break;
+                       case 'k':
+                               keepBoot = 1;
+                               break;
+                       case 'h':
+                               argheads = atoi(optarg);
+                               break;
+                       case 'd':
+                               Fs.num_fat = atoi(optarg);
+                               break;
+                       case 'm':
+                               mediaDesc = strtoul(optarg,0,0);
+                               break;
+                       default:
+                               usage(1);
+               }
+       }
+
+       if (argc - optind != 1 ||
+           !argv[optind][0] || argv[optind][1] != ':')
+               usage(1);
+
+#ifdef USE_XDF
+       if(create && format_xdf) {
+               fprintf(stderr,"Create and XDF can't be used together\n");
+               exit(1);
+       }
+#endif
+       
+       drive = toupper(argv[argc -1][0]);
+
+       /* check out a drive whose letter and parameters match */       
+       sprintf(errmsg, "Drive '%c:' not supported", drive);    
+       Fs.Direct = NULL;
+       blocksize = 0;
+       for(dev=devices;dev->drive;dev++) {
+               FREE(&(Fs.Direct));
+               /* drive letter */
+               if (dev->drive != drive)
+                       continue;
+               used_dev = *dev;
+
+               SET_INT(used_dev.tracks, argtracks);
+               SET_INT(used_dev.heads, argheads);
+               SET_INT(used_dev.sectors, argsectors);
+               SET_INT(used_dev.use_2m, arguse_2m);
+               SET_INT(used_dev.ssize, argssize);
+               if(hs_set)
+                       used_dev.hidden = hs;
+               
+               expand(dev->name, name);
+#ifdef USING_NEW_VOLD
+               strcpy(name, getVoldName(dev, name));
+#endif
+
+#ifdef USE_XDF
+               if(!format_xdf) {
+#endif
+                       Fs.Direct = 0;
+#ifdef USE_FLOPPYD
+                       Fs.Direct = FloppydOpen(&used_dev, dev, name,
+                                               O_RDWR | create,
+                                               errmsg, 0, 1);
+                       if(Fs.Direct) {
+                               maxSize = max_off_t_31;
+                       }
+#endif
+                       if(!Fs.Direct) {                        
+                               Fs.Direct = SimpleFileOpen(&used_dev, dev, name,
+                                                          O_RDWR | create,
+                                                          errmsg, 0, 1,
+                                                          &maxSize);
+                       }
+#ifdef USE_XDF
+               } else {
+                       used_dev.misc_flags |= USE_XDF_FLAG;
+                       Fs.Direct = XdfOpen(&used_dev, name, O_RDWR,
+                                           errmsg, &info);
+                       if(Fs.Direct && !Fs.fat_len)
+                               Fs.fat_len = info.FatSize;
+                       if(Fs.Direct && !Fs.dir_len)
+                               Fs.dir_len = info.RootDirSize;
+               }
+#endif
+
+               if (!Fs.Direct)
+                       continue;
+
+#ifdef OS_linux
+               if ((!used_dev.tracks || !used_dev.heads || !used_dev.sectors) &&
+                       (!IS_SCSI(dev))) {
+                       int fd= get_fd(Fs.Direct);
+                       struct MT_STAT stbuf;
+
+                       if (MT_FSTAT(fd, &stbuf) < 0) {
+                               sprintf(errmsg, "Could not stat file (%s)", strerror(errno));
+                               continue;                                               
+                       }
+
+                       if (S_ISBLK(stbuf.st_mode) &&
+                           get_block_geom(fd, &stbuf, &used_dev, errmsg) < 0)
+                               continue;
+               }
+#endif
+
+               /* no way to find out geometry */
+               if (!used_dev.tracks || !used_dev.heads || !used_dev.sectors){
+                       sprintf(errmsg,
+                               "Unknown geometry "
+                               "(You must tell the complete geometry "
+                               "of the disk, \neither in /etc/mtools.conf or "
+                               "on the command line) ");
+                       continue;
+               }
+
+#if 0
+               /* set parameters, if needed */
+               if(SET_GEOM(Fs.Direct, &used_dev, 0xf0, boot)){
+                       sprintf(errmsg,"Can't set disk parameters: %s",
+                               strerror(errno));
+                       continue;
+               }
+#endif
+               Fs.sector_size = 512;
+               if( !(used_dev.use_2m & 0x7f)) {
+                       Fs.sector_size = 128 << (used_dev.ssize & 0x7f);
+               }
+
+               SET_INT(Fs.sector_size, msize);
+               {
+                   unsigned int j;
+                   for(j = 0; j < 31; j++) {
+                       if (Fs.sector_size == (unsigned int) (1 << j)) {
+                           Fs.sectorShift = j;
+                           break;
+                       }
+                   }
+                   Fs.sectorMask = Fs.sector_size - 1;
+               }
+
+               if(!used_dev.blocksize || used_dev.blocksize < Fs.sector_size)
+                       blocksize = Fs.sector_size;
+               else
+                       blocksize = used_dev.blocksize;
+               
+               if(blocksize > MAX_SECTOR)
+                       blocksize = MAX_SECTOR;
+
+               /* do a "test" read */
+               if (!create &&
+                   READS(Fs.Direct, &boot.characters, 0, Fs.sector_size) !=
+                   (signed int) Fs.sector_size) {
+                       sprintf(errmsg,
+                               "Error reading from '%s', wrong parameters?",
+                               name);
+                       continue;
+               }
+               break;
+       }
+
+
+       /* print error msg if needed */ 
+       if ( dev->drive == 0 ){
+               FREE(&Fs.Direct);
+               fprintf(stderr,"%s: %s\n", argv[0],errmsg);
+               exit(1);
+       }
+
+       /* calculate the total number of sectors */
+       tot_sectors = used_dev.tracks*used_dev.heads*used_dev.sectors - used_dev.hidden;
+
+       /* create the image file if needed */
+       if (create) {
+               WRITES(Fs.Direct, &boot.characters,
+                      sectorsToBytes((Stream_t*)&Fs, tot_sectors-1),
+                      Fs.sector_size);
+       }
+
+       /* the boot sector */
+       if(bootSector) {
+               int fd;
+
+               fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
+               if(fd < 0) {
+                       perror("open boot sector");
+                       exit(1);
+               }
+               if(read(fd, &boot.bytes, blocksize) < blocksize) {
+                       perror("short read on boot sector");
+                       exit(1);
+               }
+               keepBoot = 1;
+       }
+       if(!keepBoot && !(used_dev.use_2m & 0x7f)) {
+               memset(boot.characters, '\0', Fs.sector_size);
+               if(Fs.sector_size == 512 && !used_dev.partition) {
+                       /* install fake partition table pointing to itself */
+                       struct partition *partTable=(struct partition *)
+                               (&boot.bytes[0x1ae]);
+                       setBeginEnd(&partTable[1], 0,
+                                               used_dev.heads * used_dev.sectors * used_dev.tracks,
+                                               used_dev.heads, used_dev.sectors, 1, 0);
+               }
+       }
+       set_dword(boot.boot.nhs, used_dev.hidden);
+
+       Fs.Next = buf_init(Fs.Direct,
+                          blocksize * used_dev.heads * used_dev.sectors,
+                          blocksize * used_dev.heads * used_dev.sectors,
+                          blocksize);
+       Fs.Buffer = 0;
+
+       boot.boot.nfat = Fs.num_fat;
+       if(!keepBoot)
+               set_word(&boot.bytes[510], 0xaa55);
+       
+       /* Initialize the remaining parameters */
+       set_word(boot.boot.nsect, used_dev.sectors);
+       set_word(boot.boot.nheads, used_dev.heads);
+
+       used_dev.fat_bits = comp_fat_bits(&Fs,used_dev.fat_bits, tot_sectors, fat32);
+
+       if(used_dev.fat_bits == 32) {
+               Fs.primaryFat = 0;
+               Fs.writeAllFats = 1;
+               Fs.fat_start = 32;
+               calc_fs_parameters_32(tot_sectors, &Fs, &boot);
+
+               Fs.clus_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
+
+               /* extension flags: mirror fats, and use #0 as primary */
+               set_word(boot.boot.ext.fat32.extFlags,0);
+
+               /* fs version.  What should go here? */
+               set_word(boot.boot.ext.fat32.fsVersion,fsVersion);
+
+               /* root directory */
+               set_dword(boot.boot.ext.fat32.rootCluster, Fs.rootCluster = 2);
+
+               /* info sector */
+               set_word(boot.boot.ext.fat32.infoSector, Fs.infoSectorLoc = 1);
+               Fs.infoSectorLoc = 1;
+
+               /* no backup boot sector */
+               set_word(boot.boot.ext.fat32.backupBoot, 6);
+               
+               labelBlock = & boot.boot.ext.fat32.labelBlock;
+       } else {
+               Fs.infoSectorLoc = 0;
+               Fs.fat_start = 1;
+               calc_fs_parameters(&used_dev, tot_sectors, &Fs, &boot);
+               Fs.dir_start = Fs.num_fat * Fs.fat_len + Fs.fat_start;
+               Fs.clus_start = Fs.dir_start + Fs.dir_len;
+               labelBlock = & boot.boot.ext.old.labelBlock;
+
+       }
+
+       /* Set the codepage */
+       Fs.cp = cp_open(used_dev.codepage);
+       if(Fs.cp == NULL)
+               exit(1);
+
+       if (!keepBoot)
+               /* only zero out physdrive if we don't have a template
+                * bootsector */
+               labelBlock->physdrive = 0x00;
+       labelBlock->reserved = 0;
+       labelBlock->dos4 = 0x29;
+
+       if (!serial_set || Atari)
+               srandom((long)time (0));
+       if (!serial_set)
+               serial=random();
+       set_dword(labelBlock->serial, serial);  
+       label_name(GET_DOSCONVERT((Stream_t *)&Fs),
+                  label[0] ? label : "NO NAME    ", 0, &mangled, &shortlabel);
+       strncpy(labelBlock->label, shortlabel.base, 11);
+       sprintf(labelBlock->fat_type, "FAT%2.2d  ", Fs.fat_bits);
+       labelBlock->fat_type[7] = ' ';
+
+       set_word(boot.boot.secsiz, Fs.sector_size);
+       boot.boot.clsiz = (unsigned char) Fs.cluster_size;
+       set_word(boot.boot.nrsvsect, Fs.fat_start);
+
+       bootOffset = init_geometry_boot(&boot, &used_dev, sectors0,
+                                       rate_0, rate_any,
+                                       &tot_sectors, keepBoot);
+       if(!bootOffset) {
+               bootOffset = ((unsigned char *) labelBlock) - boot.bytes +
+                       sizeof(struct label_blk_t);
+       }
+       if(Atari) {
+               boot.boot.banner[4] = 0;
+               boot.boot.banner[5] = random();
+               boot.boot.banner[6] = random();
+               boot.boot.banner[7] = random();
+       }               
+
+       if(!keepBoot)
+               inst_boot_prg(&boot, bootOffset);
+       /* Mimic 3.8 behavior, else 2m disk do not work (???)
+        * luferbu@fluidsignal.com (Luis Bustamante), Fri, 14 Jun 2002
+        */
+       if(used_dev.use_2m & 0x7f) {
+         boot.boot.jump[0] = 0xeb;
+         boot.boot.jump[1] = 0x80;
+         boot.boot.jump[2] = 0x90;
+       }
+       if(used_dev.use_2m & 0x7f)
+               Fs.num_fat = 1;
+       if(mediaDesc != -1)
+               boot.boot.descr=mediaDesc;
+       Fs.lastFatSectorNr = 0;
+       Fs.lastFatSectorData = 0;
+       zero_fat(&Fs, boot.boot.descr);
+       Fs.freeSpace = Fs.num_clus;
+       Fs.last = 2;
+
+#ifdef USE_XDF
+       if(format_xdf)
+               for(i=0;
+                   i < (info.BadSectors+Fs.cluster_size-1)/Fs.cluster_size;
+                   i++)
+                       fatEncode(&Fs, i+2, 0xfff7);
+#endif
+
+       format_root(&Fs, label, &boot);
+       WRITES((Stream_t *)&Fs, boot.characters,
+              (mt_off_t) 0, Fs.sector_size);
+       if(Fs.fat_bits == 32 && WORD_S(ext.fat32.backupBoot) != MAX16) {
+               WRITES((Stream_t *)&Fs, boot.characters,
+                      sectorsToBytes((Stream_t*)&Fs,
+                                     WORD_S(ext.fat32.backupBoot)),
+                      Fs.sector_size);
+       }
+       FLUSH((Stream_t *)&Fs); /* flushes Fs.
+                                * This triggers the writing of the FAT */
+       FREE(&Fs.Next);
+       Fs.Class->freeFunc((Stream_t *)&Fs);
+#ifdef USE_XDF
+       if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF"))
+               fprintf(stderr,
+                       "Note:\n"
+                       "Remember to set the \"MTOOLS_USE_XDF\" environmental\n"
+                       "variable before accessing this disk\n\n"
+                       "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\n"
+                       " export MTOOLS_USE_XDF=1\n\n"
+                       "C shell syntax (csh and tcsh):\n"
+                       " setenv MTOOLS_USE_XDF 1\n" ); 
+#endif
+       exit(0);
+}
diff --git a/minfo.1 b/minfo.1
new file mode 100644 (file)
index 0000000..adf7ae0
--- /dev/null
+++ b/minfo.1
@@ -0,0 +1,101 @@
+.TH minfo 1 "03Nov09" mtools-4.0.12
+.SH Name
+minfo - print the parameters of a MSDOS filesystem
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p minfo"
+.iX "c mformat parameters"
+.iX "c getting parameters of a Dos fs"
+.PP
+The \fR\&\f(CWminfo\fR command prints the parameters of a Dos filesystem, such
+as number of sectors, heads and cylinders.  It also prints an mformat
+command line which can be used to create a similar Dos filesystem on
+another media.  However, this doesn't work with 2m or Xdf media, and
+with Dos 1.0 filesystems
+.ft I
+.nf
+\&\fR\&\f(CWminfo\fR \fIdrive\fR:
+.fi
+.ft R
+.PP
+Mlabel supports the following option:
+.TP
+\&\fR\&\f(CWv\fR\ 
+Prints a hexdump of the bootsector, in addition to the other information
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/minfo.c b/minfo.c
new file mode 100644 (file)
index 0000000..641b352
--- /dev/null
+++ b/minfo.c
@@ -0,0 +1,208 @@
+/*  Copyright 1997-2003,2006,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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));
+}
+
+
+void minfo(int argc, char **argv, int type)
+{
+       union bootsector boot;
+
+       char name[EXPAND_BUF];
+       int media;
+       int tot_sectors;
+       int size_code;
+       int sector_size;
+       int i;
+       struct device dev;
+       char drive;
+       int verbose=0;
+       int c;
+       Stream_t *Stream;
+       struct label_blk_t *labelBlock;
+       
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:vh")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'v':
+                               verbose = 1;
+                               break;
+                       case 'h':
+                               usage(0);
+                       default:
+                               usage(1);
+               }
+       }
+
+       if(argc == optind)
+               usage(1);
+
+       for(;optind < argc; optind++) {
+               if(!argv[optind][0] || argv[optind][1] != ':')
+                       usage(1);
+               drive = toupper(argv[optind][0]);
+
+               if(! (Stream = find_device(drive, O_RDONLY, &dev, &boot, 
+                                          name, &media, 0, NULL)))
+                       exit(1);
+
+               tot_sectors = DWORD_S(bigsect);
+               SET_INT(tot_sectors, WORD_S(psect));
+               sector_size = WORD_S(secsiz);
+               size_code=2;
+               for(i=0; i<7; i++) {
+                       if(sector_size == 128 << i) {
+                               size_code = i;
+                               break;
+                       }
+               }
+               printf("device information:\n");
+               printf("===================\n");
+               printf("filename=\"%s\"\n", name);
+               printf("sectors per track: %d\n", dev.sectors);
+               printf("heads: %d\n", dev.heads);
+               printf("cylinders: %d\n\n", dev.tracks);
+               printf("mformat command line: mformat -t %d -h %d -s %d ",
+                      dev.tracks, dev.heads, dev.sectors);
+               if(DWORD_S(nhs))
+                       printf("-H %d ", DWORD_S(nhs));
+               if(size_code != 2)
+                       printf("-S %d ",size_code);
+               printf("%c:\n", tolower(drive));
+               printf("\n");
+               
+               printf("bootsector information\n");
+               printf("======================\n");
+               printf("banner:\"%8s\"\n", boot.boot.banner);
+               printf("sector size: %d bytes\n", WORD_S(secsiz));
+               printf("cluster size: %d sectors\n", boot.boot.clsiz);
+               printf("reserved (boot) sectors: %d\n", WORD_S(nrsvsect));
+               printf("fats: %d\n", boot.boot.nfat);
+               printf("max available root directory slots: %d\n", 
+                      WORD_S(dirents));
+               printf("small size: %d sectors\n", WORD_S(psect));
+               printf("media descriptor byte: 0x%x\n", boot.boot.descr);
+               printf("sectors per fat: %d\n", WORD_S(fatlen));
+               printf("sectors per track: %d\n", WORD_S(nsect));
+               printf("heads: %d\n", WORD_S(nheads));
+               printf("hidden sectors: %d\n", DWORD_S(nhs));
+               printf("big size: %d sectors\n", DWORD_S(bigsect));
+
+               if(WORD_S(fatlen)) {
+                   labelBlock = &boot.boot.ext.old.labelBlock;
+               } else {
+                   labelBlock = &boot.boot.ext.fat32.labelBlock;
+               }
+
+               printf("physical drive id: 0x%x\n", 
+                      labelBlock->physdrive);
+               printf("reserved=0x%x\n", 
+                      labelBlock->reserved);
+               printf("dos4=0x%x\n", 
+                      labelBlock->dos4);
+               printf("serial number: %08X\n", 
+                      _DWORD(labelBlock->serial));
+               printf("disk label=\"%11.11s\"\n", 
+                      labelBlock->label);
+               printf("disk type=\"%8.8s\"\n", 
+                      labelBlock->fat_type);
+
+               if(!WORD_S(fatlen)){
+                       printf("Big fatlen=%u\n",
+                              DWORD_S(ext.fat32.bigFat));
+                       printf("Extended flags=0x%04x\n",
+                              WORD_S(ext.fat32.extFlags));
+                       printf("FS version=0x%04x\n",
+                              WORD_S(ext.fat32.fsVersion));
+                       printf("rootCluster=%u\n",
+                              DWORD_S(ext.fat32.rootCluster));
+                       if(WORD_S(ext.fat32.infoSector) != MAX16)
+                               printf("infoSector location=%d\n",
+                                      WORD_S(ext.fat32.infoSector));
+                       if(WORD_S(ext.fat32.backupBoot) != MAX16)
+                               printf("backup boot sector=%d\n",
+                                      WORD_S(ext.fat32.backupBoot));
+                       displayInfosector(Stream,&boot);
+               }
+
+               if(verbose) {
+                       int size;
+                       unsigned char *buf;
+
+                       printf("\n");
+                       size = WORD_S(secsiz);
+                       
+                       buf = (unsigned char *) malloc(size);
+                       if(!buf) {
+                               fprintf(stderr, "Out of memory error\n");
+                               exit(1);
+                       }
+
+                       size = READS(Stream, buf, (mt_off_t) 0, size);
+                       if(size < 0) {
+                               perror("read boot sector");
+                               exit(1);
+                       }
+
+                       print_sector("Boot sector hexdump", buf, size);
+               }
+       }
+       FREE(&Stream);
+       exit(0);
+}
diff --git a/misc.c b/misc.c
new file mode 100644 (file)
index 0000000..c27940c
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,235 @@
+/*  Copyright 1996-2002,2005,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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");
+       }
+}
+
+
+time_t getTimeNow(time_t *now)
+{
+       static int haveTime = 0;
+       static time_t sharedNow;
+
+       if(!haveTime) {
+               time(&sharedNow);
+               haveTime = 1;
+       }
+       if(now)
+               *now = sharedNow;
+       return sharedNow;
+}
+
+#if 0
+
+#undef free
+#undef malloc
+
+static int total=0;
+
+void myfree(void *ptr)
+{
+       int *size = ((int *) ptr)-1;
+       total -= *size;
+       fprintf(stderr, "freeing %d bytes at %p total alloced=%d\n",
+               *size, ptr, total);
+       free(size);
+}
+
+void *mymalloc(size_t size)
+{
+       int *ptr;
+       ptr = (int *)malloc(size+sizeof(int));
+       if(!ptr)
+               return 0;
+       *ptr = size;
+       ptr++;
+       total += size;
+       fprintf(stderr, "allocating %d bytes at %p total allocated=%d\n",
+               size, ptr, total);
+       return (void *) ptr;
+}
+
+void *mycalloc(size_t nmemb, size_t size)
+{
+       void *ptr = mymalloc(nmemb * size);
+       if(!ptr)
+               return 0;
+       memset(ptr, 0, size);
+       return ptr;
+}
+
+void *myrealloc(void *ptr, size_t size)
+{
+       int oldsize = ((int *)ptr) [-1];
+       void *new = mymalloc(size);
+       if(!new)
+               return 0;
+       memcpy(new, ptr, oldsize);
+       myfree(ptr);
+       return new;
+}
+
+char *mystrdup(char *src)
+{
+       char *dest;
+       dest = mymalloc(strlen(src)+1);
+       if(!dest)
+               return 0;
+       strcpy(dest, src);
+       return dest;
+}
+
+
+#endif
diff --git a/missFuncs.c b/missFuncs.c
new file mode 100644 (file)
index 0000000..e16d9e3
--- /dev/null
@@ -0,0 +1,477 @@
+/*  Copyright 1991 Free Software Foundation, Inc.
+ *  Copyright 1997,1999-2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 */
+
+#ifdef HAVE_WCHAR_H
+#ifndef HAVE_WCSDUP
+wchar_t *wcsdup(const wchar_t *wcs)
+{
+    wchar_t *nwcs;
+
+    if (wcs == (wchar_t*)0)
+        return 0;
+
+    nwcs = (wchar_t*)calloc(wcslen(wcs) + 1, sizeof(wchar_t));
+
+    if (nwcs == (wchar_t*)0)
+    {
+        (void)fprintf(stderr, "wcsdup(): not enough memory to duplicate `%ls'\n",
+                     wcs);
+       exit(1);
+    }
+
+    (void)wcscpy(nwcs, wcs);
+
+    return nwcs;
+}
+#endif /* HAVE_WCSDUP */
+#endif
+
+#ifndef HAVE_MEMCPY
+/*
+ * Copy contents of memory (with possible overlapping).
+ */
+char *memcpy(char *s1, const char *s2, size_t n)
+{
+       bcopy(s2, s1, n);
+       return(s1);
+}
+#endif
+
+#ifndef HAVE_MEMSET
+/*
+ * Copies the character c, n times to string s
+ */
+char *memset(char *s, char c, size_t n)
+{
+       char *s1 = s;
+
+       while (n > 0) {
+               --n;
+               *s++ = c;
+       }
+       return(s1);
+}
+#endif /* HAVE_MEMSET */
+
+
+#ifndef HAVE_STRCHR
+
+char * strchr (const char* s, int c)
+{
+       if (!s) return NULL;
+       while (*s && *s != c) s++;
+       if (*s) 
+               return (char*) s;
+       else
+               return NULL;
+}
+
+#endif
+
+#ifndef HAVE_STRRCHR
+
+char * strrchr (const char* s1, int c) 
+{
+       char* s = (char*) s1;
+       char* start = (char*) s;
+       if (!s) return NULL;
+       s += strlen(s)-1;
+       while (*s != c && (unsigned long) s != (unsigned long) start) s--;
+       if ((unsigned long) s == (unsigned long) start && *s != c)
+               return NULL;
+       else
+               return s;
+}
+
+#endif
+
+#ifndef HAVE_STRPBRK
+/*
+ * Return ptr to first occurrence of any character from `brkset'
+ * in the character string `string'; NULL if none exists.
+ */
+char *strpbrk(const char *string, const char *brkset)
+{
+       register char *p;
+
+       if (!string || !brkset)
+               return(0);
+       do {
+               for (p = brkset; *p != '\0' && *p != *string; ++p)
+                       ;
+               if (*p != '\0')
+                       return(string);
+       }
+       while (*string++);
+       return(0);
+}
+#endif /* HAVE_STRPBRK */
+
+
+#ifndef HAVE_STRTOUL
+static int getdigit(char a, int max)
+{
+       int dig;
+       
+       if(a < '0')
+               return -1;
+       if(a <= '9') {
+               dig = a - '0';
+       } else if(a >= 'a')
+               dig = a - 'a' + 10;
+       else if(a >= 'A')
+               dig = a - 'A' + 10;
+       if(dig >= max)
+               return -1;
+       else
+               return dig;
+}
+
+unsigned long strtoul(const char *string, char **eptr, int base)
+{
+       int accu, dig;
+
+       if(base < 1 || base > 36) {
+               if(string[0] == '0') {
+                       switch(string[1]) {
+                               case 'x':
+                               case 'X':
+                                       return strtoul(string+2, eptr, 16);
+                               case 'b':
+                               case 'B':
+                                       return strtoul(string+2, eptr, 2);
+                               default:
+                                       return strtoul(string, eptr, 8);
+                       }
+               }
+               return strtoul(string, eptr, 10);
+       }
+       if(base == 16 && string[0] == '0' &&
+          (string[1] == 'x' || string[1] == 'X'))
+               string += 2;
+
+       if(base == 2 && string[0] == '0' &&
+          (string[1] == 'b' || string[1] == 'B'))
+               string += 2;
+       accu = 0;
+       while( (dig = getdigit(*string, base)) != -1 ) {
+               accu = accu * base + dig;
+               string++;
+       }
+       if(eptr)
+               *eptr = (char *) string;
+       return accu;
+}
+#endif /* HAVE_STRTOUL */
+
+#ifndef HAVE_STRTOL
+long strtol(const char *string, char **eptr, int base)
+{
+       long l;
+
+       if(*string == '-') {
+               return -(long) strtoul(string+1, eptr, base);
+       } else {
+               if (*string == '+')
+                       string ++;
+               return (long) strtoul(string, eptr, base);
+       }
+}
+#endif
+
+
+
+#ifndef HAVE_STRSPN
+/* Return the length of the maximum initial segment
+   of S which contains only characters in ACCEPT.  */
+size_t strspn(const char *s, const char *accept)
+{
+  register char *p;
+  register char *a;
+  register size_t count = 0;
+
+  for (p = s; *p != '\0'; ++p)
+    {
+      for (a = accept; *a != '\0'; ++a)
+       if (*p == *a)
+         break;
+      if (*a == '\0')
+       return count;
+      else
+       ++count;
+    }
+
+  return count;
+}
+#endif /* HAVE_STRSPN */
+
+#ifndef HAVE_STRCSPN
+/* Return the length of the maximum inital segment of S
+   which contains no characters from REJECT.  */
+size_t strcspn (const char *s, const char *reject)
+{
+  register size_t count = 0;
+
+  while (*s != '\0')
+    if (strchr (reject, *s++) == NULL)
+      ++count;
+    else
+      return count;
+
+  return count;
+}
+
+#endif /* HAVE_STRCSPN */
+
+#ifndef HAVE_STRERROR
+
+#ifndef DECL_SYS_ERRLIST
+extern char *sys_errlist[];
+#endif
+
+char *strerror(int errno)
+{
+  return sys_errlist[errno];
+}
+#endif
+
+#ifndef HAVE_STRCASECMP
+/* Compare S1 and S2, ignoring case, returning less than, equal to or
+   greater than zero if S1 is lexiographically less than,
+   equal to or greater than S2.  */
+int strcasecmp(const char *s1, const char *s2)
+{
+  register const unsigned char *p1 = (const unsigned char *) s1;
+  register const unsigned char *p2 = (const unsigned char *) s2;
+  unsigned char c1, c2;
+
+  if (p1 == p2)
+    return 0;
+
+  do
+    {
+      c1 = tolower (*p1++);
+      c2 = tolower (*p2++);
+      if (c1 == '\0')
+       break;
+    }
+  while (c1 == c2);
+
+  return c1 - c2;
+}
+#endif
+
+#ifdef HAVE_WCHAR_H
+#ifndef HAVE_WCSCASECMP
+/* Compare S1 and S2, ignoring case, returning less than, equal to or
+   greater than zero if S1 is lexiographically less than,
+   equal to or greater than S2.  */
+int wcscasecmp(const wchar_t *s1, const wchar_t *s2)
+{
+  register const wchar_t *p1 = s1;
+  register const wchar_t *p2 = s2;
+  wchar_t c1, c2;
+
+  if (p1 == p2)
+    return 0;
+
+  do
+    {
+      c1 = towlower (*p1++);
+      c2 = towlower (*p2++);
+      if (c1 == '\0')
+       break;
+    }
+  while (c1 == c2);
+
+  return c1 - c2;
+}
+#endif
+#endif
+
+
+#ifndef HAVE_STRCASECMP
+/* Compare S1 and S2, ignoring case, returning less than, equal to or
+   greater than zero if S1 is lexiographically less than,
+   equal to or greater than S2.  */
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+  register const unsigned char *p1 = (const unsigned char *) s1;
+  register const unsigned char *p2 = (const unsigned char *) s2;
+  unsigned char c1, c2;
+
+  if (p1 == p2)
+    return 0;
+
+  c1 = c2 = 1;
+  while (c1 && c1 == c2 && n-- > 0)
+    {
+      c1 = tolower (*p1++);
+      c2 = tolower (*p2++);
+    }
+
+  return c1 - c2;
+}
+#endif
+
+#ifndef HAVE_GETPASS
+char *getpass(const char *prompt)
+{
+       static char password[129];
+       int l;
+
+       fprintf(stderr,"%s",prompt);
+       fgets(password, 128, stdin);
+       l = strlen(password);
+       if(l && password[l-1] == '\n')
+               password[l-1] = '\0';
+       return password;
+
+}
+#endif
+
+#ifndef HAVE_ATEXIT
+
+#ifdef HAVE_ON_EXIT
+int atexit(void (*function)(void))
+{
+       return on_exit( (void(*)(int,void*)) function, 0);
+}
+#else
+
+typedef struct exitCallback {
+       void (*function) (void);
+       struct exitCallback *next;
+} exitCallback_t;
+
+static exitCallback_t *callback = 0;
+
+int atexit(void (*function) (void))
+{
+       exitCallback_t *newCallback;
+               
+       newCallback = New(exitCallback_t);
+       if(!newCallback) {
+               printOom();
+               exit(1);
+       }
+       newCallback->function = function;
+       newCallback->next = callback;
+       callback = newCallback;
+       return 0;
+}
+#undef exit
+
+void myexit(int code)
+{
+  void (*function)(void);
+
+  while(callback) {
+    function = callback->function;
+    callback = callback->next;
+    function();
+  }
+  exit(code);
+}
+
+#endif
+
+#endif
+
+static const char PATH_SEP = '/';
+
+/*#ifndef HAVE_BASENAME*/
+const char *_basename(const char *filename)
+{
+       char *ptr;
+
+       ptr = strrchr(filename, PATH_SEP);
+       if(ptr)
+               filename = ptr + 1;
+
+#ifdef OS_mingw32msvc
+       ptr = strrchr(filename, '\\');
+       if(ptr)
+               filename = ptr + 1;
+#endif
+
+       return filename;
+}
+/*#endif*/
+
+/* Strip the suffix ".exe" from the argument, if present. */
+void _stripexe(char *filename)
+{
+       char *ptr;
+       ptr = strrchr(filename, '.');
+       if(ptr && !strcasecmp(ptr, ".exe"))
+               *ptr = '\0';
+}
+
+#ifndef HAVE_STRNLEN
+size_t strnlen(const char *str, size_t l)
+{
+  size_t i;
+  for(i=0; i<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 (file)
index 0000000..cba1846
--- /dev/null
@@ -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';
+       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;
+
+#define maxsize (isprimary ?  MAX_VNAMELEN+1 : 11+1)
+#define name (isprimary ? argname : shortname)
+
+       mangled = 0;
+       do {
+               char tname[4*MAX_VNAMELEN+1];
+               fprintf(stderr, "New %s name for \"%s\": ",
+                       isprimary ? "primary" : "secondary", longname);
+               fflush(stderr);
+               if (! fgets(tname, 4*MAX_VNAMELEN+1, opentty(0)))
+                       return 0;
+               chomp(tname);
+               if (isprimary)
+                       strcpy(longname, tname);
+               else
+                       mangled = convert_to_shortname(cp, 
+                                                      ch, tname, shortname);
+       } while (mangled & 1);
+       return 1;
+#undef maxsize
+#undef name
+}
+
+/**
+ * This function determines the action to be taken in case there is a problem
+ * with target name (clash, illegal characters, or reserved)
+ * The decision either comes from the default (ch), or the user will be
+ * prompted if there is no default
+ */
+static __inline__ clash_action ask_namematch(doscp_t *cp,
+                                            dos_name_t *dosname,
+                                            char *longname,
+                                            int isprimary, 
+                                            ClashHandling_t *ch,
+                                            int no_overwrite,
+                                            int reason)
+{
+       /* User's answer letter (from keyboard). Only first letter is used,
+        * but we allocate space for 10 in order to account for extra garbage
+        * that user may enter
+        */
+       char ans[10];
+
+       /**
+        * Return value: action to be taken
+        */
+       clash_action a;
+
+       /**
+        * Should this decision be made permanent (do no longer ask same
+        * question)
+        */
+       int perm;
+
+       /**
+        * Buffer for shortname
+        */
+       char name_buffer[4*13];
+
+       /**
+        * Name to be printed
+        */
+       char *name;
+
+#define EXISTS 0
+#define RESERVED 1
+#define ILLEGALS 2
+
+       static const char *reasons[]= {
+               "already exists",
+               "is reserved",
+               "contains illegal character(s)"};
+
+       a = ch->action[isprimary];
+
+       if(a == NAMEMATCH_NONE && !opentty(1)) {
+               /* no default, and no tty either . Skip the troublesome file */
+               return NAMEMATCH_SKIP;
+       }
+
+       if (!isprimary)
+               name = unix_normalize(cp, name_buffer, dosname);
+       else
+               name = longname;
+
+       perm = 0;
+       while (a == NAMEMATCH_NONE) {
+               fprintf(stderr, "%s file name \"%s\" %s.\n",
+                       isprimary ? "Long" : "Short", name, reasons[reason]);
+               fprintf(stderr,
+                       "a)utorename A)utorename-all r)ename R)ename-all ");
+               if(!no_overwrite)
+                       fprintf(stderr,"o)verwrite O)verwrite-all");
+               fprintf(stderr,
+                       "\ns)kip S)kip-all q)uit (aArR");
+               if(!no_overwrite)
+                       fprintf(stderr,"oO");
+               fprintf(stderr,"sSq): ");
+               fflush(stderr);
+               fflush(opentty(1));
+               if (mtools_raw_tty) {
+                       int rep;
+                       rep = fgetc(opentty(1));                        
+                       fputs("\n", stderr);
+                       if(rep == EOF)
+                               ans[0] = 'q';
+                       else
+                               ans[0] = rep;
+               } else {
+                       if(fgets(ans, 9, opentty(0)) == NULL)
+                               ans[0] = 'q';
+               }
+               perm = isupper((unsigned char)ans[0]);
+               switch(tolower((unsigned char)ans[0])) {
+                       case 'a':
+                               a = NAMEMATCH_AUTORENAME;
+                               break;
+                       case 'r':
+                               if(isprimary)
+                                       a = NAMEMATCH_PRENAME;
+                               else
+                                       a = NAMEMATCH_RENAME;
+                               break;
+                       case 'o':
+                               if(no_overwrite)
+                                       continue;
+                               a = NAMEMATCH_OVERWRITE;
+                               break;
+                       case 's':
+                               a = NAMEMATCH_SKIP;
+                               break;
+                       case 'q':
+                               perm = 0;
+                               a = NAMEMATCH_QUIT;
+                               break;
+                       default:
+                               perm = 0;
+               }
+       }
+
+       /* Keep track of this action in case this file collides again */
+       ch->action[isprimary]  = a;
+       if (perm)
+               ch->namematch_default[isprimary] = a;
+
+       /* if we were asked to overwrite be careful. We can't set the action
+        * to overwrite, else we get won't get a chance to specify another
+        * action, should overwrite fail. Indeed, we'll be caught in an
+        * infinite loop because overwrite will fail the same way for the
+        * second time */
+       if(a == NAMEMATCH_OVERWRITE)
+               ch->action[isprimary] = NAMEMATCH_NONE;
+       return a;
+}
+
+/*
+ * Processes a name match
+ *  dosname short dosname (ignored if is_primary)
+ *
+ *
+ * Returns:
+ * 2 if file is to be overwritten
+ * 1 if file was renamed
+ * 0 if it was skipped
+ *
+ * If a short name is involved, handle conversion between the 11-character
+ * fixed-length record DOS name and a literal null-terminated name (e.g.
+ * "COMMAND  COM" (no null) <-> "COMMAND.COM" (null terminated)).
+ *
+ * Also, immediately copy the original name so that messages can use it.
+ */
+static __inline__ clash_action process_namematch(doscp_t *cp,
+                                                dos_name_t *dosname,
+                                                char *longname,
+                                                int isprimary,
+                                                ClashHandling_t *ch,
+                                                int no_overwrite,
+                                                int reason)
+{
+       clash_action action;
+
+#if 0
+       fprintf(stderr,
+               "process_namematch: name=%s, default_action=%d, ask=%d.\n",
+               name, default_action, ch->ask);
+#endif
+
+       action = ask_namematch(cp, dosname, longname,
+                              isprimary, ch, no_overwrite, reason);
+
+       switch(action){
+       case NAMEMATCH_QUIT:
+               got_signal = 1;
+               return NAMEMATCH_SKIP;
+       case NAMEMATCH_SKIP:
+               return NAMEMATCH_SKIP;
+       case NAMEMATCH_RENAME:
+       case NAMEMATCH_PRENAME:
+               /* We need to rename the file now.  This means we must pass
+                * back through the loop, a) ensuring there isn't a potential
+                * new name collision, and b) finding a big enough VSE.
+                * Change the name, so that it won't collide again.
+                */
+               ask_rename(cp, ch, dosname, longname, isprimary);
+               return action;
+       case NAMEMATCH_AUTORENAME:
+               /* Very similar to NAMEMATCH_RENAME, except that we need to
+                * first generate the name.
+                * TODO: Remember previous name so we don't
+                * keep trying the same one.
+                */
+               if (isprimary) {
+                       autorename_long(longname, 1);
+                       return NAMEMATCH_PRENAME;
+               } else {
+                       autorename_short(dosname, 1);
+                       return NAMEMATCH_RENAME;
+               }
+       case NAMEMATCH_OVERWRITE:
+               if(no_overwrite)
+                       return NAMEMATCH_SKIP;
+               else
+                       return NAMEMATCH_OVERWRITE;
+       default:
+               return NAMEMATCH_NONE;
+       }
+}
+
+static int contains_illegals(const char *string, const char *illegals,
+                            int len)
+{
+       for(; *string && len--; string++)
+               if((*string < ' ' && *string != '\005' && !(*string & 0x80)) ||
+                  strchr(illegals, *string))
+                       return 1;
+       return 0;
+}
+
+static int is_reserved(char *ans, int islong)
+{
+       unsigned int i;
+       static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", "   "};
+       static const char *dev4[] = {"COM", "LPT" };
+
+       for (i = 0; i < sizeof(dev3)/sizeof(*dev3); i++)
+               if (!strncasecmp(ans, dev3[i], 3) &&
+                   ((islong && !ans[3]) ||
+                    (!islong && !strncmp(ans+3,"     ",5))))
+                       return 1;
+
+       for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++)
+               if (!strncasecmp(ans, dev4[i], 3) &&
+                   (ans[3] >= '1' && ans[3] <= '4') &&
+                   ((islong && !ans[4]) ||
+                    (!islong && !strncmp(ans+4,"    ",4))))
+                       return 1;
+       
+       return 0;
+}
+
+static __inline__ clash_action get_slots(Stream_t *Dir,
+                                        dos_name_t *dosname,
+                                        char *longname,
+                                        struct scan_state *ssp,
+                                        ClashHandling_t *ch)
+{
+       int error;
+       clash_action ret;
+       int match_pos=0;
+       direntry_t entry;
+       int isprimary;
+       int no_overwrite;
+       int reason;
+       int pessimisticShortRename;
+       doscp_t *cp = GET_DOSCONVERT(Dir);
+
+       pessimisticShortRename = (ch->action[0] == NAMEMATCH_AUTORENAME);
+
+       entry.Dir = Dir;
+       no_overwrite = 1;
+       if((is_reserved(longname,1)) ||
+          longname[strspn(longname,". ")] == '\0'){
+               reason = RESERVED;
+               isprimary = 1;
+       } else if(contains_illegals(longname,long_illegals,1024)) {
+               reason = ILLEGALS;
+               isprimary = 1;
+       } else if(is_reserved(dosname->base,0)) {
+               reason = RESERVED;
+               ch->use_longname = 1;
+               isprimary = 0;
+       } else if(contains_illegals(dosname->base,short_illegals,11)) {
+               reason = ILLEGALS;
+               ch->use_longname = 1;
+               isprimary = 0;
+       } else {
+               reason = EXISTS;
+               switch (lookupForInsert(Dir,
+                                       &entry,
+                                       dosname, longname, ssp,
+                                       ch->ignore_entry,
+                                       ch->source_entry,
+                                       pessimisticShortRename &&
+                                       ch->use_longname,
+                                       ch->use_longname)) {
+                       case -1:
+                               return NAMEMATCH_ERROR;
+                               
+                       case 0:
+                               return NAMEMATCH_SKIP;
+                               /* Single-file error error or skip request */
+                               
+                       case 5:
+                               return NAMEMATCH_GREW;
+                               /* Grew directory, try again */
+                               
+                       case 6:
+                               return NAMEMATCH_SUCCESS; /* Success */
+               }       
+               match_pos = -2;
+               if (ssp->longmatch > -1) {
+                       /* Primary Long Name Match */
+#ifdef debug
+                       fprintf(stderr,
+                               "Got longmatch=%d for name %s.\n",
+                               longmatch, longname);
+#endif                 
+                       match_pos = ssp->longmatch;
+                       isprimary = 1;
+               } else if ((ch->use_longname & 1) && (ssp->shortmatch != -1)) {
+                       /* Secondary Short Name Match */
+#ifdef debug
+                       fprintf(stderr,
+                               "Got secondary short name match for name %s.\n",
+                               longname);
+#endif
+
+                       match_pos = ssp->shortmatch;
+                       isprimary = 0;
+               } else if (ssp->shortmatch >= 0) {
+                       /* Primary Short Name Match */
+#ifdef debug
+                       fprintf(stderr,
+                               "Got primary short name match for name %s.\n",
+                               longname);
+#endif
+                       match_pos = ssp->shortmatch;
+                       isprimary = 1;
+               } else
+                       return NAMEMATCH_RENAME;
+
+               if(match_pos > -1) {
+                       entry.entry = match_pos;
+                       dir_read(&entry, &error);
+                       if (error)
+                           return NAMEMATCH_ERROR;
+                       /* if we can't overwrite, don't propose it */
+                       no_overwrite = (match_pos == ch->source || IS_DIR(&entry));
+               }
+       }
+       ret = process_namematch(cp, dosname, longname,
+                               isprimary, ch, no_overwrite, reason);
+       
+       if (ret == NAMEMATCH_OVERWRITE && match_pos > -1){
+               if((entry.dir.attr & 0x5) &&
+                  (ask_confirmation("file is read only, overwrite anyway (y/n) ? ")))
+                       return NAMEMATCH_RENAME;
+               /* Free up the file to be overwritten */
+               if(fatFreeWithDirentry(&entry))
+                       return NAMEMATCH_ERROR;
+               
+#if 0
+               if(isprimary &&
+                  match_pos - ssp->match_free + 1 >= ssp->size_needed){
+                       /* reuse old entry and old short name for overwrite */
+                       ssp->free_start = match_pos - ssp->size_needed + 1;
+                       ssp->free_size = ssp->size_needed;
+                       ssp->slot = match_pos;
+                       ssp->got_slots = 1;
+                       strncpy(dosname, dir.name, 3);
+                       strncpy(dosname + 8, dir.ext, 3);
+                       return ret;
+               } else
+#endif
+                       {
+                       wipeEntry(&entry);
+                       return NAMEMATCH_RENAME;
+               }
+       }
+
+       return ret;
+}
+
+
+static __inline__ int write_slots(Stream_t *Dir,
+                                 dos_name_t *dosname,
+                                 char *longname,
+                                 struct scan_state *ssp,
+                                 write_data_callback *cb,
+                                 void *arg,
+                                 int Case)
+{
+       direntry_t entry;
+
+       /* write the file */
+       if (fat_error(Dir))
+               return 0;
+
+       entry.Dir = Dir;
+       entry.entry = ssp->slot;
+       native_to_wchar(longname, entry.name, MAX_VNAMELEN, 0, 0);
+       entry.name[MAX_VNAMELEN]='\0';
+       entry.dir.Case = Case & (EXTCASE | BASECASE);
+       if (cb(dosname, longname, arg, &entry) >= 0) {
+               if ((ssp->size_needed > 1) &&
+                   (ssp->free_end - ssp->free_start >= ssp->size_needed)) {
+                       ssp->slot = write_vfat(Dir, dosname, longname,
+                                              ssp->free_start, &entry);
+               } else {
+                       ssp->size_needed = 1;
+                       write_vfat(Dir, dosname, 0,
+                                  ssp->free_start, &entry);
+               }
+               /* clear_vses(Dir, ssp->free_start + ssp->size_needed,
+                  ssp->free_end); */
+       } else
+               return 0;
+
+       return 1;       /* Successfully wrote the file */
+}
+
+static void stripspaces(char *name)
+{
+       char *p,*non_space;
+
+       non_space = name;
+       for(p=name; *p; p++)
+               if (*p != ' ')
+                       non_space = p;
+       if(name[0])
+               non_space[1] = '\0';
+}
+
+
+static int _mwrite_one(Stream_t *Dir,
+                      char *argname,
+                      char *shortname,
+                      write_data_callback *cb,
+                      void *arg,
+                      ClashHandling_t *ch)
+{
+       char longname[VBUFSIZE];
+       const char *dstname;
+       dos_name_t dosname;
+       int expanded;
+       struct scan_state scan;
+       clash_action ret;
+       doscp_t *cp = GET_DOSCONVERT(Dir);
+
+       expanded = 0;
+
+       if(isSpecial(argname)) {
+               fprintf(stderr, "Cannot create entry named . or ..\n");
+               return -1;
+       }
+
+       if(ch->name_converter == dos_name) {
+               if(shortname)
+                       stripspaces(shortname);
+               if(argname)
+                       stripspaces(argname);
+       }
+
+       if(shortname){
+               convert_to_shortname(cp, ch, shortname, &dosname);
+               if(ch->use_longname & 1){
+                       /* short name mangled, treat it as a long name */
+                       argname = shortname;
+                       shortname = 0;
+               }
+       }
+
+       if (argname[0] && (argname[1] == ':')) {
+               /* Skip drive letter */
+               dstname = argname + 2;
+       } else {
+               dstname = argname;
+       }
+
+       /* Copy original argument dstname to working value longname */
+       strncpy(longname, dstname, VBUFSIZE-1);
+
+       if(shortname) {
+               ch->use_longname =
+                       convert_to_shortname(cp, ch, shortname, &dosname);
+               if(strcmp(shortname, longname))
+                       ch->use_longname |= 1;
+       } else {
+               ch->use_longname =
+                       convert_to_shortname(cp, ch, longname, &dosname);
+       }
+
+       ch->action[0] = ch->namematch_default[0];
+       ch->action[1] = ch->namematch_default[1];
+
+       while (1) {
+               switch((ret=get_slots(Dir, &dosname, longname, &scan, ch))){
+                       case NAMEMATCH_ERROR:
+                               return -1;      /* Non-file-specific error,
+                                                * quit */
+                               
+                       case NAMEMATCH_SKIP:
+                               return -1;      /* Skip file (user request or
+                                                * error) */
+
+                       case NAMEMATCH_PRENAME:
+                               ch->use_longname =
+                                       convert_to_shortname(cp, ch,
+                                                            longname,
+                                                            &dosname);
+                               continue;
+                       case NAMEMATCH_RENAME:
+                               continue;       /* Renamed file, loop again */
+
+                       case NAMEMATCH_GREW:
+                               /* No collision, and not enough slots.
+                                * Try to grow the directory
+                                */
+                               if (expanded) { /* Already tried this
+                                                * once, no good */
+                                       fprintf(stderr,
+                                               "%s: No directory slots\n",
+                                               progname);
+                                       return -1;
+                               }
+                               expanded = 1;
+                               
+                               if (dir_grow(Dir, scan.max_entry))
+                                       return -1;
+                               continue;
+                       case NAMEMATCH_OVERWRITE:
+                       case NAMEMATCH_SUCCESS:
+                               return write_slots(Dir, &dosname, longname,
+                                                  &scan, cb, arg,
+                                                  ch->use_longname);
+                       default:
+                               fprintf(stderr,
+                                       "Internal error: clash_action=%d\n",
+                                       ret);
+                               return -1;
+               }
+
+       }
+}
+
+int mwrite_one(Stream_t *Dir,
+              const char *_argname,
+              const char *_shortname,
+              write_data_callback *cb,
+              void *arg,
+              ClashHandling_t *ch)
+{
+       char *argname;
+       char *shortname;
+       int ret;
+
+       if(_argname)
+               argname = strdup(_argname);
+       else
+               argname = 0;
+       if(_shortname)
+               shortname = strdup(_shortname);
+       else
+               shortname = 0;
+       ret = _mwrite_one(Dir, argname, shortname, cb, arg, ch);
+       if(argname)
+               free(argname);
+       if(shortname)
+               free(shortname);
+       return ret;
+}
+
+void init_clash_handling(ClashHandling_t *ch)
+{
+       ch->ignore_entry = -1;
+       ch->source_entry = -2;
+       ch->nowarn = 0; /*Don't ask, just do default action if name collision */
+       ch->namematch_default[0] = NAMEMATCH_AUTORENAME;
+       ch->namematch_default[1] = NAMEMATCH_NONE;
+       ch->name_converter = dos_name; /* changed by mlabel */
+       ch->source = -2;
+}
+
+int handle_clash_options(ClashHandling_t *ch, char c)
+{
+       int isprimary;
+       if(isupper(c))
+               isprimary = 0;
+       else
+               isprimary = 1;
+       c = tolower(c);
+       switch(c) {
+               case 'o':
+                       /* Overwrite if primary name matches */
+                       ch->namematch_default[isprimary] = NAMEMATCH_OVERWRITE;
+                       return 0;
+               case 'r':
+                               /* Rename primary name interactively */
+                       ch->namematch_default[isprimary] = NAMEMATCH_RENAME;
+                       return 0;
+               case 's':
+                       /* Skip file if primary name collides */
+                       ch->namematch_default[isprimary] = NAMEMATCH_SKIP;
+                       return 0;
+               case 'm':
+                       ch->namematch_default[isprimary] = NAMEMATCH_NONE;
+                       return 0;
+               case 'a':
+                       ch->namematch_default[isprimary] = NAMEMATCH_AUTORENAME;
+                       return 0;
+               default:
+                       return -1;
+       }
+}
+
+void dosnameToDirentry(const struct dos_name_t *dn, struct directory *dir) {
+       strncpy(dir->name, dn->base, 8);
+       strncpy(dir->ext, dn->ext, 3);
+}
diff --git a/mkdosboot b/mkdosboot
new file mode 100755 (executable)
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 (executable)
index 0000000..6a5fd0b
--- /dev/null
@@ -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 "$pathcomp" || errstatus=$?
+     fi
+
+     pathcomp="$pathcomp/"
+   done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/mkmanifest.1 b/mkmanifest.1
new file mode 100644 (file)
index 0000000..33e2126
--- /dev/null
@@ -0,0 +1,181 @@
+.TH mkmanifest 1 "03Nov09" mtools-4.0.12
+.SH Name
+mkmanifest - makes list of file names and their DOS 8+3 equivalent
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mkmanifest"
+.iX "c packing list"
+.PP
+The \fR\&\f(CWmkmanifest\fR command is used to create a shell script (packing
+list) to restore Unix filenames. Its syntax is:
+.PP
+\&\fR\&\f(CWmkmanifest\fR [ \fIfiles\fR ]
+.PP
+\&\fR\&\f(CWMkmanifest\fR creates a shell script that aids in the restoration of
+Unix filenames that got clobbered by the MS-DOS filename restrictions.
+MS-DOS filenames are restricted to 8 character names, 3 character
+extensions, upper case only, no device names, and no illegal characters.
+.PP
+The mkmanifest program is compatible with the methods used in
+\&\fR\&\f(CWpcomm, arc,\fR and \fR\&\f(CWmtools\fR to change perfectly good Unix
+filenames to fit the MS-DOS restrictions. This command is only useful if
+the target system which will read the diskette cannot handle vfat long
+names.
+.PP
+.SH Example
+You want to copy the following Unix files to a MS-DOS diskette (using the
+\&\fR\&\f(CWmcopy\fR command).
+.PP
+.nf
+.ft 3
+.in +0.3i
+  very_long_name
+  2.many.dots
+  illegal:
+  good.c
+  prn.dev
+  Capital
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+\&\fR\&\f(CWMcopy\fR
+converts the names to:
+.PP
+.nf
+.ft 3
+.in +0.3i
+  very_lon
+  2xmany.dot
+  illegalx
+  good.c
+  xprn.dev
+  capital
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The command:
+.nf
+.ft 3
+.in +0.3i
+mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRwould produce the following:
+.nf
+.ft 3
+.in +0.3i
+  mv very_lon very_long_name
+  mv 2xmany.dot 2.many.dots
+  mv illegalx illegal:
+  mv xprn.dev prn.dev
+  mv capital Capital
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+Notice that "good.c" did not require any conversion, so it did not
+appear in the output.
+.PP
+Suppose I've copied these files from the diskette to another Unix
+system, and I now want the files back to their original names.  If the
+file "manifest" (the output captured above) was sent along with those
+files, it could be used to convert the filenames.
+.PP
+.SH Bugs
+.PP
+The short names generated by \fR\&\f(CWmkmanifest\fR follow the old convention
+(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mkmanifest.c b/mkmanifest.c
new file mode 100644 (file)
index 0000000..1b56b3d
--- /dev/null
@@ -0,0 +1,112 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-1998,2001,2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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] = tolower((unsigned char)buf[i]);
+       }
+                                       /* if no name */
+       if (*temp == '\0')
+               strcpy(ans, "x");
+       else {
+               /* if name is a device */
+               for (i=0; i<9; i++) {
+                       if (!strcasecmp(temp, dev[i])) 
+                               *temp = 'x';
+               }
+               /* name too long? */
+               if (strlen(temp) > 8)
+                       *(temp+8) = '\0';
+               /* extension too long? */
+               if (ext && strlen(ext) > 3)
+                       *(ext+3) = '\0';
+               /* illegal characters? */
+               while ((s = strpbrk(temp, "^+=/[]:',?*\\<>|\". ")))
+                       *s = 'x';
+
+               while (ext && (s = strpbrk(ext, "^+=/[]:',?*\\<>|\". ")))
+                       *s = 'x';             
+               strncpy(ans, temp, 12);
+       }
+       if (ext && *ext) {
+               strcat(ans, ".");
+               strcat(ans, ext);
+       }
+       return(ans);
+}
diff --git a/mkmanpages b/mkmanpages
new file mode 100755 (executable)
index 0000000..47235c2
--- /dev/null
@@ -0,0 +1,134 @@
+#!/bin/bash
+
+# Copyright 1997,1999,2001,2002,2004,2009 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <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()
+{
+  echo extracting $name
+  command=$1
+  outfile=`echo $command | tr '[A-Z]' '[a-z]'`.1
+  
+  echo \'\\\" t >>$outfile
+# '
+  echo .TH\ $command\ 1\ \"$date\" $package >$outfile
+  echo .SH Name >>$outfile
+  grep -i $command cmdname | fgrep -v '#' >>$outfile
+  #echo ".SH Description" >>$outfile
+  
+  cat man-warning.texi mtools.texi man-warning-end.texi |
+  egrep -v '@end copying|@copying|@insertcopying' |
+  sed \
+   -e "/^@c\(omment\)\? skipskipskip/,/^@node $command/d" \
+   -e "/^@node [^,]*, [^,]*, $command, Commands$/,/^@bye/d" \
+   -e "/^@node [^,]*, [^,]*, Commands/,/^@bye/d" \
+   -e 's/^@section/@chapter/' \
+   -e 's/^@subs/@s/' \
+   -e 's/^@chapter.*$/@chapter Description/' \
+   -e 's/^@section/@chapter/' \
+   -e 's/^@subs/@s/' \
+   -e 's/^@c\(omment\)\? xMANoptions/@chapter Options/' \
+   -e "s/^@c\(omment\)\? MAN/@MAN/"  |
+  texi2roff -ma  |
+  sed -f strip-pp.sed >>$outfile
+#  echo ".SH See Also" >>$outfile
+#  echo "Mtools' texinfo doc" >>$outfile
+}
+
+
+for name in `fgrep -v '#' cmdname | cut -f1 -d\  ` ; do
+  extract $name
+done
+
+echo \'\\\" t >mtools.1
+# '
+echo .TH mtools.1 3 \"$date\" $package >>mtools.1
+echo .SH Name >>mtools.1
+echo "mtools - utilities to access DOS disks in Unix." >>mtools.1
+cat mtools.texi |
+  egrep -v '@end copying|@copying|@insertcopying' |
+       sed \
+        -e "1,/^@c\(omment\)\? MANstart 1/d" \
+        -e '/^@c\(omment\)\? MANskip 1/,/^@c\(omment\)\? MANend-skip 1/d' \
+        -e '/^@c\(omment\)\? MANend-skip 5/d' \
+        -e '/^@c\(omment\)\? MANend 5/d' \
+        -e "s/^@c\(omment\)\? MAN/@MAN/" \
+        -e "s/@value{VERSION}/$VERSION/g" |
+       texi2roff -ma  |
+       sed -f strip-pp.sed >>mtools.1
+
+echo .SH See also >>mtools.1
+echo floppyd_installtest >>mtools.1
+echo mattrib >>mtools.1
+echo mbadblocks >>mtools.1
+echo mcd >>mtools.1
+echo mclasserase >>mclasserase.1
+echo mcopy >>mtools.1
+echo mdel >>mtools.1
+echo mdeltree >>mtools.1
+echo mdir >>mtools.1
+echo mdu >>mtools.1
+echo mformat >>mtools.1
+echo minfo >>mtools.1
+echo mkmanifest >>mtools.1
+echo mlabel >>mtools.1
+echo mmd >>mtools.1
+echo mmount >>mtools.1
+echo mmove >>mtools.1
+echo mrd >>mtools.1
+echo mren >>mtools.1
+echo mtoolstest >>mtools.1
+echo mtype >>mtools.1
+
+echo \'\\\" t >mtools.5
+# '
+echo .TH mtools.1 3 \"$date\" "MTOOLS" "MTOOLS" >>mtools.5
+echo .SH Name >>mtools.5
+echo "mtools.conf - mtools configuration files" >>mtools.5
+cat mtools.texi |
+  egrep -v '@end copying|@copying|@insertcopying' |
+       sed \
+               -e '1d' \
+               -e '/^@c\(omment\)\? MANskip 5/,/^@c\(omment\)\? MANend-skip 5/d' \
+               -e '/^@c\(omment\)\? MANend-skip 1/d' \
+               -e '/^@c\(omment\)\? MANskip 1/d' \
+               -e "s/^@c\(omment\)\? MAN/@MAN/"  \
+               -e "/@include/ d" \
+               -e "s/@value{VERSION}/$VERSION/g" \
+               -e "s/@value{UPDATED}/$UPDATED/g" \
+               -e "/@top/d" \
+               -e "/@format/d" \
+               -e "/@end format/d" \
+               -e "/@ifnottex/d" \
+               -e "/@end ifnottex/d" |
+       texi2roff -ma  |
+       sed -f strip-pp.sed |
+       sed 's/\.SS Description/.SH Description/' >>mtools.5
+
+echo .SH See also >>mtools.5
+echo mtools >>mtools.5
diff --git a/mlabel.1 b/mlabel.1
new file mode 100644 (file)
index 0000000..7453edc
--- /dev/null
+++ b/mlabel.1
@@ -0,0 +1,117 @@
+.TH mlabel 1 "03Nov09" mtools-4.0.12
+.SH Name
+mlabel - make an MSDOS volume label
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mlabel"
+.iX "c Labeling a disk"
+.iX "c Disk label"
+.PP
+The \fR\&\f(CWmlabel\fR command adds a volume label to a disk. Its syntax is:
+.ft I
+.nf
+\&\fR\&\f(CWmlabel\fR [\fR\&\f(CW-vcsn\fR] [\fR\&\f(CW-N\fR \fIserial\fR] \fIdrive\fR:[\fInew_label\fR]
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMlabel\fR displays the current volume label, if present. If
+\&\fInew_label\fR is not given, and if neither the \fR\&\f(CWc\fR nor the
+\&\fR\&\f(CWs\fR options are set, it prompts the user for a new volume label.
+To delete an existing volume label, press return at the prompt.
+.PP
+Reasonable care is taken to create a valid MS-DOS volume label.  If an
+invalid label is specified, \fR\&\f(CWmlabel\fR changes the label (and
+displays the new label if the verbose mode is set). \fR\&\f(CWMlabel\fR
+returns 0 on success or 1 on failure.
+.PP
+Mlabel supports the following options:
+.TP
+\&\fR\&\f(CWc\fR\ 
+Clears an existing label, without prompting the user
+.TP
+\&\fR\&\f(CWs\fR\ 
+Shows the existing label, without prompting the user.
+.TP
+\&\fR\&\f(CWn\ \fR\ 
+Assigns a new (random) serial number to the disk
+.TP
+\&\fR\&\f(CWN\ \fIserial\fR\&\f(CW\fR\ 
+Sets the supplied serial number. The serial number should be supplied as
+an 8 digit hexadecimal number, without spaces
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mlabel.c b/mlabel.c
new file mode 100644 (file)
index 0000000..7ffbed3
--- /dev/null
+++ b/mlabel.c
@@ -0,0 +1,285 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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"
+
+void label_name(doscp_t *cp, const char *filename, int verbose,
+               int *mangled, dos_name_t *ans)
+{
+       int len;
+       int i;
+       int have_lower, have_upper;
+       wchar_t wbuffer[12];
+
+       memset(ans, ' ', sizeof(ans)-1);
+       ans->sentinel = '\0';
+       len = native_to_wchar(filename, wbuffer, 11, 0, 0);
+       if(len > 11){
+               *mangled = 1;
+               len = 11;
+       } else
+               *mangled = 0;
+
+       have_lower = have_upper = 0;
+       for(i=0; i<len; i++){
+               if(islower(wbuffer[i]))
+                       have_lower = 1;
+               if(isupper(wbuffer[i]))
+                       have_upper = 1;
+               wbuffer[i] = 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);
+}
+
+int labelit(struct dos_name_t *dosname,
+           char *longname,
+           void *arg0,
+           direntry_t *entry)
+{
+       time_t now;
+
+       /* find out current time */
+       getTimeNow(&now);
+       mk_entry(dosname, 0x8, 0, 0, now, &entry->dir);
+       return 0;
+}
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr, "Mtools version %s, dated %s\n",
+               mversion, mdate);
+       fprintf(stderr, "Usage: %s [-vscVn] [-N serial] drive:\n", progname);
+       exit(ret);
+}
+
+
+void mlabel(int argc, char **argv, int type)
+{
+
+       char *newLabel;
+       int verbose, clear, interactive, show;
+       direntry_t entry;
+       int result=0;
+       char longname[VBUFSIZE];
+       char shortname[45];
+       ClashHandling_t ch;
+       struct MainParam_t mp;
+       Stream_t *RootDir;
+       int c;
+       int mangled;
+       enum { SER_NONE, SER_RANDOM, SER_SET }  set_serial = SER_NONE;
+       long serial = 0;
+       int need_write_boot = 0;
+       int have_boot = 0;
+       char *eptr;
+       union bootsector boot;
+       Stream_t *Fs=0;
+       int r;
+       struct label_blk_t *labelBlock;
+       int isRo=0;
+       int *isRop=NULL;
+
+       init_clash_handling(&ch);
+       ch.name_converter = label_name;
+       ch.ignore_entry = -2;
+
+       verbose = 0;
+       clear = 0;
+       show = 0;
+
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:vcsnN:h")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'v':
+                               verbose = 1;
+                               break;
+                       case 'c':
+                               clear = 1;
+                               break;
+                       case 's':
+                               show = 1;
+                               break;
+                       case 'n':
+                               set_serial = SER_RANDOM;
+                               srandom((long)time (0));
+                               serial=random();
+                               break;
+                       case 'N':
+                               set_serial = SER_SET;
+                               serial = strtol(optarg, &eptr, 16);
+                               if(*eptr) {
+                                       fprintf(stderr,
+                                               "%s not a valid serial number\n",
+                                               optarg);
+                                       exit(1);
+                               }
+                               break;
+                       case 'h':
+                               usage(0);
+                       default:
+                               usage(1);
+                       }
+       }
+
+       if (argc - optind != 1 || !argv[optind][0] || argv[optind][1] != ':')
+               usage(1);
+
+       init_mp(&mp);
+       newLabel = argv[optind]+2;
+       if(strlen(newLabel) > VBUFSIZE) {
+               fprintf(stderr, "Label too long\n");
+               FREE(&RootDir);
+               exit(1);
+       }
+
+       interactive = !show && !clear &&!newLabel[0] &&
+               (set_serial == SER_NONE);
+       if(!clear && !newLabel[0]) {
+               isRop = &isRo;
+       }
+       RootDir = open_root_dir(argv[optind][0], isRop ? 0 : O_RDWR, isRop);
+       if(isRo) {
+               show = 1;
+               interactive = 0;
+       }       
+       if(!RootDir) {
+               fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
+               exit(1);
+       }
+
+       initializeDirentry(&entry, RootDir);
+       r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
+                     shortname, longname);
+       if (r == -2) {
+               FREE(&RootDir);
+               exit(1);
+       }
+
+       if(show || interactive){
+               if(isNotFound(&entry))
+                       printf(" Volume has no label\n");
+               else if (*longname)
+                       printf(" Volume label is %s (abbr=%s)\n",
+                              longname, shortname);
+               else
+                       printf(" Volume label is %s\n",  shortname);
+
+       }
+
+       /* ask for new label */
+       if(interactive){
+               newLabel = longname;
+               fprintf(stderr,"Enter the new volume label : ");
+               if(fgets(newLabel, VBUFSIZE, stdin) == NULL) {
+                       newLabel[0] = '\0';
+                       fprintf(stderr, "\n");
+               }
+               if(newLabel[0])
+                       newLabel[strlen(newLabel)-1] = '\0';
+       }
+
+       if((!show || newLabel[0]) && !isNotFound(&entry)){
+               /* if we have a label, wipe it out before putting new one */
+               if(interactive && newLabel[0] == '\0')
+                       if(ask_confirmation("Delete volume label (y/n): ")){
+                               FREE(&RootDir);
+                               exit(0);
+                       }
+               entry.dir.attr = 0; /* for old mlabel */
+               wipeEntry(&entry);
+       }
+
+       if (newLabel[0] != '\0') {
+               ch.ignore_entry = 1;
+               result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
+                 0 : 1;
+       }
+
+       have_boot = 0;
+       if( (!show || newLabel[0]) || set_serial != SER_NONE) {
+               Fs = GetFs(RootDir);
+               have_boot = (force_read(Fs,boot.characters,0,sizeof(boot)) ==
+                            sizeof(boot));
+       }
+
+       if(WORD_S(fatlen)) {
+           labelBlock = &boot.boot.ext.old.labelBlock;
+       } else {
+           labelBlock = &boot.boot.ext.fat32.labelBlock;
+       }
+
+       if(!show || newLabel[0]){
+               dos_name_t dosname;
+               const char *shrtLabel;
+               doscp_t *cp;
+               if(!newLabel[0])
+                       shrtLabel = "NO NAME    ";
+               else
+                       shrtLabel = newLabel;
+               cp = GET_DOSCONVERT(Fs);
+               label_name(cp, shrtLabel, verbose, &mangled, &dosname);
+
+               if(have_boot && boot.boot.descr >= 0xf0 &&
+                  labelBlock->dos4 == 0x29) {
+                       strncpy(labelBlock->label, dosname.base, 11);
+                       need_write_boot = 1;
+
+               }
+       }
+
+       if((set_serial != SER_NONE) & have_boot) {
+               if(have_boot && boot.boot.descr >= 0xf0 &&
+                  labelBlock->dos4 == 0x29) {
+                       set_dword(labelBlock->serial, serial);  
+                       need_write_boot = 1;
+               }
+       }
+
+       if(need_write_boot) {
+               force_write(Fs, (char *)&boot, 0, sizeof(boot));
+       }
+
+       FREE(&RootDir);
+       exit(result);
+}
diff --git a/mmd.1 b/mmd.1
new file mode 100644 (file)
index 0000000..a642eb8
--- /dev/null
+++ b/mmd.1
@@ -0,0 +1,95 @@
+.TH mmd 1 "03Nov09" mtools-4.0.12
+.SH Name
+mmd - make an MSDOS subdirectory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mmd"
+.iX "c Making a directory"
+.iX "c Creating a directory"
+.iX "c Directory creation"
+.iX "c Subdirectory creation"
+.PP
+The \fR\&\f(CWmmd\fR command is used to make an MS-DOS subdirectory. Its
+syntax is:
+.PP
+\&\fR\&\f(CWmmd\fR [\fR\&\f(CW-D\fR \fIclash_option\fR] \fImsdosdirectory\fR [
+\&\fImsdosdirectories\fR\&... ]
+.PP
+\&\fR\&\f(CWMmd\fR makes a new directory on an MS-DOS filesystem. An error occurs
+if the directory already exists.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mmd.c b/mmd.c
new file mode 100644 (file)
index 0000000..24e4db9
--- /dev/null
+++ b/mmd.c
@@ -0,0 +1,199 @@
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mmd.c
+ * Makes an MSDOS directory
+ */
+
+
+#define LOWERCASE
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "mainloop.h"
+#include "plain_io.h"
+#include "nameclash.h"
+#include "file.h"
+#include "fs.h"
+
+/*
+ * Preserve the file modification times after the fclose()
+ */
+
+typedef struct Arg_t {
+       char *target;
+       MainParam_t mp;
+
+       Stream_t *SrcDir;
+       int entry;
+       ClashHandling_t ch;
+       Stream_t *targetDir;
+} Arg_t;
+
+
+typedef struct CreateArg_t {
+       Stream_t *Dir;
+       Stream_t *NewDir;
+       unsigned char attr;
+       time_t mtime;
+} CreateArg_t;
+
+/*
+ * Open the named file for read, create the cluster chain, return the
+ * directory structure or NULL on error.
+ */
+static int makeit(dos_name_t *dosname,
+                 char *longname,
+                 void *arg0,
+                 direntry_t *targetEntry)
+{
+       Stream_t *Target;
+       CreateArg_t *arg = (CreateArg_t *) arg0;
+       int fat;
+       direntry_t subEntry;    
+
+       /* will it fit? At least one cluster must be free */
+       if (!getfreeMinClusters(targetEntry->Dir, 1))
+               return -1;
+       
+       mk_entry(dosname, ATTR_DIR, 1, 0, arg->mtime, &targetEntry->dir);
+       Target = OpenFileByDirentry(targetEntry);
+       if(!Target){
+               fprintf(stderr,"Could not open Target\n");
+               return -1;
+       }
+
+       /* this allocates the first cluster for our directory */
+
+       initializeDirentry(&subEntry, Target);
+
+       subEntry.entry = 1;
+       GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
+       if (fat == fat32RootCluster(targetEntry->Dir)) {
+           fat = 0;
+       }
+       mk_entry_from_base("..      ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
+       dir_write(&subEntry);
+
+       FLUSH((Stream_t *) Target);
+       subEntry.entry = 0;
+       GET_DATA(Target, 0, 0, 0, &fat);
+       mk_entry_from_base(".       ", ATTR_DIR, fat, 0, arg->mtime, &subEntry.dir);
+       dir_write(&subEntry);
+
+       mk_entry(dosname, ATTR_DIR | arg->attr, fat, 0, arg->mtime,
+                &targetEntry->dir);
+       arg->NewDir = Target;
+       return 0;
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr,
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr,
+               "Usage: %s [-D clash_option] file targetfile\n", progname);
+       fprintf(stderr,
+               "       %s [-D clash_option] file [files...] target_directory\n",
+               progname);
+       exit(ret);
+}
+
+Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch,
+                                       unsigned char attr, time_t mtime)
+{
+       CreateArg_t arg;
+       int ret;
+
+       arg.Dir = Dir;
+       arg.attr = attr;
+       arg.mtime = mtime;
+
+       if (!getfreeMinClusters(Dir, 1))
+               return NULL;
+
+       ret = mwrite_one(Dir, filename, 0, makeit, &arg, ch);
+       if(ret < 1)
+               return NULL;
+       else
+               return arg.NewDir;
+}
+
+static int createDirCallback(direntry_t *entry, MainParam_t *mp)
+{
+       Stream_t *ret;
+       time_t now;
+
+       ret = createDir(mp->File, mp->targetName, &((Arg_t *)(mp->arg))->ch,
+                                       ATTR_DIR, getTimeNow(&now));
+       if(ret == NULL)
+               return ERROR_ONE;
+       else {
+               FREE(&ret);
+               return GOT_ONE;
+       }
+       
+}
+
+void mmd(int argc, char **argv, int type)
+{
+       Arg_t arg;
+       int c;
+
+       /* get command line options */
+
+       init_clash_handling(& arg.ch);
+
+       /* get command line options */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:D:oh")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case '?':
+                               usage(1);
+                       case 'o':
+                               handle_clash_options(&arg.ch, c);
+                               break;
+                       case 'D':
+                               if(handle_clash_options(&arg.ch, *optarg))
+                                       usage(1);
+                               break;
+                       case 'h':
+                               usage(0);
+                       default:
+                               usage(1);
+                               break;
+               }
+       }
+
+       if (argc - optind < 1)
+               usage(1);
+
+       init_mp(&arg.mp);
+       arg.mp.arg = (void *) &arg;
+       arg.mp.openflags = O_RDWR;
+       arg.mp.callback = createDirCallback;
+       arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS;
+       exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mmount.1 b/mmount.1
new file mode 100644 (file)
index 0000000..861bdda
--- /dev/null
+++ b/mmount.1
@@ -0,0 +1,99 @@
+.TH mmount 1 "03Nov09" mtools-4.0.12
+.SH Name
+mmount - mount an MSDOS disk
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mmount"
+.iX "c Linux enhancements (mmount)"
+.iX "c Mounting a disk"
+.iX "c High capacity formats, mounting"
+.PP
+The \fR\&\f(CWmmount\fR command is used to mount an MS-DOS disk. It is only
+available on Linux, as it is only useful if the OS kernel allows to
+configure the disk geometry. Its syntax is:
+.PP
+\&\fR\&\f(CWmmount\fR \fImsdosdrive\fR [\fImountargs\fR]
+.PP
+\&\fR\&\f(CWMmount\fR
+reads the boot sector of an MS-DOS disk, configures the drive geometry,
+and finally mounts it passing
+\&\fR\&\f(CWmountargs\fR to \fR\&\f(CWmount. \fR
+If no mount arguments are specified, the name of the device is
+used. If the disk is write protected, it is automatically mounted read
+only.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mmount.c b/mmount.c
new file mode 100644 (file)
index 0000000..241e645
--- /dev/null
+++ b/mmount.c
@@ -0,0 +1,107 @@
+/*  Copyright 1994,1996-2002,2005-2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+       char drive;
+       int pid;
+       int status;
+       struct device dev;
+       char name[EXPAND_BUF];
+       int media;
+       union bootsector boot;
+       Stream_t *Stream;
+       
+       if (argc<2 || !argv[1][0]  || argv[1][1] != ':' || argv[1][2]){
+               fprintf(stderr,"Usage: %s -V drive:\n", argv[0]);
+               exit(1);
+       }
+       drive = toupper(argv[1][0]);
+       Stream= find_device(drive, O_RDONLY, &dev, &boot, name, &media, 0, NULL);
+       if(!Stream)
+               exit(1);
+       FREE(&Stream);
+
+       destroy_privs();
+
+       if ( dev.partition ) {
+               char part_name[4];
+               sprintf(part_name, "%d", dev.partition %1000);
+               strcat(name, part_name); 
+       }
+
+       /* and finally mount it */
+       switch((pid=fork())){
+       case -1:
+               fprintf(stderr,"fork failed\n");
+               exit(1);
+       case 0:
+               close(2);
+               open("/dev/null", O_RDWR | O_BINARY | O_LARGEFILE);
+               argv[1] = strdup("mount");
+               if ( argc > 2 )
+                       execvp("mount", argv + 1 );
+               else
+                       execlp("mount", "mount", name, NULL);
+               perror("exec mount");
+               exit(1);
+       default:
+               while ( wait(&status) != pid );
+       }       
+       if ( WEXITSTATUS(status) == 0 )
+               exit(0);
+       argv[0] = strdup("mount");
+       argv[1] = strdup("-r");
+       if(!argv[0] || !argv[1]){
+               printOom();
+               exit(1);
+       }
+       if ( argc > 2 )
+               execvp("mount", argv);
+       else
+               execlp("mount", "mount","-r", name, NULL);
+       exit(1);
+}
+
+#else /* linux */
+
+#include "msdos.h"
+
+void mmount(int argc, char **argv, int type)
+{
+  fprintf(stderr,"This command is only available for LINUX \n");
+  exit(1);
+}
+#endif /* linux */
+
diff --git a/mmove.1 b/mmove.1
new file mode 100644 (file)
index 0000000..4d52838
--- /dev/null
+++ b/mmove.1
@@ -0,0 +1,101 @@
+.TH mmove 1 "03Nov09" mtools-4.0.12
+.SH Name
+mmove - move or rename an MSDOS file or subdirectory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mmove"
+.iX "c Moving files (mmove)"
+.iX "c Renaming files (mmove)"
+.PP
+The \fR\&\f(CWmmove\fR command is used to moves or renames an existing MS-DOS
+file or subdirectory.
+.ft I
+.nf
+\&\fR\&\f(CWmmove\fR [\fR\&\f(CW-v\fR] [\fR\&\f(CW-D\fR \fIclash_option\fR] \fIsourcefile\fR \fItargetfile\fR
+\&\fR\&\f(CWmmove\fR [\fR\&\f(CW-v\fR]  [\fR\&\f(CW-D\fR \fIclash_option\fR] \fIsourcefile\fR [ \fIsourcefiles\fR\&... ] \fItargetdirectory\fR
+.fi
+.ft R
+\&\fR\&\f(CWMmove\fR moves or renames an existing MS-DOS file or
+subdirectory. Unlike the MS-DOS version of \fR\&\f(CWMOVE\fR, \fR\&\f(CWmmove\fR is
+able to move subdirectories.  Files or directories can only be moved
+within one filesystem. Data cannot be moved from Dos to Unix or
+vice-versa.  If you omit the drive letter from the target file or
+directory, the same letter as for the source is assumed.  If you omit
+the drive letter from all parameters, drive a: is assumed by default.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mmove.c b/mmove.c
new file mode 100644 (file)
index 0000000..13576dc
--- /dev/null
+++ b/mmove.c
@@ -0,0 +1,323 @@
+/*  Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mmove.c
+ * Renames/moves an MSDOS file
+ *
+ */
+
+
+#define LOWERCASE
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "mainloop.h"
+#include "plain_io.h"
+#include "nameclash.h"
+#include "file.h"
+#include "fs.h"
+
+/*
+ * Preserve the file modification times after the fclose()
+ */
+
+typedef struct Arg_t {
+       const char *fromname;
+       int verbose;
+       MainParam_t mp;
+
+       direntry_t *entry;
+       ClashHandling_t ch;
+} Arg_t;
+
+
+/*
+ * Open the named file for read, create the cluster chain, return the
+ * directory structure or NULL on error.
+ */
+static int renameit(dos_name_t *dosname,
+                   char *longname,
+                   void *arg0,
+                   direntry_t *targetEntry)
+{
+       Arg_t *arg = (Arg_t *) arg0;
+       int fat;
+
+       targetEntry->dir = arg->entry->dir;
+       dosnameToDirentry(dosname, &targetEntry->dir);
+
+       if(IS_DIR(targetEntry)) {
+               direntry_t *movedEntry;
+
+               /* get old direntry. It is important that we do this
+                * on the actual direntry which is stored in the file,
+                * and not on a copy, because we will modify it, and the
+                * modification should be visible at file 
+                * de-allocation time */
+               movedEntry = getDirentry(arg->mp.File);
+               if(movedEntry->Dir != targetEntry->Dir) {
+                       /* we are indeed moving it to a new directory */
+                       direntry_t subEntry;
+                       Stream_t *oldDir;
+                       /* we have a directory here. Change its parent link */
+                       
+                       initializeDirentry(&subEntry, arg->mp.File);
+
+                       switch(vfat_lookup(&subEntry, "..", 2, ACCEPT_DIR,
+                                          NULL, NULL)) {
+                           case -1:
+                               fprintf(stderr,
+                                       " Directory has no parent entry\n");
+                               break;
+                           case -2:
+                               return ERROR_ONE;
+                           case 0:
+                               GET_DATA(targetEntry->Dir, 0, 0, 0, &fat);
+                               if (fat == fat32RootCluster(targetEntry->Dir)) {
+                                   fat = 0;
+                               }
+
+                               subEntry.dir.start[1] = (fat >> 8) & 0xff;
+                               subEntry.dir.start[0] = fat & 0xff;
+                               dir_write(&subEntry);
+                               if(arg->verbose){
+                                       fprintf(stderr,
+                                               "Easy, isn't it? I wonder why DOS can't do this.\n");
+                               }
+                               break;
+                       }
+
+                       wipeEntry(movedEntry);
+                       
+                       /* free the old parent, allocate the new one. */
+                       oldDir = movedEntry->Dir;
+                       *movedEntry = *targetEntry;
+                       COPY(targetEntry->Dir);
+                       FREE(&oldDir);
+                       return 0;
+               }
+       }
+
+       /* wipe out original entry */
+       wipeEntry(arg->mp.direntry);
+       return 0;
+}
+
+
+
+static int rename_file(direntry_t *entry, MainParam_t *mp)
+/* rename a messy DOS file to another messy DOS file */
+{
+       int result;
+       Stream_t *targetDir;
+       char *shortname;
+       const char *longname;
+
+       Arg_t * arg = (Arg_t *) (mp->arg);
+
+       arg->entry = entry;
+       targetDir = mp->targetDir;
+
+       if (targetDir == entry->Dir){
+               arg->ch.ignore_entry = -1;
+               arg->ch.source = entry->entry;
+               arg->ch.source_entry = entry->entry;
+       } else {
+               arg->ch.ignore_entry = -1;
+               arg->ch.source = -2;
+       }
+
+       longname = mpPickTargetName(mp);
+       shortname = 0;
+       result = mwrite_one(targetDir, longname, shortname,
+                           renameit, (void *)arg, &arg->ch);
+       if(result == 1)
+               return GOT_ONE;
+       else
+               return ERROR_ONE;
+}
+
+
+static int rename_directory(direntry_t *entry, MainParam_t *mp)
+{
+       int ret;
+
+       /* moves a DOS dir */
+       if(isSubdirOf(mp->targetDir, mp->File)) {
+               fprintf(stderr, "Cannot move directory ");
+               fprintPwd(stderr, entry,0);
+               fprintf(stderr, " into one of its own subdirectories (");
+               fprintPwd(stderr, getDirentry(mp->targetDir),0);
+               fprintf(stderr, ")\n");
+               return ERROR_ONE;
+       }
+
+       if(entry->entry == -3) {
+               fprintf(stderr, "Cannot move a root directory: ");
+               fprintPwd(stderr, entry,0);
+               return ERROR_ONE;
+       }
+
+       ret = rename_file(entry, mp);
+       if(ret & ERROR_ONE)
+               return ret;
+       
+       return ret;
+}
+
+static int rename_oldsyntax(direntry_t *entry, MainParam_t *mp)
+{
+       int result;
+       Stream_t *targetDir;
+       const char *shortname, *longname;
+
+       Arg_t * arg = (Arg_t *) (mp->arg);
+       arg->entry = entry;
+       targetDir = entry->Dir;
+
+       arg->ch.ignore_entry = -1;
+       arg->ch.source = entry->entry;
+       arg->ch.source_entry = entry->entry;
+
+#if 0
+       if(!strcasecmp(mp->shortname, arg->fromname)){
+               longname = mp->longname;
+               shortname = mp->targetName;
+       } else {
+#endif
+               longname = mp->targetName;
+               shortname = 0;
+#if 0
+       }
+#endif
+       result = mwrite_one(targetDir, longname, shortname,
+                           renameit, (void *)arg, &arg->ch);
+       if(result == 1)
+               return GOT_ONE;
+       else
+               return ERROR_ONE;
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr,
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr,
+               "Usage: %s [-vV] [-D clash_option] file targetfile\n", progname);
+       fprintf(stderr,
+               "       %s [-vV] [-D clash_option] file [files...] target_directory\n", 
+               progname);
+       exit(ret);
+}
+
+void mmove(int argc, char **argv, int oldsyntax)
+{
+       Arg_t arg;
+       int c;
+       char shortname[13];
+       char longname[VBUFSIZE];
+       char def_drive;
+       int i;
+
+       /* get command line options */
+
+       init_clash_handling(& arg.ch);
+
+       /* get command line options */
+       arg.verbose = 0;
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:vD:oh")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'v':       /* dummy option for mcopy */
+                               arg.verbose = 1;
+                               break;
+                       case 'o':
+                               handle_clash_options(&arg.ch, c);
+                               break;
+                       case 'D':
+                               if(handle_clash_options(&arg.ch, *optarg))
+                                       usage(1);
+                               break;
+                       case 'h':
+                               usage(0);
+                       case '?':
+                               usage(1);
+                       default:
+                               break;
+               }
+       }
+
+       if (argc - optind < 2)
+               usage(1);
+
+       init_mp(&arg.mp);               
+       arg.mp.arg = (void *) &arg;
+       arg.mp.openflags = O_RDWR;
+
+       /* look for a default drive */
+       def_drive = '\0';
+       for(i=optind; i<argc; i++)
+               if(argv[i][0] && argv[i][1] == ':' ){
+                       if(!def_drive)
+                               def_drive = toupper(argv[i][0]);
+                       else if(def_drive != 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 = longname;
+       longname[0]='\0';
+
+       arg.mp.shortname = 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 (file)
index 0000000..156248b
--- /dev/null
@@ -0,0 +1,187 @@
+.TH mpartition 1 "03Nov09" mtools-4.0.12
+.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
+.iX "p mpartition"
+.iX "c partitions (creating)"
+.iX "c Zip disks (partitioning them)"
+.iX "c Jaz disks (partitioning them)"
+.PP
+The \fR\&\f(CWmpartition\fR command is used to create MS-DOS filesystems as
+partitions.  This is intended to be used on non-Linux systems,
+i.e. systems where fdisk and easy access to Scsi devices are not
+available.  This command only works on drives whose partition variable
+is set.
+.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\ 
+"Desactivates" 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 neighbouring 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, mpartition 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, 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.
+.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 consistenct checks, such as checking for overlaps and
+proper alignment of the partitions.  If any of these checks fails, the
+partition table is not changes.  The \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, mpartition 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 See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mpartition.c b/mpartition.c
new file mode 100644 (file)
index 0000000..d76557f
--- /dev/null
@@ -0,0 +1,742 @@
+/*  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, int offset, int heads, int sectors)
+{
+       int head, sector, cyl;
+
+       if(! heads || !sectors)
+               head = sector = cyl = 0; /* linear mode */
+       else {
+               sector = offset % sectors;
+               offset = offset / sectors;
+
+               head = offset % heads;
+               cyl = offset / heads;
+               if(cyl > 1023) cyl = 1023;
+       }
+
+       h->head = head;
+       h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
+       h->cyl = cyl & 0xff;
+}
+
+void setBeginEnd(struct partition *partTable, int begin, int end,
+                int heads, int sectors, int activate, int type)
+{
+       set_offset(&partTable->start, begin, heads, sectors);
+       set_offset(&partTable->end, end-1, heads, sectors);
+       set_dword(partTable->start_sect, begin);
+       set_dword(partTable->nr_sects, end-begin);
+       if(activate)
+               partTable->boot_ind = 0x80;
+       else
+               partTable->boot_ind = 0;
+       if(!type) {
+               if(end-begin < 4096)
+                       type = 1; /* DOS 12-bit FAT */
+               else if(end-begin<32*2048)
+                       type = 4; /* DOS 16-bit FAT, <32M */
+               else
+                       type = 6; /* DOS 16-bit FAT >= 32M */
+       }
+       partTable->sys_ind = type;
+}
+
+int consistencyCheck(struct partition *partTable, int doprint, int verbose,
+                    int *has_activated, unsigned int *last_end,
+                    unsigned int *j, 
+                    struct device *used_dev, int target_partition)
+{
+       unsigned int i;
+       unsigned int inconsistency;
+       
+       *j = 0;
+       *last_end = 1;
+
+       /* quick consistency check */
+       inconsistency = 0;
+       *has_activated = 0;
+       for(i=1; i<5; i++){
+               if(!partTable[i].sys_ind)
+                       continue;
+               if(partTable[i].boot_ind)
+                       (*has_activated)++;
+               if((used_dev && 
+                   (used_dev->heads != head(partTable[i].end)+1 ||
+                    used_dev->sectors != sector(partTable[i].end))) ||
+                  sector(partTable[i].start) != 1){
+                       fprintf(stderr,
+                               "Partition %d is not aligned\n",
+                               i);
+                       inconsistency=1;
+               }
+               
+               if(*j && 
+                  *last_end > BEGIN(partTable[i])) {
+                       fprintf(stderr,
+                               "Partitions %d and %d badly ordered or overlapping\n",
+                               *j,i);
+                       inconsistency=1;
+               }
+                       
+               *last_end = END(partTable[i]);
+               *j = i;
+
+               if(used_dev &&
+                  cyl(partTable[i].start) != 1023 &&
+                  tolinear(partTable[i].start) != BEGIN(partTable[i])) {
+                       fprintf(stderr,
+                               "Start position mismatch for partition %d\n",
+                               i);
+                       inconsistency=1;
+               }
+               if(used_dev &&
+                  cyl(partTable[i].end) != 1023 &&
+                  tolinear(partTable[i].end)+1 != END(partTable[i])) {
+                       fprintf(stderr,
+                               "End position mismatch for partition %d\n",
+                               i);
+                       inconsistency=1;
+               }
+
+               if(doprint && verbose) {
+                       if(i==target_partition)
+                               putchar('*');
+                       else
+                               putchar(' ');
+                       printf("Partition %d\n",i);
+
+                       printf("  active=%x\n", partTable[i].boot_ind);
+                       printf("  start:");
+                       print_hsc(&partTable[i].start);
+                       printf("  type=0x%x\n", partTable[i].sys_ind);
+                       printf("  end:");
+                       print_hsc(&partTable[i].end);
+                       printf("  start=%d\n", BEGIN(partTable[i]));
+                       printf("  nr=%d\n", _DWORD(partTable[i].nr_sects));
+                       printf("\n");
+               }
+       }
+       return inconsistency;
+}
+
+/* setsize function.  Determines scsicam mapping if this cannot be inferred from
+ * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
+
+/*
+ * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
+ *     unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine a near-optimal int 0x13 mapping for a
+ *     SCSI disk in terms of lost space of size capacity, storing
+ *     the results in *cyls, *hds, and *secs.
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ * Extracted from
+ *
+ * WORKING                                                    X3T9.2
+ * DRAFT                                                        792D
+ *
+ *
+ *                                                        Revision 6
+ *                                                         10-MAR-94
+ * Information technology -
+ * SCSI-2 Common access method
+ * transport and SCSI interface module
+ * 
+ * ANNEX A :
+ *
+ * setsize() converts a read capacity value to int 13h
+ * head-cylinder-sector requirements. It minimizes the value for
+ * number of heads and maximizes the number of cylinders. This
+ * will support rather large disks before the number of heads
+ * will not fit in 4 bits (or 6 bits). This algorithm also
+ * minimizes the number of sectors that will be unused at the end
+ * of the disk while allowing for very large disks to be
+ * accommodated. This algorithm does not use physical geometry. 
+ */
+
+static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
+    unsigned int *secs) { 
+    unsigned int rv = 0; 
+    unsigned long heads, sectors, cylinders, temp; 
+
+    cylinders = 1024L;                 /* Set number of cylinders to max */ 
+    sectors = 62L;                     /* Maximize sectors per track */ 
+
+    temp = cylinders * sectors;                /* Compute divisor for heads */ 
+    heads = capacity / temp;           /* Compute value for number of heads */
+    if (capacity % temp) {             /* If no remainder, done! */ 
+       heads++;                        /* Else, increment number of heads */ 
+       temp = cylinders * heads;       /* Compute divisor for sectors */ 
+       sectors = capacity / temp;      /* Compute value for sectors per
+                                              track */ 
+       if (capacity % temp) {          /* If no remainder, done! */ 
+           sectors++;                  /* Else, increment number of sectors */ 
+           temp = heads * sectors;     /* Compute divisor for cylinders */
+           cylinders = capacity / temp;/* Compute number of cylinders */ 
+       } 
+    } 
+    if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ 
+
+    *cyls = (unsigned int) cylinders;  /* Stuff return values */ 
+    *secs = (unsigned int) sectors; 
+    *hds  = (unsigned int) heads; 
+    return(rv); 
+} 
+
+static void setsize0(unsigned long capacity,unsigned int *cyls,
+                    unsigned int *hds, unsigned int *secs)
+{
+       int r;
+
+       /* 1. First try "Megabyte" sizes */
+       if(capacity < 1024 * 2048 && !(capacity % 1024)) {
+               *cyls = capacity >> 11;
+               *hds  = 64;
+               *secs = 32;
+               return;
+       }
+
+       /* then try scsicam's size */
+       r = setsize(capacity,cyls,hds,secs);
+       if(r || *hds > 255 || *secs > 63) {
+               /* scsicam failed. Do megabytes anyways */
+               *cyls = capacity >> 11;
+               *hds  = 64;
+               *secs = 32;
+               return;
+       }
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr, 
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr, 
+               "Usage: %s [-pradcv] [-I] [-B bootsect-template] [-s sectors] "
+                       "[-t cylinders] "
+               "[-h heads] [-T type] [-b begin] [-l length] "
+               "drive\n", progname);
+       exit(ret);
+}
+
+void mpartition(int argc, char **argv, int dummy)
+{
+       Stream_t *Stream;
+       unsigned int dummy2;
+
+       unsigned int i,j;
+
+       int sec_per_cyl;
+       int doprint = 0;
+       int verbose = 0;
+       int create = 0;
+       int force = 0;
+       int length = 0;
+       int do_remove = 0;
+       int initialize = 0;
+       unsigned int tot_sectors=0;
+       int type = 0;
+       int begin_set = 0;
+       int size_set = 0;
+       int end_set = 0;
+       unsigned int last_end = 0;
+       int activate = 0;
+       int has_activated = 0;
+       int inconsistency=0;
+       int begin=0;
+       int end=0;
+       int sizetest=0;
+       int dirty = 0;
+       int open2flags = NO_OFFSET;
+       
+       int c;
+       struct device used_dev;
+       int argtracks, argheads, argsectors;
+
+       char drive, name[EXPAND_BUF];
+       unsigned char buf[512];
+       struct partition *partTable=(struct partition *)(buf+ 0x1ae);
+       struct device *dev;
+       char errmsg[200];
+       char *bootSector=0;
+
+       argtracks = 0;
+       argheads = 0;
+       argsectors = 0;
+
+       /* get command line options */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'B':
+                               bootSector = optarg;
+                               break;
+                       case 'a':
+                               /* no privs, as it could be abused to
+                                * make other partitions unbootable, or
+                                * to boot a rogue kernel from this one */
+                               open2flags |= NO_PRIV;
+                               activate = 1;
+                               dirty = 1;
+                               break;
+                       case 'd':
+                               activate = -1;
+                               dirty = 1;
+                               break;
+                       case 'p':
+                               doprint = 1;
+                               break;
+                       case 'r':
+                               do_remove = 1;
+                               dirty = 1;
+                               break;
+                       case 'I':
+                               /* could be abused to nuke all other 
+                                * partitions */
+                               open2flags |= NO_PRIV;
+                               initialize = 1;
+                               dirty = 1;
+                               break;
+                       case 'c':
+                               create = 1;
+                               dirty = 1;
+                               break;
+
+                       case 'T':
+                               /* could be abused to "manually" create
+                                * extended partitions */
+                               open2flags |= NO_PRIV;
+                               type = strtoul(optarg,0,0);
+                               break;
+
+                       case 't':
+                               argtracks = atoi(optarg);
+                               break;
+                       case 'h':
+                               argheads = atoi(optarg);
+                               break;
+                       case 's':
+                               argsectors = atoi(optarg);
+                               break;
+
+                       case 'f':
+                               /* could be abused by creating overlapping
+                                * partitions and other such Snafu */
+                               open2flags |= NO_PRIV;
+                               force = 1;
+                               break;
+
+                       case 'v':
+                               verbose++;
+                               break;
+                       case 'S':
+                               /* testing only */
+                               /* could be abused to create partitions
+                                * extending beyond the actual size of the
+                                * device */
+                               open2flags |= NO_PRIV;
+                               tot_sectors = strtoul(optarg,0,0);
+                               sizetest = 1;
+                               break;
+                       case 'b':
+                               begin_set = 1;
+                               begin = atoi(optarg);
+                               break;
+                       case 'l':
+                               size_set = 1;
+                               length = atoi(optarg);
+                               break;
+
+                       default:
+                               usage(1);
+               }
+       }
+
+       if (argc - optind != 1 ||
+           !argv[optind][0] || argv[optind][1] != ':')
+               usage(1);
+       
+       drive = toupper(argv[optind][0]);
+
+       /* check out a drive whose letter and parameters match */       
+       sprintf(errmsg, "Drive '%c:' not supported", drive);
+       Stream = 0;
+       for(dev=devices;dev->drive;dev++) {
+               int mode ;
+
+               FREE(&(Stream));
+               /* drive letter */
+               if (dev->drive != drive)
+                       continue;
+               if (dev->partition < 1 || dev->partition > 4) {
+                       sprintf(errmsg, 
+                               "Drive '%c:' is not a partition", 
+                               drive);
+                       continue;
+               }
+               used_dev = *dev;
+
+               SET_INT(used_dev.tracks, argtracks);
+               SET_INT(used_dev.heads, argheads);
+               SET_INT(used_dev.sectors, argsectors);
+               
+               expand(dev->name, name);
+
+               mode = dirty ? O_RDWR : O_RDONLY;
+               if(initialize)
+                       mode |= O_CREAT;
+
+#ifdef USING_NEW_VOLD
+               strcpy(name, getVoldName(dev, name));
+#endif
+               Stream = SimpleFileOpen(&used_dev, dev, name, mode, 
+                                       errmsg, open2flags, 1, 0);
+
+               if (!Stream) {
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg,199,"init: open: %s", strerror(errno));
+#else
+                       sprintf(errmsg,"init: open: %s", strerror(errno));
+#endif
+                       continue;
+               }                       
+
+
+               /* try to find out the size */
+               if(!sizetest)
+                       tot_sectors = 0;
+               if(IS_SCSI(dev)) {
+                       unsigned char cmd[10];
+                       unsigned char data[10];
+                       cmd[0] = SCSI_READ_CAPACITY;
+                       memset ((void *) &cmd[2], 0, 8);
+                       memset ((void *) &data[0], 137, 10);
+                       scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
+                                data, 10, get_extra_data(Stream));
+                       
+                       tot_sectors = 1 +
+                               (data[0] << 24) +
+                               (data[1] << 16) +
+                               (data[2] <<  8) +
+                               (data[3]      );
+                       if(verbose)
+                               printf("%d sectors in total\n", tot_sectors);
+               }
+
+#ifdef OS_linux
+               if (tot_sectors == 0) {
+                       ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors);
+               }
+#endif
+
+               /* read the partition table */
+               if (READS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg, 199,
+                               "Error reading from '%s', wrong parameters?",
+                               name);
+#else
+                       sprintf(errmsg,
+                               "Error reading from '%s', wrong parameters?",
+                               name);
+#endif
+                       continue;
+               }
+               if(verbose>=2)
+                       print_sector("Read sector", buf, 512);
+               break;
+       }
+
+       /* print error msg if needed */ 
+       if ( dev->drive == 0 ){
+               FREE(&Stream);
+               fprintf(stderr,"%s: %s\n", argv[0],errmsg);
+               exit(1);
+       }
+
+       if((used_dev.sectors || used_dev.heads) &&
+          (!used_dev.sectors || !used_dev.heads)) {
+               fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n");
+               fprintf(stderr," or none of them\n");
+               exit(1);
+       }
+
+       if(initialize) {
+               if (bootSector) {
+                       int fd;
+                       fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
+                       if (fd < 0) {
+                               perror("open MBR");
+                               exit(1);
+                       }
+                       if(read(fd, (char *) buf, 512) < 512) {
+                               perror("read MBR");
+                               exit(1);
+                       }
+               }
+               memset((char *)(partTable+1), 0, 4*sizeof(*partTable));
+               set_word(((unsigned char*)buf)+510, 0xaa55);
+       }
+
+       /* check for boot signature, and place it if needed */
+       if((buf[510] != 0x55) || (buf[511] != 0xaa)) {
+               fprintf(stderr,"Boot signature not set\n");
+               fprintf(stderr,
+                       "Use the -I flag to initialize the partition table, and set the boot signature\n");
+               inconsistency = 1;
+       }
+       
+       if(do_remove){
+               if(!partTable[dev->partition].sys_ind)
+                       fprintf(stderr,
+                               "Partition for drive %c: does not exist\n",
+                               drive);
+               if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
+                       fprintf(stderr,
+                               "Partition for drive %c: may be an extended partition\n",
+                               drive);
+                       fprintf(stderr,
+                               "Use the -f flag to remove it anyways\n");
+                       inconsistency = 1;
+               }
+               memset(&partTable[dev->partition], 0, sizeof(*partTable));
+       }
+
+       if(create && partTable[dev->partition].sys_ind) {
+               fprintf(stderr,
+                       "Partition for drive %c: already exists\n", drive);
+               fprintf(stderr,
+                       "Use the -r flag to remove it before attempting to recreate it\n");
+       }
+
+
+       /* find out number of heads and sectors, and whether there is
+       * any activated partition */
+       has_activated = 0;
+       for(i=1; i<5; i++){
+               if(!partTable[i].sys_ind)
+                       continue;
+               
+               if(partTable[i].boot_ind)
+                       has_activated++;
+
+               /* set geometry from entry */
+               if (!used_dev.heads)
+                       used_dev.heads = head(partTable[i].end)+1;
+               if(!used_dev.sectors)
+                       used_dev.sectors = sector(partTable[i].end);
+               if(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);
+       }
+
+       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 (file)
index 0000000..7d7c6bf
--- /dev/null
+++ b/mrd.1
@@ -0,0 +1,100 @@
+.TH mrd 1 "03Nov09" mtools-4.0.12
+.SH Name
+mrd - remove an MSDOS subdirectory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mrd"
+.iX "c Removing a directory"
+.iX "c Erasing a directory"
+.iX "c Deleting a directory"
+.iX "c Directory removing"
+.iX "c Subdirectory removing"
+.PP
+The \fR\&\f(CWmrd\fR command is used to remove an MS-DOS subdirectory. Its
+syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmrd\fR [\fR\&\f(CW-v\fR] \fImsdosdirectory\fR [ \fImsdosdirectories\fR\&... ]
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMrd\fR removes a directory from an MS-DOS filesystem. An error occurs
+if the directory does not exist or is not empty.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mren.1 b/mren.1
new file mode 100644 (file)
index 0000000..ff42566
--- /dev/null
+++ b/mren.1
@@ -0,0 +1,107 @@
+.TH mren 1 "03Nov09" mtools-4.0.12
+.SH Name
+mren - rename an existing MSDOS file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mren"
+.iX "c Renaming files (mren)"
+.iX "c Moving files (mren)"
+.PP
+The \fR\&\f(CWmren\fR command is used to rename or move an existing MS-DOS
+file or subdirectory. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmren\fR [\fR\&\f(CW-voOsSrRA\fR] \fIsourcefile\fR \fItargetfile\fR
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMren\fR
+renames an existing file on an MS-DOS filesystem.
+.PP
+In verbose mode, \fR\&\f(CWMren\fR displays the new filename if the name
+supplied is invalid.
+.PP
+If the first syntax is used (only one sourcefile), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+\&\fR\&\f(CWmcd\fR directory as would be the case with \fR\&\f(CWmmove\fR. Unlike the
+MS-DOS version of \fR\&\f(CWREN\fR, \fR\&\f(CWmren\fR can be used to rename
+directories.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/msdos.h b/msdos.h
new file mode 100644 (file)
index 0000000..b0dd5ff
--- /dev/null
+++ b/msdos.h
@@ -0,0 +1,278 @@
+#ifndef MTOOLS_MSDOS_H
+#define MTOOLS_MSDOS_H
+
+/*  Copyright 1986-1992 Emmet P. Gray.
+ *  Copyright 1996-1998,2000-2003,2006,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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) ((unsigned short)((unsigned char)(x)[0] + (((unsigned char)(x)[1]) << 8)))
+#define _DWORD(x) ((unsigned int)(_WORD(x) + (_WORD((x)+2) << 16)))
+
+#define DELMARK ((char) 0xe5)
+
+struct directory {
+       char name[8];                   /*  0 file name */
+       char ext[3];                    /*  8 file extension */
+       unsigned char attr;             /* 11 attribute byte */
+       unsigned char Case;             /* 12 case of short filename */
+       unsigned char ctime_ms;         /* 13 creation time, milliseconds (?) */
+       unsigned char ctime[2];         /* 14 creation time */
+       unsigned char cdate[2];         /* 16 creation date */
+       unsigned char adate[2];         /* 18 last access date */
+       unsigned char startHi[2];       /* 20 start cluster, Hi */
+       unsigned char time[2];          /* 22 time stamp */
+       unsigned char date[2];          /* 24 date stamp */
+       unsigned char start[2];         /* 26 starting cluster number */
+       unsigned char size[4];          /* 28 size of the file */
+};
+
+#define EXTCASE 0x10
+#define BASECASE 0x8
+
+#define MAX16 0xffff
+#define MAX32 0xffffffff
+#define MAX_SIZE 0x7fffffff
+
+#define FILE_SIZE(dir)  (_DWORD((dir)->size))
+#define START(dir) (_WORD((dir)->start))
+#define STARTHI(dir) (_WORD((dir)->startHi))
+
+/* ASSUMPTION: long is at least 32 bits */
+UNUSED(static __inline__ void set_dword(unsigned char *data, unsigned long value))
+{
+       data[3] = (value >> 24) & 0xff;
+       data[2] = (value >> 16) & 0xff;
+       data[1] = (value >>  8) & 0xff;
+       data[0] = (value >>  0) & 0xff;
+}
+
+
+/* ASSUMPTION: short is at least 16 bits */
+UNUSED(static __inline__ void set_word(unsigned char *data, unsigned short value))
+{
+       data[1] = (value >>  8) & 0xff;
+       data[0] = (value >>  0) & 0xff;
+}
+
+
+/*
+ *         hi byte     |    low byte
+ *     |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
+ *  | | | | | | | | | | | | | | | | |
+ *  \   7 bits    /\4 bits/\ 5 bits /
+ *     year +80     month     day
+ */
+#define        DOS_YEAR(dir) (((dir)->date[1] >> 1) + 1980)
+#define        DOS_MONTH(dir) (((((dir)->date[1]&0x1) << 3) + ((dir)->date[0] >> 5)))
+#define        DOS_DAY(dir) ((dir)->date[0] & 0x1f)
+
+/*
+ *         hi byte     |    low byte
+ *     |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
+ *      | | | | | | | | | | | | | | | | |
+ *      \  5 bits /\  6 bits  /\ 5 bits /
+ *         hour      minutes     sec*2
+ */
+#define        DOS_HOUR(dir) ((dir)->time[1] >> 3)
+#define        DOS_MINUTE(dir) (((((dir)->time[1]&0x7) << 3) + ((dir)->time[0] >> 5)))
+#define        DOS_SEC(dir) (((dir)->time[0] & 0x1f) * 2)
+
+
+typedef struct InfoSector_t {
+       unsigned char signature1[4];
+       unsigned char filler1[0x1e0];
+       unsigned char signature2[4];
+       unsigned char count[4];
+       unsigned char pos[4];
+       unsigned char filler2[14];
+       unsigned char signature3[2];
+} InfoSector_t;
+
+#define INFOSECT_SIGNATURE1 0x41615252
+#define INFOSECT_SIGNATURE2 0x61417272
+
+
+typedef struct label_blk_t {
+       unsigned char physdrive;        /* 36 physical drive ? */
+       unsigned char reserved;         /* 37 reserved */
+       unsigned char dos4;             /* 38 dos > 4.0 diskette */
+       unsigned char serial[4];        /* 39 serial number */
+       char label[11];                 /* 43 disk label */
+       char fat_type[8];               /* 54 FAT type */
+} label_blk_t;
+
+/* FAT32 specific info in the bootsector */
+struct fat32_t {
+       unsigned char bigFat[4];        /* 36 nb of sectors per FAT */
+       unsigned char extFlags[2];      /* 40 extension flags */
+       unsigned char fsVersion[2];     /* 42 ? */
+       unsigned char rootCluster[4];   /* 44 start cluster of root dir */
+       unsigned char infoSector[2];    /* 48 changeable global info */
+       unsigned char backupBoot[2];    /* 50 back up boot sector */
+       unsigned char reserved[6];      /* 52 ? */
+       unsigned char reserved2[6];     /* 52 ? */
+       struct label_blk_t labelBlock;
+}; /* ends at 58 */
+
+typedef struct oldboot_t {
+       struct label_blk_t labelBlock;
+       unsigned char res_2m;           /* 62 reserved by 2M */
+       unsigned char CheckSum;         /* 63 2M checksum (not used) */
+       unsigned char fmt_2mf;          /* 64 2MF format version */
+       unsigned char wt;               /* 65 1 if write track after format */
+       unsigned char rate_0;           /* 66 data transfer rate on track 0 */
+       unsigned char rate_any;         /* 67 data transfer rate on track<>0 */
+       unsigned char BootP[2];         /* 68 offset to boot program */
+       unsigned char Infp0[2];         /* 70 T1: information for track 0 */
+       unsigned char InfpX[2];         /* 72 T2: information for track<>0 */
+       unsigned char InfTm[2];         /* 74 T3: track sectors size table */
+       unsigned char DateF[2];         /* 76 Format date */
+       unsigned char TimeF[2];         /* 78 Format time */
+       unsigned char junk[1024 - 80];  /* 80 remaining data */
+} oldboot_t;
+
+struct bootsector_s {
+       unsigned char jump[3];          /* 0  Jump to boot code */
+       char banner[8];                 /* 3  OEM name & version */
+       unsigned char secsiz[2];        /* 11 Bytes per sector hopefully 512 */
+       unsigned char clsiz;            /* 13 Cluster size in sectors */
+       unsigned char nrsvsect[2];      /* 14 Number of reserved (boot) sectors */
+       unsigned char nfat;             /* 16 Number of FAT tables hopefully 2 */
+       unsigned char dirents[2];       /* 17 Number of directory slots */
+       unsigned char psect[2];         /* 19 Total sectors on disk */
+       unsigned char descr;            /* 21 Media descriptor=first byte of FAT */
+       unsigned char fatlen[2];        /* 22 Sectors in FAT */
+       unsigned char nsect[2];         /* 24 Sectors/track */
+       unsigned char nheads[2];        /* 26 Heads */
+       unsigned char nhs[4];           /* 28 number of hidden sectors */
+       unsigned char bigsect[4];       /* 32 big total sectors */
+
+       union {
+               struct fat32_t fat32;
+               struct oldboot_t old;
+       } ext;
+};
+
+#define MAX_BOOT 4096
+
+union bootsector {
+       unsigned char bytes[MAX_BOOT];
+       char characters[MAX_BOOT];
+       struct bootsector_s boot;
+};
+
+#define CHAR(x) (boot->x[0])
+#define WORD(x) (_WORD(boot->boot.x))
+#define DWORD(x) (_DWORD(boot->boot.x))
+
+#define WORD_S(x) (_WORD(boot.boot.x))
+#define DWORD_S(x) (_DWORD(boot.boot.x))
+
+#define OFFSET(x) (((char *) (boot->x)) - ((char *)(boot->jump)))
+
+
+extern struct OldDos_t {
+       unsigned int tracks;
+       unsigned int sectors;
+       unsigned int heads;
+       
+       unsigned int dir_len;
+       unsigned int cluster_size;
+       unsigned int fat_len;
+
+       int media;
+} old_dos[];
+
+/* max FAT12/FAT16 sizes, according to
+   
+ http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf
+
+ interestingly enough, another Microsoft document 
+ [http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b67321]
+ gives different values, but the first seems to be more sure about
+ itself, so we believe that one ;-)
+*/
+#define FAT12 4085 /* max. number of clusters described by a 12 bit FAT */
+#define FAT16 65525 /* max number of clusters for a 16 bit FAT */
+
+#define ATTR_ARCHIVE 0x20
+#define ATTR_DIR 0x10
+#define ATTR_LABEL 0x8
+#define ATTR_SYSTEM 0x4
+#define ATTR_HIDDEN 0x2
+#define ATTR_READONLY 0x1
+
+#define HAS_BIT(entry,x) ((entry)->dir.attr & (x))
+
+#define IS_ARCHIVE(entry) (HAS_BIT((entry),ATTR_ARCHIVE))
+#define IS_DIR(entry) (HAS_BIT((entry),ATTR_DIR))
+#define IS_LABEL(entry) (HAS_BIT((entry),ATTR_LABEL))
+#define IS_SYSTEM(entry) (HAS_BIT((entry),ATTR_SYSTEM))
+#define IS_HIDDEN(entry) (HAS_BIT((entry),ATTR_HIDDEN))
+#define IS_READONLY(entry) (HAS_BIT((entry),ATTR_READONLY))
+
+
+#define MAX_BYTES_PER_CLUSTER (32*1024)
+/* Experimentally, it turns out that DOS only accepts cluster sizes
+ * which are powers of two, and less than 128 sectors (else it gets a
+ * divide overflow) */
+
+
+#define FAT_SIZE(bits, sec_siz, clusters) \
+       ((((clusters)+2) * ((bits)/4) - 1) / 2 / (sec_siz) + 1)
+
+#define NEEDED_FAT_SIZE(x) FAT_SIZE((x)->fat_bits, (x)->sector_size, \
+                                   (x)->num_clus)
+
+/* disk size taken by FAT and clusters */
+#define DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \
+       ((n) * FAT_SIZE(bits, sec_siz, clusters) + \
+        (clusters) * (cluster_size))
+
+#define TOTAL_DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) \
+       (DISK_SIZE(bits, sec_siz, clusters, n, cluster_size) + 2)
+/* approx. total disk size: assume 1 boot sector and one directory sector */
+
+extern const char *mversion;
+extern const char *mdate;
+extern const char *mformat_banner;
+
+extern char *Version;
+extern char *Date;
+
+
+int init(char drive, int mode);
+
+#define MT_READ 1
+#define MT_WRITE 2
+
+#endif
+
diff --git a/mshowfat.1 b/mshowfat.1
new file mode 100644 (file)
index 0000000..0f35bfe
--- /dev/null
@@ -0,0 +1,94 @@
+.TH mshowfat 1 "03Nov09" mtools-4.0.12
+.SH Name
+mshowfat - shows FAT clusters allocated to file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mshowfat"
+.iX "c Clusters of a file"
+.iX "c Fat"
+.PP
+The \fR\&\f(CWmshowfat\fR command is used to display the FAT entries for a
+file.  Syntax:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CW$ mshowfat files\fR
+.fi
+.ft R
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mshowfat.c b/mshowfat.c
new file mode 100644 (file)
index 0000000..4828474
--- /dev/null
@@ -0,0 +1,110 @@
+/*  Copyright 1997,2000-2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mcopy.c
+ * Copy an MSDOS files to and from Unix
+ *
+ */
+
+
+#define LOWERCASE
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "mainloop.h"
+#include "plain_io.h"
+#include "nameclash.h"
+#include "file.h"
+#include "fs.h"
+
+
+
+typedef struct Arg_t {
+       char *target;
+       MainParam_t mp;
+       ClashHandling_t ch;
+       Stream_t *sourcefile;
+} Arg_t;
+
+static int dos_showfat(direntry_t *entry, MainParam_t *mp)
+{
+       Stream_t *File=mp->File;
+
+       fprintPwd(stdout, entry,0);
+       putchar(' ');
+       printFat(File);
+       printf("\n");
+       return GOT_ONE;
+}
+
+static int unix_showfat(MainParam_t *mp)
+{
+       fprintf(stderr,"File does not reside on a Dos fs\n");
+       return ERROR_ONE;
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+       fprintf(stderr,
+               "Mtools version %s, dated %s\n", mversion, mdate);
+       fprintf(stderr,
+               "Usage: %s files\n", progname);
+       exit(ret);
+}
+
+void mshowfat(int argc, char **argv, int mtype)
+{
+       Arg_t arg;
+       int c, ret;
+       
+       /* get command line options */
+
+       init_clash_handling(& arg.ch);
+
+       /* get command line options */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:h")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, 0);
+                               break;
+                       case 'h':
+                               usage(0);
+                       case '?':
+                               usage(1);
+                               break;
+               }
+       }
+
+       if (argc - optind < 1)
+               usage(1);
+
+       /* only 1 file to copy... */
+       init_mp(&arg.mp);
+       arg.mp.arg = (void *) &arg;
+
+       arg.mp.callback = dos_showfat;
+       arg.mp.unixcallback = unix_showfat;
+
+       arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
+       ret=main_loop(&arg.mp, argv + optind, argc - optind);
+       exit(ret);
+}
diff --git a/mtools.1 b/mtools.1
new file mode 100644 (file)
index 0000000..e099497
--- /dev/null
+++ b/mtools.1
@@ -0,0 +1,555 @@
+'\" t
+.TH mtools.1 3 "03Nov09" mtools-4.0.12
+.SH Name
+mtools - utilities to access DOS disks in Unix.
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.PP
+.SH Introduction
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS
+filesystem (typically a floppy disk).  Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However,
+unnecessary restrictions and oddities of DOS are not emulated. For
+instance, it is possible to move subdirectories from one subdirectory
+to another.
+.PP
+Mtools is sufficient to give access to MS-DOS filesystems.  For
+instance, commands such as \fR\&\f(CWmdir a:\fR work on the \fR\&\f(CWa:\fR floppy
+without any preliminary mounting or initialization (assuming the default
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR works on your machine).  With mtools, one can
+change floppies too without unmounting and mounting.
+.PP
+.SH Where\ to\ get\ mtools
+.iX "c bugs"
+.iX "c ALPHA patches"
+.iX "c patches"
+.iX "c diffs"
+.iX "c mailing list"
+.PP
+Mtools can be found at the following places (and their mirrors):
+.nf
+.ft 3
+.in +0.3i
+http://ftp.gnu.org/gnu/mtools/mtools-4.0.12.tar.gz
+http://mtools.linux.lu/mtools-4.0.12.tar.gz
+ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.12.tar.gz
+ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.12.tar.gz
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+Before reporting a bug, make sure that it has not yet been fixed in the
+Alpha patches which can be found at:
+.nf
+.ft 3
+.in +0.3i
+http://ftp.gnu.org/gnu/mtools/
+http://mtools.linux.lu/
+ftp://www.tux.org/pub/knaff/mtools
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+These patches are named
+\&\fR\&\f(CWmtools-\fR\fIversion\fR\fR\&\f(CW-\fR\fIddmm\fR\fR\&\f(CW.taz\fR, where version
+stands for the base version, \fIdd\fR for the day and \fImm\fR for the
+month. Due to a lack of space, I usually leave only the most recent
+patch.
+.PP
+There is an mtools mailing list at mtools @ tux.org .  Please
+send all bug reports to this list.  You may subscribe to the list by
+sending a message with 'subscribe mtools @ tux.org' in its
+body to majordomo @ tux.org . (N.B. Please remove the spaces
+around the "@" both times. I left them there in order to fool
+spambots.)  Announcements of new mtools versions will also be sent to
+the list, in addition to the linux announce newsgroups.  The mailing
+list is archived at http://lists.gnu.org/pipermail/info-mtools/
+.PP
+.SH Common\ features\ of\ all\ mtools\ commands
+.PP
+.SS Options\ and\ filenames
+.iX "c Filenames"
+.iX "c Options"
+MS-DOS filenames are composed of a drive letter followed by a colon, a
+subdirectory, and a filename. Only the filename part is mandatory, the
+drive letter and the subdirectory are optional. Filenames without a
+drive letter refer to Unix files. Subdirectory names can use either the
+\&'\fR\&\f(CW/\fR' or '\fR\&\f(CW\e\fR' separator.  The use of the '\fR\&\f(CW\e\fR' separator
+or wildcards requires the names to be enclosed in quotes to protect them
+from the shell. However, wildcards in Unix filenames should not be
+enclosed in quotes, because here we \fBwant\fR the shell to expand
+them.
+.PP
+The regular expression "pattern matching" routines follow the Unix-style
+rules.  For example, `\fR\&\f(CW*\fR' matches all MS-DOS files in lieu of
+`\fR\&\f(CW*.*\fR'.  The archive, hidden, read-only and system attribute bits
+are ignored during pattern matching.
+.PP
+All options use the \fR\&\f(CW-\fR (minus) as their first character, not
+\&\fR\&\f(CW/\fR as you'd expect in MS-DOS.
+.PP
+Most mtools commands allow multiple filename parameters, which
+doesn't follow MS-DOS conventions, but which is more user-friendly.
+.PP
+Most mtools commands allow options that instruct them how to handle file
+name clashes. See section name clashes, for more details on these. All
+commands accept the \fR\&\f(CW-V\fR flags which prints the version, and most
+accept the \fR\&\f(CW-v\fR flag, which switches on verbose mode. In verbose
+mode, these commands print out the name of the MS-DOS files upon which
+they act, unless stated otherwise. See section Commands, for a description of
+the options which are specific to each command.
+.PP
+.SS Drive\ letters
+.PP
+The meaning of the drive letters depends on the target architectures.
+However, on most target architectures, drive A is the first floppy
+drive, drive B is the second floppy drive (if available), drive J is a
+Jaz drive (if available), and drive Z is a Zip drive (if available).  On
+those systems where the device name is derived from the SCSI id, the Jaz
+drive is assumed to be at Scsi target 4, and the Zip at Scsi target 5
+(factory default settings).  On Linux, both drives are assumed to be the
+second drive on the Scsi bus (/dev/sdb). The default settings can be
+changes using a configuration file (see section  Configuration).
+.PP
+The drive letter : (colon) has a special meaning. It is used to access
+image files which are directly specified on the command line using the
+\&\fR\&\f(CW-i\fR options.
+.PP
+Example:
+.nf
+.ft 3
+.in +0.3i
+ mcopy -i my-image-file.bin ::file1 ::file2 .
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+This copies \fR\&\f(CWfile1\fR and \fR\&\f(CWfile2\fR from the image file
+(\fR\&\f(CWmy-image-file.bin\fR) to the \fR\&\f(CW/tmp\fR directory.
+.PP
+You can also supply an offset within the image file by including
+\&\fR\&\f(CW@@\fR\fIoffset\fR into the file name.
+.PP
+Example:
+.nf
+.ft 3
+.in +0.3i
+ mcopy -i my-image-file.bin@@1M ::file1 ::file2 .
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+This looks for the image at the offset of 1M in the file, rather than
+at its beginning.
+.PP
+.SS Current\ working\ directory
+.iX "p mcd (introduction)"
+.iX "c Directory"
+.iX "c Working directory"
+.iX "c Current working directory"
+.iX "c Default directory"
+.PP
+The \fR\&\f(CWmcd\fR command (\(ifmcd\(is) is used to establish the device and
+the current working directory (relative to the MS-DOS filesystem),
+otherwise the default is assumed to be \fR\&\f(CWA:/\fR. However, unlike
+MS-DOS, there is only one working directory for all drives, and not one
+per drive.
+.PP
+.SS VFAT-style\ long\ file\ names
+.iX "c Long file name"
+.iX "c Windows 95-style file names"
+.iX "c VFAT-style file names"
+.iX "c Primary file name (long names)"
+.iX "c Secondary file name (long names)"
+.PP
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a
+VFAT long name, and a companion short name is generated. This short
+name is what you see when you examine the disk with a pre-7.0 version
+of DOS.
+ The following table shows some examples of short names:
+.PP
+.nf
+.ft 3
+.in +0.3i
+Long name       MS-DOS name     Reason for the change
+---------       ----------      ---------------------
+thisisatest     THISIS~1        filename too long
+alain.knaff     ALAIN~1.KNA     extension too long
+prn.txt         PRN~1.TXT       PRN is a device name
+\&\&.abc            ABC~1           null filename
+hot+cold        HOT_CO~1        illegal character
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+ As you see, the following transformations happen to derive a short
+name:
+.TP
+* \ \ 
+Illegal characters are replaced by underscores. The illegal characters
+are \fR\&\f(CW;+=[]',\e"*\e\e<>/?:|\fR.
+.TP
+* \ \ 
+Extra dots, which cannot be interpreted as a main name/extension
+separator are removed
+.TP
+* \ \ 
+A \fR\&\f(CW~\fR\fIn\fR number is generated,
+.TP
+* \ \ 
+The name is shortened so as to fit in the 8+3 limitation
+.PP
+ The initial Unix-style file name (whether long or short) is also called
+the \fIprimary\fR name, and the derived short name is also called the
+\&\fIsecondary\fR name.
+.PP
+ Example:
+.nf
+.ft 3
+.in +0.3i
+ mcopy /etc/motd a:Reallylongname
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+.nf
+.ft 3
+.in +0.3i
+ mcopy /etc/motd a:motd
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+.PP
+ In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+.PP
+ Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (\fR\&\f(CW\e"*\e\e<>/?:|\fR), and device names are still
+reserved.
+.PP
+.nf
+.ft 3
+.in +0.3i
+Unix name       Long name       Reason for the change
+---------       ----------      ---------------------
+prn             prn-1           PRN is a device name
+ab:c            ab_c-1          illegal character
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+ As you see, the following transformations happen if a long name is
+illegal:
+.TP
+* \ \ 
+Illegal characters are replaces by underscores,
+.TP
+* \ \ 
+A \fR\&\f(CW-\fR\fIn\fR number is generated,
+.PP
+.SS Name\ clashes
+.iX "c Name clashes"
+.iX "c Duplicate file names"
+.iX "c Overwriting files"
+.iX "c Primary file name (name clashes)"
+.iX "c Secondary file name (name clashes)"
+.PP
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as \fR\&\f(CWmcopy\fR,
+\&\fR\&\f(CWmmd\fR, \fR\&\f(CWmren\fR, \fR\&\f(CWmmove\fR. When a name clash happens, mtools
+asks you what it should do. It offers several choices:
+.TP
+\&\fR\&\f(CWoverwrite\fR\ 
+Overwrites the existing file. It is not possible to overwrite a
+directory with a file.
+.TP
+\&\fR\&\f(CWrename\fR\ 
+Renames the newly created file. Mtools prompts for the new filename
+.TP
+\&\fR\&\f(CWautorename\fR\ 
+Renames the newly created file. Mtools chooses a name by itself, without
+prompting
+.TP
+\&\fR\&\f(CWskip\fR\ 
+Gives up on this file, and moves on to the next (if any)
+.PP
+To chose one of these actions, type its first letter at the prompt. If
+you use a lower case letter, the action only applies for this file only,
+if you use an upper case letter, the action applies to all files, and
+you won't be prompted again.
+.PP
+You may also chose actions (for all files) on the command line, when
+invoking mtools:
+.TP
+\&\fR\&\f(CW-D\ o\fR\ 
+Overwrites primary names by default.
+.TP
+\&\fR\&\f(CW-D\ O\fR\ 
+Overwrites secondary names by default.
+.TP
+\&\fR\&\f(CW-D\ r\fR\ 
+Renames primary name by default.
+.TP
+\&\fR\&\f(CW-D\ R\fR\ 
+Renames secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ a\fR\ 
+Autorenames primary name by default.
+.TP
+\&\fR\&\f(CW-D\ A\fR\ 
+Autorenames secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ s\fR\ 
+Skip primary name by default.
+.TP
+\&\fR\&\f(CW-D\ S\fR\ 
+Skip secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ m\fR\ 
+Ask user what to do with primary name.
+.TP
+\&\fR\&\f(CW-D\ M\fR\ 
+Ask user what to do with secondary name.
+.PP
+Note that for command line switches lower/upper differentiates between
+primary/secondary name whereas for interactive choices, lower/upper
+differentiates between just-this-time/always.
+.PP
+The primary name is the name as displayed in Windows 95 or Windows NT:
+i.e. the long name if it exists, and the short name otherwise.  The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+.PP
+By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+.PP
+If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+.PP
+.SS Case\ sensitivity\ of\ the\ VFAT\ filesystem
+.iX "c Case sensitivity"
+.PP
+The VFAT filesystem is able to remember the case of the
+filenames. However, filenames which differ only in case are not allowed
+to coexist in the same directory. For example if you store a file called
+LongFileName on a VFAT filesystem, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+.PP
+The VFAT filesystem allows to store the case of a filename in the
+attribute byte, if all letters of the filename are the same case, and if
+all letters of the extension are the same case too. Mtools uses this
+information when displaying the files, and also to generate the Unix
+filename when mcopying to a Unix directory. This may have unexpected
+results when applied to files written using an pre-7.0 version of DOS:
+Indeed, the old style filenames map to all upper case. This is different
+from the behavior of the old version of mtools which used to generate
+lower case Unix filenames.
+.PP
+.SS high\ capacity\ formats
+.iX "c Special formats"
+.iX "c High capacity formats"
+.iX "c Odd formats"
+.iX "c Weird formats"
+.iX "c Formats, high capacity"
+.iX "c Linux enhancements (High Capacity Formats)"
+.PP
+Mtools supports a number of formats which allow to store more data on
+disk as usual. Due to different operating system abilities, these
+formats are not supported on all OS'es. Mtools recognizes these formats
+transparently where supported.
+.PP
+In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+\&\fR\&\f(CWfdutils\fR package at the following locations~:
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWftp://www.tux.org/pub/knaff/fdutils/.
+\&\fR\&\f(CWftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-*
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+See the manpages included in that package for further detail: Use
+\&\fR\&\f(CWsuperformat\fR to format all formats except XDF, and use
+\&\fR\&\f(CWxdfcopy\fR to format XDF.
+.PP
+.SS \ \ More\ sectors
+.iX "c fdformat"
+.iX "c vgacopy"
+.iX "c DMF disks"
+.iX "c Windows 95 (DMF disks)"
+.PP
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+.PP
+These formats are supported by numerous DOS shareware utilities such as
+\&\fR\&\f(CWfdformat\fR and \fR\&\f(CWvgacopy\fR. In his infinite hybris, Bill Gate$
+believed that he invented this, and called it \fR\&\f(CW\(ifDMF disks\(is\fR, or
+\&\fR\&\f(CW\(ifWindows formatted disks\(is\fR. But in reality, it has already existed
+years before! Mtools supports these formats on Linux, on SunOs and on
+the DELL Unix PC.
+.PP
+.SS \ \ Bigger\ sectors
+.iX "c bigger sectors"
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+\&\fIfewer\fR, but bigger sectors. For example, 1 sector of 4K only takes
+up header space once, whereas 8 sectors of 512 bytes have also 8
+headers, for the same amount of useful data.
+.PP
+This method allows to store up to 1992K on a 3 1/2 HD disk.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ 2m
+.iX "c 2m"
+.PP
+The 2m format was originally invented by Ciriaco Garcia de Celis. It
+also uses bigger sectors than usual in order to fit more data on the
+disk.  However, it uses the standard format (18 sectors of 512 bytes
+each) on the first cylinder, in order to make these disks easyer to
+handle by DOS. Indeed this method allows to have a standard sized
+bootsector, which contains a description of how the rest of the disk
+should be read.
+.PP
+However, the drawback of this is that the first cylinder can hold less
+data than the others. Unfortunately, DOS can only handle disks where
+each track contains the same amount of data. Thus 2m hides the fact that
+the first track contains less data by using a \fIshadow
+FAT\fR. (Usually, DOS stores the FAT in two identical copies, for
+additional safety.  XDF stores only one copy, and it tells DOS that it
+stores two. Thus the same that would be taken up by the second FAT copy
+is saved.) This also means that your should \fBnever use a 2m disk
+to store anything else than a DOS fs\fR.
+.PP
+Mtools supports these format only on Linux.
+.PP
+.SS \ \ XDF
+.iX "c XDF disks"
+.iX "c OS/2 (XDF disks)"
+.PP
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the \fR\&\f(CWuse_xdf\fR variable for the drive in the
+configuration file. See section Compiling mtools, and \(ifmisc variables\(is,
+for details on how to do this. Fast XDF access is only available for
+Linux kernels which are more recent than 1.1.34.
+.PP
+Mtools supports this format only on Linux.
+.PP
+\&\fBCaution / Attention distributors\fR: If mtools is compiled on a
+Linux kernel more recent than 1.3.34, it won't run on an older
+kernel. However, if it has been compiled on an older kernel, it still
+runs on a newer kernel, except that XDF access is slower. It is
+recommended that distribution authors only include mtools binaries
+compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will
+be out, mtools binaries compiled on newer kernels may (and should) be
+distributed. Mtools binaries compiled on kernels older than 1.3.34 won't
+run on any 2.1 kernel or later.
+.PP
+.SS Exit\ codes
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure.  All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or minix disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(see section  global variables)
+.SS Bugs
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver.  These can be safely ignored.  
+.PP
+The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7
+mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the
+corresponding configuration file variable, \(ifglobal variables\(is) to
+bypass the fat checking.
+.PP
+.SH See also
+floppyd_installtest
+mattrib
+mbadblocks
+mcd
+mcopy
+mdel
+mdeltree
+mdir
+mdu
+mformat
+minfo
+mkmanifest
+mlabel
+mmd
+mmount
+mmove
+mrd
+mren
+mtoolstest
+mtype
diff --git a/mtools.5 b/mtools.5
new file mode 100644 (file)
index 0000000..7f12b64
--- /dev/null
+++ b/mtools.5
@@ -0,0 +1,633 @@
+'\" t
+.TH mtools.1 3 "03Nov09" MTOOLS MTOOLS
+.SH Name
+mtools.conf - mtools configuration files
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.ds St Mtools\ 4.0.12
+.oh '\\*(St''%'
+.eh '%''\\*(St'
+.PP
+.SH Description
+.PP
+This manpage describes the configuration files for mtools. They 
+are called \fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR. If
+the environmental variable \fR\&\f(CWMTOOLSRC\fR is set, its contents is used
+as the filename for a third configuration file. These configuration
+files describe the following items:
+.TP
+* \ Global\ configuration\ flags\ and\ variables\ 
+.TP
+* \ Per\ drive\ flags\ and\ variables\ 
+.PP
+.SS Location\ of\ the\ configuration\ files
+.PP
+.iX "c Configuration file name"
+.iX "c Name of configuration files"
+.iX "c Location of configuration files"
+.PP
+\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR is the system-wide configuration file,
+and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR is the user's private configuration file.
+.PP
+On some systems, the system-wide configuration file is called
+\&\fR\&\f(CW\(if/etc/default/mtools.conf\(is\fR instead.
+.PP
+.SS \ \ General\ configuration\ file\ syntax
+.iX "c Syntax of the configuration file"
+.iX "c Configuration file syntax"
+.PP
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon.
+Then follow variable assignments and flags. Variable assignments take
+the following form:
+.ft I
+.nf
+name=value
+.fi
+.ft R
+Flags are lone keywords without an equal sign and value following
+them.  A section either ends at the end of the file or where the next
+section begins.
+.PP
+Lines starting with a hash (\fR\&\f(CW#\fR) are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+.PP
+.SS Default\ values
+.iX "c Default values"
+.iX "c Default configuration"
+.iX "c Configuration file"
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives.  Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+dosemu image files.
+.PP
+.SS Global\ variables
+.iX "c Global configuration variables"
+.iX "c Drive independent configuration variables"
+.iX "c Environmental variables"
+.iX "v MTOOLS_SKIP_CHECK"
+.iX "v MTOOLS_FAT_COMPATIBILITY"
+.iX "v MTOOLS_LOWER_CASE"
+.iX "v MTOOLS_NO_VFAT"
+.iX "c FreeDos"
+.PP
+Global flags may be set to 1 or to 0.
+.PP
+The following global flags are recognized:
+.TP
+\&\fR\&\f(CWMTOOLS_SKIP_CHECK\fR\ 
+If this is set to 1, mtools skips most of its sanity checks. This is
+needed to read some Atari disks which have been made with the earlier
+ROMs, and which would not be recognized otherwise.
+.TP
+\&\fR\&\f(CWMTOOLS_FAT_COMPATIBILITY\fR\ 
+If this is set to 1, mtools skips the fat size checks. Some disks have
+a bigger FAT than they really need to. These are rejected if this
+option is not set.
+.TP
+\&\fR\&\f(CWMTOOLS_LOWER_CASE\fR\ 
+If this is set to 1, mtools displays all-upper-case short filenames as
+lowercase. This has been done to allow a behavior which is consistent
+with older versions of mtools which didn't know about the case bits.
+.TP
+\&\fR\&\f(CWMTOOLS_NO_VFAT\fR\ 
+If this is set to 1, mtools won't generate VFAT entries for filenames
+which are mixed-case, but otherwise legal dos filenames.  This is useful
+when working with DOS versions which can't grok VFAT longnames, such as
+FreeDos.
+.TP
+\&\fR\&\f(CWMTOOLS_DOTTED_DIR\fR\ 
+In a wide directory, prints the short name with a dot instead of spaces
+separating the basename and the extension.
+.TP
+\&\fR\&\f(CWMTOOLS_NAME_NUMERIC_TAIL\fR\ 
+If this is set to one (default), generate numeric tails for all long
+names (~1).  If set to zero, only generate numeric tails if otherwise a
+clash would have happened.
+.TP
+\&\fR\&\f(CWMTOOLS_TWENTY_FOUR_HOUR_CLOCK\fR\ 
+If 1, uses the European notation for times (twenty four hour clock),
+else uses the UK/US notation (am/pm)
+.PP
+Example:
+Inserting the following line into your configuration file instructs
+mtools to skip the sanity checks:
+.nf
+.ft 3
+.in +0.3i
+  MTOOLS_SKIP_CHECK=1
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+Global variables may also be set via the environment:
+.nf
+.ft 3
+.in +0.3i
+  export MTOOLS_SKIP_CHECK=1
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+Global string variables may be set to any value:
+.TP
+\&\fR\&\f(CWMTOOLS_DATE_STRING\fR\ 
+The format used for printing dates of files.  By default, is dd-mm-yyyy.
+.PP
+.SS Per\ drive\ flags\ and\ variables
+.iX "c Drive description"
+.iX "c Drive configuration"
+.PP
+.SS \ \ General\ information
+.iX "c Drive description, example"
+.iX "c Drive configuration, example"
+.iX "v drive"
+.PP
+Per drive flags and values may be described in a drive section. A
+drive section starts with
+\&\fR\&\f(CWdrive\fR "\fIdriveletter\fR" :
+.PP
+Then follow variable-value pairs and flags.
+.PP
+This is a sample drive description:
+.nf
+.ft 3
+.in +0.3i
+  drive a:
+    file="/dev/fd0" use_xdf=1
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+.SS \ \ Location\ information
+.iX "c Hdimage"
+.PP
+For each drive, you need to describe where its data is physically
+stored (imag file, physical device, partition, offset).
+.TP
+\&\fR\&\f(CWfile\fR\ 
+.iX "c Image file"
+.iX "c Name of device node"
+.iX "c File name of device node"
+.iX "v file"
+The name of the file or device holding the disk image. This is
+mandatory. The file name should be enclosed in quotes.
+.TP
+\&\fR\&\f(CWpartition\fR\ 
+.iX "c Dosemu hard disk image"
+.iX "c Zip disks (partitions)"
+.iX "c Jaz disks (partitions)"
+.iX "c Syquest disks"
+.iX "c Magneto-optical disks"
+.iX "c OS/2 (layout of removable media)"
+.iX "c Windows NT (layout of removable media)"
+.iX "c Removable media"
+.iX "c Partitioned image file"
+Tells mtools to treat the drive as a partitioned device, and to use the
+given partition. Only primary partitions are accessible using this
+method, and they are numbered from 1 to 4. For logical partitions, use
+the more general \fR\&\f(CWoffset\fR variable. The \fR\&\f(CWpartition\fR variable
+is intended for removable media such as Syquests, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquests and
+magneto-optical disks as \fR\&\f(CW\(ifgiant floppy disks\(is\fR which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partioned devices. The \fR\&\f(CWpartition\fR flag is also useful DOSEMU
+hdimages. It is not recommended for hard disks for which direct access
+to partitions is available through mounting.
+.TP
+\&\fR\&\f(CWoffset\fR\ 
+.iX "c Ram disk"
+.iX "c Atari Ram disk"
+Describes where in the file the MS-DOS filesystem starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the filesystem starts right at the
+beginning of the device or file.
+.PP
+.SS \ \ Disk\ Geometry\ Configuration
+.iX "c Disk Geometry"
+.iX "c Configuration of disk geometry"
+.iX "c Description of disk geometry"
+.iX "c Format of disk"
+.iX "c High density disk"
+.iX "c Low density disk"
+.iX "p mformat (geometry used for)"
+.PP
+Geometry information describes the physical characteristics about the
+disk. Its has three purposes:
+.TP
+formatting\ 
+The geometry information is written into the boot sector of the newly
+made disk. However, you may also describe the geometry information on
+the command line. See section mformat, for details.
+.TP
+filtering\ 
+On some Unices there are device nodes which only support one physical
+geometry. For instance, you might need a different node to access a disk
+as high density or as low density. The geometry is compared to the
+actual geometry stored on the boot sector to make sure that this device
+node is able to correctly read the disk. If the geometry doesn't match,
+this drive entry fails, and the next drive entry bearing the same drive
+letter is tried. See section multiple descriptions, for more details on
+supplying several descriptions for one drive letter.
+.IP
+If no geometry information is supplied in the configuration file, all
+disks are accepted. On Linux (and on Sparc) there exist device nodes
+with configurable geometry (\fR\&\f(CW\(if/dev/fd0\(is\fR, \fR\&\f(CW\(if/dev/fd1\(is\fR etc),
+and thus filtering is not needed (and ignored) for disk drives.  (Mtools
+still does do filtering on plain files (disk images) in Linux: this is
+mainly intended for test purposes, as I don't have access to a Unix
+which would actually need filtering).
+.IP
+If you do not need filtering, but want still a default geometry for
+mformatting, you may switch off filtering using the \fR\&\f(CWmformat_only\fR
+flag.
+.IP
+If you want filtering, you should supply the \fR\&\f(CWfilter\fR flag.  If you 
+supply a geometry, you must supply one of both flags.
+.TP
+initial\ geometry\ 
+On devices that support it (usually floppy devices), the geometry
+information is also used to set the initial geometry. This initial
+geometry is applied while reading the boot sector, which contains the
+real geometry.  If no geometry information is supplied in the
+configuration file, or if the \fR\&\f(CWmformat_only\fR flag is supplied, no
+initial configuration is done.
+.IP
+On Linux, initial geometry is not really needed, as the configurable
+devices are able to auto-detect the disk type accurately enough (for
+most common formats) to read the boot sector.
+.PP
+Wrong geometry information may lead to very bizarre errors. That's why I
+strongly recommend that you add the \fR\&\f(CWmformat_only\fR flag to your
+drive description, unless you really need filtering or initial geometry.
+.PP
+The following geometry related variables are available:
+.TP
+\&\fR\&\f(CWcylinders\fR\ 
+.TQ
+\&\fR\&\f(CWtracks\fR
+.iX "v cylinders"
+.iX "v tracks"
+The number of cylinders. (\fR\&\f(CWcylinders\fR is the preferred form,
+\&\fR\&\f(CWtracks\fR is considered obsolete)
+.TP
+\&\fR\&\f(CWheads\fR\ 
+.iX "v heads"
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWsectors\fR\ 
+.iX "v sectors"
+The number of sectors per track.
+.PP
+Example: the following drive section describes a 1.44M drive:
+.PP
+.nf
+.ft 3
+.in +0.3i
+  drive a:
+      file="/dev/fd0H1440"
+      fat_bits=12
+      cylinders=80 heads=2 sectors=18
+      mformat_only
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The following shorthand geometry descriptions are available:
+.TP
+\&\fR\&\f(CW1.44m\fR\ 
+high density 3 1/2 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=18\fR
+.TP
+\&\fR\&\f(CW1.2m\fR\ 
+high density 5 1/4 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=15\fR
+.TP
+\&\fR\&\f(CW720k\fR\ 
+double density 3 1/2 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=9\fR
+.TP
+\&\fR\&\f(CW360k\fR\ 
+double density 5 1/4 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=9\fR
+.PP
+The shorthand format descriptions may be amended. For example,
+\&\fR\&\f(CW360k sectors=8\fR
+describes a 320k disk and is equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=8\fR
+.PP
+.SS \ \ Open\ Flags
+.iX "v sync"
+.iX "v nodelay"
+.iX "v exclusive"
+.iX "c open flags"
+.iX "c synchronous writing"
+.iX "c exclusive access to a drive"
+.PP
+Moreover, the following flags are available:
+.TP
+\&\fR\&\f(CWsync\fR\ 
+All i/o operations are done synchronously
+.TP
+\&\fR\&\f(CWnodelay\fR\ 
+The device or file is opened with the O_NDELAY flag. This is needed on
+some non-Linux architectures.
+.TP
+\&\fR\&\f(CWexclusive\fR\ 
+The device or file is opened with the O_EXCL flag. On Linux, this
+ensures exclusive access to the floppy drive. On most other
+architectures, and for plain files it has no effect at all.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Variables
+.PP
+The following general purpose drive variables are available.  Depending
+to their type, these variables can be set to a string (precmd) or
+an integer (all others)
+.TP
+\&\fR\&\f(CWfat_bits\fR\ 
+.iX "v fat_bits"
+The number of FAT bits. This may be 12 or 16. This is very rarely
+needed, as it can almost always be deduced from information in the
+boot sector. On the contrary, describing the number of fat bits may
+actually be harmful if you get it wrong. You should only use it if
+mtools gets the autodetected number of fat bits wrong, or if you want
+to mformat a disk with a weird number of fat bits.
+.TP
+\&\fR\&\f(CWcodepage\fR\ 
+Describes the DOS codepage used for short filenames. This is a number
+between 1 and 999. By default, codepage 850 is used. The reason for
+this is because this codepage contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global codepage
+for all drives by using the global \fR\&\f(CWdefault_codepage\fR parameter
+(outside of any drive description). This parameters exists starting at
+version 4.0.0
+.TP
+\&\fR\&\f(CWprecmd\fR\ 
+.iX "c Solaris (volcheck)"
+.iX "c Executing commands before opening the device"
+On some variants of Solaris, it is necessary to call 'volcheck -v'
+before opening a floppy device, in order for the system to notice that
+there is indeed a disk in the drive. \fR\&\f(CWprecmd="volcheck -v"\fR in the
+drive clause establishes the desired behavior.
+.TP
+\&\fR\&\f(CWblocksize\fR\ 
+.iX "c raw device"
+.iX "c character devices"
+.iX "c blocksize"
+This parameter represents a default block size to be always used on this
+device.  All I/O is done with multiples of this block size,
+independantly of the sector size registered in the filesystem's boot
+sector.  This is useful for character devices whose sector size is not
+512, such as for example CD Rom drives on Solaris.
+.PP
+Only the \fR\&\f(CWfile\fR variable is mandatory. The other parameters may
+be left out. In that case a default value or an autodetected value is
+used.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Flags
+.PP
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+ommitted, it is enabled.  For example, \fR\&\f(CWscsi\fR is equivalent to
+\&\fR\&\f(CWscsi=1\fR
+.TP
+\&\fR\&\f(CWnolock\fR\ 
+.iX "c disable locking"
+.iX "c locking (disabling it)"
+.iX "c plain floppy: device xxx busy"
+Instruct mtools to not use locking on this drive.  This is needed on
+systems with buggy locking semantics.  However, enabling this makes
+operation less safe in cases where several users may access the same
+drive at the same time.
+.TP
+\&\fR\&\f(CWscsi\fR\ 
+.iX "c setuid installation (needed for raw SCSI I/O)"
+.iX "c Solaris (Raw access to SCSI devices such as Zip & Jaz)"
+.iX "c SunOS (Raw access to SCSI devices such as Zip & Jaz)"
+.iX "c Zip disks (raw Scsi access)"
+.iX "c Jaz disks (raw Scsi access)"
+.iX "c Syquests (raw Scsi access)"
+.iX "c SCSI devices"
+When set to 1, this option tells mtools to use raw SCSI I/O instead of
+the standard read/write calls to access the device. Currently, this is
+supported on HP/UX, Solaris and SunOs.  This is needed because on some
+architectures, such as SunOs or Solaris, PC media can't be accessed
+using the \fR\&\f(CWread\fR and \fR\&\f(CWwrite\fR syscalls, because the OS expects
+them to contain a Sun specific "disk label".
+.IP
+As raw Scsi access always uses the whole device, you need to specify the
+"partition" flag in addition
+.IP
+On some architectures, such as Solaris, mtools needs root privileges to
+be able to use the \fR\&\f(CWscsi\fR option.  Thus mtools should be installed
+set uid root on Solaris if you want to access Zip/Jaz drives.  Thus, if
+the \fR\&\f(CWscsi\fR flag is given, \fR\&\f(CWprivileged\fR is automatically
+implied, unless explicitly disabled by \fR\&\f(CWprivileged=0\fR
+.IP
+Mtools uses its root privileges to open the device, and to issue the
+actual SCSI I/O calls.  Moreover, root privileges are only used for
+drives described in a system-wide configuration file such as
+\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR, and not for those described in
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR or \fR\&\f(CW\(if$MTOOLSRC\(is\fR.  
+.TP
+\&\fR\&\f(CWprivileged\fR\ 
+.iX "c setuid installation"
+.iX "c setgid installation"
+When set to 1, this instructs mtools to use its set-uid and set-gid
+privileges for opening the given drive.  This option is only valid for
+drives described in the system-wide configuration files (such as
+\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR, not \fR\&\f(CW\(if~/.mtoolsrc\(is\fR or
+\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR).  Obviously, this option is also a no op if mtools is
+not installed setuid or setgid.  This option is implied by 'scsi=1', but
+again only for drives defined in system-wide configuration files.
+Privileged may also be set explicitely to 0, in order to tell mtools not
+to use its privileges for a given drive even if \fR\&\f(CWscsi=1\fR is set.
+.IP
+Mtools only needs to be installed setuid if you use the
+\&\fR\&\f(CWprivileged\fR or \fR\&\f(CWscsi\fR drive variables.  If you do not use
+these options, mtools works perfectly well even when not installed
+setuid root.
+.TP
+\&\fR\&\f(CWvold\fR\ 
+.iX "c Solaris (vold)"
+.iX "c Vold (mediamgr)"
+.IP
+Instructs mtools to interpret the device name as a vold identifier
+rather than as a filename.  The vold identifier is translated into a
+real filename using the \fR\&\f(CWmedia_findname()\fR and
+\&\fR\&\f(CWmedia_oldaliases()\fR functions of the \fR\&\f(CWvolmgt\fR library.  This
+flag is only available if you configured mtools with the
+\&\fR\&\f(CW--enable-new-vold\fR option before compilation.
+.TP
+\&\fR\&\f(CWswap\fR\ 
+.iX "c Atari"
+.iX "c Wordswapped"
+.IP
+Consider the media as a word-swapped Atari disk.
+.TP
+\&\fR\&\f(CWuse_xdf\fR\ 
+.iX "c XDF disks (how to configure)"
+.iX "v use_xdf"
+If this is set to a non-zero value, mtools also tries to access this
+disk as an XDF disk. XDF is a high capacity format used by OS/2. This
+is off by default. See section XDF, for more details.
+.TP
+\&\fR\&\f(CWmformat_only\fR\ 
+.iX "v mformat_only"
+Tells mtools to use the geometry for this drive only for mformatting and 
+not for filtering.
+.TP
+\&\fR\&\f(CWfilter\fR\ 
+.iX "v filter"
+Tells mtools to use the geometry for this drive both for mformatting and 
+filtering.
+.TP
+\&\fR\&\f(CWremote\fR\ 
+Tells mtools to connect to floppyd (see section  floppyd).
+.PP
+.SS \ \ Supplying\ multiple\ descriptions\ for\ a\ drive
+.PP
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that
+fits. Descriptions may fail for several reasons:
+.TP
+1.\ 
+because the geometry is not appropriate,
+.TP
+2.\ 
+because there is no disk in the drive,
+.TP
+3.\ 
+or because of other problems.
+.PP
+Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry.
+Example:
+.nf
+.ft 3
+.in +0.3i
+  drive a: file="/dev/fd0H1440" 1.44m
+  drive a: file="/dev/fd0H720" 720k
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+.PP
+You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+.PP
+.nf
+.ft 3
+.in +0.3i
+  drive z: file="/dev/fd0"
+  drive z: file="/dev/fd1"
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+With this description, \fR\&\f(CWmdir z:\fR accesses your first physical
+drive if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+.PP
+When using multiple configuration files, drive descriptions in the files
+parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the \fR\&\f(CWdrive+\fR or \fR\&\f(CW+drive\fR
+keywords instead of \fR\&\f(CWdrive\fR. The first adds a description to the
+end of the list (i.e. it will be tried last), and the first adds it to
+the start of the list.
+.PP
+.SS Location\ of\ configuration\ files\ and\ parsing\ order
+.iX "c Parsing order"
+.iX "c Configuration file parsing order"
+.iX "c Configuration file name (parsing order)"
+.iX "c Name of configuration files (parsing order)"
+.iX "c Location of configuration files (parsing order)"
+.PP
+The configuration files are parsed in the following order:
+.TP
+1.\ 
+compiled-in defaults
+.TP
+2.\ 
+\&\fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR
+.TP
+3.\ 
+\&\fR\&\f(CW\(if/etc/mtools\(is\fR
+This is for backwards compatibility only, and is only parsed if
+\&\fR\&\f(CW\(ifmtools.conf\(is\fR
+doesn't exist.
+.TP
+4.\ 
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR.
+.TP
+5.\ 
+\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR (file pointed by the \fR\&\f(CWMTOOLSRC\fR environmental
+variable)
+.PP
+Options described in the later files override those described in the
+earlier files. Drives defined in earlier files persist if they are not
+overridden in the later files. For instance, drives A and B may be
+defined in \fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR and drives C and D may be
+defined in \fR\&\f(CW\(if~/.mtoolsrc\(is\fR However, if \fR\&\f(CW\(if~/.mtoolsrc\(is\fR also
+defines drive A, this new description would override the description of
+drive A in \fR\&\f(CW\(if/usr/local/etc/mtools.conf\(is\fR instead of adding to it. If
+you want to add a new description to a drive already described in an
+earlier file, you need to use either the \fR\&\f(CW+drive\fR or \fR\&\f(CWdrive+\fR
+keyword.
+.PP
+.SS Backwards\ compatibility\ with\ old\ configuration\ file\ syntax
+.iX "c Backwards compatibility"
+.iX "c Old configuration file syntax"
+.iX "c Configuration file, old syntax"
+.PP
+The syntax described herein is new for version \fR\&\f(CWmtools-3.0\fR. The
+old line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+.PP
+.SH See also
+mtools
diff --git a/mtools.c b/mtools.c
new file mode 100644 (file)
index 0000000..4d148b6
--- /dev/null
+++ b/mtools.c
@@ -0,0 +1,200 @@
+/*  Copyright 1996-2004,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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},
+       {"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 (file)
index 0000000..dc186df
--- /dev/null
@@ -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 (file)
index 0000000..0d4fa6f
--- /dev/null
+++ b/mtools.h
@@ -0,0 +1,275 @@
+#ifndef MTOOLS_MTOOLS_H
+#define MTOOLS_MTOOLS_H
+/*  Copyright 1996-2005,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 1
+#define PRIV_FLAG 2
+#define NOLOCK_FLAG 4
+#define USE_XDF_FLAG 8
+#define MFORMAT_ONLY_FLAG 16
+#define VOLD_FLAG 32
+#define FLOPPYD_FLAG 64
+#define FILTER_FLAG 128
+#define SWAP_FLAG 256 
+
+#define IS_SCSI(x)  ((x) && ((x)->misc_flags & SCSI_FLAG))
+#define IS_PRIVILEGED(x) ((x) && ((x)->misc_flags & PRIV_FLAG))
+#define IS_NOLOCK(x) ((x) && ((x)->misc_flags & NOLOCK_FLAG))
+#define IS_MFORMAT_ONLY(x) ((x) && ((x)->misc_flags & MFORMAT_ONLY_FLAG))
+#define SHOULD_USE_VOLD(x) ((x)&& ((x)->misc_flags & VOLD_FLAG))
+#define SHOULD_USE_XDF(x) ((x)&& ((x)->misc_flags & USE_XDF_FLAG))
+#define DO_SWAP(x)  ((x) && ((x)->misc_flags & SWAP_FLAG))
+
+typedef struct device {
+       const char *name;       /* full path to device */
+
+       char drive;                     /* the drive letter */
+       int fat_bits;                   /* FAT encoding scheme */
+
+       unsigned int mode;              /* any special open() flags */
+       unsigned int tracks;    /* tracks */
+       unsigned int heads;             /* heads */
+       unsigned int sectors;   /* sectors */
+       unsigned int hidden;    /* number of hidden sectors. Used for
+                                                        * mformatting partitioned devices */
+
+       off_t offset;           /* skip this many bytes */
+
+       unsigned int partition;
+
+       unsigned int misc_flags;
+
+       /* Linux only stuff */
+       unsigned int ssize;
+       unsigned int use_2m;
+
+       char *precmd;           /* command to be executed before opening
+                                                * the drive */
+
+       /* internal variables */
+       int file_nr;            /* used during parsing */
+       unsigned int blocksize;   /* size of disk block in bytes */
+
+       int codepage; /* codepage for shortname encoding */
+
+       const char *cfg_filename; /* used for debugging purposes */
+} device_t;
+
+
+#ifndef OS_linux
+#define BOOTSIZE 512
+#else
+#define BOOTSIZE 256
+#endif
+
+typedef struct doscp_t doscp_t;
+
+#include "stream.h"
+
+
+extern const char *short_illegals, *long_illegals;
+
+#define maximize(target, max) do { \
+  if(max < 0) { \
+    if(target > 0) \
+      target = 0; \
+  } else if(target > max) { \
+    target = max; \
+  } \
+} while(0)
+
+#define minimize(target, min) do { \
+  if(target < min) \
+    target = min; \
+} while(0) 
+
+int init_geom(int fd, struct device *dev, struct device *orig_dev,
+             struct MT_STAT *statbuf);
+
+int readwrite_sectors(int fd, /* file descriptor */
+                     int *drive,
+                     int rate,
+                     int seektrack,
+                     int track, int head, int sector, int size, /* address */
+                     char *data, 
+                     int bytes,
+                     int direction,
+                     int retries);
+
+int lock_dev(int fd, int mode, struct device *dev);
+
+char *unix_normalize (doscp_t *cp, char *ans, struct dos_name_t *dn);
+void dos_name(doscp_t *cp, const char *filename, int verbose, int *mangled,
+             struct dos_name_t *);
+struct directory *mk_entry(const dos_name_t *filename, char attr,
+                          unsigned int fat, size_t size, time_t date,
+                          struct directory *ndir);
+
+struct directory *mk_entry_from_base(const char *base, char attr,
+                                    unsigned int fat, size_t size, time_t date,
+                                    struct directory *ndir);
+
+int copyfile(Stream_t *Source, Stream_t *Target);
+int getfreeMinClusters(Stream_t *Stream, size_t ref);
+
+FILE *opentty(int mode);
+
+int is_dir(Stream_t *Dir, char *path);
+void bufferize(Stream_t **Dir);
+
+int dir_grow(Stream_t *Dir, int size);
+int match(const wchar_t *, const wchar_t *, wchar_t *, int,  int);
+
+wchar_t *unix_name(doscp_t *fromDos,
+                  const char *base, const char *ext, char Case,
+                  wchar_t *answer);
+void *safe_malloc(size_t size);
+Stream_t *open_filter(Stream_t *Next,int convertCharset);
+
+extern int got_signal;
+/* int do_gotsignal(char *, int);
+#define got_signal do_gotsignal(__FILE__, __LINE__) */
+
+void setup_signal(void);
+
+
+#define SET_INT(target, source) \
+if(source)target=source
+
+
+UNUSED(static __inline__ int compare (long ref, long testee))
+{
+       return (ref && ref != testee);
+}
+
+Stream_t *GetFs(Stream_t *Fs);
+
+void label_name(doscp_t *cp, const char *filename, int verbose, 
+               int *mangled, dos_name_t *ans);
+
+/* environmental variables */
+extern unsigned int mtools_skip_check;
+extern unsigned int mtools_fat_compatibility;
+extern unsigned int mtools_ignore_short_case;
+extern unsigned int mtools_no_vfat;
+extern unsigned int mtools_numeric_tail;
+extern unsigned int mtools_dotted_dir;
+extern unsigned int mtools_twenty_four_hour_clock;
+extern const char *mtools_date_string;
+extern unsigned int mtools_rate_0, mtools_rate_any;
+extern unsigned int mtools_default_codepage;
+extern int mtools_raw_tty;
+
+extern int batchmode;
+
+char get_default_drive(void);
+void set_cmd_line_image(char *img, int flags);
+void read_config(void);
+extern struct device *devices;
+extern struct device const_devices[];
+extern const int nr_const_devices;
+
+#define New(type) ((type*)(calloc(1,sizeof(type))))
+#define Grow(adr,n,type) ((type*)(realloc((char *)adr,n*sizeof(type))))
+#define Free(adr) (free((char *)adr));
+#define NewArray(size,type) ((type*)(calloc((size),sizeof(type))))
+
+void mattrib(int argc, char **argv, int type);
+void mbadblocks(int argc, char **argv, int type);
+void mcat(int argc, char **argv, int type);
+void mcd(int argc, char **argv, int type);
+void mclasserase(int argc, char **argv, int type);
+void mcopy(int argc, char **argv, int type);
+void mdel(int argc, char **argv, int type);
+void mdir(int argc, char **argv, int type);
+void mdoctorfat(int argc, char **argv, int type);
+void mdu(int argc, char **argv, int type);
+void mformat(int argc, char **argv, int type);
+void minfo(int argc, char **argv, int type);
+void mlabel(int argc, char **argv, int type);
+void mmd(int argc, char **argv, int type);
+void mmount(int argc, char **argv, int type);
+void mmove(int argc, char **argv, int type);
+void mpartition(int argc, char **argv, int type);
+void mshowfat(int argc, char **argv, int mtype);
+void mtoolstest(int argc, char **argv, int type);
+void mzip(int argc, char **argv, int type);
+
+extern int noPrivileges;
+void init_privs(void);
+void reclaim_privs(void);
+void drop_privs(void);
+void destroy_privs(void);
+uid_t get_real_uid(void);
+void closeExec(int fd);
+
+extern const char *progname;
+
+void precmd(struct device *dev);
+
+void print_sector(const char *message, unsigned char *data, int size);
+time_t getTimeNow(time_t *now);
+
+#ifdef USING_NEW_VOLD
+char *getVoldName(struct device *dev, char *name);
+#endif
+
+
+Stream_t *OpenDir(Stream_t *Parent, const char *filename);
+/* int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); 
+int unix_loop(MainParam_t *mp, char *arg); */
+
+struct dirCache_t **getDirCacheP(Stream_t *Stream);
+int isRootDir(Stream_t *Stream);
+unsigned int getStart(Stream_t *Dir, struct directory *dir);
+unsigned int countBlocks(Stream_t *Dir, unsigned int block);
+char getDrive(Stream_t *Stream);
+
+
+void printOom(void);
+int ask_confirmation(const char *, ...)  __attribute__ ((format (printf, 1, 2)));
+
+int helpFlag(int, char **);
+
+char *get_homedir(void);
+#define EXPAND_BUF 2048
+const char *expand(const char *, char *);
+FILE *open_mcwd(const char *mode);
+void unlink_mcwd(void);
+
+#ifndef OS_mingw32msvc
+int safePopenOut(const char **command, char *output, int len);
+#endif
+
+#define ROUND_DOWN(value, grain) ((value) - (value) % (grain))
+#define ROUND_UP(value, grain) ROUND_DOWN((value) + (grain)-1, (grain))
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#endif
diff --git a/mtools.info b/mtools.info
new file mode 100644 (file)
index 0000000..efdd3bd
--- /dev/null
@@ -0,0 +1,2736 @@
+This is mtools.info, produced by makeinfo version 4.11 from mtools.texi.
+
+This manual is for Mtools (version 4.0.12, November 2009), which is a
+collection of tools to allow Unix systems to manipulate MS-DOS files.
+
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.  Copyright
+(C) 1996-2005,2007-2009 Alain Knaff.
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.3 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, with no Front-Cover Texts,
+     and with no Back-Cover Texts.  A copy of the license is included
+     in the section entitled "GNU Free Documentation License".
+
+INFO-DIR-SECTION DOS
+START-INFO-DIR-ENTRY
+* Mtools: (mtools).        Mtools: utilities to access DOS disks in Unix.
+END-INFO-DIR-ENTRY
+
+\1f
+File: mtools.info,  Node: Top,  Next: Location,  Prev: (dir),  Up: (dir)
+
+Mtools doc
+**********
+
+This is mtools' documentation.
+
+Introduction
+************
+
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS
+filesystem (typically a floppy disk).  Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However, unnecessary
+restrictions and oddities of DOS are not emulated. For instance, it is
+possible to move subdirectories from one subdirectory to another.
+
+   Mtools is sufficient to give access to MS-DOS filesystems.  For
+instance, commands such as `mdir a:' work on the `a:' floppy without
+any preliminary mounting or initialization (assuming the default
+`/etc/mtools.conf' works on your machine).  With mtools, one can change
+floppies too without unmounting and mounting.
+
+   This manual is for Mtools (version 4.0.12, November 2009), which is
+a collection of tools to allow Unix systems to manipulate MS-DOS files.
+
+   Copyright (C) 2007, 2009 Free Software Foundation, Inc.  Copyright
+(C) 1996-2005,2007-2009 Alain Knaff.
+
+     Permission is granted to copy, distribute and/or modify this
+     document under the terms of the GNU Free Documentation License,
+     Version 1.3 or any later version published by the Free Software
+     Foundation; with no Invariant Sections, with no Front-Cover Texts,
+     and with no Back-Cover Texts.  A copy of the license is included
+     in the section entitled "GNU Free Documentation License".
+
+* Menu:
+
+* Location::          Where to find mtools and early bug fixes
+* Common features::   Common features of all mtools commands
+* Configuration::     How to configure mtools for your environment
+* Commands::          The available mtools commands
+* Compiling mtools::  Architecture specific compilation flags
+* Porting mtools::    Porting mtools to architectures which are not
+                      yet supported
+
+* Command Index::     Command Index
+* Variable Index::    Variable Index
+* Concept Index::     Concept Index
+
+\1f
+File: mtools.info,  Node: Location,  Next: Common features,  Prev: Top,  Up: Top
+
+1 Where to get mtools
+*********************
+
+Mtools can be found at the following places (and their mirrors):
+     http://ftp.gnu.org/gnu/mtools/mtools-4.0.12.tar.gz
+     http://mtools.linux.lu/mtools-4.0.12.tar.gz
+     ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.12.tar.gz
+     ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.12.tar.gz
+
+   Before reporting a bug, make sure that it has not yet been fixed in
+the Alpha patches which can be found at:
+     http://ftp.gnu.org/gnu/mtools/
+     http://mtools.linux.lu/
+     ftp://www.tux.org/pub/knaff/mtools
+
+   These patches are named `mtools-'VERSION`-'DDMM`.taz', where version
+stands for the base version, DD for the day and MM for the month. Due
+to a lack of space, I usually leave only the most recent patch.
+
+   There is an mtools mailing list at mtools @ tux.org .  Please send
+all bug reports to this list.  You may subscribe to the list by sending
+a message with 'subscribe mtools @ tux.org' in its body to majordomo @
+tux.org . (N.B. Please remove the spaces around the "@" both times. I
+left them there in order to fool spambots.)  Announcements of new
+mtools versions will also be sent to the list, in addition to the linux
+announce newsgroups.  The mailing list is archived at
+http://lists.gnu.org/pipermail/info-mtools/
+
+\1f
+File: mtools.info,  Node: Common features,  Next: Configuration,  Prev: Location,  Up: Top
+
+2 Common features of all mtools commands
+****************************************
+
+* Menu:
+
+* arguments::              What the command line parameters of mtools
+                           mean
+* drive letters::          Which drives are defined by default
+* directory::              Current working directory
+* long names::             VFAT-style long filenames
+* name clashes::           Name clash handling, and associated command
+                           line options
+* case sensitivity::       Case sensitivity
+* high capacity formats::  How to fit more data on your floppies
+* exit codes::             Exit codes
+* bugs::                   Happens to everybody
+
+\1f
+File: mtools.info,  Node: arguments,  Next: drive letters,  Prev: Common features,  Up: Common features
+
+2.1 Options and filenames
+=========================
+
+MS-DOS filenames are composed of a drive letter followed by a colon, a
+subdirectory, and a filename. Only the filename part is mandatory, the
+drive letter and the subdirectory are optional. Filenames without a
+drive letter refer to Unix files. Subdirectory names can use either the
+'`/'' or '`\'' separator.  The use of the '`\'' separator or wildcards
+requires the names to be enclosed in quotes to protect them from the
+shell. However, wildcards in Unix filenames should not be enclosed in
+quotes, because here we *want* the shell to expand them.
+
+   The regular expression "pattern matching" routines follow the
+Unix-style rules.  For example, ``*'' matches all MS-DOS files in lieu
+of ``*.*''.  The archive, hidden, read-only and system attribute bits
+are ignored during pattern matching.
+
+   All options use the `-' (minus) as their first character, not `/' as
+you'd expect in MS-DOS.
+
+   Most mtools commands allow multiple filename parameters, which
+doesn't follow MS-DOS conventions, but which is more user-friendly.
+
+   Most mtools commands allow options that instruct them how to handle
+file name clashes. *Note name clashes::, for more details on these. All
+commands accept the `-V' flags which prints the version, and most
+accept the `-v' flag, which switches on verbose mode. In verbose mode,
+these commands print out the name of the MS-DOS files upon which they
+act, unless stated otherwise. *Note Commands::, for a description of
+the options which are specific to each command.
+
+\1f
+File: mtools.info,  Node: drive letters,  Next: directory,  Prev: arguments,  Up: Common features
+
+2.2 Drive letters
+=================
+
+The meaning of the drive letters depends on the target architectures.
+However, on most target architectures, drive A is the first floppy
+drive, drive B is the second floppy drive (if available), drive J is a
+Jaz drive (if available), and drive Z is a Zip drive (if available).  On
+those systems where the device name is derived from the SCSI id, the Jaz
+drive is assumed to be at Scsi target 4, and the Zip at Scsi target 5
+(factory default settings).  On Linux, both drives are assumed to be the
+second drive on the Scsi bus (/dev/sdb). The default settings can be
+changes using a configuration file (*note Configuration::).
+
+   The drive letter : (colon) has a special meaning. It is used to
+access image files which are directly specified on the command line
+using the `-i' options.
+
+   Example:
+      mcopy -i my-image-file.bin ::file1 ::file2 .
+
+   This copies `file1' and `file2' from the image file
+(`my-image-file.bin') to the `/tmp' directory.
+
+   You can also supply an offset within the image file by including
+`@@'OFFSET into the file name.
+
+   Example:
+      mcopy -i my-image-file.bin@@1M ::file1 ::file2 .
+
+   This looks for the image at the offset of 1M in the file, rather than
+at its beginning.
+
+\1f
+File: mtools.info,  Node: directory,  Next: long names,  Prev: drive letters,  Up: Common features
+
+2.3 Current working directory
+=============================
+
+The `mcd' command (*note mcd::) is used to establish the device and the
+current working directory (relative to the MS-DOS filesystem),
+otherwise the default is assumed to be `A:/'. However, unlike MS-DOS,
+there is only one working directory for all drives, and not one per
+drive.
+
+\1f
+File: mtools.info,  Node: long names,  Next: name clashes,  Prev: directory,  Up: Common features
+
+2.4 VFAT-style long file names
+==============================
+
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a VFAT
+long name, and a companion short name is generated. This short name is
+what you see when you examine the disk with a pre-7.0 version of DOS.
+The following table shows some examples of short names:
+
+     Long name       MS-DOS name     Reason for the change
+     ---------       ----------      ---------------------
+     thisisatest     THISIS~1        filename too long
+     alain.knaff     ALAIN~1.KNA     extension too long
+     prn.txt         PRN~1.TXT       PRN is a device name
+     .abc            ABC~1           null filename
+     hot+cold        HOT_CO~1        illegal character
+
+   As you see, the following transformations happen to derive a short
+name:
+   * Illegal characters are replaced by underscores. The illegal
+     characters are `;+=[]',\"*\\<>/?:|'.
+
+   * Extra dots, which cannot be interpreted as a main name/extension
+     separator are removed
+
+   * A `~'N number is generated,
+
+   * The name is shortened so as to fit in the 8+3 limitation
+
+   The initial Unix-style file name (whether long or short) is also
+called the "primary" name, and the derived short name is also called the
+"secondary" name.
+
+   Example:
+      mcopy /etc/motd a:Reallylongname
+    Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+      mcopy /etc/motd a:motd
+    Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+
+   In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+
+   Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (`\"*\\<>/?:|'), and device names are still reserved.
+
+     Unix name       Long name       Reason for the change
+     ---------       ----------      ---------------------
+     prn             prn-1           PRN is a device name
+     ab:c            ab_c-1          illegal character
+
+   As you see, the following transformations happen if a long name is
+illegal:
+   * Illegal characters are replaces by underscores,
+
+   * A `-'N number is generated,
+
+\1f
+File: mtools.info,  Node: name clashes,  Next: case sensitivity,  Prev: long names,  Up: Common features
+
+2.5 Name clashes
+================
+
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as `mcopy', `mmd',
+`mren', `mmove'. When a name clash happens, mtools asks you what it
+should do. It offers several choices:
+
+`overwrite'
+     Overwrites the existing file. It is not possible to overwrite a
+     directory with a file.
+
+`rename'
+     Renames the newly created file. Mtools prompts for the new filename
+
+`autorename'
+     Renames the newly created file. Mtools chooses a name by itself,
+     without prompting
+
+`skip'
+     Gives up on this file, and moves on to the next (if any)
+
+   To chose one of these actions, type its first letter at the prompt.
+If you use a lower case letter, the action only applies for this file
+only, if you use an upper case letter, the action applies to all files,
+and you won't be prompted again.
+
+   You may also chose actions (for all files) on the command line, when
+invoking mtools:
+
+`-D o'
+     Overwrites primary names by default.
+
+`-D O'
+     Overwrites secondary names by default.
+
+`-D r'
+     Renames primary name by default.
+
+`-D R'
+     Renames secondary name by default.
+
+`-D a'
+     Autorenames primary name by default.
+
+`-D A'
+     Autorenames secondary name by default.
+
+`-D s'
+     Skip primary name by default.
+
+`-D S'
+     Skip secondary name by default.
+
+`-D m'
+     Ask user what to do with primary name.
+
+`-D M'
+     Ask user what to do with secondary name.
+
+   Note that for command line switches lower/upper differentiates
+between primary/secondary name whereas for interactive choices,
+lower/upper differentiates between just-this-time/always.
+
+   The primary name is the name as displayed in Windows 95 or Windows
+NT: i.e. the long name if it exists, and the short name otherwise.  The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+
+   By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+
+   If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+
+\1f
+File: mtools.info,  Node: case sensitivity,  Next: high capacity formats,  Prev: name clashes,  Up: Common features
+
+2.6 Case sensitivity of the VFAT filesystem
+===========================================
+
+The VFAT filesystem is able to remember the case of the filenames.
+However, filenames which differ only in case are not allowed to coexist
+in the same directory. For example if you store a file called
+LongFileName on a VFAT filesystem, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+
+   The VFAT filesystem allows to store the case of a filename in the
+attribute byte, if all letters of the filename are the same case, and if
+all letters of the extension are the same case too. Mtools uses this
+information when displaying the files, and also to generate the Unix
+filename when mcopying to a Unix directory. This may have unexpected
+results when applied to files written using an pre-7.0 version of DOS:
+Indeed, the old style filenames map to all upper case. This is different
+from the behavior of the old version of mtools which used to generate
+lower case Unix filenames.
+
+\1f
+File: mtools.info,  Node: high capacity formats,  Next: exit codes,  Prev: case sensitivity,  Up: Common features
+
+2.7 high capacity formats
+=========================
+
+Mtools supports a number of formats which allow to store more data on
+disk as usual. Due to different operating system abilities, these
+formats are not supported on all OS'es. Mtools recognizes these formats
+transparently where supported.
+
+   In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+`fdutils' package at the following locations~:
+     `ftp://www.tux.org/pub/knaff/fdutils/'.
+     `ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-*'
+
+   See the manpages included in that package for further detail: Use
+`superformat' to format all formats except XDF, and use `xdfcopy' to
+format XDF.
+
+* Menu:
+
+* more sectors::      Putting more sectors per track on the disk
+* bigger sectors::    Use bigger sectors to save header space
+* 2m::                Use a standard first track
+* XDF::               OS/2's eXtended density format
+
+\1f
+File: mtools.info,  Node: more sectors,  Next: bigger sectors,  Prev: high capacity formats,  Up: high capacity formats
+
+2.7.1 More sectors
+------------------
+
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+
+   These formats are supported by numerous DOS shareware utilities such
+as `fdformat' and `vgacopy'. In his infinite hybris, Bill Gate$
+believed that he invented this, and called it `DMF disks', or `Windows
+formatted disks'. But in reality, it has already existed years before!
+Mtools supports these formats on Linux, on SunOs and on the DELL Unix
+PC.
+
+\1f
+File: mtools.info,  Node: bigger sectors,  Next: 2m,  Prev: more sectors,  Up: high capacity formats
+
+2.7.2 Bigger sectors
+--------------------
+
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+_fewer_, but bigger sectors. For example, 1 sector of 4K only takes up
+header space once, whereas 8 sectors of 512 bytes have also 8 headers,
+for the same amount of useful data.
+
+   This method allows to store up to 1992K on a 3 1/2 HD disk.
+
+   Mtools supports these formats only on Linux.
+
+\1f
+File: mtools.info,  Node: 2m,  Next: XDF,  Prev: bigger sectors,  Up: high capacity formats
+
+2.7.3 2m
+--------
+
+The 2m format was originally invented by Ciriaco Garcia de Celis. It
+also uses bigger sectors than usual in order to fit more data on the
+disk.  However, it uses the standard format (18 sectors of 512 bytes
+each) on the first cylinder, in order to make these disks easyer to
+handle by DOS. Indeed this method allows to have a standard sized
+bootsector, which contains a description of how the rest of the disk
+should be read.
+
+   However, the drawback of this is that the first cylinder can hold
+less data than the others. Unfortunately, DOS can only handle disks
+where each track contains the same amount of data. Thus 2m hides the
+fact that the first track contains less data by using a "shadow FAT".
+(Usually, DOS stores the FAT in two identical copies, for additional
+safety.  XDF stores only one copy, and it tells DOS that it stores two.
+Thus the same that would be taken up by the second FAT copy is saved.)
+This also means that your should *never use a 2m disk to store anything
+else than a DOS fs*.
+
+   Mtools supports these format only on Linux.
+
+\1f
+File: mtools.info,  Node: XDF,  Prev: 2m,  Up: high capacity formats
+
+2.7.4 XDF
+---------
+
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the `use_xdf' variable for the drive in the
+configuration file. *Note Compiling mtools::, and *note misc
+variables::, for details on how to do this. Fast XDF access is only
+available for Linux kernels which are more recent than 1.1.34.
+
+   Mtools supports this format only on Linux.
+
+   *Caution / Attention distributors*: If mtools is compiled on a Linux
+kernel more recent than 1.3.34, it won't run on an older kernel.
+However, if it has been compiled on an older kernel, it still runs on a
+newer kernel, except that XDF access is slower. It is recommended that
+distribution authors only include mtools binaries compiled on kernels
+older than 1.3.34 until 2.0 comes out. When 2.0 will be out, mtools
+binaries compiled on newer kernels may (and should) be distributed.
+Mtools binaries compiled on kernels older than 1.3.34 won't run on any
+2.1 kernel or later.
+
+\1f
+File: mtools.info,  Node: exit codes,  Next: bugs,  Prev: high capacity formats,  Up: Common features
+
+2.8 Exit codes
+==============
+
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure.  All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or minix disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(*note global variables::)
+
+\1f
+File: mtools.info,  Node: bugs,  Prev: exit codes,  Up: Common features
+
+2.9 Bugs
+========
+
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver.  These can be safely ignored.
+
+   The fat checking code chokes on 1.72 Mb disks mformatted with
+pre-2.0.7 mtools. Set the environmental variable
+MTOOLS_FAT_COMPATIBILITY (or the corresponding configuration file
+variable, *note global variables::) to bypass the fat checking.
+
+\1f
+File: mtools.info,  Node: Configuration,  Next: Commands,  Prev: Common features,  Up: Top
+
+3 How to configure mtools for your environment
+**********************************************
+
+3.1 Description
+===============
+
+This sections explains the syntax of the configurations files for
+mtools. The configuration files are called `/usr/local/etc/mtools.conf'
+and `~/.mtoolsrc'. If the environmental variable `MTOOLSRC' is set, its
+contents is used as the filename for a third configuration file. These
+configuration files describe the following items:
+
+   * Global configuration flags and variables
+
+   * Per drive flags and variables
+
+* Menu:
+
+* config file location::  Where mtools looks for its configuration files
+* general syntax::        The layout of the configuration files
+* default values::        Why you don't need a config file in most cases
+* global variables::      Variables that are independent of the drive
+* per drive variables::   Variables that are specific to a given drive
+* parsing order::         Location of configuration files and parsing order
+* old style config::      Backwards compatibility
+
+\1f
+File: mtools.info,  Node: config file location,  Next: general syntax,  Prev: Configuration,  Up: Configuration
+
+3.2 Location of the configuration files
+=======================================
+
+`/usr/local/etc/mtools.conf' is the system-wide configuration file, and
+`~/.mtoolsrc' is the user's private configuration file.
+
+   On some systems, the system-wide configuration file is called
+`/etc/default/mtools.conf' instead.
+
+\1f
+File: mtools.info,  Node: general syntax,  Next: default values,  Prev: config file location,  Up: Configuration
+
+3.2.1 General configuration file syntax
+---------------------------------------
+
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon.  Then
+follow variable assignments and flags. Variable assignments take the
+following form:
+     name=value
+   Flags are lone keywords without an equal sign and value following
+them.  A section either ends at the end of the file or where the next
+section begins.
+
+   Lines starting with a hash (`#') are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+
+\1f
+File: mtools.info,  Node: default values,  Next: global variables,  Prev: general syntax,  Up: Configuration
+
+3.3 Default values
+==================
+
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives.  Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+dosemu image files.
+
+\1f
+File: mtools.info,  Node: global variables,  Next: per drive variables,  Prev: default values,  Up: Configuration
+
+3.4 Global variables
+====================
+
+Global flags may be set to 1 or to 0.
+
+   The following global flags are recognized:
+
+`MTOOLS_SKIP_CHECK'
+     If this is set to 1, mtools skips most of its sanity checks. This
+     is needed to read some Atari disks which have been made with the
+     earlier ROMs, and which would not be recognized otherwise.
+
+`MTOOLS_FAT_COMPATIBILITY'
+     If this is set to 1, mtools skips the fat size checks. Some disks
+     have a bigger FAT than they really need to. These are rejected if
+     this option is not set.
+
+`MTOOLS_LOWER_CASE'
+     If this is set to 1, mtools displays all-upper-case short
+     filenames as lowercase. This has been done to allow a behavior
+     which is consistent with older versions of mtools which didn't
+     know about the case bits.
+
+`MTOOLS_NO_VFAT'
+     If this is set to 1, mtools won't generate VFAT entries for
+     filenames which are mixed-case, but otherwise legal dos filenames.
+     This is useful when working with DOS versions which can't grok
+     VFAT longnames, such as FreeDos.
+
+`MTOOLS_DOTTED_DIR'
+     In a wide directory, prints the short name with a dot instead of
+     spaces separating the basename and the extension.
+
+`MTOOLS_NAME_NUMERIC_TAIL'
+     If this is set to one (default), generate numeric tails for all
+     long names (~1).  If set to zero, only generate numeric tails if
+     otherwise a clash would have happened.
+
+`MTOOLS_TWENTY_FOUR_HOUR_CLOCK'
+     If 1, uses the European notation for times (twenty four hour
+     clock), else uses the UK/US notation (am/pm)
+
+   Example: Inserting the following line into your configuration file
+instructs mtools to skip the sanity checks:
+       MTOOLS_SKIP_CHECK=1
+
+   Global variables may also be set via the environment:
+       export MTOOLS_SKIP_CHECK=1
+
+   Global string variables may be set to any value:
+`MTOOLS_DATE_STRING'
+     The format used for printing dates of files.  By default, is
+     dd-mm-yyyy.
+
+\1f
+File: mtools.info,  Node: per drive variables,  Next: parsing order,  Prev: global variables,  Up: Configuration
+
+3.5 Per drive flags and variables
+=================================
+
+* Menu:
+
+* general information::   What a drive description looks like
+* location information::  Where is the drive data physically stored
+* geometry description::  Describes the physical characteristics of
+                          the media
+* open flags::            Flags passed to the open system call when the
+                          device is opened
+* misc variables::        Variables which don't fit in either category
+* misc flags::           Switch variables, which can be enabled or disabled
+* multiple descriptions:: How to supply several descriptions for a
+                          drive, to be tried one after the other.
+
+\1f
+File: mtools.info,  Node: general information,  Next: location information,  Prev: per drive variables,  Up: per drive variables
+
+3.5.1 General information
+-------------------------
+
+Per drive flags and values may be described in a drive section. A drive
+section starts with `drive' "DRIVELETTER" :
+
+   Then follow variable-value pairs and flags.
+
+   This is a sample drive description:
+       drive a:
+         file="/dev/fd0" use_xdf=1
+
+\1f
+File: mtools.info,  Node: location information,  Next: geometry description,  Prev: general information,  Up: per drive variables
+
+3.5.2 Location information
+--------------------------
+
+For each drive, you need to describe where its data is physically
+stored (imag file, physical device, partition, offset).
+
+`file'
+     The name of the file or device holding the disk image. This is
+     mandatory. The file name should be enclosed in quotes.
+
+`partition'
+     Tells mtools to treat the drive as a partitioned device, and to
+     use the given partition. Only primary partitions are accessible
+     using this method, and they are numbered from 1 to 4. For logical
+     partitions, use the more general `offset' variable. The
+     `partition' variable is intended for removable media such as
+     Syquests, ZIP drives, and magneto-optical disks. Although
+     traditional DOS sees Syquests and magneto-optical disks as `giant
+     floppy disks' which are unpartitioned, OS/2 and Windows NT treat
+     them like hard disks, i.e. partioned devices. The `partition' flag
+     is also useful DOSEMU hdimages. It is not recommended for hard
+     disks for which direct access to partitions is available through
+     mounting.
+
+`offset'
+     Describes where in the file the MS-DOS filesystem starts. This is
+     useful for logical partitions in DOSEMU hdimages, and for ATARI
+     ram disks. By default, this is zero, meaning that the filesystem
+     starts right at the beginning of the device or file.
+
+\1f
+File: mtools.info,  Node: geometry description,  Next: open flags,  Prev: location information,  Up: per drive variables
+
+3.5.3 Disk Geometry Configuration
+---------------------------------
+
+Geometry information describes the physical characteristics about the
+disk. Its has three purposes:
+
+formatting
+     The geometry information is written into the boot sector of the
+     newly made disk. However, you may also describe the geometry
+     information on the command line. *Note mformat::, for details.
+
+filtering
+     On some Unices there are device nodes which only support one
+     physical geometry. For instance, you might need a different node
+     to access a disk as high density or as low density. The geometry
+     is compared to the actual geometry stored on the boot sector to
+     make sure that this device node is able to correctly read the
+     disk. If the geometry doesn't match, this drive entry fails, and
+     the next drive entry bearing the same drive letter is tried. *Note
+     multiple descriptions::, for more details on supplying several
+     descriptions for one drive letter.
+
+     If no geometry information is supplied in the configuration file,
+     all disks are accepted. On Linux (and on Sparc) there exist device
+     nodes with configurable geometry (`/dev/fd0', `/dev/fd1' etc), and
+     thus filtering is not needed (and ignored) for disk drives.
+     (Mtools still does do filtering on plain files (disk images) in
+     Linux: this is mainly intended for test purposes, as I don't have
+     access to a Unix which would actually need filtering).
+
+     If you do not need filtering, but want still a default geometry for
+     mformatting, you may switch off filtering using the `mformat_only'
+     flag.
+
+     If you want filtering, you should supply the `filter' flag.  If you
+     supply a geometry, you must supply one of both flags.
+
+initial geometry
+     On devices that support it (usually floppy devices), the geometry
+     information is also used to set the initial geometry. This initial
+     geometry is applied while reading the boot sector, which contains
+     the real geometry.  If no geometry information is supplied in the
+     configuration file, or if the `mformat_only' flag is supplied, no
+     initial configuration is done.
+
+     On Linux, initial geometry is not really needed, as the
+     configurable devices are able to auto-detect the disk type
+     accurately enough (for most common formats) to read the boot
+     sector.
+
+   Wrong geometry information may lead to very bizarre errors. That's
+why I strongly recommend that you add the `mformat_only' flag to your
+drive description, unless you really need filtering or initial geometry.
+
+   The following geometry related variables are available:
+
+`cylinders'
+`tracks'
+     The number of cylinders. (`cylinders' is the preferred form,
+     `tracks' is considered obsolete)
+
+`heads'
+     The number of heads (sides).
+
+`sectors'
+     The number of sectors per track.
+
+   Example: the following drive section describes a 1.44M drive:
+
+       drive a:
+           file="/dev/fd0H1440"
+           fat_bits=12
+           cylinders=80 heads=2 sectors=18
+           mformat_only
+
+   The following shorthand geometry descriptions are available:
+
+`1.44m'
+     high density 3 1/2 disk. Equivalent to: `fat_bits=12 cylinders=80
+     heads=2 sectors=18'
+
+`1.2m'
+     high density 5 1/4 disk. Equivalent to: `fat_bits=12 cylinders=80
+     heads=2 sectors=15'
+
+`720k'
+     double density 3 1/2 disk. Equivalent to: `fat_bits=12
+     cylinders=80 heads=2 sectors=9'
+
+`360k'
+     double density 5 1/4 disk. Equivalent to: `fat_bits=12
+     cylinders=40 heads=2 sectors=9'
+
+   The shorthand format descriptions may be amended. For example, `360k
+sectors=8' describes a 320k disk and is equivalent to: `fat_bits=12
+cylinders=40 heads=2 sectors=8'
+
+\1f
+File: mtools.info,  Node: open flags,  Next: misc variables,  Prev: geometry description,  Up: per drive variables
+
+3.5.4 Open Flags
+----------------
+
+Moreover, the following flags are available:
+
+`sync'
+     All i/o operations are done synchronously
+
+`nodelay'
+     The device or file is opened with the O_NDELAY flag. This is
+     needed on some non-Linux architectures.
+
+`exclusive'
+     The device or file is opened with the O_EXCL flag. On Linux, this
+     ensures exclusive access to the floppy drive. On most other
+     architectures, and for plain files it has no effect at all.
+
+\1f
+File: mtools.info,  Node: misc variables,  Next: misc flags,  Prev: open flags,  Up: per drive variables
+
+3.5.5 General Purpose Drive Variables
+-------------------------------------
+
+The following general purpose drive variables are available.  Depending
+to their type, these variables can be set to a string (precmd) or an
+integer (all others)
+
+`fat_bits'
+     The number of FAT bits. This may be 12 or 16. This is very rarely
+     needed, as it can almost always be deduced from information in the
+     boot sector. On the contrary, describing the number of fat bits may
+     actually be harmful if you get it wrong. You should only use it if
+     mtools gets the autodetected number of fat bits wrong, or if you
+     want to mformat a disk with a weird number of fat bits.
+
+`codepage'
+     Describes the DOS codepage used for short filenames. This is a
+     number between 1 and 999. By default, codepage 850 is used. The
+     reason for this is because this codepage contains most of the
+     characters that are also available in ISO-Latin-1. You may also
+     specify a global codepage for all drives by using the global
+     `default_codepage' parameter (outside of any drive description).
+     This parameters exists starting at version 4.0.0
+
+`precmd'
+     On some variants of Solaris, it is necessary to call 'volcheck -v'
+     before opening a floppy device, in order for the system to notice
+     that there is indeed a disk in the drive. `precmd="volcheck -v"'
+     in the drive clause establishes the desired behavior.
+
+`blocksize'
+     This parameter represents a default block size to be always used
+     on this device.  All I/O is done with multiples of this block size,
+     independantly of the sector size registered in the filesystem's
+     boot sector.  This is useful for character devices whose sector
+     size is not 512, such as for example CD Rom drives on Solaris.
+
+
+   Only the `file' variable is mandatory. The other parameters may be
+left out. In that case a default value or an autodetected value is used.
+
+\1f
+File: mtools.info,  Node: misc flags,  Next: multiple descriptions,  Prev: misc variables,  Up: per drive variables
+
+3.5.6 General Purpose Drive Flags
+---------------------------------
+
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+ommitted, it is enabled.  For example, `scsi' is equivalent to `scsi=1'
+
+`nolock'
+     Instruct mtools to not use locking on this drive.  This is needed
+     on systems with buggy locking semantics.  However, enabling this
+     makes operation less safe in cases where several users may access
+     the same drive at the same time.
+
+`scsi'
+     When set to 1, this option tells mtools to use raw SCSI I/O
+     instead of the standard read/write calls to access the device.
+     Currently, this is supported on HP/UX, Solaris and SunOs.  This is
+     needed because on some architectures, such as SunOs or Solaris, PC
+     media can't be accessed using the `read' and `write' syscalls,
+     because the OS expects them to contain a Sun specific "disk label".
+
+     As raw Scsi access always uses the whole device, you need to
+     specify the "partition" flag in addition
+
+     On some architectures, such as Solaris, mtools needs root
+     privileges to be able to use the `scsi' option.  Thus mtools
+     should be installed set uid root on Solaris if you want to access
+     Zip/Jaz drives.  Thus, if the `scsi' flag is given, `privileged'
+     is automatically implied, unless explicitly disabled by
+     `privileged=0'
+
+     Mtools uses its root privileges to open the device, and to issue
+     the actual SCSI I/O calls.  Moreover, root privileges are only
+     used for drives described in a system-wide configuration file such
+     as `/usr/local/etc/mtools.conf', and not for those described in
+     `~/.mtoolsrc' or `$MTOOLSRC'.
+
+`privileged'
+     When set to 1, this instructs mtools to use its set-uid and set-gid
+     privileges for opening the given drive.  This option is only valid
+     for drives described in the system-wide configuration files (such
+     as `/usr/local/etc/mtools.conf', not `~/.mtoolsrc' or
+     `$MTOOLSRC').  Obviously, this option is also a no op if mtools is
+     not installed setuid or setgid.  This option is implied by
+     'scsi=1', but again only for drives defined in system-wide
+     configuration files.  Privileged may also be set explicitely to 0,
+     in order to tell mtools not to use its privileges for a given
+     drive even if `scsi=1' is set.
+
+     Mtools only needs to be installed setuid if you use the
+     `privileged' or `scsi' drive variables.  If you do not use these
+     options, mtools works perfectly well even when not installed
+     setuid root.
+
+`vold'
+     Instructs mtools to interpret the device name as a vold identifier
+     rather than as a filename.  The vold identifier is translated into
+     a real filename using the `media_findname()' and
+     `media_oldaliases()' functions of the `volmgt' library.  This flag
+     is only available if you configured mtools with the
+     `--enable-new-vold' option before compilation.
+
+`swap'
+     Consider the media as a word-swapped Atari disk.
+
+`use_xdf'
+     If this is set to a non-zero value, mtools also tries to access
+     this disk as an XDF disk. XDF is a high capacity format used by
+     OS/2. This is off by default. *Note XDF::, for more details.
+
+`mformat_only'
+     Tells mtools to use the geometry for this drive only for
+     mformatting and not for filtering.
+
+`filter'
+     Tells mtools to use the geometry for this drive both for
+     mformatting and filtering.
+
+`remote'
+     Tells mtools to connect to floppyd (*note floppyd::).
+
+\1f
+File: mtools.info,  Node: multiple descriptions,  Prev: misc flags,  Up: per drive variables
+
+3.5.7 Supplying multiple descriptions for a drive
+-------------------------------------------------
+
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that fits.
+Descriptions may fail for several reasons:
+
+  1. because the geometry is not appropriate,
+
+  2. because there is no disk in the drive,
+
+  3. or because of other problems.
+
+   Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry.  Example:
+       drive a: file="/dev/fd0H1440" 1.44m
+       drive a: file="/dev/fd0H720" 720k
+
+   This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+
+   You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+
+       drive z: file="/dev/fd0"
+       drive z: file="/dev/fd1"
+
+   With this description, `mdir z:' accesses your first physical drive
+if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+
+   When using multiple configuration files, drive descriptions in the
+files parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the `drive+' or `+drive' keywords
+instead of `drive'. The first adds a description to the end of the list
+(i.e. it will be tried last), and the first adds it to the start of the
+list.
+
+\1f
+File: mtools.info,  Node: parsing order,  Next: old style config,  Prev: per drive variables,  Up: Configuration
+
+3.6 Location of configuration files and parsing order
+=====================================================
+
+The configuration files are parsed in the following order:
+  1. compiled-in defaults
+
+  2. `/usr/local/etc/mtools.conf'
+
+  3. `/etc/mtools' This is for backwards compatibility only, and is
+     only parsed if `mtools.conf' doesn't exist.
+
+  4. `~/.mtoolsrc'.
+
+  5. `$MTOOLSRC' (file pointed by the `MTOOLSRC' environmental variable)
+
+   Options described in the later files override those described in the
+earlier files. Drives defined in earlier files persist if they are not
+overridden in the later files. For instance, drives A and B may be
+defined in `/usr/local/etc/mtools.conf' and drives C and D may be
+defined in `~/.mtoolsrc' However, if `~/.mtoolsrc' also defines drive
+A, this new description would override the description of drive A in
+`/usr/local/etc/mtools.conf' instead of adding to it. If you want to
+add a new description to a drive already described in an earlier file,
+you need to use either the `+drive' or `drive+' keyword.
+
+\1f
+File: mtools.info,  Node: old style config,  Prev: parsing order,  Up: Configuration
+
+3.7 Backwards compatibility with old configuration file syntax
+==============================================================
+
+The syntax described herein is new for version `mtools-3.0'. The old
+line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+
+\1f
+File: mtools.info,  Node: Commands,  Next: Compiling mtools,  Prev: Configuration,  Up: Top
+
+4 Command list
+**************
+
+This section describes the available mtools commands, and the command
+line parameters that each of them accepts. Options which are common to
+all mtools commands are not described here, *note arguments:: for a
+description of those.
+
+* Menu:
+
+* floppyd::           floppy daemon to run on your X server box
+* floppyd_installtest:: small utility to check for the presence of floppyd
+* mattrib::           change MS-DOS file attribute flags
+* mbadblocks::        tests a floppy disk, and marks the bad blocks in the FAT
+* mcat::              same as cat. Only usefull with floppyd.
+* mcd::               change MS-DOS directory
+* mclasserase::       erase memory card
+* mcopy::             copy MS-DOS files to/from Unix
+* mdel::              delete an MS-DOS file
+* mdeltree::          recursively delete an MS-DOS directory
+* mdir::              display an MS-DOS directory
+* mdu::               list space occupied by directory and its contents
+* mformat::           add an MS-DOS filesystem to a low-level formatted floppy disk
+* minfo::             get information about an MS-DOS filesystem.
+* mlabel::            make an MS-DOS volume label
+* mkmanifest::        makes a list of short name equivalents
+* mmd::               make an MS-DOS subdirectory
+* mmount::            mount an MS-DOS disk
+* mpartition::        create an MS-DOS as a partition
+* mrd::               remove an MS-DOS subdirectory
+* mmove::             move or rename an MS-DOS file or subdirectory
+* mren::              rename an existing MS-DOS file
+* mshowfat::          shows the FAT map of a file
+* mtoolstest::        tests and displays the configuration
+* mtype::             display contents of an MS-DOS file
+* mzip::              zip disk specific commands
+
+\1f
+File: mtools.info,  Node: floppyd,  Next: floppyd_installtest,  Prev: Commands,  Up: Commands
+
+4.1 Floppyd
+===========
+
+`Floppyd' is used as a server to grant access to the floppy drive to
+clients running on a remote machine, just as an X server grants access
+to the display to remote clients.  It has the following syntax:
+
+   `floppyd' [`-d'] [`-l'] [`-s' PORT] [`-r' USER] [`-b' IPADDR] [`-x'
+DISPLAY] DEVICENAMES
+
+   `floppyd' is always associated with an X server.  It runs on the
+same machine as its X server, and listens on port 5703 and above.
+
+4.1.1 Authentication
+--------------------
+
+`floppyd' authenticates remote clients using the `Xauthority' protocol.
+Xhost authentication is not supported. Each floppyd is associated with
+an X server.  When a remote client attempts to connect to floppyd, it
+sends floppyd the X authority record corresponding to floppyd's X
+server.  Floppyd in turn then tries to open up a connection to the X
+server in order to verify the authenticity of the xauth record.  If the
+connection to the X server succeeds, the client is granted access.
+`DISPLAY'.
+
+   *Caution*: In order to make authentication work correctly, the local
+host should *not* be listed in the `xhost' list of allowed hosts.
+Indeed, hosts listed in `xhost' do not need a correct `Xauthority'
+cookie to connect to the X server. As `floppyd' runs on the same host
+as the X server, all its probe connection would succeed even for
+clients who supplied a bad cookie.  This means that your floppy drive
+would be open to the world, i.e. a huge security hole.   If your X
+server does not allow you to remove `localhost:0' and `:0' from the
+`xhost' list, you can prevent floppyd from probing those display names
+with the `-l' option.
+
+4.1.2 Command line options
+--------------------------
+
+`d'
+     Daemon mode. Floppyd runs its own server loop.  Do not supply this
+     if you start floppyd from `inetd.conf'
+
+`s  PORT'
+     Port number for deamon mode.  Default is 5703 + DISPLAYNUMBER.
+     This flag implies daemon mode.  For example, for display
+     `hitchhiker:5', the port would be 5708.
+
+`b  IPADDR'
+     Bind address (for multihomed hosts). This flag implies daemon mode
+
+`r USER'
+     Run the server under as the given user
+
+`x DISPLAY'
+     X display to use for authentication. By default, this is taken
+     from the `DISPLAY' variable. If neither the `x' attribute is
+     present nor `DISPLAY' is set, floppyd uses `:0.0'.
+
+   DEVICENAMES is a list of device nodes to be opened.  Default is
+`/dev/fd0'. Multiple devices are only supported on mtools versions
+newer than 3.9.11.
+
+4.1.3 Connecting to floppyd
+---------------------------
+
+In order to use floppyd, add the flag `remote' to the device
+description in your `~/.mtoolsrc' file.  If the flag `remote' is given,
+the `file' parameter of the device description is taken to be a remote
+address.  It's format is the following:
+HOSTNAME`:'DISPLAYNUMBER[`/'[BASEPORT][`/'DRIVE]]. When using this
+entry, mtools connects to port BASEPORT+DISPLAYNUMBER at HOSTNAME. By
+default BASEPORT is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+
+4.1.4 Examples:
+---------------
+
+The following starts a floppy daemon giving access to `/dev/fd0',
+listening on the default port 5703, tied to the default X servers:
+
+     floppyd -d /dev/fd0
+
+   Each of the following starts a floppy daemon giving access to
+`/dev/fd1', tied to the :1 local X servers, and listening on port 5704.
+We assume that the local host is named `hitchhiker'.
+
+     floppyd -d /dev/fd0
+     floppyd -d -x :1 -p 5704 /dev/fd0
+
+   If you want to start floppyd by `inetd' instead of running it as a
+daemon, insert the following lines into `/etc/services':
+     # floppy daemon
+     floppyd-0    5703/tcp    # floppy daemon for X server :0
+     floppyd-1    5704/tcp    # floppy daemon for X server :1
+
+   And insert the following into `/etc/inetd.conf' (assuming that you
+have defined a user named floppy in your `/etc/passwd'):
+
+     # floppy daemon
+     floppyd-0 stream  tcp  wait  floppy  /usr/sbin/floppyd floppyd /dev/fd0
+     floppyd-1 stream  tcp  wait  floppy  /usr/sbin/floppyd floppyd -x :1 /dev/fd0
+
+   Note that you need to supply the X display names for the second
+floppyd.  This is because the port is opened by inetd.conf, and hence
+floppyd cannot know its number to interfere the display number.
+
+   On the client side, insert the following into your `~/.mtoolsrc' to
+define a drive letter accessing floppy drive in your X terminal:
+     drive x: file="$DISPLAY" remote
+
+   If your X terminal has more than one drive, you may access the
+additional drives as follows:
+     drive y: file="$DISPLAY//1" remote
+     drive z: file="$DISPLAY//2" remote
+
+\1f
+File: mtools.info,  Node: floppyd_installtest,  Next: mattrib,  Prev: floppyd,  Up: Commands
+
+4.2 Floppyd_installtest
+=======================
+
+`Floppyd_installtest' is used to check for the presence of a running
+floppyd daemon. This is usefull, if you have a small frontend script to
+mtools, which decides whether to use floppyd or not.
+
+   `floppyd_installtest' [`-f']  Connect-String
+
+   If the `-f' option is specified, `floppyd_installtest' does a full
+X-Cookie authentication and complains if this does not work.
+
+   The connect-String has the format described in the floppyd-section:
+HOSTNAME`:'DISPLAYNUMBER[`/'BASEPORT]
+
+\1f
+File: mtools.info,  Node: mattrib,  Next: mbadblocks,  Prev: floppyd_installtest,  Up: Commands
+
+4.3 Mattrib
+===========
+
+`Mattrib' is used to change MS-DOS file attribute flags. It has the
+following syntax:
+
+   `mattrib' [`-a|+a'] [`-h|+h'] [`-r|+r'] [`-s|+s'] [`-/']  [`-p']
+[`-X'] MSDOSFILE [ MSDOSFILES ... ]
+
+   `Mattrib' adds attribute flags to an MS-DOS file (with the ``+''
+operator) or remove attribute flags (with the ``-'' operator).
+
+   `Mattrib' supports the following attribute bits:
+
+`a'
+     Archive bit.  Used by some backup programs to indicate a new file.
+
+`r'
+     Read-only bit.  Used to indicate a read-only file.  Files with
+     this bit set cannot be erased by `DEL' nor modified.
+
+`s'
+     System bit.  Used by MS-DOS to indicate a operating system file.
+
+`h'
+     Hidden bit.  Used to make files hidden from `DIR'.
+
+   `Mattrib' supports the following command line flags:
+`/'
+     Recursive.  Recursively list the attributes of the files in the
+     subdirectories.
+
+`X'
+     Concise. Prints the attributes whithout any whitespace padding.  If
+     neither the "/" option is given, nor the MSDOSFILE contains a
+     wildcard, and there is only one Msdos file parameter on the command
+     line, only the attribute is printed, and not the filename.  This
+     option is convenient for scripts
+
+`p'
+     Replay mode.  Outputs a series of mformat commands that will
+     reproduce the current situation, starting from a situation as left
+     by untarring the Dos filesystem.  Commands are only output for
+     attribute settings that differ from the default (archive bit set
+     for files, unset for directories).  This option is intended to be
+     used in addition to tar. The `readonly' attribute is not taken
+     into account, as tar can set that one itself.
+
+\1f
+File: mtools.info,  Node: mbadblocks,  Next: mcat,  Prev: mattrib,  Up: Commands
+
+4.4 Mbadblocks
+==============
+
+The `mbadblocks' command is used to scan an MS-DOS floppy and mark its
+unused bad blocks as bad. It uses the following syntax:
+
+   `mbadblocks' DRIVE`:' 
+
+   `Mbadblocks' scans an MS-DOS floppy for bad blocks. All unused bad
+blocks are marked as such in the FAT. This is intended to be used right
+after `mformat'.  It is not intended to salvage bad disks.
+
+4.4.1 Bugs
+----------
+
+`Mbadblocks' should (but doesn't yet :-( ) also try to salvage bad
+blocks which are in use by reading them repeatedly, and then mark them
+bad.
+
+\1f
+File: mtools.info,  Node: mcat,  Next: mcd,  Prev: mbadblocks,  Up: Commands
+
+4.5 Mcat
+========
+
+The `mcat' command is used to copy an entire disk image from or to the
+floppy device. It uses the following syntax:
+
+   `mcat' [`-w'] DRIVE`:' 
+
+   `Mcat' performs the same task as the unix `cat' command. It is
+included into the mtools package, since `cat' cannot access remote
+floppy devices offered by the mtools floppy daemon.  Now it is possible
+to create boot floppies remotely.
+
+   The default operation is reading. The output is written to stdout.
+
+   If the `-w' option is specified, mcat reads a disk-image from stdin
+and writes it to the given device.  *Use this carefully!* Because of
+the lowlevel nature of this command, it will happily destroy any data
+written before on the disk without warning!
+
+\1f
+File: mtools.info,  Node: mcd,  Next: mclasserase,  Prev: mcat,  Up: Commands
+
+4.6 Mcd
+=======
+
+The `mcd' command is used to change the mtools working directory on the
+MS-DOS disk. It uses the following syntax:
+
+     `mcd' [MSDOSDIRECTORY]
+
+   Without arguments, `mcd' reports the current device and working
+directory.  Otherwise, `mcd' changes the current device and current
+working directory relative to an MS-DOS filesystem.
+
+   The environmental variable `MCWD' may be used to locate the file
+where the device and current working directory information is stored.
+The default is `$HOME/.mcwd'.  Information in this file is ignored if
+the file is more than 6 hours old.
+
+   `Mcd' returns 0 on success or 1 on failure.
+
+   Unlike MS-DOS versions of `CD', `mcd' can be used to change to
+another device. It may be wise to remove old `.mcwd' files at logout.
+
+\1f
+File: mtools.info,  Node: mclasserase,  Next: mcopy,  Prev: mcd,  Up: Commands
+
+4.7 Mclasserase
+===============
+
+The `mclasserase' command is used to wipe memory cards by overwriting
+it three times: first with `0xff', then with `0x00', then with `0xff'
+again. The command uses the following syntax:
+
+     `mclasserase' [`-d'] MSDOSDRIVE
+
+   Dos drive is optional, if none is specified, use `A:'. If more than
+one drive are specified, all but the last are ignored.
+
+   `Mclasserase' accepts the following command line options:
+
+`d'
+     Stop after each erase cycle, for testing purposes
+
+`p'
+     Not yet implemented
+
+   `Mclasserase' returns 0 on success or -1 on failure.
+
+\1f
+File: mtools.info,  Node: mcopy,  Next: mdel,  Prev: mclasserase,  Up: Commands
+
+4.8 Mcopy
+=========
+
+The `mcopy' command is used to copy MS-DOS files to and from Unix. It
+uses the following syntax:
+
+     `mcopy' [`-bspanvmQT'] [`-D' CLASH_OPTION] SOURCEFILE TARGETFILE
+     `mcopy' [`-bspanvmQT'] [`-D' CLASH_OPTION] SOURCEFILE [ SOURCEFILES... ] TARGETDIRECTORY
+     `mcopy' [`-tnvm'] MSDOSSOURCEFILE
+
+   `Mcopy' copies the specified file to the named file, or copies
+multiple files to the named directory.  The source and target can be
+either MS-DOS or Unix files.
+
+   The use of a drive letter designation on the MS-DOS files, 'a:' for
+example, determines the direction of the transfer.  A missing drive
+designation implies a Unix file whose path starts in the current
+directory.  If a source drive letter is specified with no attached file
+name (e.g. `mcopy a: .'), all files are copied from that drive.
+
+   If only a single, MS-DOS source parameter is provided (e.g. "mcopy
+a:foo.exe"), an implied destination of the current directory (``.'') is
+assumed.
+
+   A filename of ``-'' means standard input or standard output,
+depending on its position on the command line.
+
+   `Mcopy' accepts the following command line options:
+
+`t'
+     Text file transfer.  Mcopy translates incoming carriage return/line
+     feeds to line feeds when copying from Dos to Unix, and vice-versa
+     when copying from Unix to Dos.
+
+`b'
+     Batch mode. Optimized for huge recursive copies, but less secure
+     if a crash happens during the copy.
+
+`s'
+     Recursive copy.  Also copies directories and their contents
+
+`p'
+     Preserves the attributes of the copied files
+
+`Q'
+     When mcopying multiple files, quits as soon as one copy fails (for
+     example due to lacking storage space on the target disk)
+
+`a'
+     Text (Ascii) file transfer.  `Mcopy' translates incoming carriage
+     return/line feeds to line feeds.
+
+`T'
+     Text (Ascii) file transfer with charset conversion.  Differs from
+     `-a' in the `Mcopy' also translates incoming PC-8 characters to
+     ISO-8859-1 equivalents as far as possible.  When reading DOS files,
+     untranslatable characters are replaced by '`#''; when writing DOS
+     files, untranslatable characters are replaced by '`.''.
+
+`n'
+     No confirmation when overwriting Unix files.  `Mcopy' doesn't warn
+     the user when overwriting an existing Unix file. If the target
+     file already exists, and the `-n' option is not in effect, `mcopy'
+     asks whether to overwrite the file or to rename the new file
+     (*note name clashes::) for details).  In order to switch off
+     confirmation for DOS files, use `-o'.
+
+`m'
+     Preserve the file modification time.
+
+`v'
+     Verbose. Displays the name of each file as it is copied.
+
+4.8.1 Bugs
+----------
+
+Unlike MS-DOS, the '+' operator (append) from MS-DOS is not supported.
+However, you may use `mtype' to produce the same effect:
+     mtype a:file1 a:file2 a:file3 >unixfile
+     mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile
+
+\1f
+File: mtools.info,  Node: mdel,  Next: mdeltree,  Prev: mcopy,  Up: Commands
+
+4.9 Mdel
+========
+
+The `mdel' command is used to delete an MS-DOS file. Its syntax is:
+
+     `mdel' [`-v'] MSDOSFILE [ MSDOSFILES ...  ]
+
+   `Mdel' deletes files on an MS-DOS filesystem.
+
+   `Mdel' asks for verification prior to removing a read-only file.
+
+\1f
+File: mtools.info,  Node: mdeltree,  Next: mdir,  Prev: mdel,  Up: Commands
+
+4.10 Mdeltree
+=============
+
+The `mdeltree' command is used to delete an MS-DOS file. Its syntax is:
+
+     `mdeltree' [`-v'] MSDOSDIRECTORY [MSDOSDIRECTORIES...]
+
+   `Mdeltree' removes a directory and all the files and subdirectories
+it contains from an MS-DOS filesystem. An error occurs if the directory
+to be removed does not exist.
+
+\1f
+File: mtools.info,  Node: mdir,  Next: mdu,  Prev: mdeltree,  Up: Commands
+
+4.11 Mdir
+=========
+
+The `mdir' command is used to display an MS-DOS directory. Its syntax
+is:
+
+   `mdir' [`-/'] [`-f'] [`-w'] [`-a'] [`-b'] MSDOSFILE [ MSDOSFILES...]
+
+   `Mdir' displays the contents of MS-DOS directories, or the entries
+for some MS-DOS files.
+
+   `Mdir' supports the following command line options:
+
+`/'
+     Recursive output, just like Dos' `-s' option
+
+`w'
+     Wide output.  With this option, `mdir' prints the filenames across
+     the page without displaying the file size or creation date.
+
+`a'
+     Also list hidden files.
+
+`f'
+     Fast.  Do not try to find out free space.  On larger disks,
+     finding out the amount of free space takes up some non trivial
+     amount of time, as the whole FAT must be read in and scanned.  The
+     `-f' flag bypasses this step.  This flag is not needed on FAT32
+     filesystems, which store the size explicitely.
+
+`b'
+     Concise listing. Lists each directory name or filename, one per
+     line (including the filename extension). This switch displays no
+     heading information and no summary. Only a newline separated list
+     of pathnames is displayed.
+
+   An error occurs if a component of the path is not a directory.
+
+\1f
+File: mtools.info,  Node: mdu,  Next: mformat,  Prev: mdir,  Up: Commands
+
+4.12 Mdu
+========
+
+`Mdu' is used to list the space occupied by a directory, its
+subdirectories and its files. It is similar to the `du' command on
+Unix.  The unit used are clusters.  Use the minfo command to find out
+the cluster size.
+
+   `mdu' [`-a'] [ MSDOSFILES ... ]
+
+`a'
+     All files.  List also the space occupied for individual files.
+
+`s'
+     Only list the total space, don't give details for each
+     subdirectory.
+
+\1f
+File: mtools.info,  Node: mformat,  Next: mkmanifest,  Prev: mdu,  Up: Commands
+
+4.13 Mformat
+============
+
+The `mformat' command is used to add an MS-DOS filesystem to a
+low-level formatted diskette. Its syntax is:
+
+     `mformat' [`-t' CYLINDERS] [`-h' HEADS] [`-s' SECTORS]
+       [`-f' SIZE] [`-1'] [`-4'] [`-8']
+       [`-v' VOLUME_LABEL]
+       [`-F'] [`-S' SIZECODE] [`-X']
+       [`-2' SECTORS_ON_TRACK_0] [`-3']
+       [`-0' RATE_ON_TRACK_0] [`-A' RATE_ON_OTHER_TRACKS]
+       [`-M' SOFTWARE_SECTOR_SIZE]
+       [`-N' SERIAL_NUMBER] [`-a']
+       [`-C'] [`-H' HIDDEN_SECTORS] [`-I' FSVERSION]
+       [`-r' ROOT_SECTORS] [`-L' FAT_LEN]
+       [`-B' BOOT_SECTOR] [`-k']
+       [`-m' MEDIA_DESCRIPTOR]
+       DRIVE:
+
+   `Mformat' adds a minimal MS-DOS filesystem (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+
+   The following options are supported: (The S, 2, 1 and M options may
+not exist if this copy of mtools has been compiled without the USE_2M
+option)
+
+   The following options are the same as for Dos's format command:
+
+`v'
+     Specifies the volume label. A volume label identifies the disk and
+     can be a maximum of 11 characters. If you omit the -v switch,
+     mlabel will assign no label to the disk.
+
+`f'
+     Specifies the size of the DOS filesystem to format. Only a certain
+     number of predefined sizes are supported by this flag; for others
+     use the -h/-t/-s flags. The following sizes are supported:
+    160
+          160K, single-sided, 8 sectors per track, 40 cylinders (for 5
+          1/4 DD)
+
+    180
+          160K, single-sided, 9 sectors per track, 40 cylinders (for 5
+          1/4 DD)
+
+    320
+          320K, double-sided, 8 sectors per track, 40 cylinders (for 5
+          1/4 DD)
+
+    360
+          360K, double-sided, 9 sectors per track, 40 cylinders (for 5
+          1/4 DD)
+
+    720
+          720K, double-sided, 9 sectors per track, 80 cylinders (for 3
+          1/2 DD)
+
+    1200
+          1200K, double-sided, 15 sectors per track, 80 cylinders (for
+          5 1/4 HD)
+
+    1440
+          1440K, double-sided, 18 sectors per track, 80 cylinders (for
+          3 1/2 HD)
+
+    2880
+          2880K, double-sided, 36 sectors per track, 80 cylinders (for
+          3 1/2 ED)
+
+`t'
+     Specifies the number of tracks on the disk.
+
+`h'
+     The number of heads (sides).
+
+`n'
+     Specifies the number of sectors per track. If the 2m option is
+     given, number of 512-byte sector equivalents on generic tracks
+     (i.e. not head 0 track 0).  If the 2m option is not given, number
+     of physical sectors per track (which may be bigger than 512 bytes).
+
+`1'
+     Formats a single side (equivalent to -h 1)
+
+`4'
+     Formats a 360K double-sided disk (equivalent to -f 360). When used
+     together with -the 1 switch, this switch formats a 180K disk
+
+`8'
+     Formats a disk with 8 sectors per track.
+
+
+   MSDOS format's `q', `u' and `b' options are not supported, and `s'
+has a different meaning.
+
+   The following options are specific to mtools:
+
+`F'
+     Format the partition as FAT32.
+
+`S'
+     The sizecode. The size of the sector is 2 ^ (sizecode + 7).
+
+`X'
+     formats the disk as an XDF disk. *Note XDF::, for more details.
+     The disk has first to be low-level formatted using the xdfcopy
+     utility included in the fdutils package. XDF disks are used for
+     instance for OS/2 install disks.
+
+`2'
+     2m format. The parameter to this option describes the number of
+     sectors on track 0, head 0. This option is recommended for sectors
+     bigger than normal.
+
+`3'
+     don't use a 2m format, even if the current geometry of the disk is
+     a 2m geometry.
+
+`0'
+     Data transfer rate on track 0
+
+`A'
+     Data transfer rate on tracks other than 0
+
+`M'
+     software sector size. This parameter describes the sector size in
+     bytes used by the MS-DOS filesystem. By default it is the physical
+     sector size.
+
+`N'
+     Uses the requested serial number, instead of generating one
+     automatically
+
+`a'
+     If this option is given, an Atari style serial number is generated.
+     Ataris store their serial number in the OEM label.
+
+`C'
+     creates the disk image file to install the MS-DOS filesystem on
+     it. Obviously, this is useless on physical devices such as floppies
+     and hard disk partitions, but is interesting for image files.
+
+`H'
+     number of hidden sectors. This parameter is useful for formatting
+     hard disk partition, which are not aligned on track boundaries
+     (i.e. first head of first track doesn't belong to the partition,
+     but contains a partition table). In that case the number of hidden
+     sectors is in general the number of sectors per cylinder. This is
+     untested.
+
+`I'
+     Sets the fsVersion id when formatting a FAT32 drive.  In order to
+     find this out, run minfo on an existing FAT32 drive, and mail me
+     about it, so I can include the correct value in future versions of
+     mtools.
+
+`c'
+     Sets the size of a cluster (in sectors).  If this cluster size
+     would generate a FAT that too big for its number of bits, mtools
+     automatically increases the cluster size, until the FAT is small
+     enough.
+
+`d'
+     Sets the number of FAT copies. Default is 2. This setting can also
+     be specified using the `MTOOLS_NFATS' environment variable.
+
+`r'
+     Sets the size of the root directory (in sectors).  Only applicable
+     to 12 and 16 bit FATs. This setting can also be specified using the
+     `MTOOLS_DIR_LEN' environment variable.
+
+`L'
+     Sets the length of the FAT.
+
+`B'
+     Use the bootsector stored in the given file or device, instead of
+     using its own.  Only the geometry fields are updated to match the
+     target disks parameters.
+
+`k'
+     Keep the existing boot sector as much as possible.  Only the
+     geometry fields and other similar filesystem data are updated to
+     match the target disks parameters.
+
+`m'
+     Use a non-standard media descriptor byte for this disk. The media
+     descriptor is stored at position 21 of the boot sector, and as
+     first byte in each FAT copy. Using this option may confuse DOS or
+     older mtools version, and may make the disk unreadable. Only use
+     if you know what you are doing.
+
+
+   To format a diskette at a density other than the default, you must
+supply (at least) those command line parameters that are different from
+the default.
+
+   `Mformat' returns 0 on success or 1 on failure.
+
+   It doesn't record bad block information to the Fat, use `mbadblocks'
+for that.
+
+\1f
+File: mtools.info,  Node: mkmanifest,  Next: minfo,  Prev: mformat,  Up: Commands
+
+4.14 Mkmanifest
+===============
+
+The `mkmanifest' command is used to create a shell script (packing
+list) to restore Unix filenames. Its syntax is:
+
+   `mkmanifest' [ FILES ]
+
+   `Mkmanifest' creates a shell script that aids in the restoration of
+Unix filenames that got clobbered by the MS-DOS filename restrictions.
+MS-DOS filenames are restricted to 8 character names, 3 character
+extensions, upper case only, no device names, and no illegal characters.
+
+   The mkmanifest program is compatible with the methods used in
+`pcomm, arc,' and `mtools' to change perfectly good Unix filenames to
+fit the MS-DOS restrictions. This command is only useful if the target
+system which will read the diskette cannot handle vfat long names.
+
+4.14.1 Example
+--------------
+
+You want to copy the following Unix files to a MS-DOS diskette (using
+the `mcopy' command).
+
+       very_long_name
+       2.many.dots
+       illegal:
+       good.c
+       prn.dev
+       Capital
+
+   `Mcopy' converts the names to:
+
+       very_lon
+       2xmany.dot
+       illegalx
+       good.c
+       xprn.dev
+       capital
+
+   The command:
+     mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest
+   would produce the following:
+       mv very_lon very_long_name
+       mv 2xmany.dot 2.many.dots
+       mv illegalx illegal:
+       mv xprn.dev prn.dev
+       mv capital Capital
+
+   Notice that "good.c" did not require any conversion, so it did not
+appear in the output.
+
+   Suppose I've copied these files from the diskette to another Unix
+system, and I now want the files back to their original names.  If the
+file "manifest" (the output captured above) was sent along with those
+files, it could be used to convert the filenames.
+
+4.14.2 Bugs
+-----------
+
+The short names generated by `mkmanifest' follow the old convention
+(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0.
+
+\1f
+File: mtools.info,  Node: minfo,  Next: mlabel,  Prev: mkmanifest,  Up: Commands
+
+4.15 Minfo
+==========
+
+The `minfo' command prints the parameters of a Dos filesystem, such as
+number of sectors, heads and cylinders.  It also prints an mformat
+command line which can be used to create a similar Dos filesystem on
+another media.  However, this doesn't work with 2m or Xdf media, and
+with Dos 1.0 filesystems
+     `minfo' DRIVE:
+
+   Mlabel supports the following option:
+`v'
+     Prints a hexdump of the bootsector, in addition to the other
+     information
+
+\1f
+File: mtools.info,  Node: mlabel,  Next: mmd,  Prev: minfo,  Up: Commands
+
+4.16 Mlabel
+===========
+
+The `mlabel' command adds a volume label to a disk. Its syntax is:
+     `mlabel' [`-vcsn'] [`-N' SERIAL] DRIVE:[NEW_LABEL]
+
+   `Mlabel' displays the current volume label, if present. If NEW_LABEL
+is not given, and if neither the `c' nor the `s' options are set, it
+prompts the user for a new volume label.  To delete an existing volume
+label, press return at the prompt.
+
+   Reasonable care is taken to create a valid MS-DOS volume label.  If
+an invalid label is specified, `mlabel' changes the label (and displays
+the new label if the verbose mode is set). `Mlabel' returns 0 on
+success or 1 on failure.
+
+   Mlabel supports the following options:
+`c'
+     Clears an existing label, without prompting the user
+
+`s'
+     Shows the existing label, without prompting the user.
+
+`n'
+     Assigns a new (random) serial number to the disk
+
+`N SERIAL'
+     Sets the supplied serial number. The serial number should be
+     supplied as an 8 digit hexadecimal number, without spaces
+
+\1f
+File: mtools.info,  Node: mmd,  Next: mmount,  Prev: mlabel,  Up: Commands
+
+4.17 Mmd
+========
+
+The `mmd' command is used to make an MS-DOS subdirectory. Its syntax is:
+
+   `mmd' [`-D' CLASH_OPTION] MSDOSDIRECTORY [ MSDOSDIRECTORIES... ]
+
+   `Mmd' makes a new directory on an MS-DOS filesystem. An error occurs
+if the directory already exists.
+
+\1f
+File: mtools.info,  Node: mmount,  Next: mmove,  Prev: mmd,  Up: Commands
+
+4.18 Mmount
+===========
+
+The `mmount' command is used to mount an MS-DOS disk. It is only
+available on Linux, as it is only useful if the OS kernel allows to
+configure the disk geometry. Its syntax is:
+
+   `mmount' MSDOSDRIVE [MOUNTARGS]
+
+   `Mmount' reads the boot sector of an MS-DOS disk, configures the
+drive geometry, and finally mounts it passing `mountargs' to `mount. '
+If no mount arguments are specified, the name of the device is used. If
+the disk is write protected, it is automatically mounted read only.
+
+\1f
+File: mtools.info,  Node: mmove,  Next: mpartition,  Prev: mmount,  Up: Commands
+
+4.19 Mmove
+==========
+
+The `mmove' command is used to moves or renames an existing MS-DOS file
+or subdirectory.
+     `mmove' [`-v'] [`-D' CLASH_OPTION] SOURCEFILE TARGETFILE
+     `mmove' [`-v']  [`-D' CLASH_OPTION] SOURCEFILE [ SOURCEFILES... ] TARGETDIRECTORY
+   `Mmove' moves or renames an existing MS-DOS file or subdirectory.
+Unlike the MS-DOS version of `MOVE', `mmove' is able to move
+subdirectories.  Files or directories can only be moved within one
+filesystem. Data cannot be moved from Dos to Unix or vice-versa.  If
+you omit the drive letter from the target file or directory, the same
+letter as for the source is assumed.  If you omit the drive letter from
+all parameters, drive a: is assumed by default.
+
+\1f
+File: mtools.info,  Node: mpartition,  Next: mrd,  Prev: mmove,  Up: Commands
+
+4.20 Mpartition
+===============
+
+The `mpartition' command is used to create MS-DOS filesystems as
+partitions.  This is intended to be used on non-Linux systems, i.e.
+systems where fdisk and easy access to Scsi devices are not available.
+This command only works on drives whose partition variable is set.
+
+     `mpartition' `-p' DRIVE
+     `mpartition' `-r' DRIVE
+     `mpartition' `-I' [`-B' BOOTSECTOR] DRIVE
+     `mpartition' `-a' DRIVE
+     `mpartition' `-d' DRIVE
+     `mpartition' `-c' [`-s' SECTORS] [`-h' HEADS]
+     [`-t' CYLINDERS] [`-v' [`-T' TYPE] [`-b'
+     BEGIN] [`-l' length] [`-f']
+
+   Mpartition supports the following operations:
+
+`p'
+     Prints a command line to recreate the partition for the drive.
+     Nothing is printed if the partition for the drive is not defined,
+     or an inconsistency has been detected.  If verbose (`-v') is also
+     set, prints the current partition table.
+
+`r'
+     Removes the partition described by DRIVE.
+
+`I'
+     Initializes the partition table, and removes all partitions.
+
+`c'
+     Creates the partition described by DRIVE.
+
+`a'
+     "Activates" the partition, i.e. makes it bootable.  Only one
+     partition can be bootable at a time.
+
+`d'
+     "Desactivates" the partition, i.e. makes it unbootable.
+
+   If no operation is given, the current settings are printed.
+
+   For partition creations, the following options are available:
+`s SECTORS'
+     The number of sectors per track of the partition (which is also the
+     number of sectors per track for the whole drive).
+
+`h HEADS'
+     The number of heads of the partition (which is also the number of
+     heads for the whole drive).  By default, the geometry information
+     (number of sectors and heads) is figured out from neighbouring
+     partition table entries, or guessed from the size.
+
+`t CYLINDERS'
+     The number of cylinders of the partition (not the number of
+     cylinders of the whole drive.
+
+`b BEGIN'
+     The starting offset of the partition, expressed in sectors. If
+     begin is not given, mpartition lets the partition begin at the
+     start of the disk (partition number 1), or immediately after the
+     end of the previous partition.
+
+`l LENGTH'
+     The size (length) of the partition, expressed in sectors.  If end
+     is not given, mpartition figures out the size from the number of
+     sectors, heads and cylinders.  If these are not given either, it
+     gives the partition the biggest possible size, considering disk
+     size and start of the next partition.
+
+   The following option is available for all operation which modify the
+partition table:
+`f'
+     Usually, before writing back any changes to the partition,
+     mpartition performs certain consistenct checks, such as checking
+     for overlaps and proper alignment of the partitions.  If any of
+     these checks fails, the partition table is not changes.  The `-f'
+     allows you to override these safeguards.
+
+   The following options are available for all operations:
+`v'
+     Together with `-p' prints the partition table as it is now (no
+     change operation), or as it is after it is modified.
+
+`vv'
+     If the verbosity flag is given twice, mpartition will print out a
+     hexdump of the partition table when reading it from and writing it
+     to the device.
+
+   The following option is available for partition table initialization:
+`B BOOTSECTOR'
+     Reads the template master boot record from file BOOTSECTOR.
+
+\1f
+File: mtools.info,  Node: mrd,  Next: mren,  Prev: mpartition,  Up: Commands
+
+4.21 Mrd
+========
+
+The `mrd' command is used to remove an MS-DOS subdirectory. Its syntax
+is:
+
+     `mrd' [`-v'] MSDOSDIRECTORY [ MSDOSDIRECTORIES... ]
+
+   `Mrd' removes a directory from an MS-DOS filesystem. An error occurs
+if the directory does not exist or is not empty.
+
+\1f
+File: mtools.info,  Node: mren,  Next: mshowfat,  Prev: mrd,  Up: Commands
+
+4.22 Mren
+=========
+
+The `mren' command is used to rename or move an existing MS-DOS file or
+subdirectory. Its syntax is:
+
+     `mren' [`-voOsSrRA'] SOURCEFILE TARGETFILE
+
+   `Mren' renames an existing file on an MS-DOS filesystem.
+
+   In verbose mode, `Mren' displays the new filename if the name
+supplied is invalid.
+
+   If the first syntax is used (only one sourcefile), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+`mcd' directory as would be the case with `mmove'. Unlike the MS-DOS
+version of `REN', `mren' can be used to rename directories.
+
+\1f
+File: mtools.info,  Node: mshowfat,  Next: mtoolstest,  Prev: mren,  Up: Commands
+
+4.23 Mshowfat
+=============
+
+The `mshowfat' command is used to display the FAT entries for a file.
+Syntax:
+
+     `$ mshowfat files'
+
+\1f
+File: mtools.info,  Node: mtoolstest,  Next: mtype,  Prev: mshowfat,  Up: Commands
+
+4.24 Mtoolstest
+===============
+
+The `mtoolstest' command is used to tests the mtools configuration
+files. To invoke it, just type `mtoolstest' without any arguments.
+`Mtoolstest' reads the mtools configuration files, and prints the
+cumulative configuration to `stdout'. The output can be used as a
+configuration file itself (although you might want to remove redundant
+clauses).  You may use this program to convert old-style configuration
+files into new style configuration files.
+
+\1f
+File: mtools.info,  Node: mtype,  Next: mzip,  Prev: mtoolstest,  Up: Commands
+
+4.25 Mtype
+==========
+
+The `mtype' command is used to display contents of an MS-DOS file. Its
+syntax is:
+
+     `mtype' [`-ts'] MSDOSFILE [ MSDOSFILES... ]
+
+   `Mtype' displays the specified MS-DOS file on the screen.
+
+   In addition to the standard options, `Mtype' allows the following
+command line options:
+
+`t'
+     Text file viewing.  `Mtype' translates incoming carriage
+     return/line feeds to line feeds.
+
+`s'
+     `Mtype' strips the high bit from the data.
+
+   The `mcd' command may be used to establish the device and the
+current working directory (relative to MS-DOS), otherwise the default is
+`A:/'.
+
+   `Mtype' returns 0 on success, 1 on utter failure, or 2 on partial
+failure.
+
+   Unlike the MS-DOS version of `TYPE', `mtype' allows multiple
+arguments.
+
+\1f
+File: mtools.info,  Node: mzip,  Prev: mtype,  Up: Commands
+
+4.26 Mzip
+=========
+
+The `mzip' command is used to issue ZIP disk specific commands on
+Linux, Solaris or HPUX. Its syntax is:
+
+     `mzip' [`-epqrwx']
+
+   `Mzip' allows the following command line options:
+
+`e'
+     Ejects the disk.
+
+`f'
+     Force eject even if the disk is mounted (must be given in addition
+     to `-e').
+
+`r'
+     Write protect the disk.
+
+`w'
+     Remove write protection.
+
+`p'
+     Password write protect.
+
+`x'
+     Password protect
+
+`u'
+     Temporarily unprotect the disk until it is ejected.  The disk
+     becomes writable, and reverts back to its old state when ejected.
+
+`q'
+     Queries the status
+
+   To remove the password, set it to one of the passwordless modes `-r'
+or `-w': mzip will then ask you for the password, and unlock the disk.
+If you have forgotten the password, you can get rid of it by low-level
+formatting the disk (using your SCSI adaptor's BIOS setup).
+
+   The ZipTools disk shipped with the drive is also password protected.
+On Dos or on a Mac, this password is automatically removed once the
+ZipTools have been installed.  From various articles posted to Usenet, I
+learned that the password for the tools disk is
+`APlaceForYourStuff'(1).  Mzip knows about this password, and tries it
+first, before prompting you for a password.  Thus `mzip -w z:' unlocks
+the tools disk(2).  The tools disk is formatted in a special way so as
+to be usable both in a PC and in a Mac.  On a PC, the Mac filesystem
+appears as a hidden file named `partishn.mac'.  You may erase it to
+reclaim the 50 Megs of space taken up by the Mac filesystem.
+
+4.26.1 Bugs
+-----------
+
+This command is a big kludge.  A proper implementation would take a
+rework of significant parts of mtools, but unfortunately I don't have
+the time for this right now. The main downside of this implementation is
+that it is inefficient on some architectures (several successive calls
+to mtools, which defeats mtools' caching).
+
+   ---------- Footnotes ----------
+
+   (1) To see the articles, search for `APlaceForYourStuff' using
+Dejanews
+
+   (2) I didn't know about this yet when I bought my own Zip drive.
+Thus I ended up reformatting my tools disk, and hence I haven't had the
+opportunity to test the password yet.  If anybody still has their tools
+disk with the original password, could you try it out? Thanks in advance
+
+\1f
+File: mtools.info,  Node: Compiling mtools,  Next: Porting mtools,  Prev: Commands,  Up: Top
+
+5 Architecture specific compilation flags
+*****************************************
+
+To compile mtools, first invoke `./configure' before `make'. In
+addition to the standard `autoconfigure' flags, there are two
+architecture specific flags available.
+
+`./configure --enable-xdf'
+`./configure --disable-xdf'
+     Enables support for XDF disks. This is on by default. *Note XDF::,
+     for details.
+
+`./configure --enable-vold'
+`./configure --disable-vold'
+     Enables support for vold on Solaris. When used in conjunction with
+     vold, mtools should use different device nodes than for direct
+     access.
+
+`./configure --enable-new-vold'
+`./configure --disable-new-vold'
+     Enables new support for vold on Solaris. This is supposed to work
+     more smoothly than the old support.
+
+`./configure --enable-floppyd'
+`./configure --disable-floppyd'
+     Enables support for floppyd.  By default, floppyd support is
+     enabled as long as the necessary X includes and libraries are
+     available.
+
+\1f
+File: mtools.info,  Node: Porting mtools,  Next: Command Index,  Prev: Compiling mtools,  Up: Top
+
+6 Porting mtools to architectures which are not supported yet
+*************************************************************
+
+This chapter is only interesting for those who want to port mtools to
+an architecture which is not yet supported. For most common systems,
+default drives are already defined. If you want to add default drives
+for a still unsupported system, run config.guess, to see which
+identification autoconf uses for that system. This identification is of
+the form cpu-vendor-os (for example sparc-sun-sunos). The cpu and the
+os parts are passed to the compiler as preprocessor flags.   The OS
+part is passed to the compiler in three forms.
+  1. The complete os name, with dots replaced by underscores.  sco3.2v2
+     would yield sco3_2v2
+
+  2. The base os name. Sco3.2v2 would yield Sco
+
+  3. The base os name plus its major version. Sco3.2v2 would yield Sco3
+
+   All three versions are passed, if they are different.
+
+   To define the devices, use the entries for the systems that are
+already present as templates. In general, they have the following form:
+
+     #if (defined (my_cpu) && defined(my_os))
+     #define predefined_devices
+     struct device devices[] = {
+             { "/dev/first_drive", 'drive_letter', drive_description},
+             ...
+             { "/dev/last_drive", 'drive_letter', drive_description}
+     }
+     #define INIT_NOOP
+     #endif
+
+   "/dev/first_drive" is the name of the device or image file
+representing the drive. Drive_letter is a letter ranging from a to z
+giving access to the drive. Drive_description describes the type of the
+drive:
+`ED312'
+     extra density (2.88M) 3 1/2 disk
+
+`HD312'
+     high density 3 1/2 disk
+
+`DD312'
+     double density 3 1/2 disk
+
+`HD514'
+     high density 5 1/4 disk
+
+`DD514'
+     double density 5 1/4 disk
+
+`DDsmall'
+     8 sector double density 5 1/4 disk
+
+`SS514'
+     single sided double density 5 1/4 disk
+
+`SSsmall'
+     single sided 8 sector double density 5 1/4 disk
+
+`GENFD'
+     generic floppy drive (12 bit FAT)
+
+`GENHD'
+     generic hard disk (16 bit FAT)
+
+`GEN'
+     generic device (all parameters match)
+
+`ZIPJAZ(flags)'
+     generic ZIP drive using normal access. This uses partition 4.
+     `Flags' are any special flags to be passed to open.
+
+`RZIPJAZ(flags)'
+     generic ZIP drive using raw SCSI access. This uses partition 4.
+     `Flags' are any special flags to be passed to open.
+
+`REMOTE'
+     the remote drive used for floppyd.  Unlike the other items, this
+     macro also includes the file name ($DISPLAY) and the drive letter
+     (X)
+
+   Entries may be described in more detail:
+      fat_bits,open_flags,cylinders,heads,sectors,DEF_ARG
+    or, if you need to describe an offset (filesystem doesn't start at
+beginning of filesystem)
+      fat_bits, open_flags, cylinders, heads, sectors, offset, DEF_ARG0
+
+`fat_bits'
+     is either 12, 16 or 0. 0 means that the device accepts both types
+     of FAT.
+
+`open_flags'
+     may include flags such as O_NDELAY, or O_RDONLY, which might be
+     necessary to open the device. 0 means no special flags are needed.
+
+`cylinders,heads,sectors'
+     describe the geometry of the disk. If cylinders is 0, the heads
+     and sectors parameters are ignored, and the drive accepts any
+     geometry.
+
+`offset'
+     is used if the DOS filesystem doesn't begin at the start of the
+     device or image file. This is mostly useful for Atari Ram disks
+     (which contain their device driver at the beginning of the file)
+     or for DOS emulator images (which may represent a partitioned
+     device.
+
+   Definition of defaults in the devices file should only be done if
+these same devices are found on a large number of hosts of this type.
+In that case, could you also let me know about your new definitions, so
+that I can include them into the next release.  For purely local file, I
+recommend that you use the `/usr/local/etc/mtools.conf' and
+`~/.mtoolsrc' configuration files.
+
+   However, the devices files also allows to supply geometry setting
+routines. These are necessary if you want to access high capacity disks.
+
+   Two routines should be supplied:
+
+  1. Reading the current parameters
+          static inline int get_parameters(int fd, struct generic_floppy_struct *floppy)
+
+     This probes the current configured geometry, and return it in the
+     structure generic_floppy_struct (which must also be declared).
+     Fd is an open file descriptor for the device, and buf is an already
+     filled in stat structure, which may be useful.   This routine
+     should return 1 if the probing fails, and 0 otherwise.
+
+  2. Setting new parameters
+          static inline int set_parameters(int fd, struct generic_floppy_struct *floppy)
+                                           struct stat *buf)
+      This configures the geometry contained in floppy on the file
+     descriptor fd. Buf is the result of a stat call (already filled
+     in).  This should return 1 if the new geometry cannot be
+     configured, and 0 otherwise.
+
+   A certain number of preprocessor macros should also be supplied:
+
+`TRACKS(floppy)'
+     refers to the track field in the floppy structure
+
+`HEADS(floppy)'
+     refers to the heads field in the floppy structure
+
+`SECTORS(floppy)'
+     refers to the sectors per track field in the floppy structure
+
+`SECTORS_PER_DISK(floppy)'
+     refers to the sectors per disk field in the floppy structure (if
+     applicable, otherwise leave undefined)
+
+`BLOCK_MAJOR'
+     major number of the floppy device, when viewed as a block device
+
+`CHAR_MAJOR'
+     major number of the floppy device, when viewed as a character
+     device (a.k.a. "raw" device, used for fsck) (leave this undefined,
+     if your OS doesn't have raw devices)
+
+   For the truly high capacity formats (XDF, 2m, etc), there is no clean
+and documented interface yet.
+
+\1f
+File: mtools.info,  Node: Command Index,  Next: Variable Index,  Prev: Porting mtools,  Up: Top
+
+Command Index
+*************
+
+\0\b[index\0\b]
+* Menu:
+\1f
+File: mtools.info,  Node: Variable Index,  Next: Concept Index,  Prev: Command Index,  Up: Top
+
+Variable index
+**************
+
+\0\b[index\0\b]
+* Menu:
+
+* cylinders:                             geometry description. (line 61)
+* drive:                                 general information.  (line  6)
+* exclusive:                             open flags.           (line  6)
+* fat_bits:                              misc variables.       (line 11)
+* file:                                  location information. (line 10)
+* filter:                                misc flags.           (line 77)
+* heads:                                 geometry description. (line 65)
+* mformat_only:                          misc flags.           (line 73)
+* MTOOLS_FAT_COMPATIBILITY:              global variables.     (line  6)
+* MTOOLS_LOWER_CASE:                     global variables.     (line  6)
+* MTOOLS_NO_VFAT:                        global variables.     (line  6)
+* MTOOLS_SKIP_CHECK:                     global variables.     (line  6)
+* MTOOLSRC:                              Configuration.        (line  9)
+* nodelay:                               open flags.           (line  6)
+* sectors:                               geometry description. (line 68)
+* sync:                                  open flags.           (line  6)
+* tracks:                                geometry description. (line 61)
+* use_xdf:                               misc flags.           (line 68)
+
+\1f
+File: mtools.info,  Node: Concept Index,  Prev: Variable Index,  Up: Top
+
+Concept index
+*************
+
+\0\b[index\0\b]
+* Menu:
+
+* 2m:                                    2m.                   (line  6)
+* ALPHA patches:                         Location.             (line  6)
+* APlaceForYourStuff:                    mzip.                 (line  6)
+* Archive bit:                           mattrib.              (line  6)
+* Atari:                                 misc flags.           (line 65)
+* Atari Ram disk:                        location information. (line 28)
+* Backwards compatibility:               old style config.     (line  6)
+* Bad blocks:                            mbadblocks.           (line  9)
+* bigger sectors:                        bigger sectors.       (line  6)
+* blocksize:                             misc variables.       (line 34)
+* bugs:                                  Location.             (line  6)
+* Case sensitivity:                      case sensitivity.     (line  6)
+* Changing file attributes:              mattrib.              (line  6)
+* character devices:                     misc variables.       (line 34)
+* Checking configuration file:           mtoolstest.           (line  6)
+* Clusters of a file:                    mshowfat.             (line  6)
+* Command list:                          Commands.             (line  6)
+* Compile time configuration:            Compiling mtools.     (line  6)
+* Compiled-in defaults:                  Porting mtools.       (line  6)
+* Concatenating MS-DOS files:            mcopy.                (line  6)
+* Configuration file:                    default values.       (line  6)
+* Configuration file name:               config file location. (line  6)
+* Configuration file name (parsing order): parsing order.      (line  6)
+* Configuration file parsing order:      parsing order.        (line  6)
+* Configuration file syntax:             general syntax.       (line  6)
+* Configuration file, old syntax:        old style config.     (line  6)
+* Configuration files:                   Configuration.        (line  9)
+* Configuration of disk geometry:        geometry description. (line  6)
+* Copying an entire disk image:          mcat.                 (line  9)
+* Copying MS-DOS files:                  mcopy.                (line  6)
+* CR/LF conversions:                     mcopy.                (line  6)
+* Creating a directory:                  mmd.                  (line  6)
+* Current working directory:             directory.            (line  6)
+* Current working directory (changing the): mcd.               (line  6)
+* Default configuration:                 default values.       (line  6)
+* Default directory:                     directory.            (line  6)
+* Default directory (changing the):      mcd.                  (line  6)
+* Default values:                        default values.       (line  6)
+* Deleting a directory:                  mrd.                  (line  6)
+* deleting an MS-DOS directory recursively: mdeltree.          (line  6)
+* deleting MS-DOS files:                 mdel.                 (line  6)
+* Description of disk geometry:          geometry description. (line  6)
+* diffs:                                 Location.             (line  6)
+* Directory:                             directory.            (line  6)
+* Directory (changing):                  mcd.                  (line  6)
+* Directory creation:                    mmd.                  (line  6)
+* Directory listing:                     mdir.                 (line  6)
+* Directory removing:                    mrd.                  (line  6)
+* disable locking:                       misc flags.           (line 10)
+* Disk Geometry:                         geometry description. (line  6)
+* Disk image:                            mcat.                 (line  9)
+* Disk label:                            mlabel.               (line  6)
+* DMF disks:                             more sectors.         (line  6)
+* Dosemu hard disk image:                location information. (line 14)
+* Drive configuration:                   per drive variables.  (line  6)
+* Drive configuration, example:          general information.  (line  6)
+* Drive description:                     per drive variables.  (line  6)
+* Drive description, example:            general information.  (line  6)
+* Drive independent configuration variables: global variables. (line  6)
+* du:                                    mdu.                  (line  6)
+* Duplicate file names:                  name clashes.         (line  6)
+* Ejecting a Zip/Jaz disk:               mzip.                 (line  6)
+* Environmental variables:               global variables.     (line  6)
+* Erasing a directory:                   mrd.                  (line  6)
+* erasing an MS-DOS directory recursively: mdeltree.           (line  6)
+* erasing MS-DOS files:                  mdel.                 (line  6)
+* exclusive access to a drive:           open flags.           (line  6)
+* Executing commands before opening the device: misc variables.
+                                                               (line 28)
+* Fat:                                   mshowfat.             (line  6)
+* fdformat:                              more sectors.         (line  6)
+* File name of device node:              location information. (line 10)
+* Filenames:                             arguments.            (line  6)
+* Filesystem creation:                   mformat.              (line  6)
+* floppyd:                               floppyd.              (line  6)
+* Floppyd cat:                           mcat.                 (line  9)
+* floppyd_installtest:                   floppyd_installtest.  (line  6)
+* Format of disk:                        geometry description. (line  6)
+* Formats, high capacity:                high capacity formats.
+                                                               (line  6)
+* Formatting disks:                      mformat.              (line  6)
+* FreeDos:                               global variables.     (line  6)
+* getting parameters of a Dos fs:        minfo.                (line  6)
+* Global configuration variables:        global variables.     (line  6)
+* Hdimage:                               location information. (line  6)
+* Hidden files:                          mattrib.              (line  6)
+* High capacity formats:                 high capacity formats.
+                                                               (line  6)
+* High capacity formats, mounting:       mmount.               (line  6)
+* High density disk:                     geometry description. (line  6)
+* Image file:                            location information. (line 10)
+* Initializing disks:                    mformat.              (line  6)
+* Jaz disk (utilities):                  mzip.                 (line  6)
+* Jaz disks (partitioning them):         mpartition.           (line  6)
+* Jaz disks (partitions):                location information. (line 14)
+* Jaz disks (raw Scsi access):           misc flags.           (line 16)
+* Labeling a disk:                       mlabel.               (line  6)
+* Linux enhancements (High Capacity Formats): high capacity formats.
+                                                               (line  6)
+* Linux enhancements (mmount):           mmount.               (line  6)
+* List of available commands:            Commands.             (line  6)
+* Listing a directory:                   mdir.                 (line  6)
+* Listing space occupied by directories and files: mdu.        (line  6)
+* Location of configuration files:       config file location. (line  6)
+* Location of configuration files (parsing order): parsing order.
+                                                               (line  6)
+* locking (disabling it):                misc flags.           (line 10)
+* Long file name:                        long names.           (line  6)
+* Low density disk:                      geometry description. (line  6)
+* Magneto-optical disks:                 location information. (line 14)
+* mailing list:                          Location.             (line  6)
+* Making a directory:                    mmd.                  (line  6)
+* Marking blocks as bad:                 mbadblocks.           (line  9)
+* mattrib:                               mattrib.              (line  6)
+* mbadblocks:                            mbadblocks.           (line  9)
+* mcat:                                  mcat.                 (line  9)
+* mcd:                                   mcd.                  (line  6)
+* mcd (introduction):                    directory.            (line  6)
+* mclasserase:                           mclasserase.          (line  6)
+* mcopy:                                 mcopy.                (line  6)
+* Mcwd file:                             mcd.                  (line  6)
+* mdel:                                  mdel.                 (line  6)
+* mdeltree:                              mdeltree.             (line  6)
+* mdir:                                  mdir.                 (line  6)
+* mdu:                                   mdu.                  (line  6)
+* Memory Card:                           mclasserase.          (line  6)
+* mformat:                               mformat.              (line  6)
+* mformat (geometry used for):           geometry description. (line  6)
+* mformat parameters:                    minfo.                (line  6)
+* minfo:                                 minfo.                (line  6)
+* mkmanifest:                            mkmanifest.           (line  6)
+* mlabel:                                mlabel.               (line  6)
+* mmd:                                   mmd.                  (line  6)
+* mmount:                                mmount.               (line  6)
+* mmove:                                 mmove.                (line  6)
+* Mounting a disk:                       mmount.               (line  6)
+* Moving files (mmove):                  mmove.                (line  6)
+* Moving files (mren):                   mren.                 (line  6)
+* mpartition:                            mpartition.           (line  6)
+* mrd:                                   mrd.                  (line  6)
+* mren:                                  mren.                 (line  6)
+* mshowfat:                              mshowfat.             (line  6)
+* mtoolstest:                            mtoolstest.           (line  6)
+* mzip:                                  mzip.                 (line  6)
+* Name clashes:                          name clashes.         (line  6)
+* Name of configuration files:           config file location. (line  6)
+* Name of configuration files (parsing order): parsing order.  (line  6)
+* Name of device node:                   location information. (line 10)
+* Occupation of space by directories and files: mdu.           (line  6)
+* Odd formats:                           high capacity formats.
+                                                               (line  6)
+* Old configuration file syntax:         old style config.     (line  6)
+* open flags:                            open flags.           (line  6)
+* Options:                               arguments.            (line  6)
+* OS/2 (layout of removable media):      location information. (line 14)
+* OS/2 (XDF disks):                      XDF.                  (line  6)
+* Overwriting files:                     name clashes.         (line  6)
+* packing list:                          mkmanifest.           (line  6)
+* Parsing order:                         parsing order.        (line  6)
+* Partitioned image file:                location information. (line 14)
+* partitions (creating):                 mpartition.           (line  6)
+* password protected Zip disks:          mzip.                 (line  6)
+* patches:                               Location.             (line  6)
+* Physically erase:                      mclasserase.          (line  6)
+* plain floppy: device xxx busy:         misc flags.           (line 10)
+* Porting:                               Porting mtools.       (line  6)
+* Primary file name (long names):        long names.           (line  6)
+* Primary file name (name clashes):      name clashes.         (line  6)
+* Ram disk:                              location information. (line 28)
+* raw device:                            misc variables.       (line 34)
+* Read errors:                           mbadblocks.           (line  9)
+* Read-only files (changing the attribute): mattrib.           (line  6)
+* Read-only files (listing them):        mdir.                 (line  6)
+* Reading MS-DOS files:                  mcopy.                (line  6)
+* recursively removing an MS-DOS directory: mdeltree.          (line  6)
+* remote floppy access <1>:              floppyd_installtest.  (line  6)
+* remote floppy access:                  floppyd.              (line  6)
+* Removable media:                       location information. (line 14)
+* Removing a directory:                  mrd.                  (line  6)
+* removing an MS-DOS directory recursively: mdeltree.          (line  6)
+* removing MS-DOS files:                 mdel.                 (line  6)
+* Renaming files (mmove):                mmove.                (line  6)
+* Renaming files (mren):                 mren.                 (line  6)
+* SCSI devices:                          misc flags.           (line 16)
+* Secondary file name (long names):      long names.           (line  6)
+* Secondary file name (name clashes):    name clashes.         (line  6)
+* setgid installation:                   misc flags.           (line 40)
+* setuid installation:                   misc flags.           (line 40)
+* setuid installation (needed for raw SCSI I/O): misc flags.   (line 16)
+* Solaris (compile time configuration of vold): Compiling mtools.
+                                                               (line  6)
+* Solaris (Raw access to SCSI devices such as Zip & Jaz): misc flags.
+                                                               (line 16)
+* Solaris (volcheck):                    misc variables.       (line 28)
+* Solaris (vold):                        misc flags.           (line 57)
+* Space occupied by directories and files: mdu.                (line  6)
+* Special formats:                       high capacity formats.
+                                                               (line  6)
+* Subdirectory creation:                 mmd.                  (line  6)
+* Subdirectory removing:                 mrd.                  (line  6)
+* SunOS (Raw access to SCSI devices such as Zip & Jaz): misc flags.
+                                                               (line 16)
+* synchronous writing:                   open flags.           (line  6)
+* Syntax of the configuration file:      general syntax.       (line  6)
+* Syquest disks:                         location information. (line 14)
+* Syquests (raw Scsi access):            misc flags.           (line 16)
+* System files:                          mattrib.              (line  6)
+* Testing configuration file for correctness: mtoolstest.      (line  6)
+* Text files:                            mcopy.                (line  6)
+* Tools disk (Zip and Jaz drives):       mzip.                 (line  6)
+* Verifying configuration file:          mtoolstest.           (line  6)
+* VFAT-style file names:                 long names.           (line  6)
+* vgacopy:                               more sectors.         (line  6)
+* Vold (compile time configuration):     Compiling mtools.     (line  6)
+* Vold (mediamgr):                       misc flags.           (line 57)
+* Weird formats:                         high capacity formats.
+                                                               (line  6)
+* Windows 95 (DMF disks):                more sectors.         (line  6)
+* Windows 95-style file names:           long names.           (line  6)
+* Windows NT (layout of removable media): location information.
+                                                               (line 14)
+* Wordswapped:                           misc flags.           (line 65)
+* Working directory <1>:                 mcd.                  (line  6)
+* Working directory:                     directory.            (line  6)
+* Write protecting a Zip/Jaz disk:       mzip.                 (line  6)
+* Writing MS-DOS files:                  mcopy.                (line  6)
+* X terminal <1>:                        floppyd_installtest.  (line  6)
+* X terminal:                            floppyd.              (line  6)
+* XDF disks:                             XDF.                  (line  6)
+* XDF disks (compile time configuration): Compiling mtools.    (line  6)
+* XDF disks (how to configure):          misc flags.           (line 68)
+* Zip disk (utilities):                  mzip.                 (line  6)
+* Zip disks (partitioning them):         mpartition.           (line  6)
+* Zip disks (partitions):                location information. (line 14)
+* Zip disks (raw Scsi access):           misc flags.           (line 16)
+* ZipTools disk:                         mzip.                 (line  6)
+
+
+\1f
+Tag Table:
+Node: Top\7f869
+Node: Location\7f2948
+Node: Common features\7f4334
+Node: arguments\7f5098
+Node: drive letters\7f6752
+Node: directory\7f8104
+Node: long names\7f8548
+Node: name clashes\7f11094
+Node: case sensitivity\7f13377
+Node: high capacity formats\7f14601
+Node: more sectors\7f15704
+Node: bigger sectors\7f16753
+Node: 2m\7f17475
+Node: XDF\7f18646
+Node: exit codes\7f19972
+Node: bugs\7f20608
+Node: Configuration\7f21140
+Node: config file location\7f22264
+Node: general syntax\7f22691
+Node: default values\7f23511
+Node: global variables\7f24038
+Node: per drive variables\7f26118
+Node: general information\7f26935
+Node: location information\7f27376
+Node: geometry description\7f28879
+Node: open flags\7f32731
+Node: misc variables\7f33321
+Node: misc flags\7f35364
+Node: multiple descriptions\7f38999
+Node: parsing order\7f40660
+Node: old style config\7f41832
+Node: Commands\7f42520
+Node: floppyd\7f44387
+Node: floppyd_installtest\7f49171
+Node: mattrib\7f49802
+Node: mbadblocks\7f51595
+Node: mcat\7f52234
+Node: mcd\7f53044
+Node: mclasserase\7f53904
+Node: mcopy\7f54580
+Node: mdel\7f57601
+Node: mdeltree\7f57938
+Node: mdir\7f58354
+Node: mdu\7f59627
+Node: mformat\7f60133
+Node: mkmanifest\7f66700
+Node: minfo\7f68672
+Node: mlabel\7f69230
+Node: mmd\7f70307
+Node: mmount\7f70653
+Node: mmove\7f71249
+Node: mpartition\7f72051
+Node: mrd\7f75573
+Node: mren\7f75928
+Node: mshowfat\7f76671
+Node: mtoolstest\7f76889
+Node: mtype\7f77459
+Node: mzip\7f78310
+Ref: mzip-Footnote-1\7f80335
+Ref: mzip-Footnote-2\7f80411
+Node: Compiling mtools\7f80697
+Node: Porting mtools\7f81792
+Node: Command Index\7f87707
+Node: Variable Index\7f87855
+Node: Concept Index\7f89320
+\1f
+End Tag Table
diff --git a/mtools.spec b/mtools.spec
new file mode 100644 (file)
index 0000000..d38619d
--- /dev/null
@@ -0,0 +1,128 @@
+Summary: mtools, read/write/list/format DOS disks under Unix
+Name: mtools
+Version: 4.0.12
+Release: 1
+Group: Utilities/System
+URL: http://mtools.linux.lu
+Source0: mtools-%{version}.tar.gz
+#Patch1: mtools-%{version}-20071226.diff.gz
+Buildroot: %{_tmppath}/%{name}-%{version}-buildroot
+License: GPL
+%description
+Mtools is a collection of utilities to access MS-DOS disks from GNU
+and Unix without mounting them. It supports long file names, OS/2 Xdf
+disks, ZIP/JAZ disks and 2m disks (store up to 1992k on a high density
+3 1/2 disk).
+
+
+%prep
+%setup -q
+#%patch1 -p1
+./configure --prefix=%{buildroot}%{_prefix} --sysconfdir=/etc --infodir=%{buildroot}%{_infodir} --mandir=%{buildroot}%{_mandir} --enable-floppyd
+
+%build
+make
+
+%clean
+[ X%{buildroot} != X ] && [ X%{buildroot} != X/ ] && rm -r %{buildroot}
+
+%install
+make install
+make install-info
+strip %{buildroot}%{_bindir}/mtools %{buildroot}%{_bindir}/mkmanifest %{buildroot}%{_bindir}/floppyd
+rm %{buildroot}%{_infodir}/dir
+
+%files
+%defattr(-,root,root)
+%{_infodir}/mtools.info*
+%{_mandir}/man1/floppyd.1*
+%{_mandir}/man1/floppyd_installtest.1.gz
+%{_mandir}/man1/mattrib.1*
+%{_mandir}/man1/mbadblocks.1*
+%{_mandir}/man1/mcat.1*
+%{_mandir}/man1/mcd.1*
+%{_mandir}/man1/mclasserase.1*
+%{_mandir}/man1/mcopy.1*
+%{_mandir}/man1/mdel.1*
+%{_mandir}/man1/mdeltree.1*
+%{_mandir}/man1/mdir.1*
+%{_mandir}/man1/mdu.1*
+%{_mandir}/man1/mformat.1*
+%{_mandir}/man1/minfo.1*
+%{_mandir}/man1/mkmanifest.1*
+%{_mandir}/man1/mlabel.1*
+%{_mandir}/man1/mmd.1*
+%{_mandir}/man1/mmount.1*
+%{_mandir}/man1/mmove.1*
+%{_mandir}/man1/mpartition.1*
+%{_mandir}/man1/mrd.1*
+%{_mandir}/man1/mren.1*
+%{_mandir}/man1/mshowfat.1*
+%{_mandir}/man1/mtools.1*
+%{_mandir}/man5/mtools.5*
+%{_mandir}/man1/mtoolstest.1*
+%{_mandir}/man1/mtype.1*
+%{_mandir}/man1/mzip.1*
+%{_bindir}/amuFormat.sh
+%{_bindir}/mattrib
+%{_bindir}/mbadblocks
+%{_bindir}/mcat
+%{_bindir}/mcd
+%{_bindir}/mclasserase
+%{_bindir}/mcopy
+%{_bindir}/mdel
+%{_bindir}/mdeltree
+%{_bindir}/mdir
+%{_bindir}/mdu
+%{_bindir}/mformat
+%{_bindir}/minfo
+%{_bindir}/mkmanifest
+%{_bindir}/mlabel
+%{_bindir}/mmd
+%{_bindir}/mmount
+%{_bindir}/mmove
+%{_bindir}/mpartition
+%{_bindir}/mrd
+%{_bindir}/mren
+%{_bindir}/mshowfat
+%{_bindir}/mtools
+%{_bindir}/mtoolstest
+%{_bindir}/mtype
+%{_bindir}/mzip
+%{_bindir}/floppyd
+%{_bindir}/floppyd_installtest
+%{_bindir}/mcheck
+%{_bindir}/mcomp
+%{_bindir}/mxtar
+%{_bindir}/tgz
+%{_bindir}/uz
+%{_bindir}/lz
+
+%pre
+groupadd floppy 2>/dev/null || echo -n ""
+
+%post
+if [ -f %{_bindir}/install-info ] ; then
+       if [ -f %{_infodir}/dir ] ; then
+               %{_bindir}/install-info %{_infodir}/mtools.info %{_infodir}/dir
+       fi
+       if [ -f %{_infodir}/dir.info ] ; then
+               %{_bindir}/install-info %{_infodir}/mtools.info %{_infodir}/dir.info
+       fi
+fi
+
+
+%preun
+install-info --delete %{_infodir}/mtools.info %{_infodir}/dir.info
+if [ -f %{_bindir}/install-info ] ; then
+       if [ -f %{_infodir}/dir ] ; then
+               %{_bindir}/install-info --delete %{_infodir}/mtools.info %{_infodir}/dir
+       fi
+       if [ -f %{_infodir}/dir.info ] ; then
+               %{_bindir}/install-info --delete %{_infodir}/mtools.info %{_infodir}/dir.info
+       fi
+fi
+
+%changelog
+* Tue Nov 03 2009 Alain Knaff <alain@knaff.lu>
+- Mingw compatibility fixes
diff --git a/mtools.texi b/mtools.texi
new file mode 100644 (file)
index 0000000..250d195
--- /dev/null
@@ -0,0 +1,2589 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header
+@setfilename mtools.info
+@include version.texi
+@settitle Mtools @value{VERSION}
+@syncodeindex pg cp
+@comment %**end of header
+
+@comment MANskip 5
+
+@copying
+This manual is for Mtools (version @value{VERSION}, @value{UPDATED}),
+which is a collection of tools to allow Unix systems to manipulate
+MS-DOS files.
+
+Copyright @copyright{} 2007, 2009 Free Software Foundation, Inc.
+Copyright @copyright{} 1996-2005,2007-2009 Alain Knaff.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts.  A copy of the license is included in the section entitled
+``GNU Free Documentation License''.
+@end quotation
+@end copying
+
+@ignore
+@unnumbered Name
+mtools - utilities to access DOS disks in Unix.
+@end ignore
+
+@iftex
+@finalout
+@end iftex
+
+@dircategory DOS
+@direntry
+* Mtools: (mtools).        Mtools: utilities to access DOS disks in Unix.
+@end direntry
+
+
+@titlepage
+@title Mtools
+
+@c The following two commands start the copyright page.
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@c Output the table contents at the beginning
+@contents
+
+@ifnottex
+@node Top, Location, (dir), (dir)
+@top Mtools doc
+
+This is mtools' documentation.
+@end ifnottex
+
+@comment MANstart 1
+
+@unnumbered Introduction
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS
+filesystem (typically a floppy disk).  Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However,
+unnecessary restrictions and oddities of DOS are not emulated. For
+instance, it is possible to move subdirectories from one subdirectory
+to another.
+
+Mtools is sufficient to give access to MS-DOS filesystems.  For
+instance, commands such as @code{mdir a:} work on the @code{a:} floppy
+without any preliminary mounting or initialization (assuming the default
+@file{/etc/mtools.conf} works on your machine).  With mtools, one can
+change floppies too without unmounting and mounting.
+
+@insertcopying
+
+@menu
+* Location::          Where to find mtools and early bug fixes
+* Common features::   Common features of all mtools commands
+* Configuration::     How to configure mtools for your environment
+* Commands::          The available mtools commands
+* Compiling mtools::  Architecture specific compilation flags
+* Porting mtools::    Porting mtools to architectures which are not
+                      yet supported
+
+* Command Index::     Command Index
+* Variable Index::    Variable Index
+* Concept Index::     Concept Index
+@end menu
+
+@node Location, Common features, Top, Top
+@chapter Where to get mtools
+@cindex bugs
+@cindex ALPHA patches
+@cindex patches
+@cindex diffs
+@cindex mailing list
+
+Mtools can be found at the following places (and their mirrors):
+@example
+http://ftp.gnu.org/gnu/mtools/mtools-@value{VERSION}.tar.gz
+http://mtools.linux.lu/mtools-@value{VERSION}.tar.gz
+ftp://www.tux.org/pub/knaff/mtools/mtools-@value{VERSION}.tar.gz
+ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-@value{VERSION}.tar.gz
+@end example
+
+Before reporting a bug, make sure that it has not yet been fixed in the
+Alpha patches which can be found at:
+@example
+http://ftp.gnu.org/gnu/mtools/
+http://mtools.linux.lu/
+ftp://www.tux.org/pub/knaff/mtools
+@end example
+
+These patches are named
+@code{mtools-}@var{version}@code{-}@var{ddmm}@code{.taz}, where version
+stands for the base version, @var{dd} for the day and @var{mm} for the
+month. Due to a lack of space, I usually leave only the most recent
+patch.
+
+There is an mtools mailing list at mtools @@ tux.org .  Please
+send all bug reports to this list.  You may subscribe to the list by
+sending a message with 'subscribe mtools @@ tux.org' in its
+body to majordomo @@ tux.org . (N.B. Please remove the spaces
+around the "@@" both times. I left them there in order to fool
+spambots.)  Announcements of new mtools versions will also be sent to
+the list, in addition to the linux announce newsgroups.  The mailing
+list is archived at http://lists.gnu.org/pipermail/info-mtools/
+
+
+@node Common features, Configuration, Location, Top
+@chapter Common features of all mtools commands
+
+@menu
+* arguments::              What the command line parameters of mtools
+                           mean
+* drive letters::          Which drives are defined by default
+* directory::              Current working directory
+* long names::             VFAT-style long filenames
+* name clashes::           Name clash handling, and associated command
+                           line options
+* case sensitivity::       Case sensitivity
+* high capacity formats::  How to fit more data on your floppies
+* exit codes::             Exit codes
+* bugs::                   Happens to everybody
+@end menu
+
+@node arguments, drive letters, Common features, Common features
+@section Options and filenames
+@cindex Filenames
+@cindex Options
+MS-DOS filenames are composed of a drive letter followed by a colon, a
+subdirectory, and a filename. Only the filename part is mandatory, the
+drive letter and the subdirectory are optional. Filenames without a
+drive letter refer to Unix files. Subdirectory names can use either the
+'@code{/}' or '@code{\}' separator.  The use of the '@code{\}' separator
+or wildcards requires the names to be enclosed in quotes to protect them
+from the shell. However, wildcards in Unix filenames should not be
+enclosed in quotes, because here we @strong{want} the shell to expand
+them.
+
+The regular expression "pattern matching" routines follow the Unix-style
+rules.  For example, `@code{*}' matches all MS-DOS files in lieu of
+`@code{*.*}'.  The archive, hidden, read-only and system attribute bits
+are ignored during pattern matching.
+
+All options use the @code{-} (minus) as their first character, not
+@code{/} as you'd expect in MS-DOS.
+
+Most mtools commands allow multiple filename parameters, which
+doesn't follow MS-DOS conventions, but which is more user-friendly.
+
+Most mtools commands allow options that instruct them how to handle file
+name clashes. @xref{name clashes}, for more details on these. All
+commands accept the @code{-V} flags which prints the version, and most
+accept the @code{-v} flag, which switches on verbose mode. In verbose
+mode, these commands print out the name of the MS-DOS files upon which
+they act, unless stated otherwise. @xref{Commands}, for a description of
+the options which are specific to each command.
+
+
+@node drive letters, directory, arguments, Common features
+@section Drive letters
+
+The meaning of the drive letters depends on the target architectures.
+However, on most target architectures, drive A is the first floppy
+drive, drive B is the second floppy drive (if available), drive J is a
+Jaz drive (if available), and drive Z is a Zip drive (if available).  On
+those systems where the device name is derived from the SCSI id, the Jaz
+drive is assumed to be at Scsi target 4, and the Zip at Scsi target 5
+(factory default settings).  On Linux, both drives are assumed to be the
+second drive on the Scsi bus (/dev/sdb). The default settings can be
+changes using a configuration file (@pxref{Configuration}).
+
+The drive letter : (colon) has a special meaning. It is used to access
+image files which are directly specified on the command line using the
+@code{-i} options.
+
+Example:
+@example
+ mcopy -i my-image-file.bin ::file1 ::file2 .
+@end example
+
+This copies @code{file1} and @code{file2} from the image file
+(@code{my-image-file.bin}) to the @code{/tmp} directory.
+
+You can also supply an offset within the image file by including
+@code{@@@@}@var{offset} into the file name.
+
+Example:
+@example
+ mcopy -i my-image-file.bin@@@@1M ::file1 ::file2 .
+@end example
+
+This looks for the image at the offset of 1M in the file, rather than
+at its beginning.
+
+@node directory, long names, drive letters, Common features
+@section Current working directory
+@pindex mcd (introduction)
+@cindex Directory
+@cindex Working directory
+@cindex Current working directory
+@cindex Default directory
+
+The @code{mcd} command (@ref{mcd}) is used to establish the device and
+the current working directory (relative to the MS-DOS filesystem),
+otherwise the default is assumed to be @code{A:/}. However, unlike
+MS-DOS, there is only one working directory for all drives, and not one
+per drive.
+
+@node long names, name clashes, directory, Common features
+@section VFAT-style long file names
+@cindex Long file name
+@cindex Windows 95-style file names
+@cindex VFAT-style file names
+@cindex Primary file name (long names)
+@cindex Secondary file name (long names)
+
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a
+VFAT long name, and a companion short name is generated. This short
+name is what you see when you examine the disk with a pre-7.0 version
+of DOS.
+ The following table shows some examples of short names:
+
+@example
+Long name       MS-DOS name     Reason for the change
+---------       ----------      ---------------------
+thisisatest     THISIS~1        filename too long
+alain.knaff     ALAIN~1.KNA     extension too long
+prn.txt         PRN~1.TXT       PRN is a device name
+.abc            ABC~1           null filename
+hot+cold        HOT_CO~1        illegal character
+@end example
+
+ As you see, the following transformations happen to derive a short
+name:
+@itemize @bullet
+@item
+Illegal characters are replaced by underscores. The illegal characters
+are @code{;+=[]',\"*\\<>/?:|}.
+@item
+Extra dots, which cannot be interpreted as a main name/extension
+separator are removed
+@item
+A @code{~}@var{n} number is generated,
+@item
+The name is shortened so as to fit in the 8+3 limitation
+@end itemize
+
+ The initial Unix-style file name (whether long or short) is also called
+the @dfn{primary} name, and the derived short name is also called the
+@dfn{secondary} name.
+
+ Example:
+@example
+ mcopy /etc/motd a:Reallylongname
+@end example
+ Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+@example
+ mcopy /etc/motd a:motd
+@end example
+ Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+
+ In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+
+ Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (@code{\"*\\<>/?:|}), and device names are still
+reserved.
+
+@example
+Unix name       Long name       Reason for the change
+---------       ----------      ---------------------
+prn             prn-1           PRN is a device name
+ab:c            ab_c-1          illegal character
+@end example
+
+ As you see, the following transformations happen if a long name is
+illegal:
+@itemize @bullet
+@item
+Illegal characters are replaces by underscores,
+@item
+A @code{-}@var{n} number is generated,
+@end itemize
+
+@node name clashes, case sensitivity, long names, Common features
+@section Name clashes
+@cindex Name clashes
+@cindex Duplicate file names
+@cindex Overwriting files
+@cindex Primary file name (name clashes)
+@cindex Secondary file name (name clashes)
+
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as @code{mcopy},
+@code{mmd}, @code{mren}, @code{mmove}. When a name clash happens, mtools
+asks you what it should do. It offers several choices:
+
+@table @code
+@item overwrite
+Overwrites the existing file. It is not possible to overwrite a
+directory with a file.
+@item rename
+Renames the newly created file. Mtools prompts for the new filename
+@item autorename
+Renames the newly created file. Mtools chooses a name by itself, without
+prompting
+@item skip
+Gives up on this file, and moves on to the next (if any)
+@end table
+
+To chose one of these actions, type its first letter at the prompt. If
+you use a lower case letter, the action only applies for this file only,
+if you use an upper case letter, the action applies to all files, and
+you won't be prompted again.
+
+You may also chose actions (for all files) on the command line, when
+invoking mtools:
+
+@table @code
+@item -D o
+Overwrites primary names by default.
+@item -D O
+Overwrites secondary names by default.
+@item -D r
+Renames primary name by default.
+@item -D R
+Renames secondary name by default.
+@item -D a
+Autorenames primary name by default.
+@item -D A
+Autorenames secondary name by default.
+@item -D s
+Skip primary name by default.
+@item -D S
+Skip secondary name by default.
+@item -D m
+Ask user what to do with primary name.
+@item -D M
+Ask user what to do with secondary name.
+@end table
+
+Note that for command line switches lower/upper differentiates between
+primary/secondary name whereas for interactive choices, lower/upper
+differentiates between just-this-time/always.
+
+The primary name is the name as displayed in Windows 95 or Windows NT:
+i.e. the long name if it exists, and the short name otherwise.  The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+
+By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+
+If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+
+@node case sensitivity, high capacity formats, name clashes, Common features
+@section Case sensitivity of the VFAT filesystem
+@cindex Case sensitivity
+
+The VFAT filesystem is able to remember the case of the
+filenames. However, filenames which differ only in case are not allowed
+to coexist in the same directory. For example if you store a file called
+LongFileName on a VFAT filesystem, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+
+The VFAT filesystem allows to store the case of a filename in the
+attribute byte, if all letters of the filename are the same case, and if
+all letters of the extension are the same case too. Mtools uses this
+information when displaying the files, and also to generate the Unix
+filename when mcopying to a Unix directory. This may have unexpected
+results when applied to files written using an pre-7.0 version of DOS:
+Indeed, the old style filenames map to all upper case. This is different
+from the behavior of the old version of mtools which used to generate
+lower case Unix filenames.
+
+@node high capacity formats, exit codes, case sensitivity, Common features
+@section high capacity formats
+@cindex Special formats
+@cindex High capacity formats
+@cindex Odd formats
+@cindex Weird formats
+@cindex Formats, high capacity
+@cindex Linux enhancements (High Capacity Formats)
+
+Mtools supports a number of formats which allow to store more data on
+disk as usual. Due to different operating system abilities, these
+formats are not supported on all OS'es. Mtools recognizes these formats
+transparently where supported.
+
+In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+@code{fdutils} package at the following locations~:
+@example
+@code{ftp://www.tux.org/pub/knaff/fdutils/}.
+@code{ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-*}
+@end example
+
+See the manpages included in that package for further detail: Use
+@code{superformat} to format all formats except XDF, and use
+@code{xdfcopy} to format XDF.
+
+@menu
+* more sectors::      Putting more sectors per track on the disk
+* bigger sectors::    Use bigger sectors to save header space
+* 2m::                Use a standard first track
+* XDF::               OS/2's eXtended density format
+@end menu
+
+@node more sectors, bigger sectors, high capacity formats, high capacity formats
+@subsection More sectors
+@cindex fdformat
+@cindex vgacopy
+@cindex DMF disks
+@cindex Windows 95 (DMF disks)
+
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+
+These formats are supported by numerous DOS shareware utilities such as
+@code{fdformat} and @code{vgacopy}. In his infinite hybris, Bill Gate$
+believed that he invented this, and called it @samp{DMF disks}, or
+@samp{Windows formatted disks}. But in reality, it has already existed
+years before! Mtools supports these formats on Linux, on SunOs and on
+the DELL Unix PC.
+
+@node bigger sectors, 2m, more sectors, high capacity formats
+@subsection Bigger sectors
+@cindex bigger sectors
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+@emph{fewer}, but bigger sectors. For example, 1 sector of 4K only takes
+up header space once, whereas 8 sectors of 512 bytes have also 8
+headers, for the same amount of useful data.
+
+This method allows to store up to 1992K on a 3 1/2 HD disk.
+
+Mtools supports these formats only on Linux.
+
+@node 2m, XDF, bigger sectors, high capacity formats
+@subsection 2m
+@cindex 2m
+
+The 2m format was originally invented by Ciriaco Garcia de Celis. It
+also uses bigger sectors than usual in order to fit more data on the
+disk.  However, it uses the standard format (18 sectors of 512 bytes
+each) on the first cylinder, in order to make these disks easyer to
+handle by DOS. Indeed this method allows to have a standard sized
+bootsector, which contains a description of how the rest of the disk
+should be read.
+
+However, the drawback of this is that the first cylinder can hold less
+data than the others. Unfortunately, DOS can only handle disks where
+each track contains the same amount of data. Thus 2m hides the fact that
+the first track contains less data by using a @dfn{shadow
+FAT}. (Usually, DOS stores the FAT in two identical copies, for
+additional safety.  XDF stores only one copy, and it tells DOS that it
+stores two. Thus the same that would be taken up by the second FAT copy
+is saved.) This also means that your should @strong{never use a 2m disk
+to store anything else than a DOS fs}.
+
+Mtools supports these format only on Linux.
+
+@node XDF, , 2m, high capacity formats
+@subsection XDF
+@cindex XDF disks
+@cindex OS/2 (XDF disks)
+
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the @code{use_xdf} variable for the drive in the
+configuration file. @xref{Compiling mtools}, and @ref{misc variables},
+for details on how to do this. Fast XDF access is only available for
+Linux kernels which are more recent than 1.1.34.
+
+Mtools supports this format only on Linux.
+
+@strong{Caution / Attention distributors}: If mtools is compiled on a
+Linux kernel more recent than 1.3.34, it won't run on an older
+kernel. However, if it has been compiled on an older kernel, it still
+runs on a newer kernel, except that XDF access is slower. It is
+recommended that distribution authors only include mtools binaries
+compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will
+be out, mtools binaries compiled on newer kernels may (and should) be
+distributed. Mtools binaries compiled on kernels older than 1.3.34 won't
+run on any 2.1 kernel or later.
+
+@node exit codes, bugs, high capacity formats, Common features
+@section Exit codes
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure.  All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or minix disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(@pxref{global variables})
+@node bugs, , exit codes, Common features
+@section Bugs
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver.  These can be safely ignored.  
+
+The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7
+mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the
+corresponding configuration file variable, @ref{global variables}) to
+bypass the fat checking.
+
+@comment MANskip 1
+
+@ignore
+@unnumbered Name
+mtools.conf - mtools configuration files
+
+@comment MANend-skip 5
+@section Description
+
+This manpage describes the configuration files for mtools. They 
+@comment MANskip 5
+@end ignore
+
+
+@node Configuration, Commands, Common features, Top
+
+
+@chapter How to configure mtools for your environment
+@section Description
+@cindex Configuration files
+@vindex MTOOLSRC
+
+ This sections explains the syntax of the configurations files for
+mtools. The configuration files
+@comment MANend-skip 5
+are called @file{/usr/local/etc/mtools.conf} and @file{~/.mtoolsrc}. If
+the environmental variable @code{MTOOLSRC} is set, its contents is used
+as the filename for a third configuration file. These configuration
+files describe the following items:
+
+@itemize @bullet
+@item Global configuration flags and variables
+@item Per drive flags and variables
+@end itemize
+
+
+@menu
+* config file location::  Where mtools looks for its configuration files
+* general syntax::        The layout of the configuration files
+* default values::        Why you don't need a config file in most cases
+* global variables::      Variables that are independent of the drive
+* per drive variables::   Variables that are specific to a given drive
+* parsing order::         Location of configuration files and parsing order
+* old style config::      Backwards compatibility
+@end menu
+
+@node config file location, general syntax, Configuration, Configuration
+@section Location of the configuration files
+
+@cindex Configuration file name
+@cindex Name of configuration files
+@cindex Location of configuration files
+
+@file{/usr/local/etc/mtools.conf} is the system-wide configuration file,
+and @file{~/.mtoolsrc} is the user's private configuration file.
+
+On some systems, the system-wide configuration file is called
+@file{/etc/default/mtools.conf} instead.
+
+
+@node general syntax, default values, config file location, Configuration
+@subsection General configuration file syntax
+@cindex Syntax of the configuration file
+@cindex Configuration file syntax
+
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon.
+Then follow variable assignments and flags. Variable assignments take
+the following form:
+@display
+name=value
+@end display
+Flags are lone keywords without an equal sign and value following
+them.  A section either ends at the end of the file or where the next
+section begins.
+
+Lines starting with a hash (@code{#}) are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+
+@node default values, global variables, general syntax, Configuration
+@section Default values
+@cindex Default values
+@cindex Default configuration
+@cindex Configuration file
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives.  Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+dosemu image files.
+
+@node global variables, per drive variables, default values, Configuration
+@section Global variables
+@cindex Global configuration variables
+@cindex Drive independent configuration variables
+@cindex Environmental variables
+@vindex MTOOLS_SKIP_CHECK
+@vindex MTOOLS_FAT_COMPATIBILITY
+@vindex MTOOLS_LOWER_CASE
+@vindex MTOOLS_NO_VFAT
+@cindex FreeDos
+
+Global flags may be set to 1 or to 0.
+
+The following global flags are recognized:
+
+@table @code
+@item MTOOLS_SKIP_CHECK
+If this is set to 1, mtools skips most of its sanity checks. This is
+needed to read some Atari disks which have been made with the earlier
+ROMs, and which would not be recognized otherwise.
+@item MTOOLS_FAT_COMPATIBILITY
+If this is set to 1, mtools skips the fat size checks. Some disks have
+a bigger FAT than they really need to. These are rejected if this
+option is not set.
+@item MTOOLS_LOWER_CASE
+If this is set to 1, mtools displays all-upper-case short filenames as
+lowercase. This has been done to allow a behavior which is consistent
+with older versions of mtools which didn't know about the case bits.
+@item MTOOLS_NO_VFAT
+If this is set to 1, mtools won't generate VFAT entries for filenames
+which are mixed-case, but otherwise legal dos filenames.  This is useful
+when working with DOS versions which can't grok VFAT longnames, such as
+FreeDos.
+@item MTOOLS_DOTTED_DIR
+In a wide directory, prints the short name with a dot instead of spaces
+separating the basename and the extension.
+@item MTOOLS_NAME_NUMERIC_TAIL
+If this is set to one (default), generate numeric tails for all long
+names (~1).  If set to zero, only generate numeric tails if otherwise a
+clash would have happened.
+@item MTOOLS_TWENTY_FOUR_HOUR_CLOCK
+If 1, uses the European notation for times (twenty four hour clock),
+else uses the UK/US notation (am/pm)
+@end table
+
+Example:
+Inserting the following line into your configuration file instructs
+mtools to skip the sanity checks:
+@example
+  MTOOLS_SKIP_CHECK=1
+@end example
+
+Global variables may also be set via the environment:
+@example
+  export MTOOLS_SKIP_CHECK=1
+@end example
+
+Global string variables may be set to any value:
+@table @code
+@item MTOOLS_DATE_STRING
+The format used for printing dates of files.  By default, is dd-mm-yyyy.
+@end table
+
+@node per drive variables, parsing order, global variables, Configuration
+@section Per drive flags and variables
+@cindex Drive description
+@cindex Drive configuration
+
+@menu
+* general information::   What a drive description looks like
+* location information::  Where is the drive data physically stored
+* geometry description::  Describes the physical characteristics of
+                          the media
+* open flags::            Flags passed to the open system call when the
+                          device is opened
+* misc variables::        Variables which don't fit in either category
+* misc flags::           Switch variables, which can be enabled or disabled
+* multiple descriptions:: How to supply several descriptions for a
+                          drive, to be tried one after the other.
+@end menu
+
+@node general information, location information, per drive variables, per drive variables
+@subsection General information
+@cindex Drive description, example
+@cindex Drive configuration, example
+@vindex drive
+
+Per drive flags and values may be described in a drive section. A
+drive section starts with
+@code{drive} "@var{driveletter}" :
+
+Then follow variable-value pairs and flags.
+
+This is a sample drive description:
+@example
+  drive a:
+    file="/dev/fd0" use_xdf=1
+@end example
+
+@node location information, geometry description, general information, per drive variables
+@subsection Location information
+@cindex Hdimage
+
+For each drive, you need to describe where its data is physically
+stored (imag file, physical device, partition, offset).
+
+@table @code
+@item file
+@cindex Image file
+@cindex Name of device node
+@cindex File name of device node
+@vindex file
+The name of the file or device holding the disk image. This is
+mandatory. The file name should be enclosed in quotes.
+
+@item partition
+@cindex Dosemu hard disk image
+@cindex Zip disks (partitions)
+@cindex Jaz disks (partitions)
+@cindex Syquest disks
+@cindex Magneto-optical disks
+@cindex OS/2 (layout of removable media)
+@cindex Windows NT (layout of removable media)
+@cindex Removable media
+@cindex Partitioned image file
+Tells mtools to treat the drive as a partitioned device, and to use the
+given partition. Only primary partitions are accessible using this
+method, and they are numbered from 1 to 4. For logical partitions, use
+the more general @code{offset} variable. The @code{partition} variable
+is intended for removable media such as Syquests, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquests and
+magneto-optical disks as @samp{giant floppy disks} which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partioned devices. The @code{partition} flag is also useful DOSEMU
+hdimages. It is not recommended for hard disks for which direct access
+to partitions is available through mounting.
+
+@item offset
+@cindex Ram disk
+@cindex Atari Ram disk
+Describes where in the file the MS-DOS filesystem starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the filesystem starts right at the
+beginning of the device or file.
+@end table
+
+@node geometry description, open flags, location information, per drive variables
+@subsection Disk Geometry Configuration
+@cindex Disk Geometry
+@cindex Configuration of disk geometry
+@cindex Description of disk geometry
+@cindex Format of disk
+@cindex High density disk
+@cindex Low density disk
+@pindex mformat (geometry used for)
+
+Geometry information describes the physical characteristics about the
+disk. Its has three purposes:
+
+@table @asis
+@item formatting
+The geometry information is written into the boot sector of the newly
+made disk. However, you may also describe the geometry information on
+the command line. @xref{mformat}, for details.
+@item filtering
+On some Unices there are device nodes which only support one physical
+geometry. For instance, you might need a different node to access a disk
+as high density or as low density. The geometry is compared to the
+actual geometry stored on the boot sector to make sure that this device
+node is able to correctly read the disk. If the geometry doesn't match,
+this drive entry fails, and the next drive entry bearing the same drive
+letter is tried. @xref{multiple descriptions}, for more details on
+supplying several descriptions for one drive letter.
+
+If no geometry information is supplied in the configuration file, all
+disks are accepted. On Linux (and on Sparc) there exist device nodes
+with configurable geometry (@file{/dev/fd0}, @file{/dev/fd1} etc),
+and thus filtering is not needed (and ignored) for disk drives.  (Mtools
+still does do filtering on plain files (disk images) in Linux: this is
+mainly intended for test purposes, as I don't have access to a Unix
+which would actually need filtering).
+
+If you do not need filtering, but want still a default geometry for
+mformatting, you may switch off filtering using the @code{mformat_only}
+flag.
+
+If you want filtering, you should supply the @code{filter} flag.  If you 
+supply a geometry, you must supply one of both flags.
+
+@item initial geometry
+On devices that support it (usually floppy devices), the geometry
+information is also used to set the initial geometry. This initial
+geometry is applied while reading the boot sector, which contains the
+real geometry.  If no geometry information is supplied in the
+configuration file, or if the @code{mformat_only} flag is supplied, no
+initial configuration is done.
+
+On Linux, initial geometry is not really needed, as the configurable
+devices are able to auto-detect the disk type accurately enough (for
+most common formats) to read the boot sector.
+@end table
+
+Wrong geometry information may lead to very bizarre errors. That's why I
+strongly recommend that you add the @code{mformat_only} flag to your
+drive description, unless you really need filtering or initial geometry.
+
+The following geometry related variables are available:
+
+@table @code
+@item cylinders
+@itemx tracks
+@vindex cylinders
+@vindex tracks
+The number of cylinders. (@code{cylinders} is the preferred form,
+@code{tracks} is considered obsolete)
+@item heads
+@vindex heads
+The number of heads (sides).
+@item sectors
+@vindex sectors
+The number of sectors per track.
+@end table
+
+Example: the following drive section describes a 1.44M drive:
+
+@example
+  drive a:
+      file="/dev/fd0H1440"
+      fat_bits=12
+      cylinders=80 heads=2 sectors=18
+      mformat_only
+@end example
+
+The following shorthand geometry descriptions are available:
+
+@table @code
+@item 1.44m
+high density 3 1/2 disk. Equivalent to:
+@code{fat_bits=12 cylinders=80 heads=2 sectors=18}
+@item 1.2m
+high density 5 1/4 disk. Equivalent to:
+@code{fat_bits=12 cylinders=80 heads=2 sectors=15}
+@item 720k
+double density 3 1/2 disk. Equivalent to:
+@code{fat_bits=12 cylinders=80 heads=2 sectors=9}
+@item 360k
+double density 5 1/4 disk. Equivalent to:
+@code{fat_bits=12 cylinders=40 heads=2 sectors=9}
+@end table
+
+The shorthand format descriptions may be amended. For example,
+@code{360k sectors=8}
+describes a 320k disk and is equivalent to:
+@code{fat_bits=12 cylinders=40 heads=2 sectors=8}
+
+@node open flags, misc variables, geometry description, per drive variables
+@subsection Open Flags
+@vindex sync
+@vindex nodelay
+@vindex exclusive
+@cindex open flags
+@cindex synchronous writing
+@cindex exclusive access to a drive
+
+Moreover, the following flags are available:
+
+@table @code
+@item sync
+All i/o operations are done synchronously
+@item nodelay
+The device or file is opened with the O_NDELAY flag. This is needed on
+some non-Linux architectures.
+@item exclusive
+The device or file is opened with the O_EXCL flag. On Linux, this
+ensures exclusive access to the floppy drive. On most other
+architectures, and for plain files it has no effect at all.
+@end table
+
+
+@node misc variables, misc flags, open flags, per drive variables
+@subsection General Purpose Drive Variables
+
+The following general purpose drive variables are available.  Depending
+to their type, these variables can be set to a string (precmd) or
+an integer (all others)
+
+@table @code
+@item fat_bits
+@vindex fat_bits
+The number of FAT bits. This may be 12 or 16. This is very rarely
+needed, as it can almost always be deduced from information in the
+boot sector. On the contrary, describing the number of fat bits may
+actually be harmful if you get it wrong. You should only use it if
+mtools gets the autodetected number of fat bits wrong, or if you want
+to mformat a disk with a weird number of fat bits.
+@item codepage
+Describes the DOS codepage used for short filenames. This is a number
+between 1 and 999. By default, codepage 850 is used. The reason for
+this is because this codepage contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global codepage
+for all drives by using the global @code{default_codepage} parameter
+(outside of any drive description). This parameters exists starting at
+version 4.0.0
+@item precmd
+@cindex Solaris (volcheck)
+@cindex Executing commands before opening the device
+On some variants of Solaris, it is necessary to call 'volcheck -v'
+before opening a floppy device, in order for the system to notice that
+there is indeed a disk in the drive. @code{precmd="volcheck -v"} in the
+drive clause establishes the desired behavior.
+
+@item blocksize
+@cindex raw device
+@cindex character devices
+@cindex blocksize
+This parameter represents a default block size to be always used on this
+device.  All I/O is done with multiples of this block size,
+independantly of the sector size registered in the filesystem's boot
+sector.  This is useful for character devices whose sector size is not
+512, such as for example CD Rom drives on Solaris.
+
+@end table
+
+Only the @code{file} variable is mandatory. The other parameters may
+be left out. In that case a default value or an autodetected value is
+used.
+
+
+
+@node misc flags, multiple descriptions, misc variables, per drive variables
+@subsection General Purpose Drive Flags
+
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+ommitted, it is enabled.  For example, @code{scsi} is equivalent to
+@code{scsi=1}
+
+@table @code
+@item nolock
+@cindex disable locking
+@cindex locking (disabling it)
+@cindex plain floppy: device xxx busy
+Instruct mtools to not use locking on this drive.  This is needed on
+systems with buggy locking semantics.  However, enabling this makes
+operation less safe in cases where several users may access the same
+drive at the same time.
+
+@item scsi
+@cindex setuid installation (needed for raw SCSI I/O)
+@cindex Solaris (Raw access to SCSI devices such as Zip & Jaz)
+@cindex SunOS (Raw access to SCSI devices such as Zip & Jaz)
+@cindex Zip disks (raw Scsi access)
+@cindex Jaz disks (raw Scsi access)
+@cindex Syquests (raw Scsi access)
+@cindex SCSI devices
+When set to 1, this option tells mtools to use raw SCSI I/O instead of
+the standard read/write calls to access the device. Currently, this is
+supported on HP/UX, Solaris and SunOs.  This is needed because on some
+architectures, such as SunOs or Solaris, PC media can't be accessed
+using the @code{read} and @code{write} syscalls, because the OS expects
+them to contain a Sun specific "disk label".
+
+As raw Scsi access always uses the whole device, you need to specify the
+"partition" flag in addition
+
+On some architectures, such as Solaris, mtools needs root privileges to
+be able to use the @code{scsi} option.  Thus mtools should be installed
+set uid root on Solaris if you want to access Zip/Jaz drives.  Thus, if
+the @code{scsi} flag is given, @code{privileged} is automatically
+implied, unless explicitly disabled by @code{privileged=0}
+
+Mtools uses its root privileges to open the device, and to issue the
+actual SCSI I/O calls.  Moreover, root privileges are only used for
+drives described in a system-wide configuration file such as
+@file{/usr/local/etc/mtools.conf}, and not for those described in
+@file{~/.mtoolsrc} or @file{$MTOOLSRC}.  
+
+@item privileged
+@cindex setuid installation
+@cindex setgid installation
+When set to 1, this instructs mtools to use its set-uid and set-gid
+privileges for opening the given drive.  This option is only valid for
+drives described in the system-wide configuration files (such as
+@file{/usr/local/etc/mtools.conf}, not @file{~/.mtoolsrc} or
+@file{$MTOOLSRC}).  Obviously, this option is also a no op if mtools is
+not installed setuid or setgid.  This option is implied by 'scsi=1', but
+again only for drives defined in system-wide configuration files.
+Privileged may also be set explicitely to 0, in order to tell mtools not
+to use its privileges for a given drive even if @code{scsi=1} is set.
+
+Mtools only needs to be installed setuid if you use the
+@code{privileged} or @code{scsi} drive variables.  If you do not use
+these options, mtools works perfectly well even when not installed
+setuid root.
+
+@item vold
+@cindex Solaris (vold)
+@cindex Vold (mediamgr)
+
+Instructs mtools to interpret the device name as a vold identifier
+rather than as a filename.  The vold identifier is translated into a
+real filename using the @code{media_findname()} and
+@code{media_oldaliases()} functions of the @code{volmgt} library.  This
+flag is only available if you configured mtools with the
+@code{--enable-new-vold} option before compilation.
+
+@item swap
+@cindex Atari
+@cindex Wordswapped
+
+Consider the media as a word-swapped Atari disk.
+
+@item use_xdf
+@cindex XDF disks (how to configure)
+@vindex use_xdf
+If this is set to a non-zero value, mtools also tries to access this
+disk as an XDF disk. XDF is a high capacity format used by OS/2. This
+is off by default. @xref{XDF}, for more details.
+@item mformat_only
+@vindex mformat_only
+Tells mtools to use the geometry for this drive only for mformatting and 
+not for filtering.
+
+@item filter
+@vindex filter
+Tells mtools to use the geometry for this drive both for mformatting and 
+filtering.
+
+@item remote
+Tells mtools to connect to floppyd (@pxref{floppyd}).
+@end table
+
+
+@node multiple descriptions, , misc flags, per drive variables
+@subsection Supplying multiple descriptions for a drive
+
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that
+fits. Descriptions may fail for several reasons:
+
+@enumerate
+@item
+because the geometry is not appropriate,
+@item
+because there is no disk in the drive,
+@item
+or because of other problems.
+@end enumerate
+
+Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry.
+Example:
+@example
+  drive a: file="/dev/fd0H1440" 1.44m
+  drive a: file="/dev/fd0H720" 720k
+@end example
+
+This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+
+You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+
+@example
+  drive z: file="/dev/fd0"
+  drive z: file="/dev/fd1"
+@end example
+
+With this description, @code{mdir z:} accesses your first physical
+drive if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+
+When using multiple configuration files, drive descriptions in the files
+parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the @code{drive+} or @code{+drive}
+keywords instead of @code{drive}. The first adds a description to the
+end of the list (i.e. it will be tried last), and the first adds it to
+the start of the list.
+
+@node parsing order, old style config, per drive variables, Configuration
+@section Location of configuration files and parsing order
+@cindex Parsing order
+@cindex Configuration file parsing order
+@cindex Configuration file name (parsing order)
+@cindex Name of configuration files (parsing order)
+@cindex Location of configuration files (parsing order)
+
+The configuration files are parsed in the following order:
+@enumerate
+@item
+compiled-in defaults
+@item
+@file{/usr/local/etc/mtools.conf}
+@item
+@file{/etc/mtools}
+This is for backwards compatibility only, and is only parsed if
+@file{mtools.conf}
+doesn't exist.
+@item
+@file{~/.mtoolsrc}.
+@item
+@file{$MTOOLSRC} (file pointed by the @code{MTOOLSRC} environmental
+variable)
+@end enumerate
+
+Options described in the later files override those described in the
+earlier files. Drives defined in earlier files persist if they are not
+overridden in the later files. For instance, drives A and B may be
+defined in @file{/usr/local/etc/mtools.conf} and drives C and D may be
+defined in @file{~/.mtoolsrc} However, if @file{~/.mtoolsrc} also
+defines drive A, this new description would override the description of
+drive A in @file{/usr/local/etc/mtools.conf} instead of adding to it. If
+you want to add a new description to a drive already described in an
+earlier file, you need to use either the @code{+drive} or @code{drive+}
+keyword.
+
+@node old style config, , parsing order, Configuration
+@section Backwards compatibility with old configuration file syntax
+@cindex Backwards compatibility
+@cindex Old configuration file syntax
+@cindex Configuration file, old syntax
+
+The syntax described herein is new for version @code{mtools-3.0}. The
+old line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+
+@comment MANskip 5
+
+@node Commands, Compiling mtools, Configuration, Top
+@chapter Command list
+@cindex Command list
+@cindex List of available commands
+
+ This section describes the available mtools commands, and the command
+line parameters that each of them accepts. Options which are common to
+all mtools commands are not described here, @ref{arguments} for a
+description of those.
+
+@menu
+* floppyd::           floppy daemon to run on your X server box
+* floppyd_installtest:: small utility to check for the presence of floppyd
+* mattrib::           change MS-DOS file attribute flags
+* mbadblocks::        tests a floppy disk, and marks the bad blocks in the FAT
+* mcat::              same as cat. Only usefull with floppyd.
+* mcd::               change MS-DOS directory
+* mclasserase::       erase memory card
+* mcopy::             copy MS-DOS files to/from Unix
+* mdel::              delete an MS-DOS file
+* mdeltree::          recursively delete an MS-DOS directory
+* mdir::              display an MS-DOS directory
+* mdu::               list space occupied by directory and its contents
+* mformat::           add an MS-DOS filesystem to a low-level formatted floppy disk
+* minfo::             get information about an MS-DOS filesystem.
+* mlabel::            make an MS-DOS volume label
+* mkmanifest::        makes a list of short name equivalents
+* mmd::               make an MS-DOS subdirectory
+* mmount::            mount an MS-DOS disk
+* mpartition::        create an MS-DOS as a partition
+* mrd::               remove an MS-DOS subdirectory
+* mmove::             move or rename an MS-DOS file or subdirectory
+* mren::              rename an existing MS-DOS file
+* mshowfat::          shows the FAT map of a file
+* mtoolstest::        tests and displays the configuration
+* mtype::             display contents of an MS-DOS file
+* mzip::              zip disk specific commands
+@end menu
+
+@node floppyd, floppyd_installtest, Commands, Commands
+@section Floppyd
+@pindex floppyd
+@cindex X terminal
+@cindex remote floppy access
+
+@code{Floppyd} is used as a server to grant access to the floppy drive
+to clients running on a remote machine, just as an X server grants
+access to the display to remote clients.  It has the following syntax:
+
+@code{floppyd} [@code{-d}] [@code{-l}] [@code{-s} @var{port}] [@code{-r}
+@var{user}] [@code{-b} @var{ipaddr}] [@code{-x} @var{display}] @var{devicenames}
+
+
+@code{floppyd} is always associated with an X server.  It runs on the
+same machine as its X server, and listens on port 5703 and above.
+
+@subsection Authentication
+
+@code{floppyd} authenticates remote clients using the @code{Xauthority}
+protocol. Xhost authentication is not supported. Each floppyd is
+associated with an X server.  When a remote client attempts to connect
+to floppyd, it sends floppyd the X authority record corresponding to
+floppyd's X server.  Floppyd in turn then tries to open up a connection
+to the X server in order to verify the authenticity of the xauth record.
+If the connection to the X server succeeds, the client is granted
+access.
+@code{DISPLAY}.
+
+@strong{Caution}: In order to make authentication work correctly, the
+local host should @strong{not} be listed in the @code{xhost} list of
+allowed hosts.
+ Indeed, hosts listed in @code{xhost} do not need a correct
+@code{Xauthority} cookie to connect to the X server. As @code{floppyd}
+runs on the same host as the X server, all its probe connection would
+succeed even for clients who supplied a bad cookie.  This means that
+your floppy drive would be open to the world, i.e. a huge security hole.
+ If your X server does not allow you to remove @code{localhost:0} and
+@code{:0} from the @code{xhost} list, you can prevent floppyd from
+probing those display names with the @code{-l} option.
+
+@subsection Command line options
+
+@table @code
+@item d
+Daemon mode. Floppyd runs its own server loop.  Do not supply this if
+you start floppyd from @code{inetd.conf}
+@item s  @var{port}
+Port number for deamon mode.  Default is 5703 + @var{displaynumber}.
+This flag implies daemon mode.  For example, for display
+@code{hitchhiker:5}, the port would be 5708.
+@item b  @var{ipaddr}
+Bind address (for multihomed hosts). This flag implies daemon mode
+@item r @var{user}
+Run the server under as the given user
+@item x @var{display}
+X display to use for authentication. By default, this is taken from the
+@code{DISPLAY} variable. If neither the @code{x} attribute is present
+nor @code{DISPLAY} is set, floppyd uses @code{:0.0}.
+@end table
+
+@var{devicenames} is a list of device nodes to be opened.  Default
+is @code{/dev/fd0}. Multiple devices are only supported on mtools
+versions newer than 3.9.11.
+
+
+@subsection Connecting to floppyd
+
+ In order to use floppyd, add the flag @code{remote} to the device
+description in your @file{~/.mtoolsrc} file.  If the flag @code{remote}
+is given, the @code{file} parameter of the device description is taken
+to be a remote address.  It's format is the following:
+@var{hostname}@code{:}@var{displaynumber}[@code{/}[@var{baseport}][@code{/}@var{drive}]]. When
+using this entry, mtools connects to port
+@var{baseport}+@var{displaynumber} at @var{hostname}. By default
+@var{baseport} is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+
+@subsection Examples:
+
+ The following starts a floppy daemon giving access to @file{/dev/fd0},
+listening on the default port 5703, tied to the default X servers:
+
+@example
+floppyd -d /dev/fd0
+@end example
+
+ Each of the following starts a floppy daemon giving access to
+@file{/dev/fd1}, tied to the :1 local X servers, and listening on port
+5704. We assume that the local host is named @code{hitchhiker}.
+
+@example
+floppyd -d /dev/fd0
+floppyd -d -x :1 -p 5704 /dev/fd0 
+@end example
+
+ If you want to start floppyd by @code{inetd} instead of running it as a 
+daemon, insert the following lines into @file{/etc/services}:
+@example
+# floppy daemon
+floppyd-0    5703/tcp    # floppy daemon for X server :0
+floppyd-1    5704/tcp    # floppy daemon for X server :1
+@end example
+
+ And insert the following into @file{/etc/inetd.conf} (assuming that you
+have defined a user named floppy in your @file{/etc/passwd}):
+
+@example
+# floppy daemon
+floppyd-0 stream  tcp  wait  floppy  /usr/sbin/floppyd floppyd /dev/fd0 
+floppyd-1 stream  tcp  wait  floppy  /usr/sbin/floppyd floppyd -x :1 /dev/fd0 
+@end example
+
+ Note that you need to supply the X display names for the second
+floppyd.  This is because the port is opened by inetd.conf, and hence
+floppyd cannot know its number to interfere the display number.
+
+
+On the client side, insert the following into your @file{~/.mtoolsrc}
+to define a drive letter accessing floppy drive in your X terminal:
+@example
+drive x: file="$DISPLAY" remote
+@end example
+
+If your X terminal has more than one drive, you may access the
+additional drives as follows:
+@example
+drive y: file="$DISPLAY//1" remote
+drive z: file="$DISPLAY//2" remote
+@end example
+
+@node floppyd_installtest, mattrib, floppyd, Commands
+@section Floppyd_installtest
+@pindex floppyd_installtest
+@cindex X terminal
+@cindex remote floppy access
+
+@code{Floppyd_installtest} is used to check for the presence of a running
+floppyd daemon. This is usefull, if you have a small frontend script to
+mtools, which decides whether to use floppyd or not.
+
+@code{floppyd_installtest} [@code{-f}]  Connect-String
+
+If the @code{-f} option is specified, @code{floppyd_installtest} does a
+full X-Cookie authentication and complains if this does not work.
+
+The connect-String has the format described in the floppyd-section:
+@var{hostname}@code{:}@var{displaynumber}[@code{/}@var{baseport}]
+
+@node mattrib, mbadblocks, floppyd_installtest, Commands
+@section Mattrib
+@pindex mattrib
+@cindex Changing file attributes
+@cindex Hidden files
+@cindex Read-only files (changing the attribute)
+@cindex System files
+@cindex Archive bit
+
+@code{Mattrib} is used to change MS-DOS file attribute flags. It has the
+following syntax:
+
+@code{mattrib} [@code{-a|+a}] [@code{-h|+h}] [@code{-r|+r}]
+[@code{-s|+s}] [@code{-/}]  [@code{-p}] [@code{-X}] @var{msdosfile} [ @var{msdosfiles} @dots{} ]
+
+@code{Mattrib} adds attribute flags to an MS-DOS file (with the
+`@code{+}' operator) or remove attribute flags (with the `@code{-}'
+operator).
+
+@code{Mattrib} supports the following attribute bits:
+
+@table @code
+@item a
+Archive bit.  Used by some backup programs to indicate a new file.
+@item r
+Read-only bit.  Used to indicate a read-only file.  Files with this bit
+set cannot be erased by @code{DEL} nor modified.
+@item s
+System bit.  Used by MS-DOS to indicate a operating system file.
+@item h
+Hidden bit.  Used to make files hidden from @code{DIR}.
+@end table
+
+@code{Mattrib} supports the following command line flags:
+@table @code
+@item /
+Recursive.  Recursively list the attributes of the files in the subdirectories.
+@item X
+Concise. Prints the attributes whithout any whitespace padding.  If
+neither the "/" option is given, nor the @var{msdosfile} contains a
+wildcard, and there is only one Msdos file parameter on the command
+line, only the attribute is printed, and not the filename.  This option
+is convenient for scripts
+@item p
+Replay mode.  Outputs a series of mformat commands that will reproduce
+the current situation, starting from a situation as left by untarring
+the Dos filesystem.  Commands are only output for attribute settings
+that differ from the default (archive bit set for files, unset for
+directories).  This option is intended to be used in addition to
+tar. The @code{readonly} attribute is not taken into account, as tar can
+set that one itself.
+@end table
+
+@node mbadblocks, mcat, mattrib, Commands
+@section Mbadblocks
+
+The @code{mbadblocks} command is used to scan an MS-DOS floppy and mark
+its unused bad blocks as bad. It uses the following syntax:
+
+@code{mbadblocks} @var{drive}@code{:}
+@pindex mbadblocks
+@cindex Marking blocks as bad
+@cindex Bad blocks
+@cindex Read errors
+
+@code{Mbadblocks} scans an MS-DOS floppy for bad blocks. All unused bad
+blocks are marked as such in the FAT. This is intended to be used right
+after @code{mformat}.  It is not intended to salvage bad disks.
+@subsection Bugs
+@code{Mbadblocks} should (but doesn't yet :-( ) also try to salvage bad
+blocks which are in use by reading them repeatedly, and then mark them
+bad.
+
+@node mcat, mcd, mbadblocks, Commands
+@section Mcat
+
+The @code{mcat} command is used to copy an entire disk image from or
+to the floppy device. It uses the following syntax:
+
+@code{mcat} [@code{-w}] @var{drive}@code{:}
+@pindex mcat
+@cindex Copying an entire disk image
+@cindex Disk image
+@cindex Floppyd cat
+
+@code{Mcat} performs the same task as the unix @code{cat} command. It
+is included into the mtools package, since @code{cat} cannot access
+remote floppy devices offered by the mtools floppy daemon.
+Now it is possible to create boot floppies remotely.
+
+The default operation is reading. The output is written to stdout.
+
+If the @code{-w} option is specified, mcat reads a disk-image from 
+stdin and writes it to the given device. 
+@strong{Use this carefully!} Because of the lowlevel nature of this 
+command, it will happily destroy any data written before on the
+disk without warning!
+
+@node mcd, mclasserase, mcat, Commands
+@section Mcd
+@pindex mcd
+@cindex Directory (changing)
+@cindex Working directory
+@cindex Current working directory (changing the)
+@cindex Default directory (changing the)
+@cindex Mcwd file
+
+The @code{mcd} command is used to change the mtools working directory
+on the MS-DOS disk. It uses the following syntax:
+
+@example
+@code{mcd} [@var{msdosdirectory}]
+@end example
+
+Without arguments, @code{mcd} reports the current device and working
+directory.  Otherwise, @code{mcd} changes the current device and current
+working directory relative to an MS-DOS filesystem.
+
+The environmental variable @code{MCWD} may be used to locate the file
+where the device and current working directory information is stored.
+The default is @file{$HOME/.mcwd}.  Information in this file is ignored
+if the file is more than 6 hours old.
+
+@code{Mcd} returns 0 on success or 1 on failure.
+
+Unlike MS-DOS versions of @code{CD}, @code{mcd} can be used to change to
+another device. It may be wise to remove old @file{.mcwd} files at logout.
+
+@node mclasserase, mcopy, mcd, Commands
+@section Mclasserase
+@pindex mclasserase
+@cindex Memory Card
+@cindex Physically erase
+
+The @code{mclasserase} command is used to wipe memory cards by
+overwriting it three times: first with @code{0xff}, then with
+@code{0x00}, then with @code{0xff} again. The command uses the following
+syntax:
+
+@example
+@code{mclasserase} [@code{-d}] @var{msdosdrive}
+@end example
+
+Dos drive is optional, if none is specified, use @code{A:}. If more than
+one drive are specified, all but the last are ignored.
+
+@code{Mclasserase} accepts the following command line options:
+
+@table @code
+@item d
+Stop after each erase cycle, for testing purposes
+@item p
+Not yet implemented
+@end table
+
+
+@code{Mclasserase} returns 0 on success or -1 on failure.
+
+
+@node mcopy, mdel, mclasserase, Commands
+@section Mcopy
+@pindex mcopy
+@cindex Reading MS-DOS files
+@cindex Writing MS-DOS files
+@cindex Copying MS-DOS files
+@cindex Concatenating MS-DOS files
+@cindex Text files
+@cindex CR/LF conversions
+
+The @code{mcopy} command is used to copy MS-DOS files to and from
+Unix. It uses the following syntax:
+
+@example
+@code{mcopy} [@code{-bspanvmQT}] [@code{-D} @var{clash_option}] @var{sourcefile} @var{targetfile}
+@code{mcopy} [@code{-bspanvmQT}] [@code{-D} @var{clash_option}] @var{sourcefile} [ @var{sourcefiles}@dots{} ] @var{targetdirectory}
+@code{mcopy} [@code{-tnvm}] @var{MSDOSsourcefile}
+@end example
+
+
+
+@code{Mcopy} copies the specified file to the named file, or copies
+multiple files to the named directory.  The source and target can be
+either MS-DOS or Unix files.
+
+The use of a drive letter designation on the MS-DOS files, 'a:' for
+example, determines the direction of the transfer.  A missing drive
+designation implies a Unix file whose path starts in the current
+directory.  If a source drive letter is specified with no attached file
+name (e.g. @code{mcopy a: .}), all files are copied from that drive.
+
+If only a single, MS-DOS source parameter is provided (e.g. "mcopy
+a:foo.exe"), an implied destination of the current directory
+(`@code{.}') is assumed.
+
+A filename of `@code{-}' means standard input or standard output, depending
+on its position on the command line.
+
+@code{Mcopy} accepts the following command line options:
+
+@table @code
+@item t
+Text file transfer.  Mcopy translates incoming carriage return/line
+feeds to line feeds when copying from Dos to Unix, and vice-versa when
+copying from Unix to Dos.
+@item b
+Batch mode. Optimized for huge recursive copies, but less secure if a
+crash happens during the copy.
+@item s
+Recursive copy.  Also copies directories and their contents
+@item p
+Preserves the attributes of the copied files
+@item Q
+When mcopying multiple files, quits as soon as one copy fails (for
+example due to lacking storage space on the target disk)
+@item a
+Text (Ascii) file transfer.  @code{Mcopy} translates incoming carriage
+return/line feeds to line feeds.
+@item T
+Text (Ascii) file transfer with charset conversion.  Differs from
+@code{-a} in the @code{Mcopy} also translates incoming PC-8 characters
+to ISO-8859-1 equivalents as far as possible.  When reading DOS files,
+untranslatable characters are replaced by '@code{#}'; when writing DOS files,
+untranslatable characters are replaced by '@code{.}'.
+@item n
+No confirmation when overwriting Unix files.  @code{Mcopy} doesn't warn
+the user when overwriting an existing Unix file. If the target file already exists,
+and the @code{-n} option is not in effect, @code{mcopy} asks whether to
+overwrite the file or to rename the new file (@ref{name clashes}) for
+details).  In order to switch off confirmation for DOS files, use @code{-o}.
+@item m
+Preserve the file modification time.
+@item v
+Verbose. Displays the name of each file as it is copied.
+@end table
+
+@subsection Bugs
+Unlike MS-DOS, the '+' operator (append) from MS-DOS is not
+supported. However, you may use @code{mtype} to produce the same effect:
+@example
+mtype a:file1 a:file2 a:file3 >unixfile
+mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile
+@end example
+
+@node mdel, mdeltree, mcopy, Commands
+@section Mdel
+@pindex mdel
+@cindex removing MS-DOS files
+@cindex erasing MS-DOS files
+@cindex deleting MS-DOS files
+
+The @code{mdel} command is used to delete an MS-DOS file. Its syntax
+is:
+
+@display
+@code{mdel} [@code{-v}] @var{msdosfile} [ @var{msdosfiles} @dots{}  ]
+@end display
+
+@code{Mdel} deletes files on an MS-DOS filesystem.
+
+@code{Mdel} asks for verification prior to removing a read-only file.
+
+@node mdeltree, mdir, mdel, Commands
+@section Mdeltree
+@pindex mdeltree
+@cindex removing an MS-DOS directory recursively
+@cindex erasing an MS-DOS directory recursively
+@cindex deleting an MS-DOS directory recursively
+@cindex recursively removing an MS-DOS directory
+
+The @code{mdeltree} command is used to delete an MS-DOS file. Its syntax
+is:
+
+@display
+@code{mdeltree} [@code{-v}] @var{msdosdirectory} [@var{msdosdirectories}@dots{}]
+@end display
+
+@code{Mdeltree} removes a directory and all the files and subdirectories
+it contains from an MS-DOS filesystem. An error occurs if the directory
+to be removed does not exist.
+
+@node mdir, mdu, mdeltree, Commands
+@section Mdir
+@pindex mdir
+@cindex Read-only files (listing them)
+@cindex Listing a directory
+@cindex Directory listing
+
+The @code{mdir} command is used to display an MS-DOS directory. Its
+syntax is:
+
+@code{mdir} [@code{-/}] [@code{-f}] [@code{-w}] [@code{-a}] [@code{-b}] @var{msdosfile} [ @var{msdosfiles}@dots{}] 
+
+@code{Mdir}
+displays the contents of MS-DOS directories, or the entries for some
+MS-DOS files.
+
+@code{Mdir} supports the following command line options:
+
+@table @code
+@item /
+Recursive output, just like Dos' @code{-s} option
+@item w
+Wide output.  With this option, @code{mdir} prints the filenames across
+the page without displaying the file size or creation date.
+@item a
+Also list hidden files.
+@item f
+Fast.  Do not try to find out free space.  On larger disks, finding out
+the amount of free space takes up some non trivial amount of time, as
+the whole FAT must be read in and scanned.  The @code{-f} flag bypasses
+this step.  This flag is not needed on FAT32 filesystems, which store
+the size explicitely.
+@item b
+Concise listing. Lists each directory name or filename, one per line
+(including the filename extension). This switch displays no heading
+information and no summary. Only a newline separated list of pathnames
+is displayed.
+@end table
+
+An error occurs if a component of the path is not a directory.
+
+@node mdu, mformat, mdir, Commands
+@section Mdu
+@pindex mdu
+@cindex Space occupied by directories and files
+@cindex du
+@cindex Listing space occupied by directories and files
+@cindex Occupation of space by directories and files
+
+@code{Mdu} is used to list the space occupied by a directory, its
+subdirectories and its files. It is similar to the @code{du} command on
+Unix.  The unit used are clusters.  Use the minfo command to find out
+the cluster size.
+
+@code{mdu} [@code{-a}] [ @var{msdosfiles} @dots{} ]
+
+
+@table @code
+@item a
+All files.  List also the space occupied for individual files.
+@item s
+Only list the total space, don't give details for each subdirectory.
+@end table
+
+
+
+@node mformat, mkmanifest, mdu, Commands
+@section Mformat
+@pindex mformat
+@cindex Initializing disks
+@cindex Formatting disks
+@cindex Filesystem creation
+
+The @code{mformat} command is used to add an MS-DOS filesystem to a
+low-level formatted diskette. Its syntax is:
+
+@display
+@code{mformat} [@code{-t} @var{cylinders}] [@code{-h} @var{heads}] [@code{-s} @var{sectors}]
+  [@code{-f} @var{size}] [@code{-1}] [@code{-4}] [@code{-8}]
+  [@code{-v} @var{volume_label}]
+  [@code{-F}] [@code{-S} @var{sizecode}] [@code{-X}]
+  [@code{-2} @var{sectors_on_track_0}] [@code{-3}]
+  [@code{-0} @var{rate_on_track_0}] [@code{-A} @var{rate_on_other_tracks}]
+  [@code{-M} @var{software_sector_size}]
+  [@code{-N} @var{serial_number}] [@code{-a}]
+  [@code{-C}] [@code{-H} @var{hidden_sectors}] [@code{-I} @var{fsVersion}]
+  [@code{-r} @var{root_sectors}] [@code{-L} @var{fat_len}] 
+  [@code{-B} @var{boot_sector}] [@code{-k}]
+  [@code{-m} @var{media_descriptor}]
+  @var{drive:}
+@end display
+
+@code{Mformat} adds a minimal MS-DOS filesystem (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+
+
+The following options are supported: (The S, 2, 1 and M options may not
+exist if this copy of mtools has been compiled without the USE_2M
+option)
+
+The following options are the same as for Dos's format command:
+
+@comment xMANoptions
+
+@table @code
+@item v
+Specifies the volume label. A volume label identifies the disk and can
+be a maximum of 11 characters. If you omit the -v switch, mlabel will
+assign no label to the disk.
+@item f
+Specifies the size of the DOS filesystem to format. Only a certain
+number of predefined sizes are supported by this flag; for others use
+the -h/-t/-s flags. The following sizes are supported:
+@table @asis
+@item 160
+160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 180
+160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 320
+320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 360
+360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 720
+720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD)
+@item 1200
+1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD)
+@item 1440
+1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD)
+@item 2880
+2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED)
+@end table
+
+@item t
+Specifies the number of tracks on the disk.
+@item h
+The number of heads (sides).
+@item n
+Specifies the number of sectors per track. If the 2m option is given,
+number of 512-byte sector equivalents on generic tracks (i.e. not head 0
+track 0).  If the 2m option is not given, number of physical sectors per
+track (which may be bigger than 512 bytes).
+
+@item 1
+Formats a single side (equivalent to -h 1)
+
+@item 4
+Formats a 360K double-sided disk (equivalent to -f 360). When used
+together with -the 1 switch, this switch formats a 180K disk
+
+@item 8
+Formats a disk with 8 sectors per track.
+
+@end table
+
+MSDOS format's @code{q}, @code{u} and @code{b} options are not
+supported, and @code{s} has a different meaning.
+
+The following options are specific to mtools:
+
+@table @code
+
+@item F
+Format the partition as FAT32.
+
+@item S
+The sizecode. The size of the sector is 2 ^ (sizecode + 7).
+@item X
+formats the disk as an XDF disk. @xref{XDF}, for more details. The disk
+has first to be low-level formatted using the xdfcopy utility included
+in the fdutils package. XDF disks are used for instance for OS/2 install
+disks.
+@item 2
+2m format. The parameter to this option describes the number of
+sectors on track 0, head 0. This option is recommended for sectors
+bigger than normal.
+@item 3
+don't use a 2m format, even if the current geometry of the disk is a 2m 
+geometry.
+@item 0
+Data transfer rate on track 0
+@item A
+Data transfer rate on tracks other than 0
+@item M
+software sector size. This parameter describes the sector size in bytes used
+by the MS-DOS filesystem. By default it is the physical sector size.
+@item N
+Uses the requested serial number, instead of generating one
+automatically
+@item a
+If this option is given, an Atari style serial number is generated.
+Ataris store their serial number in the OEM label.
+@item C
+creates the disk image file to install the MS-DOS filesystem on
+it. Obviously, this is useless on physical devices such as floppies
+and hard disk partitions, but is interesting for image files.
+@item H
+number of hidden sectors. This parameter is useful for formatting hard
+disk partition, which are not aligned on track boundaries (i.e. first
+head of first track doesn't belong to the partition, but contains a
+partition table). In that case the number of hidden sectors is in
+general the number of sectors per cylinder. This is untested.
+@item I
+Sets the fsVersion id when formatting a FAT32 drive.  In order to find
+this out, run minfo on an existing FAT32 drive, and mail me about it, so
+I can include the correct value in future versions of mtools.
+@item c
+Sets the size of a cluster (in sectors).  If this cluster size would
+generate a FAT that too big for its number of bits, mtools automatically
+increases the cluster size, until the FAT is small enough.
+@item d
+Sets the number of FAT copies. Default is 2. This setting can also be
+specified using the @code{MTOOLS_NFATS} environment variable.
+@item r
+Sets the size of the root directory (in sectors).  Only applicable to 12
+and 16 bit FATs. This setting can also be specified using the
+@code{MTOOLS_DIR_LEN} environment variable.
+@item L
+Sets the length of the FAT.
+@item B
+Use the bootsector stored in the given file or device, instead of using
+its own.  Only the geometry fields are updated to match the target disks
+parameters.
+@item k
+Keep the existing boot sector as much as possible.  Only the geometry
+fields and other similar filesystem data are updated to match the target
+disks parameters.
+
+@item m
+Use a non-standard media descriptor byte for this disk. The media
+descriptor is stored at position 21 of the boot sector, and as first
+byte in each FAT copy. Using this option may confuse DOS or older mtools
+version, and may make the disk unreadable. Only use if you know what you
+are doing.
+
+@end table
+
+To format a diskette at a density other than the default, you must supply
+(at least) those command line parameters that are different from the
+default.
+
+@code{Mformat} returns 0 on success or 1 on failure.
+
+It doesn't record bad block information to the Fat, use
+@code{mbadblocks} for that.
+
+@node mkmanifest, minfo, mformat, Commands
+@section Mkmanifest
+@pindex mkmanifest
+@cindex packing list
+
+The @code{mkmanifest} command is used to create a shell script (packing
+list) to restore Unix filenames. Its syntax is:
+
+@code{mkmanifest} [ @var{files} ]
+
+@code{Mkmanifest} creates a shell script that aids in the restoration of
+Unix filenames that got clobbered by the MS-DOS filename restrictions.
+MS-DOS filenames are restricted to 8 character names, 3 character
+extensions, upper case only, no device names, and no illegal characters.
+
+
+The mkmanifest program is compatible with the methods used in
+@code{pcomm, arc,} and @code{mtools} to change perfectly good Unix
+filenames to fit the MS-DOS restrictions. This command is only useful if
+the target system which will read the diskette cannot handle vfat long
+names.
+
+@subsection Example
+You want to copy the following Unix files to a MS-DOS diskette (using the
+@code{mcopy} command).
+
+@example
+  very_long_name
+  2.many.dots
+  illegal:
+  good.c
+  prn.dev
+  Capital
+@end example
+
+@code{Mcopy}
+converts the names to:
+
+@example
+  very_lon
+  2xmany.dot
+  illegalx
+  good.c
+  xprn.dev
+  capital
+@end example
+
+The command:
+@example
+mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest
+@end example
+would produce the following:
+@example
+  mv very_lon very_long_name
+  mv 2xmany.dot 2.many.dots
+  mv illegalx illegal:
+  mv xprn.dev prn.dev
+  mv capital Capital
+@end example
+
+Notice that "good.c" did not require any conversion, so it did not
+appear in the output.
+
+Suppose I've copied these files from the diskette to another Unix
+system, and I now want the files back to their original names.  If the
+file "manifest" (the output captured above) was sent along with those
+files, it could be used to convert the filenames.
+
+@subsection Bugs
+
+The short names generated by @code{mkmanifest} follow the old convention
+(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0.
+
+
+@node minfo, mlabel, mkmanifest, Commands
+@section Minfo
+@pindex minfo
+@cindex mformat parameters
+@cindex getting parameters of a Dos fs
+
+The @code{minfo} command prints the parameters of a Dos filesystem, such
+as number of sectors, heads and cylinders.  It also prints an mformat
+command line which can be used to create a similar Dos filesystem on
+another media.  However, this doesn't work with 2m or Xdf media, and
+with Dos 1.0 filesystems
+@display
+@code{minfo} @var{drive}:
+@end display
+
+Mlabel supports the following option:
+@table @code
+@item v
+Prints a hexdump of the bootsector, in addition to the other information
+@end table
+
+
+@node mlabel, mmd, minfo, Commands
+@section Mlabel
+@pindex mlabel
+@cindex Labeling a disk
+@cindex Disk label
+
+The @code{mlabel} command adds a volume label to a disk. Its syntax is:
+@display
+@code{mlabel} [@code{-vcsn}] [@code{-N} @var{serial}] @var{drive}:[@var{new_label}]
+@end display
+
+@code{Mlabel} displays the current volume label, if present. If
+@var{new_label} is not given, and if neither the @code{c} nor the
+@code{s} options are set, it prompts the user for a new volume label.
+To delete an existing volume label, press return at the prompt.
+
+Reasonable care is taken to create a valid MS-DOS volume label.  If an
+invalid label is specified, @code{mlabel} changes the label (and
+displays the new label if the verbose mode is set). @code{Mlabel}
+returns 0 on success or 1 on failure.
+
+Mlabel supports the following options:
+@table @code
+@item c
+Clears an existing label, without prompting the user
+@item s
+Shows the existing label, without prompting the user.
+@item n 
+Assigns a new (random) serial number to the disk
+@item N @var{serial}
+Sets the supplied serial number. The serial number should be supplied as
+an 8 digit hexadecimal number, without spaces
+@end table
+
+
+@node mmd, mmount, mlabel, Commands
+@section Mmd
+@pindex mmd
+@cindex Making a directory
+@cindex Creating a directory
+@cindex Directory creation
+@cindex Subdirectory creation
+
+The @code{mmd} command is used to make an MS-DOS subdirectory. Its
+syntax is:
+
+@code{mmd} [@code{-D} @var{clash_option}] @var{msdosdirectory} [
+@var{msdosdirectories}@dots{} ]
+
+@code{Mmd} makes a new directory on an MS-DOS filesystem. An error occurs
+if the directory already exists.
+
+
+@node mmount, mmove, mmd, Commands
+@section Mmount
+@pindex mmount
+@cindex Linux enhancements (mmount)
+@cindex Mounting a disk
+@cindex High capacity formats, mounting
+
+The @code{mmount} command is used to mount an MS-DOS disk. It is only
+available on Linux, as it is only useful if the OS kernel allows to
+configure the disk geometry. Its syntax is:
+
+@code{mmount} @var{msdosdrive} [@var{mountargs}]
+
+@code{Mmount}
+reads the boot sector of an MS-DOS disk, configures the drive geometry,
+and finally mounts it passing
+@code{mountargs} to @code{mount. }
+If no mount arguments are specified, the name of the device is
+used. If the disk is write protected, it is automatically mounted read
+only.
+
+
+@node mmove, mpartition, mmount, Commands
+@section Mmove
+@pindex mmove
+@cindex Moving files (mmove)
+@cindex Renaming files (mmove)
+
+The @code{mmove} command is used to moves or renames an existing MS-DOS
+file or subdirectory.
+@display
+@code{mmove} [@code{-v}] [@code{-D} @var{clash_option}] @var{sourcefile} @var{targetfile}
+@code{mmove} [@code{-v}]  [@code{-D} @var{clash_option}] @var{sourcefile} [ @var{sourcefiles}@dots{} ] @var{targetdirectory}
+@end display
+@code{Mmove} moves or renames an existing MS-DOS file or
+subdirectory. Unlike the MS-DOS version of @code{MOVE}, @code{mmove} is
+able to move subdirectories.  Files or directories can only be moved
+within one filesystem. Data cannot be moved from Dos to Unix or
+vice-versa.  If you omit the drive letter from the target file or
+directory, the same letter as for the source is assumed.  If you omit
+the drive letter from all parameters, drive a: is assumed by default.
+
+@node mpartition, mrd, mmove, Commands
+@section Mpartition
+@pindex mpartition
+@cindex partitions (creating)
+@cindex Zip disks (partitioning them)
+@cindex Jaz disks (partitioning them)
+
+The @code{mpartition} command is used to create MS-DOS filesystems as
+partitions.  This is intended to be used on non-Linux systems,
+i.e. systems where fdisk and easy access to Scsi devices are not
+available.  This command only works on drives whose partition variable
+is set.
+
+@display
+@code{mpartition} @code{-p} @var{drive}
+@code{mpartition} @code{-r} @var{drive}
+@code{mpartition} @code{-I} [@code{-B} @var{bootSector}] @var{drive} 
+@code{mpartition} @code{-a} @var{drive}
+@code{mpartition} @code{-d} @var{drive}
+@code{mpartition} @code{-c} [@code{-s} @var{sectors}] [@code{-h} @var{heads}]
+[@code{-t} @var{cylinders}] [@code{-v} [@code{-T} @var{type}] [@code{-b}
+@var{begin}] [@code{-l} length] [@code{-f}]
+
+@end display
+
+Mpartition supports the following operations:
+
+@table @code
+@item p
+Prints a command line to recreate the partition for the drive.  Nothing
+is printed if the partition for the drive is not defined, or an
+inconsistency has been detected.  If verbose (@code{-v}) is also set,
+prints the current partition table.
+@item r
+Removes the partition described by @var{drive}.
+@item I
+Initializes the partition table, and removes all partitions.
+@item c
+Creates the partition described by @var{drive}.
+@item a
+"Activates" the partition, i.e. makes it bootable.  Only one partition
+can be bootable at a time.
+@item d
+"Desactivates" the partition, i.e. makes it unbootable.
+@end table
+
+If no operation is given, the current settings are printed.
+
+For partition creations, the following options are available:
+@table @code
+@item s @var{sectors}
+The number of sectors per track of the partition (which is also the
+number of sectors per track for the whole drive).
+@item h @var{heads}
+The number of heads of the partition (which is also the number of heads
+for the whole drive).  By default, the geometry information (number of
+sectors and heads) is figured out from neighbouring partition table
+entries, or guessed from the size.
+@item t @var{cylinders}
+The number of cylinders of the partition (not the number of cylinders of
+the whole drive.
+@item b @var{begin}
+The starting offset of the partition, expressed in sectors. If begin is
+not given, mpartition lets the partition begin at the start of the disk
+(partition number 1), or immediately after the end of the previous
+partition.
+@item l @var{length}
+The size (length) of the partition, expressed in sectors.  If end is not
+given, mpartition figures out the size from the number of sectors, heads
+and cylinders.  If these are not given either, it gives the partition
+the biggest possible size, considering disk size and start of the next
+partition.
+@end table
+
+The following option is available for all operation which modify the
+partition table:
+@table @code
+@item f
+Usually, before writing back any changes to the partition, mpartition
+performs certain consistenct checks, such as checking for overlaps and
+proper alignment of the partitions.  If any of these checks fails, the
+partition table is not changes.  The @code{-f} allows you to override
+these safeguards.
+@end table
+
+The following options are available for all operations:
+@table @code
+@item v
+Together with @code{-p} prints the partition table as it is now (no
+change operation), or as it is after it is modified.
+@item vv
+If the verbosity flag is given twice, mpartition will print out a
+hexdump of the partition table when reading it from and writing it to
+the device.
+@end table
+
+The following option is available for partition table initialization:
+@table @code
+@item B @var{bootSector}
+Reads the template master boot record from file @var{bootSector}.
+@end table
+
+
+@node mrd, mren, mpartition, Commands
+@section Mrd
+@pindex mrd
+@cindex Removing a directory
+@cindex Erasing a directory
+@cindex Deleting a directory
+@cindex Directory removing
+@cindex Subdirectory removing
+
+The @code{mrd} command is used to remove an MS-DOS subdirectory. Its
+syntax is:
+
+@display
+@code{mrd} [@code{-v}] @var{msdosdirectory} [ @var{msdosdirectories}@dots{} ]
+@end display
+
+@code{Mrd} removes a directory from an MS-DOS filesystem. An error occurs
+if the directory does not exist or is not empty.
+
+@node mren, mshowfat, mrd, Commands
+@section Mren
+@pindex mren
+@cindex Renaming files (mren)
+@cindex Moving files (mren)
+
+The @code{mren} command is used to rename or move an existing MS-DOS
+file or subdirectory. Its syntax is:
+
+@display
+@code{mren} [@code{-voOsSrRA}] @var{sourcefile} @var{targetfile}
+@end display
+
+@code{Mren}
+renames an existing file on an MS-DOS filesystem.
+
+In verbose mode, @code{Mren} displays the new filename if the name
+supplied is invalid.
+
+If the first syntax is used (only one sourcefile), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+@code{mcd} directory as would be the case with @code{mmove}. Unlike the
+MS-DOS version of @code{REN}, @code{mren} can be used to rename
+directories.
+
+@node mshowfat, mtoolstest, mren, Commands
+@section Mshowfat
+@pindex mshowfat
+@cindex Clusters of a file
+@cindex Fat
+
+The @code{mshowfat} command is used to display the FAT entries for a
+file.  Syntax:
+
+@display
+@code{$ mshowfat files}
+@end display
+
+@node mtoolstest, mtype, mshowfat, Commands
+@section Mtoolstest
+@pindex mtoolstest
+@cindex Testing configuration file for correctness
+@cindex Checking configuration file
+@cindex Verifying configuration file
+
+The @code{mtoolstest} command is used to tests the mtools configuration
+files. To invoke it, just type @code{mtoolstest} without any arguments.
+@code{Mtoolstest} reads the mtools configuration files, and prints the
+cumulative configuration to @code{stdout}. The output can be used as a
+configuration file itself (although you might want to remove redundant
+clauses).  You may use this program to convert old-style configuration
+files into new style configuration files.
+
+@node mtype, mzip, mtoolstest, Commands
+@section Mtype
+
+The @code{mtype} command is used to display contents of an MS-DOS
+file. Its syntax is:
+
+@display
+@code{mtype} [@code{-ts}] @var{msdosfile} [ @var{msdosfiles}@dots{} ]
+@end display
+
+@code{Mtype} displays the specified MS-DOS file on the screen.
+
+In addition to the standard options, @code{Mtype} allows the following
+command line options:
+
+@table @code
+@item t
+Text file viewing.  @code{Mtype} translates incoming carriage
+return/line feeds to line feeds.
+@item s
+@code{Mtype} strips the high bit from the data.
+@end table
+
+The @code{mcd} command may be used to establish the device and the
+current working directory (relative to MS-DOS), otherwise the default is
+@code{A:/}.
+
+@code{Mtype} returns 0 on success, 1 on utter failure, or 2 on partial
+failure.
+
+Unlike the MS-DOS version of @code{TYPE}, @code{mtype} allows multiple
+arguments.
+
+
+@node mzip, , mtype, Commands
+@section Mzip
+@cindex Zip disk (utilities)
+@cindex Jaz disk (utilities)
+@cindex Ejecting a Zip/Jaz disk
+@cindex Write protecting a Zip/Jaz disk
+@pindex mzip
+@cindex ZipTools disk
+@cindex Tools disk (Zip and Jaz drives)
+@cindex APlaceForYourStuff
+@cindex password protected Zip disks
+
+The @code{mzip} command is used to issue ZIP disk specific commands on
+Linux, Solaris or HPUX. Its syntax is:
+
+@display
+@code{mzip} [@code{-epqrwx}]
+@end display
+
+@code{Mzip} allows the following
+command line options:
+
+@table @code
+@item e
+Ejects the disk.
+@item f
+Force eject even if the disk is mounted (must be given in addition to
+@code{-e}).
+@item r
+Write protect the disk.
+@item w
+Remove write protection.
+@item p
+Password write protect.
+@item x
+Password protect
+@item u
+Temporarily unprotect the disk until it is ejected.  The disk becomes
+writable, and reverts back to its old state when ejected.
+@item q
+Queries the status
+@end table
+
+To remove the password, set it to one of the passwordless modes
+@code{-r} or @code{-w}: mzip will then ask you for the password, and
+unlock the disk.  If you have forgotten the password, you can get rid of
+it by low-level formatting the disk (using your SCSI adaptor's BIOS
+setup).
+
+The ZipTools disk shipped with the drive is also password protected.  On
+Dos or on a Mac, this password is automatically removed once the
+ZipTools have been installed.  From various articles posted to Usenet, I
+learned that the password for the tools disk is
+@code{APlaceForYourStuff}@footnote{To see the articles, search for
+@code{APlaceForYourStuff} using Dejanews}.  Mzip knows about this
+password, and tries it first, before prompting you for a password.  Thus
+@code{mzip -w z:} unlocks the tools disk@footnote{I didn't know about
+this yet when I bought my own Zip drive.  Thus I ended up reformatting
+my tools disk, and hence I haven't had the opportunity to test the
+password yet.  If anybody still has their tools disk with the original
+password, could you try it out? Thanks in advance}.  The tools disk is
+formatted in a special way so as to be usable both in a PC and in a Mac.
+On a PC, the Mac filesystem appears as a hidden file named
+@file{partishn.mac}.  You may erase it to reclaim the 50 Megs of space
+taken up by the Mac filesystem.
+
+
+@subsection Bugs
+
+This command is a big kludge.  A proper implementation would take a
+rework of significant parts of mtools, but unfortunately I don't have
+the time for this right now. The main downside of this implementation is
+that it is inefficient on some architectures (several successive calls
+to mtools, which defeats mtools' caching).
+
+@node Compiling mtools, Porting mtools, Commands, Top
+@chapter Architecture specific compilation flags
+@cindex XDF disks (compile time configuration)
+@cindex Solaris (compile time configuration of vold)
+@cindex Vold (compile time configuration)
+@cindex Compile time configuration
+
+To compile mtools, first invoke @code{./configure} before
+@code{make}. In addition to the standard @code{autoconfigure} flags,
+there are two architecture specific flags available.
+
+@table @code
+@item ./configure --enable-xdf
+@itemx ./configure --disable-xdf
+Enables support for XDF disks. This is on by default. @xref{XDF},
+for details.
+@item ./configure --enable-vold
+@itemx ./configure --disable-vold
+Enables support for vold on Solaris. When used in conjunction with vold,
+mtools should use different device nodes than for direct access.
+
+@item ./configure --enable-new-vold
+@itemx ./configure --disable-new-vold
+Enables new support for vold on Solaris. This is supposed to work more
+smoothly than the old support.
+
+@item ./configure --enable-floppyd
+@itemx ./configure --disable-floppyd
+Enables support for floppyd.  By default, floppyd support is enabled as
+long as the necessary X includes and libraries are available.
+@end table
+
+@node Porting mtools, Command Index, Compiling mtools, Top
+@chapter Porting mtools to architectures which are not supported yet
+@cindex Porting
+@cindex Compiled-in defaults
+
+ This chapter is only interesting for those who want to port mtools to
+an architecture which is not yet supported. For most common systems,
+default drives are already defined. If you want to add default drives
+for a still unsupported system, run config.guess, to see which
+identification autoconf uses for that system. This identification is
+of the form cpu-vendor-os (for example sparc-sun-sunos). The cpu and
+the os parts are passed to the compiler as preprocessor flags.
+ The OS part is passed to the compiler in three forms.
+@enumerate
+@item
+The complete os name, with dots replaced by underscores.  sco3.2v2 would
+yield sco3_2v2
+@item
+The base os name. Sco3.2v2 would yield Sco
+@item
+The base os name plus its major version. Sco3.2v2 would yield Sco3
+@end enumerate
+
+ All three versions are passed, if they are different.
+
+ To define the devices, use the entries for the systems that are already
+present as templates. In general, they have the following form:
+
+@example
+#if (defined (my_cpu) && defined(my_os))
+#define predefined_devices
+struct device devices[] = @{
+        @{ "/dev/first_drive", 'drive_letter', drive_description@},
+        @dots{} 
+        @{ "/dev/last_drive", 'drive_letter', drive_description@}
+@}
+#define INIT_NOOP
+#endif
+@end example
+
+ "/dev/first_drive" is the name of the device or image file
+representing the drive. Drive_letter is a letter ranging from a to z
+giving access to the drive. Drive_description describes the type of the
+drive:
+@table @code
+@item ED312
+extra density (2.88M) 3 1/2 disk
+@item HD312
+high density 3 1/2 disk
+@item DD312
+double density 3 1/2 disk
+@item HD514
+high density 5 1/4 disk
+@item DD514
+double density 5 1/4 disk
+@item DDsmall
+8 sector double density 5 1/4 disk
+@item SS514
+single sided double density 5 1/4 disk
+@item SSsmall
+single sided 8 sector double density 5 1/4 disk
+@item GENFD
+generic floppy drive (12 bit FAT)
+@item GENHD
+generic hard disk (16 bit FAT)
+@item GEN
+generic device (all parameters match)
+@item ZIPJAZ(flags)
+generic ZIP drive using normal access. This uses partition 4.
+@code{Flags} are any special flags to be passed to open.
+@item RZIPJAZ(flags)
+generic ZIP drive using raw SCSI access. This uses partition 4.
+@code{Flags} are any special flags to be passed to open.
+@item REMOTE
+the remote drive used for floppyd.  Unlike the other items, this macro
+also includes the file name ($DISPLAY) and the drive letter (X)
+@end table
+
+ Entries may be described in more detail:
+@example
+ fat_bits,open_flags,cylinders,heads,sectors,DEF_ARG
+@end example
+ or, if you need to describe an offset (filesystem doesn't start at
+beginning of filesystem)
+@example
+ fat_bits, open_flags, cylinders, heads, sectors, offset, DEF_ARG0
+@end example
+
+@table @code
+@item fat_bits
+is either 12, 16 or 0. 0 means that the device accepts both types of
+FAT.
+@item open_flags
+may include flags such as O_NDELAY, or O_RDONLY, which might be
+necessary to open the device. 0 means no special flags are needed.
+@item cylinders,heads,sectors
+describe the geometry of the disk. If cylinders is 0, the heads and sectors
+parameters are ignored, and the drive accepts any geometry.
+@item offset 
+is used if the DOS filesystem doesn't begin at the start of the device
+or image file. This is mostly useful for Atari Ram disks (which contain
+their device driver at the beginning of the file) or for DOS emulator
+images (which may represent a partitioned device.
+@end table
+
+ Definition of defaults in the devices file should only be done if these
+same devices are found on a large number of hosts of this type. In that
+case, could you also let me know about your new definitions, so that I
+can include them into the next release.  For purely local file, I
+recommend that you use the @code{/usr/local/etc/mtools.conf} and
+@code{~/.mtoolsrc} configuration files.
+
+ However, the devices files also allows to supply geometry setting
+routines. These are necessary if you want to access high capacity
+disks.
+
+ Two routines should be supplied:
+
+@enumerate
+@item
+Reading the current parameters
+@example
+static inline int get_parameters(int fd, struct generic_floppy_struct *floppy)
+@end example
+
+ This probes the current configured geometry, and return it in
+the structure generic_floppy_struct (which must also be declared).
+ Fd is an open file descriptor for the device, and buf is an already
+filled in stat structure, which may be useful.
+ This routine should return 1 if the probing fails, and 0 otherwise.
+
+@item
+Setting new parameters
+@example
+static inline int set_parameters(int fd, struct generic_floppy_struct *floppy)
+                                 struct stat *buf)
+@end example
+ This configures the geometry contained in floppy on the file descriptor
+fd. Buf is the result of a stat call (already filled in).  This should
+return 1 if the new geometry cannot be configured, and 0 otherwise.
+@end enumerate
+
+ A certain number of preprocessor macros should also be supplied:
+
+@table @code
+@item TRACKS(floppy)
+refers to the track field in the floppy structure
+@item HEADS(floppy)
+refers to the heads field in the floppy structure
+@item SECTORS(floppy)
+refers to the sectors per track field in the floppy structure
+@item SECTORS_PER_DISK(floppy)
+refers to the sectors per disk field in the floppy structure (if
+applicable, otherwise leave undefined)
+
+@item BLOCK_MAJOR
+major number of the floppy device, when viewed as a block device
+
+@item CHAR_MAJOR
+major number of the floppy device, when viewed as a character device
+(a.k.a. "raw" device, used for fsck) (leave this undefined, if your OS
+doesn't have raw devices)
+@end table
+
+ For the truly high capacity formats (XDF, 2m, etc), there is no clean
+and documented interface yet.
+
+@comment MANskip 1
+
+@node Command Index, Variable Index,  Porting mtools, Top
+@unnumbered Command Index
+@printindex pg
+
+@node Variable Index, Concept Index, Command Index, Top
+@unnumbered Variable index
+@printindex vr
+
+@node Concept Index, , Variable Index, Top
+@unnumbered Concept index
+@printindex cp
+
+@comment MANend-skip 1
+@comment MANend-skip 5
+@bye
diff --git a/mtoolsDirentry.h b/mtoolsDirentry.h
new file mode 100644 (file)
index 0000000..c8e96a5
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef MTOOLS_DIRENTRY_H
+#define MTOOLS_DIRENTRY_H
+/*  Copyright 1998,2000-2002,2005,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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, char *longname);
+
+struct directory *dir_read(direntry_t *entry, int *error);
+
+void initializeDirentry(direntry_t *entry, struct Stream_t *Dir);
+int isNotFound(direntry_t *entry);
+direntry_t *getParent(direntry_t *entry);
+void dir_write(direntry_t *entry);
+void low_level_dir_write(direntry_t *entry);
+int fatFreeWithDirentry(direntry_t *entry);
+int labelit(struct dos_name_t *dosname,
+           char *longname,
+           void *arg0,
+           direntry_t *entry);
+int isSubdirOf(Stream_t *inside, Stream_t *outside);
+char *getPwd(direntry_t *entry);
+void fprintPwd(FILE *f, direntry_t *entry, int escape);
+int write_vfat(Stream_t *, dos_name_t *, char *, int, direntry_t *);
+
+void wipeEntry(struct direntry_t *entry);
+
+void dosnameToDirentry(const struct dos_name_t *n, struct directory *dir);
+
+int lookupForInsert(Stream_t *Dir,
+                   direntry_t *direntry,
+                   struct dos_name_t *dosname,
+                   char *longname,
+                   struct scan_state *ssp, 
+                   int ignore_entry,
+                   int source_entry,
+                   int pessimisticShortRename,
+                   int use_longname);
+#endif
diff --git a/mtoolsPaths.h b/mtoolsPaths.h
new file mode 100644 (file)
index 0000000..07a081a
--- /dev/null
@@ -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 (file)
index 0000000..24b7f9f
--- /dev/null
@@ -0,0 +1,93 @@
+.TH mtoolstest 1 "03Nov09" mtools-4.0.12
+.SH Name
+mtoolstest - tests and displays the configuration
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "p mtoolstest"
+.iX "c Testing configuration file for correctness"
+.iX "c Checking configuration file"
+.iX "c Verifying configuration file"
+.PP
+The \fR\&\f(CWmtoolstest\fR command is used to tests the mtools configuration
+files. To invoke it, just type \fR\&\f(CWmtoolstest\fR without any arguments.
+\&\fR\&\f(CWMtoolstest\fR reads the mtools configuration files, and prints the
+cumulative configuration to \fR\&\f(CWstdout\fR. The output can be used as a
+configuration file itself (although you might want to remove redundant
+clauses).  You may use this program to convert old-style configuration
+files into new style configuration files.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mtype.1 b/mtype.1
new file mode 100644 (file)
index 0000000..ccf510d
--- /dev/null
+++ b/mtype.1
@@ -0,0 +1,113 @@
+.TH mtype 1 "03Nov09" mtools-4.0.12
+.SH Name
+mtype - display contents of an MSDOS file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmtype\fR command is used to display contents of an MS-DOS
+file. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmtype\fR [\fR\&\f(CW-ts\fR] \fImsdosfile\fR [ \fImsdosfiles\fR\&... ]
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMtype\fR displays the specified MS-DOS file on the screen.
+.PP
+In addition to the standard options, \fR\&\f(CWMtype\fR allows the following
+command line options:
+.TP
+\&\fR\&\f(CWt\fR\ 
+Text file viewing.  \fR\&\f(CWMtype\fR translates incoming carriage
+return/line feeds to line feeds.
+.TP
+\&\fR\&\f(CWs\fR\ 
+\&\fR\&\f(CWMtype\fR strips the high bit from the data.
+.PP
+The \fR\&\f(CWmcd\fR command may be used to establish the device and the
+current working directory (relative to MS-DOS), otherwise the default is
+\&\fR\&\f(CWA:/\fR.
+.PP
+\&\fR\&\f(CWMtype\fR returns 0 on success, 1 on utter failure, or 2 on partial
+failure.
+.PP
+Unlike the MS-DOS version of \fR\&\f(CWTYPE\fR, \fR\&\f(CWmtype\fR allows multiple
+arguments.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mzip.1 b/mzip.1
new file mode 100644 (file)
index 0000000..19853fc
--- /dev/null
+++ b/mzip.1
@@ -0,0 +1,155 @@
+.TH mzip 1 "03Nov09" mtools-4.0.12
+.SH Name
+mzip - change protection mode and eject disk on Zip/Jaz drive
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete.  See the
+end of this man page for details.
+.PP
+.SH Description
+.iX "c Zip disk (utilities)"
+.iX "c Jaz disk (utilities)"
+.iX "c Ejecting a Zip/Jaz disk"
+.iX "c Write protecting a Zip/Jaz disk"
+.iX "p mzip"
+.iX "c ZipTools disk"
+.iX "c Tools disk (Zip and Jaz drives)"
+.iX "c APlaceForYourStuff"
+.iX "c password protected Zip disks"
+.PP
+The \fR\&\f(CWmzip\fR command is used to issue ZIP disk specific commands on
+Linux, Solaris or HPUX. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmzip\fR [\fR\&\f(CW-epqrwx\fR]
+.fi
+.ft R
+.PP
+\&\fR\&\f(CWMzip\fR allows the following
+command line options:
+.TP
+\&\fR\&\f(CWe\fR\ 
+Ejects the disk.
+.TP
+\&\fR\&\f(CWf\fR\ 
+Force eject even if the disk is mounted (must be given in addition to
+\&\fR\&\f(CW-e\fR).
+.TP
+\&\fR\&\f(CWr\fR\ 
+Write protect the disk.
+.TP
+\&\fR\&\f(CWw\fR\ 
+Remove write protection.
+.TP
+\&\fR\&\f(CWp\fR\ 
+Password write protect.
+.TP
+\&\fR\&\f(CWx\fR\ 
+Password protect
+.TP
+\&\fR\&\f(CWu\fR\ 
+Temporarily unprotect the disk until it is ejected.  The disk becomes
+writable, and reverts back to its old state when ejected.
+.TP
+\&\fR\&\f(CWq\fR\ 
+Queries the status
+.PP
+To remove the password, set it to one of the passwordless modes
+\&\fR\&\f(CW-r\fR or \fR\&\f(CW-w\fR: mzip will then ask you for the password, and
+unlock the disk.  If you have forgotten the password, you can get rid of
+it by low-level formatting the disk (using your SCSI adaptor's BIOS
+setup).
+.PP
+The ZipTools disk shipped with the drive is also password protected.  On
+Dos or on a Mac, this password is automatically removed once the
+ZipTools have been installed.  From various articles posted to Usenet, I
+learned that the password for the tools disk is
+\&\fR\&\f(CWAPlaceForYourStuff\fR\fR.  Mzip knows about this
+password, and tries it first, before prompting you for a password.  Thus
+\&\fR\&\f(CWmzip -w z:\fR unlocks the tools disk.  The tools disk is
+formatted in a special way so as to be usable both in a PC and in a Mac.
+On a PC, the Mac filesystem appears as a hidden file named
+\&\fR\&\f(CW\(ifpartishn.mac\(is\fR.  You may erase it to reclaim the 50 Megs of space
+taken up by the Mac filesystem.
+.PP
+.SH Bugs
+.PP
+This command is a big kludge.  A proper implementation would take a
+rework of significant parts of mtools, but unfortunately I don't have
+the time for this right now. The main downside of this implementation is
+that it is inefficient on some architectures (several successive calls
+to mtools, which defeats mtools' caching).
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process.  Indeed, these items have no appropriate
+representation in the manpage format.  Moreover, not all information has
+been translated into the manpage version.  Thus I strongly advise you to
+use the original texinfo doc.  See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \ 
+To generate a printable copy from the texinfo doc, run the following
+commands:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.TP
+* \ \ 
+To generate a html copy,  run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \ 
+To generate an info copy (browsable using emacs' info mode), run:
+.nf
+.ft 3
+.in +0.3i
+    ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.lp
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html.  Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mzip.c b/mzip.c
new file mode 100644 (file)
index 0000000..83a2b66
--- /dev/null
+++ b/mzip.c
@@ -0,0 +1,552 @@
+/*  Copyright 1996 Grant R. Guenther,  based on work of Itai Nahshon
+ *   http://www.torque.net/ziptool.html
+ *  Copyright 1997-2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+       fprintf(stderr, 
+               "Mtools version %s, dated %s\n", 
+               mversion, mdate);
+       fprintf(stderr, 
+               "Usage: %s [-V] [-q] [-e] [-u] [-r|-w|-p|-x] [drive:]\n"
+               "\t-q print status\n"
+               "\t-e eject disk\n"
+               "\t-f eject disk even when mounted\n"
+               "\t-r write protected (read-only)\n"
+               "\t-w not write-protected (read-write)\n"
+               "\t-p password write protected\n"
+               "\t-x password protected\n"
+               "\t-u unprotect till disk ejecting\n", 
+               progname);
+       exit(ret);
+}
+
+
+enum mode_t {
+       ZIP_RW = 0,
+       ZIP_RO = 2,
+       ZIP_RO_PW = 3,
+       ZIP_PW = 5,
+       ZIP_UNLOCK_TIL_EJECT = 8
+};
+
+static enum mode_t get_zip_status(int priv, int fd, void *extra_data)
+{
+       unsigned char status[128];
+       unsigned char cdb[6] = { 0x06, 0, 0x02, 0, sizeof status, 0 };
+       
+       if (zip_cmd(priv, fd, cdb, 6, SCSI_IO_READ, 
+                   status, sizeof status, extra_data) == -1) {
+               perror("status: ");
+               exit(1);
+       }
+       return status[21] & 0xf;
+}
+
+
+static int short_command(int priv, int fd, int cmd1, int cmd2, 
+                        int cmd3, const char *data, void *extra_data)
+{
+       unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 };
+
+       cdb[0] = cmd1;
+       cdb[1] = cmd2;
+       cdb[4] = cmd3;
+
+       return zip_cmd(priv, fd, cdb, 6, SCSI_IO_WRITE, 
+                      (char *) data, data ? strlen(data) : 0, extra_data);
+}
+
+
+static int iomega_command(int priv, int fd, int mode, const char *data, 
+                         void *extra_data)
+{
+       return short_command(priv, fd, 
+                            SCSI_IOMEGA, mode, data ? strlen(data) : 0,
+                            data, extra_data);
+}
+
+static int door_command(int priv, int fd, int cmd1, int cmd2,
+                       void *extra_data)
+{
+       return short_command(priv, fd, cmd1, 0, cmd2, 0, extra_data);
+}
+
+void mzip(int argc, char **argv, int type)
+{
+       void *extra_data;
+       int c;
+       char drive;
+       device_t *dev;
+       int fd = -1;
+       char name[EXPAND_BUF];
+       enum { ZIP_NIX    =      0,
+              ZIP_STATUS = 1 << 0,
+              ZIP_EJECT  = 1 << 1,
+              ZIP_MODE_CHANGE = 1 << 2,
+              ZIP_FORCE  = 1 << 3
+       } request = ZIP_NIX;
+
+       enum mode_t newMode = ZIP_RW;
+       enum mode_t oldMode = ZIP_RW;
+
+#define setMode(x) \
+       if(request & ZIP_MODE_CHANGE) usage(1); \
+       request |= ZIP_MODE_CHANGE; \
+       newMode = x; \
+       break;
+       
+       /* get command line options */
+       if(helpFlag(argc, argv))
+               usage(0);
+       while ((c = getopt(argc, argv, "i:efpqrwxuh")) != EOF) {
+               switch (c) {
+                       case 'i':
+                               set_cmd_line_image(optarg, SCSI_FLAG);
+                               break;
+                       case 'f':
+                               if (get_real_uid()) {
+                                       fprintf(stderr, 
+                                               "Only root can use force. Sorry.\n");
+                                       exit(1);
+                               }
+                               request |= ZIP_FORCE;
+                               break;
+                       case 'e': /* eject */
+                               request |= ZIP_EJECT;
+                               break;
+                       case 'q': /* status query */
+                               request |= ZIP_STATUS;
+                               break;
+
+                       case 'p': /* password read-only */
+                               setMode(ZIP_RO_PW);
+                       case 'r': /* read-only */
+                               setMode(ZIP_RO);
+                       case 'w': /* read-write */
+                               setMode(ZIP_RW);
+                       case 'x': /* password protected */
+                               setMode(ZIP_PW);
+                       case 'u': /* password protected */
+                               setMode(ZIP_UNLOCK_TIL_EJECT)
+                       case 'h':
+                               usage(0);
+                       default:  /* unrecognized */
+                               usage(1);
+                       
+               }
+       }
+       
+       if (request == ZIP_NIX) request = ZIP_STATUS;  /* default action */
+
+       if (argc - optind > 1 || 
+           (argc - optind == 1 &&
+            (!argv[optind][0] || argv[optind][1] != ':')))
+               usage(1);
+       
+       drive = toupper(argc - optind == 1 ? argv[argc - 1][0] : ':');
+       
+       for (dev = devices; dev->name; dev++) {
+               unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 };
+               struct {
+                       char    type,
+                               type_modifier,
+                               scsi_version,
+                               data_format,
+                               length,
+                               reserved1[2],
+                               capabilities,
+                               vendor[8],
+                               product[16],
+                               revision[4],
+                               vendor_specific[20],
+                               reserved2[40];
+               } inq_data;
+
+               if (dev->drive != drive) 
+                       continue;
+               expand(dev->name, name);
+               if ((request & (ZIP_MODE_CHANGE | ZIP_EJECT)) &&
+                   !(request & ZIP_FORCE) &&
+                   test_mounted(name)) {
+                       fprintf(stderr, 
+                               "Can\'t change status of/eject mounted device\n");
+                       exit(1);
+               }
+               precmd(dev);
+
+               if(IS_PRIVILEGED(dev))
+                       reclaim_privs();
+               fd = scsi_open(name, O_RDONLY
+#ifdef O_NDELAY
+                              | O_NDELAY
+#endif
+                              , 0644,
+                              &extra_data);
+               if(IS_PRIVILEGED(dev))
+                       drop_privs();
+
+                               /* need readonly, else we can't
+                                * open the drive on Solaris if
+                                * write-protected */           
+               if (fd == -1) 
+                       continue;
+               closeExec(fd);
+
+               if (!(request & (ZIP_MODE_CHANGE | ZIP_STATUS)))
+                       /* if no mode change or ZIP specific status is
+                        * involved, the command (eject) is applicable
+                        * on all drives */
+                       break;
+
+               cdb[0] = SCSI_INQUIRY;
+               cdb[4] = sizeof inq_data;
+               if (zip_cmd(IS_PRIVILEGED(dev), fd, cdb, 6, SCSI_IO_READ, 
+                           &inq_data, sizeof inq_data, extra_data) != 0) {
+                       close(fd);
+                       continue;
+               }
+               
+#ifdef DEBUG
+               fprintf(stderr, "device: %s\n\tvendor: %.8s\n\tproduct: %.16s\n"
+                       "\trevision: %.4s\n", name, inq_data.vendor,
+                       inq_data.product, inq_data.revision);
+#endif /* DEBUG */
+
+               if (strncasecmp("IOMEGA  ", inq_data.vendor,
+                               sizeof inq_data.vendor) ||
+                   (strncasecmp("ZIP 100         ",
+                                inq_data.product, sizeof inq_data.product) &&
+                    strncasecmp("ZIP 100 PLUS    ",
+                                inq_data.product, sizeof inq_data.product) &&
+                    strncasecmp("ZIP 250         ",
+                                inq_data.product, sizeof inq_data.product) &&
+                    strncasecmp("ZIP 750         ",
+                                inq_data.product, sizeof inq_data.product) &&
+                    strncasecmp("JAZ 1GB         ",
+                                inq_data.product, sizeof inq_data.product) &&
+                    strncasecmp("JAZ 2GB         ",
+                                inq_data.product, sizeof inq_data.product))) {
+
+                       /* debugging */
+                       fprintf(stderr,"Skipping drive with vendor='");
+                       fwrite(inq_data.vendor,1, sizeof(inq_data.vendor), 
+                              stderr);
+                       fprintf(stderr,"' product='");
+                       fwrite(inq_data.product,1, sizeof(inq_data.product), 
+                              stderr);
+                       fprintf(stderr,"'\n");
+                       /* end debugging */
+                       close(fd);
+                       continue;
+               }
+               break;  /* found Zip/Jaz drive */
+       }
+
+       if (dev->drive == 0) {
+               fprintf(stderr, "%s: drive '%c:' is not a Zip or Jaz drive\n",
+                       argv[0], drive);
+               exit(1);
+       }
+
+       if (request & (ZIP_MODE_CHANGE | ZIP_STATUS))
+               oldMode = get_zip_status(IS_PRIVILEGED(dev), fd, extra_data);
+
+       if (request & ZIP_MODE_CHANGE) {
+                               /* request temp unlock, and disk is already unlocked */
+               if(newMode == ZIP_UNLOCK_TIL_EJECT &&
+                  (oldMode & ZIP_UNLOCK_TIL_EJECT))
+                       request &= ~ZIP_MODE_CHANGE;
+
+                               /* no password change requested, and disk is already
+                                * in the requested state */
+               if(!(newMode & 0x01) && newMode == oldMode)
+                       request &= ~ZIP_MODE_CHANGE;
+       }
+
+       if (request & ZIP_MODE_CHANGE) {
+               int ret;
+               enum mode_t unlockMode, unlockMask;
+               const char *passwd;
+               char dummy[1];
+
+               if(newMode == ZIP_UNLOCK_TIL_EJECT) {
+                       unlockMode = newMode | oldMode;
+                       unlockMask = 9;
+               } else {
+                       unlockMode = newMode & ~0x5;
+                       unlockMask = 1;
+               }
+
+               if ((oldMode & unlockMask) == 1) {  /* unlock first */
+                       char *s;
+                       passwd = "APlaceForYourStuff";
+                       if ((s = strchr(passwd, '\n'))) *s = '\0';  /* chomp */
+                       iomega_command(IS_PRIVILEGED(dev), fd, unlockMode, 
+                                      passwd, extra_data);
+               }
+               
+               if ((get_zip_status(IS_PRIVILEGED(dev), fd, extra_data) & 
+                    unlockMask) == 1) {
+                       /* unlock first */
+                       char *s;
+                       passwd = getpass("Password: ");
+                       if ((s = strchr(passwd, '\n'))) *s = '\0';  /* chomp */
+                       if((ret=iomega_command(IS_PRIVILEGED(dev), fd, 
+                                              unlockMode, passwd, 
+                                              extra_data))){
+                               if (ret == -1) perror("passwd: ");
+                               else fprintf(stderr, "wrong password\n");
+                               exit(1);
+                       }
+                       if((get_zip_status(IS_PRIVILEGED(dev), 
+                                          fd, extra_data) & 
+                           unlockMask) == 1) {
+                               fprintf(stderr, "wrong password\n");
+                               exit(1);
+                       }
+               }
+               
+               if (newMode & 0x1) {
+                       char first_try[_PASSWORD_LEN];
+                       
+                       passwd = getpass("Enter new password:");
+                       strncpy(first_try, passwd,_PASSWORD_LEN);
+                       passwd = getpass("Re-type new password:");
+                       if(strncmp(first_try, passwd, _PASSWORD_LEN)) {
+                               fprintf(stderr,
+                                       "You mispelled it. Password not set.\n");
+                               exit(1);
+                       }
+               } else {
+                       passwd = dummy;
+                       dummy[0] = '\0';
+               }
+
+               if(newMode == ZIP_UNLOCK_TIL_EJECT)
+                       newMode |= oldMode;
+
+               if((ret=iomega_command(IS_PRIVILEGED(dev), fd, 
+                                      newMode, passwd, extra_data))){
+                       if (ret == -1) perror("set passwd: ");
+                       else fprintf(stderr, "password not changed\n");
+                       exit(1);
+               }
+#ifdef OS_linux
+               ioctl(fd, BLKRRPART); /* revalidate the disk, so that the
+                                        kernel notices that its writable
+                                        status has changed */
+#endif
+       }
+       
+       if (request & ZIP_STATUS) {
+               const char *unlocked;
+
+               if(oldMode & 8)
+                       unlocked = " and unlocked until eject";
+               else
+                       unlocked = "";          
+               switch (oldMode & ~8) {
+                       case ZIP_RW:  
+                               printf("Drive '%c:' is not write-protected\n",
+                                      drive);
+                               break;
+                       case ZIP_RO:
+                               printf("Drive '%c:' is write-protected%s\n",
+                                      drive, unlocked);
+                               break;
+                       case ZIP_RO_PW: 
+                               printf("Drive '%c:' is password write-protected%s\n", 
+                                      drive, unlocked);
+                               break;
+                       case ZIP_PW:  
+                               printf("Drive '%c:' is password protected%s\n", 
+                                      drive, unlocked);
+                               break;
+                       default: 
+                               printf("Unknown protection mode %d of drive '%c:'\n",
+                                      oldMode, drive);
+                               break;                          
+               }               
+       }
+       
+       if (request & ZIP_EJECT) {
+               if(request & ZIP_FORCE)
+                       if(door_command(IS_PRIVILEGED(dev), fd, 
+                                       SCSI_ALLOW_MEDIUM_REMOVAL, 0,
+                                       extra_data) < 0) {
+                               perror("door unlock: ");
+                               exit(1);
+                       }
+
+               if(door_command(IS_PRIVILEGED(dev), fd, 
+                               SCSI_START_STOP, 1,
+                               extra_data) < 0) {
+                       perror("stop motor: ");
+                       exit(1);
+               }
+
+               if(door_command(IS_PRIVILEGED(dev), fd, 
+                               SCSI_START_STOP, 2, extra_data) < 0) {
+                       perror("eject: ");
+                       exit(1);
+               }
+               if(door_command(IS_PRIVILEGED(dev), fd, 
+                               SCSI_START_STOP, 2, extra_data) < 0) {
+                       perror("second eject: ");
+                       exit(1);
+               }
+       }
+       
+       close(fd);
+       exit(0);
+}
diff --git a/nameclash.h b/nameclash.h
new file mode 100644 (file)
index 0000000..8ebdb4c
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef MTOOLS_NAMECLASH_H
+#define MTOOLS_NAMECLASH_H
+
+/*  Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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);
+} ClashHandling_t;
+
+/* write callback */
+typedef int (write_data_callback)(dos_name_t *,char *, void *, struct direntry_t *);
+
+int mwrite_one(Stream_t *Dir,
+              const char *argname,
+              const char *shortname,
+              write_data_callback *cb,
+              void *arg,
+              ClashHandling_t *ch);
+
+int handle_clash_options(ClashHandling_t *ch, char c);
+void init_clash_handling(ClashHandling_t *ch);
+Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch,
+                   unsigned char attr, time_t mtime);
+
+
+#endif
diff --git a/packaging/fix_mlabel_initialisation.patch b/packaging/fix_mlabel_initialisation.patch
new file mode 100644 (file)
index 0000000..77a98cf
--- /dev/null
@@ -0,0 +1,13 @@
+Index: mtools-4.0.12/mlabel.c
+===================================================================
+--- mtools-4.0.12.orig/mlabel.c
++++ mtools-4.0.12/mlabel.c
+@@ -35,7 +35,7 @@ void label_name(doscp_t *cp, const char
+       int have_lower, have_upper;
+       wchar_t wbuffer[12];
+-      memset(ans, ' ', sizeof(ans)-1);
++      memset(ans, ' ', sizeof(*ans)-1);
+       ans->sentinel = '\0';
+       len = native_to_wchar(filename, wbuffer, 11, 0, 0);
+       if(len > 11){
diff --git a/packaging/mtools-3.9.6-config.patch b/packaging/mtools-3.9.6-config.patch
new file mode 100644 (file)
index 0000000..89e2a0c
--- /dev/null
@@ -0,0 +1,38 @@
+--- mtools-3.9.6/mtools.conf.fixes     Sun Jan  4 04:29:32 1998
++++ mtools-3.9.6/mtools.conf   Wed Feb  9 11:41:36 2000
+@@ -1,22 +1,25 @@
+ # Example mtools.conf files.  Uncomment the lines which correspond to
+ # your architecture and comment out the "SAMPLE FILE" line below
+-SAMPLE FILE
+-# # Linux floppy drives
+-# drive a: file="/dev/fd0" exclusive
+-# drive b: file="/dev/fd1" exclusive
++# Linux floppy drives
++drive a: file="/dev/fd0" exclusive 1.44m mformat_only
++drive b: file="/dev/fd1" exclusive 1.44m mformat_only
+-# # First SCSI hard disk partition
+-# drive c: file="/dev/sda1"
++# First SCSI hard disk partition
++#drive c: file="/dev/sda1"
+-# # First IDE hard disk partition
+-# drive c: file="/dev/hda1"
++# First IDE hard disk partition
++#drive c: file="/dev/hda1"
+ # # dosemu floppy image
+ # drive m: file="/var/lib/dosemu/diskimage"
+-# # dosemu hdimage
+-# drive n: file="/var/lib/dosemu/diskimage" offset=3840
++# dosemu hdimage
++drive n: file="/var/lib/dosemu/hdimage" offset=8832
++
++# # HPOJ (ptal-photod)
++mtools_skip_check=1
++drive p: file=":0" remote
+ # # Atari ramdisk image
+ # drive o: file="/tmp/atari_rd" offset=136
diff --git a/packaging/mtools-3.9.7-bigdisk.patch b/packaging/mtools-3.9.7-bigdisk.patch
new file mode 100644 (file)
index 0000000..eb5e6cc
--- /dev/null
@@ -0,0 +1,13 @@
+--- mtools-3.9.7/mtools.conf.big       Wed May 16 19:07:57 2001
++++ mtools-3.9.7/mtools.conf   Wed May 16 19:08:12 2001
+@@ -2,8 +2,8 @@
+ # your architecture and comment out the "SAMPLE FILE" line below
+ # Linux floppy drives
+-drive a: file="/dev/fd0" exclusive 1.44m mformat_only
+-drive b: file="/dev/fd1" exclusive 1.44m mformat_only
++drive a: file="/dev/fd0" exclusive mformat_only
++drive b: file="/dev/fd1" exclusive mformat_only
+ # First SCSI hard disk partition
+ #drive c: file="/dev/sda1"
diff --git a/packaging/mtools.changes b/packaging/mtools.changes
new file mode 100644 (file)
index 0000000..087aec2
--- /dev/null
@@ -0,0 +1,206 @@
+* Fri Jun 01 2012 vivian zhang <vivian.zhang@intel.com> - 4.0.12
+- Initial import
+
+* Fri Feb 11 2011 Yi Yang <yi.y.yang@intel.com> - 4.0.12
+- Fix label set error (BMC#11746)
+
+* Mon Feb 01 2010 Yi Yang <yi.y.yang@intel.com> - 4.0.12
+- Update to 4.0.12
+
+* Tue Feb 17 2009 Anas Nashif <anas.nashif@intel.com> 4.0.4
+- Update to 4.0.4
+
+* Fri Sep 12 2008 vivian zhang <vivian.zhang@intel.com> 3.9.11
+- add check for the info file before installing it in post/preun
+- add %doc to man/info in spec file
+
+* Tue Feb 19 2008 Adam Tkac <atkac redhat com> 3.9.11-4
+- fixed building on x86_64 (build with --disable-floppyd)
+
+* Mon Feb 18 2008 Fedora Release Engineering <rel-eng@fedoraproject.org> - 3.9.11-3.1
+- Autorebuild for GCC 4.3
+
+* Mon Jan 14 2008 Adam Tkac <atkac redhat com> 3.9.11-2.1
+- corrected post and preun sections (#428478)
+- fix rpmlint errors
+- start use autoreconf
+
+* Wed Aug 22 2007 Adam Tkac <atkac redhat com> 3.9.11-2
+- rebuild (BuildID feature)
+- change license to GPLv2+
+
+* Wed May 31 2007 Adam Tkac <atkac redhat com> 3.9.11-1
+- updated to latest upstream (3.9.11)
+
+* Fri May 11 2007 Adam Tkac <atkac redhat com> 3.9.10-7
+- in the end script has been completely rewriten by <skasal@redhat.com>
+
+* Fri May 11 2007 Adam Tkac <atkac redhat com> 3.9.10-6
+- some minor changes in sh patch (changed sh to bash)
+
+* Fri May 11 2007 Adam Tkac <atkac redhat com> 3.9.10-5
+- patch to #239741 by Matej Cepl <mcepl@redhat.com>
+  (rewrites /usr/bin/amuFormat.sh to /bin/sh)
+
+* Tue Feb 05 2007 Adam Tkac <atkac redhat com> 3.9.10-4
+- fixed some unstandard statements in spec file (#226162)
+
+* Mon Jan 22 2007 Adam Tkac <atkac redhat com> 3.9.10-3
+- Resolves: #223712
+- applied Ville Skytta's (ville.skytta "antispam" iki.fi) patch
+  (install-info scriptlet failures)
+
+* Wed Aug 09 2006 Jitka Kudrnacova <jkudrnac@redhat.com> - 3.9.10-2
+- rebuilt to prevent corruption on the 13th character (#195528)
+
+* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 3.9.10-1.2.2
+- rebuild
+
+* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 3.9.10-1.2.1
+- bump again for double-long bug on ppc(64)
+
+* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 3.9.10-1.2
+- rebuilt for new gcc4.1 snapshot and glibc changes
+
+* Fri Dec 09 2005 Jesse Keating <jkeating@redhat.com>
+- rebuilt
+
+* Wed Oct 19 2005 Tim Waugh <twaugh@redhat.com> 3.9.10-1
+- 3.9.10.
+
+* Mon Mar 21 2005 Tim Waugh <twaugh@redhat.com> 3.9.9-13
+- Fixed memset() usage bug.
+
+* Tue Mar 15 2005 Tim Waugh <twaugh@redhat.com> 3.9.9-12
+- Fix build (bug #151135).
+
+* Wed Mar  2 2005 Tim Waugh <twaugh@redhat.com> 3.9.9-11
+- Rebuild for new GCC.
+
+* Fri Dec 10 2004 Tim Waugh <twaugh@redhat.com> 3.9.9-10
+- Fixed mpartition --help output (bug #65293).
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Thu Jan  8 2004 Tim Waugh <twaugh@redhat.com> 3.9.9-7
+- Fix mistaken use of '&' instead of '&&'.
+
+* Tue Dec  9 2003 Tim Waugh <twaugh@redhat.com> 3.9.9-6
+- Remove last (incorrect) change.
+
+* Tue Dec  9 2003 Tim Waugh <twaugh@redhat.com> 3.9.9-5
+- Fix mistaken variable assignment in comparison (bug #110823).
+
+* Thu Nov 27 2003 Tim Waugh <twaugh@redhat.com>
+- Build requires texinfo (bug #111000).
+
+* Sat Oct 25 2003 Tim Waugh <twaugh@redhat.com> 3.9.9-4
+- Rebuilt.
+
+* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Thu May 22 2003 Tim Waugh <twaugh@redhat.com> 3.9.9-2
+- Fix mcomp with no arguments (bug #91372).
+
+* Tue Mar 18 2003 Tim Waugh <twaugh@redhat.com> 3.9.9-1
+- 3.9.9.
+- Add config lines for hpoj photo-card access on drive P:.
+
+* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
+- rebuilt
+
+* Wed Nov 20 2002 Tim Powers <timp@redhat.com>
+- rebuilt in current collinst
+
+* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Thu May 23 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Sun Jun 24 2001 Bernhard Rosenkraenzer <bero@redhat.com> 3.9.8-2
+- Add patch from maintainer
+
+* Mon May 28 2001 Bernhard Rosenkraenzer <bero@redhat.com> 3.9.8-1
+- 3.9.8 final
+
+* Mon May 21 2001 Bernhard Rosenkraenzer <bero@redhat.com> 3.9.8-0.pre1.0
+- 3.9.8pre1
+
+* Wed May 16 2001 Bernhard Rosenkraenzer <bero@redhat.com> 3.9.7-6
+- Fix support for disks > 1.44 MB (#40857)
+
+* Tue May  8 2001 Bernhard Rosenkraenzer <bero@redhat.com> 3.9.7-5
+- Update to 20010507
+
+* Wed Jan 10 2001 Bernhard Rosenkraenzer <bero@redhat.com>
+- Apply the author's current patches, fixes among other things
+  ZIP drive support and doesn't crash when trying to access a BSD disk
+
+* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
+- automatic rebuild
+
+* Sat Jun 17 2000 Trond Eivind Glomsrod <teg@redhat.com>
+- specify ownership
+
+* Wed Jun 07 2000 Trond Eivind Glomsrod <teg@redhat.com>
+- Version 3.9.7
+- use %%{_mandir}, %%{_makeinstall}, %%configure, %%makeinstall
+  and %%{_tmppath}
+
+* Wed Feb 09 2000 Cristian Gafton <gafton@redhat.com>
+- get rid of mtools.texi as a doc file (we have the info file)
+- fix config file so mtools work (#9264)
+- fix references to the config file to be /etc/mtools.conf
+
+* Fri Feb  4 2000 Bill Nottingham <notting@redhat.com>
+- expunge floppyd
+
+* Thu Feb 03 2000 Cristian Gafton <gafton@redhat.com>
+- man pages are compressed
+- fix description
+- version 3.9.6
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com> 
+- auto rebuild in the new build environment (release 5)
+
+* Thu Mar 18 1999 Cristian Gafton <gafton@redhat.com>
+- patch to make the texi sources compile
+- fix the spec file group and description
+- fixed floppy drive sizes
+
+* Tue Dec 29 1998 Cristian Gafton <gafton@redhat.com>
+- build for 6.0
+- fixed invalid SAMPLE_FILE configuration file
+
+* Wed Sep 02 1998 Michael Maher <mike@redhat.com>
+- Built package for 5.2.
+- Updated Source to 3.9.1.
+- Cleaned up spec file.
+
+* Fri Apr 24 1998 Prospector System <bugs@redhat.com>
+- translations modified for de, fr, tr
+
+* Fri Apr 10 1998 Cristian Gafton <gafton@redhat.com>
+- updated to 3.8
+
+* Tue Oct 21 1997 Otto Hammersmith
+- changed buildroot to /var/tmp, rather than /tmp
+- use install-info
+
+* Mon Jul 21 1997 Erik Troan <ewt@redhat.com>
+- built against glibc
+
+* Thu Apr 17 1997 Erik Troan <ewt@redhat.com>
+- Changed sysconfdir to be /etc
+
+* Mon Apr 14 1997 Michael Fulbright <msf@redhat.com>
+- Updated to 3.6
diff --git a/packaging/mtools.spec b/packaging/mtools.spec
new file mode 100644 (file)
index 0000000..fa22613
--- /dev/null
@@ -0,0 +1,51 @@
+Summary: Programs for accessing MS-DOS disks without mounting the disks
+Name: mtools
+Version: 4.0.12
+Release: 4
+License: GPLv2+
+Group: Applications/System
+Source: ftp://ftp.gnu.org/gnu/mtools/mtools-%{version}.tar.bz2
+Url: http://mtools.linux.lu/
+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+Patch0: mtools-3.9.6-config.patch
+Patch1: mtools-3.9.7-bigdisk.patch
+Patch2: fix_mlabel_initialisation.patch
+
+BuildRequires: texinfo, autoconf
+
+%description
+Mtools is a collection of utilities for accessing MS-DOS files.
+Mtools allow you to read, write and move around MS-DOS filesystem
+files (normally on MS-DOS floppy disks).  Mtools supports Windows95
+style long file names, OS/2 XDF disks, and 2m disks
+
+Mtools should be installed if you need to use MS-DOS disks
+
+%prep
+%setup -q -n %{name}-%{version}
+%patch0 -p1
+%patch1 -p1
+%patch2 -p1
+
+%build
+autoreconf -fiv
+%configure --disable-floppyd
+make %{?_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/etc $RPM_BUILD_ROOT/%{_infodir}
+%makeinstall
+install -m644 mtools.conf $RPM_BUILD_ROOT/etc
+
+# We aren't shipping this.
+find $RPM_BUILD_ROOT -name "floppyd*" -exec rm {} \;
+
+%remove_docs
+
+%files
+%defattr(-,root,root)
+%config(noreplace) /etc/mtools.conf
+%doc COPYING README Release.notes
+/usr/bin/*
+
diff --git a/partition.h b/partition.h
new file mode 100644 (file)
index 0000000..5c43739
--- /dev/null
@@ -0,0 +1,49 @@
+/*  Copyright 1997,1998,2001-2003,2006,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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, int begin, int end,
+                                int heads, int sector, int activate, int type);
diff --git a/patchlevel.c b/patchlevel.c
new file mode 100644 (file)
index 0000000..28e0a08
--- /dev/null
@@ -0,0 +1,24 @@
+/*  Copyright 1999-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+const char *mversion="4.0.12";
+
+/* Multiple releases on same day should be marked with (b), (cd), (d) after
+ * date string below */
+const char *mdate = "November 3rd, 2009";
+
+const char *mformat_banner = "MTOO4012";
diff --git a/plain_io.c b/plain_io.c
new file mode 100644 (file)
index 0000000..a82f00b
--- /dev/null
@@ -0,0 +1,784 @@
+/*  Copyright 1995-2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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"
+
+typedef struct SimpleFile_t {
+    Class_t *Class;
+    int refs;
+    Stream_t *Next;
+    Stream_t *Buffer;
+    struct MT_STAT statbuf;
+    int fd;
+    mt_off_t offset;
+    mt_off_t lastwhere;
+    int seekable;
+    int privileged;
+#ifdef OS_hpux
+    int size_limited;
+#endif
+    int scsi_sector_size;
+    void *extra_data; /* extra system dependant information for scsi */
+    int swap; /* do the word swapping */
+} SimpleFile_t;
+
+
+#include "lockdev.h"
+
+typedef int (*iofn) (int, char *, int);
+
+
+static void swap_buffer(char *buf, size_t len)
+{
+       unsigned int i;
+       for (i=0; 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)
+{
+#if 0
+       DeclareThis(SimpleFile_t);
+
+       return fsync(This->fd);
+#endif
+       return 0;
+}
+
+static int file_free(Stream_t *Stream)
+{
+       DeclareThis(SimpleFile_t);
+
+       if (This->fd > 2)
+               return close(This->fd);
+       else
+               return 0;
+}
+
+static int file_geom(Stream_t *Stream, struct device *dev, 
+                    struct device *orig_dev,
+                    int media, union bootsector *boot)
+{
+       int ret;
+       DeclareThis(SimpleFile_t);
+       size_t tot_sectors;
+       int BootP, Infp0, InfpX, InfTm;
+       int sectors, j;
+       unsigned char sum;
+       int sect_per_track;
+       struct label_blk_t *labelBlock;
+
+       dev->ssize = 2; /* allow for init_geom to change it */
+       dev->use_2m = 0x80; /* disable 2m mode to begin */
+
+       if(media == 0xf0 || media >= 0x100){            
+               dev->heads = WORD(nheads);
+               dev->sectors = WORD(nsect);
+               tot_sectors = DWORD(bigsect);
+               SET_INT(tot_sectors, WORD(psect));
+               sect_per_track = dev->heads * dev->sectors;
+               if(sect_per_track == 0) {
+                   if(mtools_skip_check) {
+                       /* add some fake values if sect_per_track is
+                        * zero. Indeed, some atari disks lack the
+                        * geometry values (i.e. have zeroes in their
+                        * place). In order to avoid division by zero
+                        * errors later on, plug 1 everywhere
+                        */
+                       dev->heads = 1;
+                       dev->sectors = 1;
+                       sect_per_track = 1;
+                   } else {
+                       fprintf(stderr, "The devil is in the details: zero number of heads or sectors\n");
+                       exit(1);
+                   }
+               }
+               tot_sectors += sect_per_track - 1; /* round size up */
+               dev->tracks = tot_sectors / sect_per_track;
+
+               BootP = WORD(ext.old.BootP);
+               Infp0 = WORD(ext.old.Infp0);
+               InfpX = WORD(ext.old.InfpX);
+               InfTm = WORD(ext.old.InfTm);
+               
+               if(WORD(fatlen)) {
+                       labelBlock = &boot->boot.ext.old.labelBlock;
+               } else {
+                       labelBlock = &boot->boot.ext.fat32.labelBlock;
+               }
+
+               if (boot->boot.descr >= 0xf0 &&
+                   labelBlock->dos4 == 0x29 &&
+                   strncmp( boot->boot.banner,"2M", 2 ) == 0 &&
+                   BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 &&
+                   BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 && 
+                   Infp0 >= 76 ){
+                       for (sum=0, j=63; j < BootP; j++) 
+                               sum += boot->bytes[j];/* checksum */
+                       dev->ssize = boot->bytes[InfTm];
+                       if (!sum && dev->ssize <= 7){
+                               dev->use_2m = 0xff;
+                               dev->ssize |= 0x80; /* is set */
+                       }
+               }
+       } else if (media >= 0xf8){
+               media &= 3;
+               dev->heads = old_dos[media].heads;
+               dev->tracks = old_dos[media].tracks;
+               dev->sectors = old_dos[media].sectors;
+               dev->ssize = 0x80;
+               dev->use_2m = ~1;
+       } else {
+               fprintf(stderr,"Unknown media type\n");
+               exit(1);
+       }
+
+       sectors = dev->sectors;
+       dev->sectors = dev->sectors * WORD(secsiz) / 512;
+
+#ifdef JPD
+       printf("file_geom:media=%0X=>cyl=%d,heads=%d,sects=%d,ssize=%d,use2m=%X\n",
+              media, dev->tracks, dev->heads, dev->sectors, dev->ssize,
+              dev->use_2m);
+#endif
+       ret = init_geom(This->fd,dev, orig_dev, &This->statbuf);
+       dev->sectors = sectors;
+#ifdef JPD
+       printf("f_geom: after init_geom(), sects=%d\n", dev->sectors);
+#endif
+       return ret;
+}
+
+
+static int file_data(Stream_t *Stream, time_t *date, mt_size_t *size,
+                    int *type, int *address)
+{
+       DeclareThis(SimpleFile_t);
+
+       if(date)
+               *date = This->statbuf.st_mtime;
+       if(size)
+               *size = This->statbuf.st_size;
+       if(type)
+               *type = S_ISDIR(This->statbuf.st_mode);
+       if(address)
+               *address = 0;
+       return 0;
+}
+
+/* ZIP or other scsi device on Solaris or SunOS system.
+   Since Sun won't accept a non-Sun label on a scsi disk, we must
+   bypass Sun's disk interface and use low-level SCSI commands to read
+   or write the ZIP drive.  We thus replace the file_read and file_write
+   routines with our own scsi_read and scsi_write routines, that use the
+   uscsi ioctl interface.  By James Dugal, jpd@usl.edu, 11-96.  Tested
+   under Solaris 2.5 and SunOS 4.3.1_u1 using GCC.
+
+   Note: the mtools.conf entry for a ZIP drive would look like this:
+(solaris) drive C: file="/dev/rdsk/c0t5d0s2" partition=4  FAT=16 nodelay  exclusive scsi=&
+(sunos) drive C: file="/dev/rsd5c" partition=4  FAT=16 nodelay  exclusive scsi=1
+
+   Note 2: Sol 2.5 wants mtools to be suid-root, to use the ioctl.  SunOS is
+   happy if we just have access to the device, so making mtools sgid to a
+   group called, say, "ziprw" which has rw permission on /dev/rsd5c, is fine.
+ */
+
+#define MAXBLKSPERCMD 255
+
+static void scsi_init(SimpleFile_t *This)
+{
+   int fd = This->fd;
+   unsigned char cdb[10],buf[8];
+
+   memset(cdb, 0, sizeof cdb);
+   memset(buf,0, sizeof(buf));
+   cdb[0]=SCSI_READ_CAPACITY;
+   if (scsi_cmd(fd, (unsigned char *)cdb, 
+               sizeof(cdb), SCSI_IO_READ, buf, sizeof(buf), This->extra_data)==0)
+   {
+       This->scsi_sector_size=
+              ((unsigned)buf[5]<<16)|((unsigned)buf[6]<<8)|(unsigned)buf[7];
+       if (This->scsi_sector_size != 512)
+          fprintf(stderr,"  (scsi_sector_size=%d)\n",This->scsi_sector_size);
+   }
+}
+
+static int scsi_io(Stream_t *Stream, char *buf,
+                  mt_off_t where, size_t len, int rwcmd)
+{
+       unsigned int firstblock, nsect;
+       int clen,r;
+       size_t max;
+       off_t offset;
+       unsigned char cdb[10];
+       DeclareThis(SimpleFile_t);
+
+       firstblock=truncBytes32((where + This->offset)/This->scsi_sector_size);
+       /* 512,1024,2048,... bytes/sector supported */
+       offset=truncBytes32(where + This->offset - 
+                                               firstblock*This->scsi_sector_size);
+       nsect=(offset+len+This->scsi_sector_size-1)/ This->scsi_sector_size;
+#if defined(OS_sun) && defined(OS_i386)
+       if (This->scsi_sector_size>512)
+               firstblock*=This->scsi_sector_size/512; /* work around a uscsi bug */
+#endif /* sun && i386 */
+
+       if (len>512) {
+               /* avoid buffer overruns. The transfer MUST be smaller or
+               * equal to the requested size! */
+               while (nsect*This->scsi_sector_size>len)
+                       --nsect;
+               if(!nsect) {                    
+                       fprintf(stderr,"Scsi buffer too small\n");
+                       exit(1);
+               }
+               if(rwcmd == SCSI_IO_WRITE && offset) {
+                       /* there seems to be no memmove before a write */
+                       fprintf(stderr,"Unaligned write\n");
+                       exit(1);
+               }
+               /* a better implementation should use bounce buffers.
+                * However, in normal operation no buffer overruns or
+                * unaligned writes should happen anyways, as the logical
+                * sector size is (hopefully!) equal to the physical one
+                */
+       }
+
+
+       max = scsi_max_length();
+       
+       if (nsect > max)
+               nsect=max;
+       
+       /* set up SCSI READ/WRITE command */
+       memset(cdb, 0, sizeof cdb);
+
+       switch(rwcmd) {
+               case SCSI_IO_READ:
+                       cdb[0] = SCSI_READ;
+                       break;
+               case SCSI_IO_WRITE:
+                       cdb[0] = SCSI_WRITE;
+                       break;
+       }
+
+       cdb[1] = 0;
+
+       if (firstblock > 0x1fffff || nsect > 0xff) {
+               /* I suspect that the ZIP drive also understands Group 1
+                * commands. If that is indeed true, we may chose Group 1
+                * more agressively in the future */
+
+               cdb[0] |= SCSI_GROUP1;
+               clen=10; /* SCSI Group 1 cmd */
+
+               /* this is one of the rare case where explicit coding is
+                * more portable than macros... The meaning of scsi command
+                * bytes is standardised, whereas the preprocessor macros
+                * handling it might be not... */
+
+               cdb[2] = (unsigned char) (firstblock >> 24) & 0xff;
+               cdb[3] = (unsigned char) (firstblock >> 16) & 0xff;
+               cdb[4] = (unsigned char) (firstblock >> 8) & 0xff;
+               cdb[5] = (unsigned char) firstblock & 0xff;
+               cdb[6] = 0;
+               cdb[7] = (unsigned char) (nsect >> 8) & 0xff;
+               cdb[8] = (unsigned char) nsect & 0xff;
+               cdb[9] = 0;
+       } else {
+               clen = 6; /* SCSI Group 0 cmd */
+               cdb[1] |= (unsigned char) ((firstblock >> 16) & 0x1f);
+               cdb[2] = (unsigned char) ((firstblock >> 8) & 0xff);
+               cdb[3] = (unsigned char) firstblock & 0xff;
+               cdb[4] = (unsigned char) nsect;
+               cdb[5] = 0;
+       }
+       
+       if(This->privileged)
+               reclaim_privs();
+
+       r=scsi_cmd(This->fd, (unsigned char *)cdb, clen, rwcmd, buf,
+                  nsect*This->scsi_sector_size, This->extra_data);
+
+       if(This->privileged)
+               drop_privs();
+
+       if(r) {
+               perror(rwcmd == SCSI_IO_READ ? "SCMD_READ" : "SCMD_WRITE");
+               return -1;
+       }
+#ifdef JPD
+       printf("finished %u for %u\n", firstblock, nsect);
+#endif
+
+#ifdef JPD
+       printf("zip: read or write OK\n");
+#endif
+       if (offset>0) memmove(buf,buf+offset,nsect*This->scsi_sector_size-offset);
+       if (len==256) return 256;
+       else if (len==512) return 512;
+       else return nsect*This->scsi_sector_size-offset;
+}
+
+static int scsi_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
+{
+       
+#ifdef JPD
+       printf("zip: to read %d bytes at %d\n", len, where);
+#endif
+       return scsi_io(Stream, buf, where, len, SCSI_IO_READ);
+}
+
+static int scsi_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
+{
+#ifdef JPD
+       Printf("zip: to write %d bytes at %d\n", len, where);
+#endif
+       return scsi_io(Stream, buf, where, len, SCSI_IO_WRITE);
+}
+
+static Class_t ScsiClass = {
+       scsi_read, 
+       scsi_write,
+       file_flush,
+       file_free,
+       file_geom,
+       file_data,
+       0 /* pre-allocate */
+};
+
+
+static Class_t SimpleFileClass = {
+       file_read, 
+       file_write,
+       file_flush,
+       file_free,
+       file_geom,
+       file_data,
+       0 /* pre_allocate */
+};
+
+
+Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
+                        const char *name, int mode, char *errmsg, 
+                        int mode2, int locked, mt_size_t *maxSize)
+{
+       SimpleFile_t *This;
+#ifdef __EMX__
+HFILE FileHandle;
+ULONG Action;
+APIRET rc;
+#endif
+       This = New(SimpleFile_t);
+       if (!This){
+               printOom();
+               return 0;
+       }
+       This->scsi_sector_size = 512;
+       This->seekable = 1;
+#ifdef OS_hpux
+       This->size_limited = 0;
+#endif
+       This->Class = &SimpleFileClass;
+       if (!name || strcmp(name,"-") == 0 ){
+               if (mode == O_RDONLY)
+                       This->fd = 0;
+               else
+                       This->fd = 1;
+               This->seekable = 0;
+               This->refs = 1;
+               This->Next = 0;
+               This->Buffer = 0;
+               if (MT_FSTAT(This->fd, &This->statbuf) < 0) {
+                   Free(This);
+                   if(errmsg)
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg,199,"Can't stat -: %s", 
+                               strerror(errno));   
+#else
+                       sprintf(errmsg,"Can't stat -: %s", 
+                               strerror(errno));
+#endif
+                   return NULL;
+               }
+
+               return (Stream_t *) This;
+       }
+
+       
+       if(dev) {
+               if(!(mode2 & NO_PRIV))
+                       This->privileged = IS_PRIVILEGED(dev);
+               mode |= dev->mode;
+       }
+
+       precmd(dev);
+       if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
+               reclaim_privs();
+
+#ifdef __EMX__
+#define DOSOPEN_FLAGS  (OPEN_FLAGS_DASD | OPEN_FLAGS_WRITE_THROUGH | \
+                       OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_RANDOM | \
+                       OPEN_FLAGS_NO_CACHE)
+#define DOSOPEN_FD_ACCESS (OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE)
+#define DOSOPEN_HD_ACCESS (OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY)
+
+       if (isalpha(*name) && (*(name+1) == ':')) {
+               rc = DosOpen(
+                       name, &FileHandle, &Action, 0L, FILE_NORMAL,
+                       OPEN_ACTION_OPEN_IF_EXISTS, DOSOPEN_FLAGS |
+                       (IS_NOLOCK(dev)?DOSOPEN_HD_ACCESS:DOSOPEN_FD_ACCESS),
+                       0L);
+#if DEBUG
+               if (rc != NO_ERROR) fprintf (stderr, "DosOpen() returned %d\n", rc);
+#endif
+               if (!IS_NOLOCK(dev)) {
+                       rc = DosDevIOCtl(
+                       FileHandle, 0x08L, DSK_LOCKDRIVE, 0, 0, 0, 0, 0, 0);
+#if DEBUG
+                       if (rc != NO_ERROR) fprintf (stderr, "DosDevIOCtl() returned %d\n", rc);
+#endif
+               }
+               if (rc == NO_ERROR)
+                       This->fd = _imphandle(FileHandle); else This->fd = -1;
+       } else
+#endif
+           {
+               if (IS_SCSI(dev))
+                   This->fd = scsi_open(name, mode, IS_NOLOCK(dev)?0444:0666,
+                                        &This->extra_data);
+               else
+                   This->fd = open(name, mode | O_LARGEFILE | O_BINARY, 
+                                   IS_NOLOCK(dev)?0444:0666);
+           }
+
+       if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
+               drop_privs();
+               
+       if (This->fd < 0) {
+               Free(This);
+               if(errmsg)
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg, 199, "Can't open %s: %s",
+                               name, strerror(errno));
+#else
+                       sprintf(errmsg, "Can't open %s: %s",
+                               name, strerror(errno));
+#endif
+               return NULL;
+       }
+
+       if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
+               closeExec(This->fd);
+
+#ifdef __EMX__
+       if (*(name+1) != ':')
+#endif
+       if (MT_FSTAT(This->fd, &This->statbuf) < 0
+#ifdef OS_mingw32msvc
+           && strncmp(name, "\\\\.\\", 4) != 0
+#endif
+          ) {
+               Free(This);
+               if(errmsg) {
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg,199,"Can't stat %s: %s", 
+                               name, strerror(errno));
+#else
+                       if(strlen(name) > 50) {
+                           sprintf(errmsg,"Can't stat file: %s", 
+                                   strerror(errno));
+                       } else {
+                           sprintf(errmsg,"Can't stat %s: %s", 
+                               name, strerror(errno));
+                       }
+#endif
+               }
+               return NULL;
+       }
+#ifndef __EMX__
+#ifndef __CYGWIN__
+#ifndef OS_mingw32msvc
+       /* lock the device on writes */
+       if (locked && lock_dev(This->fd, mode == O_RDWR, dev)) {
+               if(errmsg)
+#ifdef HAVE_SNPRINTF
+                       snprintf(errmsg,199,
+                               "plain floppy: device \"%s\" busy (%s):",
+                               dev ? dev->name : "unknown", strerror(errno));
+#else
+                       sprintf(errmsg,
+                               "plain floppy: device \"%s\" busy (%s):",
+                               (dev && strlen(dev->name) < 50) ? 
+                                dev->name : "unknown", strerror(errno));
+#endif
+
+               close(This->fd);
+               Free(This);
+               return NULL;
+       }
+#endif
+#endif
+#endif
+       /* set default parameters, if needed */
+       if (dev){               
+               if ((!IS_MFORMAT_ONLY(dev) && dev->tracks) &&
+                       init_geom(This->fd, dev, orig_dev, &This->statbuf)){
+                       close(This->fd);
+                       Free(This);
+                       if(errmsg)
+                               sprintf(errmsg,"init: set default params");
+                       return NULL;
+               }
+               This->offset = (mt_off_t) dev->offset;
+       } else
+               This->offset = 0;
+
+       This->refs = 1;
+       This->Next = 0;
+       This->Buffer = 0;
+
+       if(maxSize) {
+               if (IS_SCSI(dev)) {
+                       *maxSize = MAX_OFF_T_B(31+log_2(This->scsi_sector_size));
+               } else {
+                       *maxSize = max_off_t_seek;
+               }
+               if(This->offset > *maxSize) {
+                       close(This->fd);
+                       Free(This);
+                       if(errmsg)
+                               sprintf(errmsg,"init: Big disks not supported");
+                       return NULL;
+               }
+               
+               *maxSize -= This->offset;
+       }
+       /* partitioned drive */
+
+       /* jpd@usl.edu: assume a partitioned drive on these 2 systems is a ZIP*/
+       /* or similar drive that must be accessed by low-level scsi commands */
+       /* AK: introduce new "scsi=1" statement to specifically set
+        * this option. Indeed, there could conceivably be partitioned
+        * devices where low level scsi commands will not be needed */
+       if(IS_SCSI(dev)) {
+               This->Class = &ScsiClass;
+               if(This->privileged)
+                       reclaim_privs();
+               scsi_init(This);
+               if(This->privileged)
+                       drop_privs();
+       }
+
+       This->swap = DO_SWAP( dev );
+
+       if(!(mode2 & NO_OFFSET) &&
+          dev && (dev->partition > 4 || dev->partition < 0))
+           fprintf(stderr, 
+                   "Invalid partition %d (must be between 0 and 4), ignoring it\n", 
+                   dev->partition);
+
+       while(!(mode2 & NO_OFFSET) &&
+             dev && dev->partition && dev->partition <= 4) {
+               int has_activated;
+               unsigned int last_end, j;
+               unsigned char buf[2048];
+               struct partition *partTable=(struct partition *)(buf+ 0x1ae);
+               size_t partOff;
+               
+               /* read the first sector, or part of it */
+               if (force_read((Stream_t *)This, (char*) buf, 0, 512) != 512)
+                       break;
+               if( _WORD(buf+510) != 0xaa55)
+                       break;
+
+               partOff = BEGIN(partTable[dev->partition]);
+               if (maxSize) {
+                       if (partOff > *maxSize >> 9) {
+                               close(This->fd);
+                               Free(This);
+                               if(errmsg)
+                                       sprintf(errmsg,"init: Big disks not supported");
+                               return NULL;
+                       }
+                       *maxSize -= (mt_off_t) partOff << 9;
+               }
+                       
+               This->offset += (mt_off_t) partOff << 9;
+               if(!partTable[dev->partition].sys_ind) {
+                       if(errmsg)
+                               sprintf(errmsg,
+                                       "init: non-existant partition");
+                       close(This->fd);
+                       Free(This);
+                       return NULL;
+               }
+
+               if(!dev->tracks) {
+                       dev->heads = head(partTable[dev->partition].end)+1;
+                       dev->sectors = sector(partTable[dev->partition].end);
+                       dev->tracks = cyl(partTable[dev->partition].end) -
+                               cyl(partTable[dev->partition].start)+1;
+               }
+               dev->hidden=
+                       dev->sectors*head(partTable[dev->partition].start) +
+                       sector(partTable[dev->partition].start)-1;
+               if(!mtools_skip_check &&
+                  consistencyCheck((struct partition *)(buf+0x1ae), 0, 0,
+                                   &has_activated, &last_end, &j, dev, 0)) {
+                       fprintf(stderr,
+                               "Warning: inconsistent partition table\n");
+                       fprintf(stderr,
+                               "Possibly unpartitioned device\n");
+                       fprintf(stderr,
+                               "\n*** Maybe try without partition=%d in "
+                               "device definition ***\n\n",
+                               dev->partition);
+                       fprintf(stderr,
+                                "If this is a PCMCIA card, or a disk "
+                               "partitioned on another computer, this "
+                               "message may be in error: add "
+                               "mtools_skip_check=1 to your .mtoolsrc "
+                               "file to suppress this warning\n");
+
+               }
+               break;
+               /* NOTREACHED */
+       }
+
+       This->lastwhere = -This->offset;
+       /* provoke a seek on those devices that don't start on a partition
+        * boundary */
+
+       return (Stream_t *) This;
+}
+
+int get_fd(Stream_t *Stream)
+{
+       Class_t *clazz;
+       DeclareThis(SimpleFile_t);
+       clazz = This->Class;
+       if(clazz != &ScsiClass &&
+          clazz != &SimpleFileClass)
+         return -1;
+       else
+         return This->fd;
+}
+
+void *get_extra_data(Stream_t *Stream)
+{
+       DeclareThis(SimpleFile_t);
+       
+       return This->extra_data;
+}
diff --git a/plain_io.h b/plain_io.h
new file mode 100644 (file)
index 0000000..5abb90c
--- /dev/null
@@ -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 (file)
index 0000000..8d1fc96
--- /dev/null
+++ b/precmd.c
@@ -0,0 +1,48 @@
+/*  Copyright 1997,1999,2001-2004,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Do filename expansion with the shell.
+ */
+
+#define EXPAND_BUF     2048
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+void precmd(struct device *dev)
+{
+#ifndef OS_mingw32msvc
+       int status;
+       pid_t pid;
+
+       if(!dev || !dev->precmd)
+               return;
+       
+       switch((pid=fork())){
+               case -1:
+                       perror("Could not fork");
+                       exit(1);
+                       break;
+               case 0: /* the son */
+                       execl("/bin/sh", "sh", "-c", dev->precmd, (char *)NULL);
+                       break;
+               default:
+                       wait(&status);
+                       break;
+       }
+#endif
+}
+               
diff --git a/privileges.c b/privileges.c
new file mode 100644 (file)
index 0000000..c2f5c74
--- /dev/null
@@ -0,0 +1,211 @@
+/*  Copyright 1997,1999,2001,2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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)
+{
+#ifdef PRIV_DEBUG
+       /* for debugging purposes only */
+       fprintf(stderr,"%s egid=%d rgid=%d\n", message, getegid(), getgid());
+       fprintf(stderr,"%s euid=%d ruid=%d\n", message, geteuid(), getuid());
+#endif
+}
+
+
+static gid_t rgid, egid;
+static uid_t ruid, euid;
+
+/* privilege management routines for SunOS and Solaris.  These are
+ * needed in order to issue raw SCSI read/write ioctls.  Mtools drops
+ * its privileges at the beginning, and reclaims them just for the
+ * above-mentioned ioctl's.  Before popen(), exec() or system, it
+ * drops its privileges completely, and issues a warning.
+ */
+
+
+/* group id handling is lots easyer, as long as we don't use group 0.
+ * If you want to use group id's, create a *new* group mtools or
+ * floppy.  Chgrp any devices that you only want to be accessible to
+ * mtools to this group, and give them the appropriate privs.  Make
+ * sure this group doesn't own any other files: be aware that any user
+ * with access to mtools may mformat these files!
+ */
+
+
+static __inline__ void Setuid(uid_t uid)
+{
+#if defined HAVE_SETEUID || defined HAVE_SETRESUID
+       if(euid == 0) {
+#ifdef HAVE_SETEUID
+               seteuid(uid);
+#else
+               setresuid(ruid, uid, euid);
+#endif
+       } else
+#endif
+               setuid(uid);
+}
+
+/* In reclaim_privs and drop privs, we have to manipulate group privileges
+ * when having no root privileges, else we might lose them */
+
+void reclaim_privs(void)
+{
+       if(noPrivileges)
+               return;
+       setgid(egid);
+       Setuid(euid);
+       print_privs("after reclaim privs, both uids should be 0 ");
+}
+
+void drop_privs(void)
+{
+       Setuid(ruid);
+       setgid(rgid);
+       print_privs("after drop_privs, real should be 0, effective should not ");
+}
+
+void destroy_privs(void)
+{
+
+#if defined HAVE_SETEUID || defined HAVE_SETRESUID
+       if(euid == 0) {
+#ifdef HAVE_SETEUID
+               setuid(0); /* get the necessary privs to drop real root id */
+               setuid(ruid); /* this should be enough to get rid of the three
+                              * ids */
+               seteuid(ruid); /* for good measure... just in case we came
+                               * accross a system which implemented sane
+                               * semantics instead of POSIXly broken
+                               * semantics for setuid */
+#else
+               setresuid(ruid, ruid, ruid);
+#endif
+       }
+#endif
+
+       /* we also destroy group privileges */
+       drop_privs();
+
+       /* saved set [ug]id will go away by itself on exec */
+
+       print_privs("destroy_privs, no uid should be zero  ");
+}
+
+
+uid_t get_real_uid(void)
+{
+       return ruid;
+}
+
+void init_privs(void)
+{
+       euid = geteuid();
+       ruid = getuid();
+       egid = getegid();
+       rgid = getgid();
+
+#ifndef F_SETFD
+       if(euid != ruid) {
+               fprintf(stderr,
+                       "Setuid installation not supported on this platform\n");
+               fprintf(stderr,
+                       "Missing F_SETFD");
+               exit(1);
+       }
+#endif
+       
+       if(euid == 0 && ruid != 0) {
+#ifdef HAVE_SETEUID
+               setuid(0); /* set real uid to 0 */
+#else
+#ifndef HAVE_SETRESUID
+               /* on this machine, it is not possible to reversibly drop
+                * root privileges.  We print an error and quit */
+
+               /* BEOS is no longer a special case, as both euid and ruid
+                * return 0, and thus we do not get any longer into this
+                * branch */
+               fprintf(stderr,
+                       "Seteuid call not supported on this architecture.\n");
+               fprintf(stderr,
+                       "Mtools cannot be installed setuid root.\n");
+               fprintf(stderr,
+                       "However, it can be installed setuid to a non root");
+               fprintf(stderr,
+                       "user or setgid to any id.\n");
+               exit(1);
+#endif
+#endif
+       }
+       
+       drop_privs();
+       print_privs("after init, real should be 0, effective should not ");
+}
+
+void closeExec(int fd)
+{
+#ifdef F_SETFD
+       fcntl(fd, F_SETFD, 1);
+#endif
+}
+#endif
diff --git a/privtest.c b/privtest.c
new file mode 100644 (file)
index 0000000..e4c60f7
--- /dev/null
@@ -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 (file)
index 0000000..fc5dd63
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef READ_DWORD
+#define READ_DWORD
+
+/*  Copyright 2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static Dword read_dword(int handle) 
+{
+       Byte val[4];
+       
+       if(read(handle, (char *)val, 4) < 4)
+               return -1;
+
+       return byte2dword(val);
+}
+#endif
diff --git a/scripts/add-disk b/scripts/add-disk
new file mode 100755 (executable)
index 0000000..3e14e58
--- /dev/null
@@ -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 (executable)
index 0000000..c9ff469
--- /dev/null
@@ -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 (executable)
index 0000000..142eb99
--- /dev/null
@@ -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 (file)
index 0000000..7fd31c1
--- /dev/null
@@ -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 (executable)
index 0000000..f2c917f
--- /dev/null
@@ -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 (executable)
index 0000000..9b12212
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Copyright 1996,1997,2001,2002,2006 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <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 (executable)
index 0000000..0f874bc
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Copyright 1996,1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <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 (executable)
index 0000000..8769ea6
--- /dev/null
@@ -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 (executable)
index 0000000..ba1cc28
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Copyright 1994,2002 David C. Niemi.
+# Copyright 1996,1997,2001-2003 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <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
+#
+# Copyright (C) 1994, 2002 David C. Niemi (niemi at tuxers dot net)
+# The author requires that any copies or derived works include this
+# copyright notice; no other restrictions are placed on its use.
+#
+
+set -e
+set -u
+
+## Default unzipping command
+uzcmd='gzip -cd'
+
+case $0 in
+*uz)
+       tarparam="-pxvf"
+       action="Extracting from "
+       ;;
+*lz)
+       tarparam="-tvf"
+       action="Reading directory of "
+       ;;
+*)
+       echo "$0: expect to be named either \"uz\" or \"lz\"." >&2
+       exit 1
+       ;;
+esac
+
+if [ $# = 0 ]; then
+       echo "$action standard input." >&2
+       $uzcmd - | tar "$tarparam" -
+       exit 0
+fi
+
+while [ $# -ge 1 ]; do
+       echo >&2
+       found=
+
+       for suffix in "" .gz .tgz .tar.gz .z .tar.z .taz .tpz .Z .tar.Z .tar.bz2; do
+               if [ -r "${1}$suffix" ]; then
+                       found=$1$suffix
+                       break
+               fi
+       done
+
+       case $found in
+               *.tar.bz2 | *.tb2)
+                       uzcmd='bzip2 -cd'
+                       ;;
+       esac
+       if [ -z "$found" ]; then
+               echo "$0: could not read \"$1\"." >&2
+       else
+               echo "$action \"$found\"." >&2
+               $uzcmd -- "$found" | tar "$tarparam" -
+       fi
+       shift
+done
+
+exit 0
diff --git a/scsi.c b/scsi.c
new file mode 100644 (file)
index 0000000..6cf6537
--- /dev/null
+++ b/scsi.c
@@ -0,0 +1,330 @@
+/*  Copyright 1996   Grant R. Guenther,  based on work of Itai Nahshon
+ *   http://www.torque.net/ziptool.html
+ *  Copyright 1997-1999,2001,2002,2005,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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
+#define SCSI_IOCTL_SEND_COMMAND 1
+struct scsi_ioctl_command {
+    int  inlen;
+    int  outlen;
+    char cmd[5008];
+};
+#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, int mode, void **extra_data)
+{
+#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
+    struct cam_device *cam_dev;
+    cam_dev = cam_open_device(name, O_RDWR);
+    *extra_data = (void *) cam_dev;
+    if (cam_dev)
+        return cam_dev->fd;
+    else
+        return -1;
+#else
+    return open(name, O_RDONLY | O_LARGEFILE | O_BINARY
+#ifdef O_NDELAY
+               | O_NDELAY
+#endif
+       /* O_RDONLY  | dev->mode*/);
+#endif
+}
+
+int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode,
+            void *data, size_t len, void *extra_data)
+{
+#if defined OS_hpux
+       struct sctl_io sctl_io;
+       
+       memset(&sctl_io, 0, sizeof sctl_io);   /* clear reserved fields */
+       memcpy(sctl_io.cdb, cdb, cmdlen);      /* copy command */
+       sctl_io.cdb_length = cmdlen;           /* command length */
+       sctl_io.max_msecs = 2000;              /* allow 2 seconds for cmd */
+
+       switch (mode) {
+               case SCSI_IO_READ:
+                       sctl_io.flags = SCTL_READ;
+                       sctl_io.data_length = len;
+                       sctl_io.data = data;
+                       break;
+               case SCSI_IO_WRITE: 
+                       sctl_io.flags = 0;
+                       sctl_io.data_length = data ? len : 0;
+                       sctl_io.data = len ? data : 0;
+                       break;
+       }
+
+       if (ioctl(fd, SIOC_IO, &sctl_io) == -1) {
+               perror("scsi_io");
+               return -1;
+       }
+
+       return sctl_io.cdb_status;
+       
+#elif defined OS_sunos || defined OS_solaris
+       struct uscsi_cmd uscsi_cmd;
+       memset(&uscsi_cmd, 0, sizeof uscsi_cmd);
+       uscsi_cmd.uscsi_cdb = (char *)cdb;
+       uscsi_cmd.uscsi_cdblen = cmdlen;
+#ifdef OS_solaris
+       uscsi_cmd.uscsi_timeout = 20;  /* msec? */
+#endif /* solaris */
+       
+       uscsi_cmd.uscsi_buflen = (u_int)len;
+       uscsi_cmd.uscsi_bufaddr = data;
+
+       switch (mode) {
+               case SCSI_IO_READ:
+                       uscsi_cmd.uscsi_flags = USCSI_READ;
+                       break;
+               case SCSI_IO_WRITE:
+                       uscsi_cmd.uscsi_flags = USCSI_WRITE;
+                       break;
+       }
+
+       if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) {
+               perror("scsi_io");
+               return -1;
+       }
+
+       if(uscsi_cmd.uscsi_status) {
+               errno = 0;
+               fprintf(stderr,"scsi status=%x\n",  
+                       (unsigned short)uscsi_cmd.uscsi_status);
+               return -1;
+       }
+       
+       return 0;
+       
+#elif defined OS_linux
+       struct scsi_ioctl_command my_scsi_cmd;
+
+
+       memcpy(my_scsi_cmd.cmd, cdb, cmdlen);        /* copy command */
+
+       switch (mode) {
+               case SCSI_IO_READ:
+                       my_scsi_cmd.inlen = 0;
+                       my_scsi_cmd.outlen = len;
+                       break;
+               case SCSI_IO_WRITE:
+                       my_scsi_cmd.inlen = len;
+                       my_scsi_cmd.outlen = 0;
+                       memcpy(my_scsi_cmd.cmd + cmdlen,data,len);
+                       break;
+       }
+       
+       if (ioctl(fd, SCSI_IOCTL_SEND_COMMAND, &my_scsi_cmd) < 0) {
+               perror("scsi_io");
+               return -1;
+       }
+       
+       switch (mode) {
+               case SCSI_IO_READ:
+                       memcpy(data, &my_scsi_cmd.cmd[0], len);
+                       break;
+               case SCSI_IO_WRITE:
+                       break;
+    }
+
+       return 0;  /* where to get scsi status? */
+
+#elif (defined _SCO_DS) && (defined SCSIUSERCMD)
+       struct scsicmd my_scsi_cmd;
+
+       memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */
+       memcpy(my_scsi_cmd.cdb, cdb, cmdlen);
+       my_scsi_cmd.cdb_len = cmdlen;
+       my_scsi_cmd.data_len = len;
+       my_scsi_cmd.data_ptr = data;
+       my_scsi_cmd.is_write = mode == SCSI_IO_WRITE;
+       if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) {
+               perror("scsi_io: SCSIUSERCMD");
+               return -1;
+       }
+       if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) {
+               fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n",
+               (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts);
+               return -1;
+       }
+       return 0;
+#elif defined sgi
+       struct dsreq my_scsi_cmd;
+
+       my_scsi_cmd.ds_cmdbuf = (char *)cdb;
+       my_scsi_cmd.ds_cmdlen = cmdlen;
+       my_scsi_cmd.ds_databuf = data;
+       my_scsi_cmd.ds_datalen = len;
+               switch (mode) {
+       case SCSI_IO_READ:
+         my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE;
+         break;
+       case SCSI_IO_WRITE:
+         my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE;
+         break;
+        } 
+       my_scsi_cmd.ds_time = 10000;
+       my_scsi_cmd.ds_link = 0;
+       my_scsi_cmd.ds_synch =0;
+       my_scsi_cmd.ds_ret =0;
+       if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) {
+                perror("scsi_io");
+                return -1;
+        }
+
+        if(my_scsi_cmd.ds_status) {
+                errno = 0;
+                fprintf(stderr,"scsi status=%x\n",  
+                        (unsigned short)my_scsi_cmd.ds_status);
+                return -1;
+        }
+        
+        return 0;
+#elif (defined OS_freebsd) && (__FreeBSD__ >= 2)
+#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
+      union ccb *ccb;
+      int flags;
+      int r;
+      struct cam_device *cam_dev = (struct cam_device *) extra_data;
+
+
+      if (cam_dev==NULL || cam_dev->fd!=fd)
+      {
+                fprintf(stderr,"invalid file descriptor\n");
+              return -1;
+      }
+      ccb = cam_getccb(cam_dev);
+
+      bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen);
+
+      if (mode == SCSI_IO_READ)
+              flags = CAM_DIR_IN;
+      else if (data && len)
+              flags = CAM_DIR_OUT;
+      else
+              flags = CAM_DIR_NONE;
+      cam_fill_csio(&ccb->csio,
+                    /* retry */ 1,
+                    /* cbfcnp */ NULL,
+                    flags,
+                    /* tag_action */ MSG_SIMPLE_Q_TAG,
+                    /*data_ptr*/ len ? data : 0,
+                    /*data_len */ data ? len : 0,
+                    96,
+                    cmdlen,
+                    5000);
+                    
+      if (cam_send_ccb(cam_dev, ccb) < 0 ||
+         (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+         return -1;
+      }
+      return 0;
+#elif defined(OS_netbsd) || defined(OS_netbsdelf)
+       struct scsireq sc;
+
+       memset(&sc, 0, sizeof(sc));
+       memcpy(sc.cmd, cdb, cmdlen);
+       sc.cmdlen = cmdlen;
+       sc.databuf = data;
+       sc.datalen = len;
+       sc.senselen = 0;
+       sc.timeout = 10000;
+       switch (mode) {
+       case SCSI_IO_READ:
+         sc.flags = SCCMD_READ;
+         break;
+       case SCSI_IO_WRITE:
+         sc.flags = SCCMD_WRITE;
+         break;
+       }
+
+       if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) {
+                perror("SCIOCCOMMAND ioctl");
+                return -1;
+       }
+
+       if (sc.retsts) {
+                errno = EIO;
+                fprintf(stderr, "SCSI command failed, retsts %d\n", 
+sc.retsts);
+                return -1;
+       }
+
+        return 0;
+#else
+      fprintf(stderr, "scsi_io not implemented\n");
+      return -1;
+#endif
+}
diff --git a/scsi.h b/scsi.h
new file mode 100644 (file)
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 (file)
index 0000000..e6a4326
--- /dev/null
+++ b/signal.c
@@ -0,0 +1,60 @@
+/*  Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+#undef got_signal
+
+int got_signal = 0;
+
+static void signal_handler(int dummy)
+{
+       got_signal = 1;
+#if 0
+       signal(SIGHUP, SIG_IGN);
+       signal(SIGINT, SIG_IGN);
+       signal(SIGTERM, SIG_IGN);
+       signal(SIGQUIT, SIG_IGN);
+#endif
+}
+
+#if 0
+int do_gotsignal(char *f, int n)
+{
+       if(got_signal)
+               fprintf(stderr, "file=%s line=%d\n", f, n);
+       return got_signal;
+}
+#endif
+
+void setup_signal(void)
+{
+       /* catch signals */
+#ifdef SIGHUP
+       signal(SIGHUP, signal_handler);
+#endif
+#ifdef SIGINT
+       signal(SIGINT, signal_handler);
+#endif
+#ifdef SIGTERM
+       signal(SIGTERM, signal_handler);
+#endif
+#ifdef SIGQUIT
+       signal(SIGQUIT, signal_handler);
+#endif
+}
diff --git a/stream.c b/stream.c
new file mode 100644 (file)
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 (file)
index 0000000..5bbba52
--- /dev/null
+++ b/stream.h
@@ -0,0 +1,93 @@
+#ifndef MTOOLS_STREAM_H
+#define MTOOLS_STREAM_H
+
+/*  Copyright 1996-1999,2001,2002,2005,2006,2008,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 *);
+} Class_t;
+
+#define READS(stream, buf, address, size) \
+((stream)->Class->read)( (stream), (char *) (buf), (address), (size) )
+
+#define WRITES(stream, buf, address, size) \
+((stream)->Class->write)( (stream), (char *) (buf), (address), (size) )
+
+#define SET_GEOM(stream, dev, orig_dev, media, boot) \
+(stream)->Class->set_geom( (stream), (dev), (orig_dev), (media), (boot) )
+
+#define GET_DATA(stream, date, size, type, address) \
+(stream)->Class->get_data( (stream), (date), (size), (type), (address) )
+
+#define PRE_ALLOCATE(stream, size) \
+(stream)->Class->pre_allocate((stream), (size))
+
+#define GET_DOSCONVERT(stream)                 \
+       (stream)->Class->get_dosConvert((stream))
+
+int flush_stream(Stream_t *Stream);
+Stream_t *copy_stream(Stream_t *Stream);
+int free_stream(Stream_t **Stream);
+
+#define FLUSH(stream) \
+flush_stream( (stream) )
+
+#define FREE(stream) \
+free_stream( (stream) )
+
+#define COPY(stream) \
+copy_stream( (stream) )
+
+
+#define DeclareThis(x) x *This = (x *) Stream
+
+int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+
+int get_data_pass_through(Stream_t *Stream, time_t *date, mt_size_t *size,
+                                                 int *type, int *address);
+
+int read_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+int write_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+
+
+#endif
+
diff --git a/streamcache.c b/streamcache.c
new file mode 100644 (file)
index 0000000..4277ef0
--- /dev/null
@@ -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 (file)
index 0000000..8e89ad1
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright 1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+:1
+/^\.[IP]P$/N
+s/^\.[IP]P\n\(\.[ITP]P\)$/\1/
+/^\.PP$/b1
diff --git a/subdir.c b/subdir.c
new file mode 100644 (file)
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/sysincludes.h b/sysincludes.h
new file mode 100644 (file)
index 0000000..2e7577c
--- /dev/null
@@ -0,0 +1,604 @@
+/*  Copyright 1996-1999,2001,2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 dependancies which cannot be covered by the autoconfigure script */
+/*                                                                     */
+/***********************************************************************/
+
+
+#ifdef OS_aux
+/* A/UX needs POSIX_SOURCE, just as AIX does. Unlike SCO and AIX, it seems
+ * to prefer TERMIO over TERMIOS */
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+#endif
+#ifndef POSIX_SOURCE
+# define POSIX_SOURCE
+#endif
+
+#endif
+
+
+/* On AIX, we have to prefer strings.h, as string.h lacks a prototype 
+ * for strcasecmp. On most other architectures, it's string.h which seems
+ * to be more complete */
+#if (defined OS_aix && defined HAVE_STRINGS_H)
+# undef HAVE_STRING_H
+#endif
+
+
+#ifdef OS_ultrix
+/* on ultrix, if termios present, prefer it instead of termio */
+# ifdef HAVE_TERMIOS_H
+#  undef HAVE_TERMIO_H
+# endif
+#endif
+
+#ifdef OS_linux_gnu
+/* RMS strikes again */
+# ifndef OS_linux
+#  define OS_linux
+# endif
+#endif
+
+/* For compiling with MingW, use the following configure line
+
+ac_cv_func_setpgrp_void=yes ../mtools/configure --build=i386-linux-gnu --host=i386-mingw32 --disable-floppyd --without-x --disable-raw-term --srcdir ../mtools
+
+ */
+#ifdef OS_mingw32
+#ifndef OS_mingw32msvc
+#define OS_mingw32msvc
+#endif
+#endif
+
+#ifdef OS_mingw32msvc
+typedef void *caddr_t;
+#endif
+
+
+/***********************************************************************/
+/*                                                                     */
+/* Compiler dependancies                                               */
+/*                                                                     */
+/***********************************************************************/
+
+
+#if defined __GNUC__ && defined __STDC__
+/* gcc -traditional doesn't have PACKED, UNUSED and NORETURN */
+# define PACKED __attribute__ ((packed))
+# if __GNUC__ == 2 && __GNUC_MINOR__ > 6 || __GNUC__ >= 3
+/* gcc 2.6.3 doesn't have "unused" */          /* mool */
+#  define UNUSED(x) x __attribute__ ((unused));x
+# else
+#  define UNUSED(x) x
+# endif
+# define NORETURN __attribute__ ((noreturn))
+#else
+# define UNUSED(x) x
+# define PACKED /* */
+# define NORETURN /* */
+#endif
+
+
+/***********************************************************************/
+/*                                                                     */
+/* Include files                                                       */
+/*                                                                     */
+/***********************************************************************/
+
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE
+
+
+#ifdef HAVE_FEATURES_H
+# include <features.h>
+#endif
+
+
+#include <sys/types.h>
+
+#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>
+#else
+typedef unsigned int uid_t;
+#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_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 USE_FLOPPYD
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.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_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 (file)
index 0000000..9140826
--- /dev/null
@@ -0,0 +1,9291 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+% 
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{2009-08-14.15}
+%
+% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
+% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+% 2007, 2008, 2009 Free Software Foundation, Inc.
+%
+% This texinfo.tex file is free software: you can redistribute it and/or
+% modify it under the terms of the GNU General Public License as
+% published by the Free Software Foundation, either version 3 of the
+% License, or (at your option) any later version.
+%
+% This texinfo.tex file is distributed in the hope that it will be
+% useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+% of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+% General Public License for more details.
+%
+% You should have received a copy of the GNU General Public License
+% along with this program.  If not, see <http://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 has been our intent since Texinfo was invented.)
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   http://www.gnu.org/software/texinfo/ (the Texinfo home page), or
+%   ftp://tug.org/tex/texinfo.tex
+%     (and all CTAN mirrors, see http://www.ctan.org).
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org.  Please include including a
+% complete document in each bug report with which we can reproduce the
+% problem.  Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution.  For a simple
+% manual foo.texi, however, you can get away with this:
+%   tex foo.texi
+%   texindex foo.??
+%   tex foo.texi
+%   tex foo.texi
+%   dvips foo.dvi -o  # or whatever; this makes foo.ps.
+% The extra TeX runs get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages, to some
+% extent.  You can get the existing language-specific files from the
+% full Texinfo distribution.
+%
+% The GNU Texinfo home page is http://www.gnu.org/software/texinfo.
+
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+  \catcode`+=\active \catcode`\_=\active}
+
+
+\chardef\other=12
+
+% We never want plain's \outer definition of \+ in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Save some plain tex macros whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexfootnote=\footnote
+\let\ptexgtr=>
+\let\ptexhat=^
+\let\ptexi=\i
+\let\ptexindent=\indent
+\let\ptexinsert=\insert
+\let\ptexlbrace=\{
+\let\ptexless=<
+\let\ptexnewwrite\newwrite
+\let\ptexnoindent=\noindent
+\let\ptexplus=+
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexstar=\*
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active
+\global\let\ptexquoteright'}% Math-mode def from plain.tex.
+\let\ptexraggedright=\raggedright
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Pre-3.0.
+\else
+  \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined  \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined   \gdef\putwordChapter{Chapter}\fi
+\ifx\putwordfile\undefined      \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined        \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined     \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined      \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined  \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined   \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined        \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined        \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined      \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined   \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined   \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined       \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined       \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined  \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined       \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined    \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined   \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined    \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined    \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined   \gdef\putwordDeffunc{Function}\fi
+
+% Since the category of space is not known, we have to be careful.
+\chardef\spacecat = 10
+\def\spaceisspace{\catcode`\ =\spacecat}
+
+% sometimes characters are active, so we need control sequences.
+\chardef\colonChar = `\:
+\chardef\commaChar = `\,
+\chardef\dashChar  = `\-
+\chardef\dotChar   = `\.
+\chardef\exclamChar= `\!
+\chardef\lquoteChar= `\`
+\chardef\questChar = `\?
+\chardef\rquoteChar= `\'
+\chardef\semiChar  = `\;
+\chardef\underChar = `\_
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+  Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+  ap-pen-dix bit-map bit-maps
+  data-base data-bases eshell fall-ing half-way long-est man-u-script
+  man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+  par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+  spell-ing spell-ings
+  stand-alone strong-est time-stamp time-stamps which-ever white-space
+  wide-spread wrap-around
+}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\pagewidth \newdimen\pageheight
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt}
+
+% @| inserts a changebar to the left of the current line.  It should
+% surround any changed text.  This approach does *not* work if the
+% change spans more than two lines of output.  To handle that, we would
+% have adopt a much more difficult approach (putting marks into the main
+% vertical list for the beginning and end of each change).
+%
+\def\|{%
+  % \vadjust can only be used in horizontal mode.
+  \leavevmode
+  %
+  % Append this vertical mode material after the current line in the output.
+  \vadjust{%
+    % We want to insert a rule with the height and depth of the current
+    % leading; that is exactly what \strutbox is supposed to record.
+    \vskip-\baselineskip
+    %
+    % \vadjust-items are inserted at the left edge of the type.  So
+    % the \llap here moves out into the left-hand margin.
+    \llap{%
+      %
+      % For a thicker or thinner bar, change the `1pt'.
+      \vrule height\baselineskip width1pt
+      %
+      % This is the space between the bar and the text.
+      \hskip 12pt
+    }%
+  }%
+}
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.  We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+  \tracingstats2
+  \tracingpages1
+  \tracinglostchars2  % 2 gives us more in etex
+  \tracingparagraphs1
+  \tracingoutput1
+  \tracingmacros2
+  \tracingrestores1
+  \showboxbreadth\maxdimen \showboxdepth\maxdimen
+  \ifx\eTeXversion\undefined\else % etex gives us more logging
+    \tracingscantokens1
+    \tracingifs1
+    \tracinggroups1
+    \tracingnesting2
+    \tracingassigns1
+  \fi
+  \tracingcommands3  % 3 gives us more in etex
+  \errorcontextlines16
+}%
+
+% add check for \lastpenalty to plain's definitions.  If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+  \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+  \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+  \removelastskip\penalty-200\bigskip\fi\fi}
+
+% For @cropmarks command.
+% Do @cropmarks to get crop marks.
+%
+\newif\ifcropmarks
+\let\cropmarks = \cropmarkstrue
+%
+% Dimensions to add cropmarks at corners.
+% Added by P. A. MacKay, 12 Nov. 1986
+%
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\cornerlong  \cornerlong=1pc
+\newdimen\cornerthick \cornerthick=.3pt
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Output a mark which sets \thischapter, \thissection and \thiscolor.
+% We dump everything together because we only have one kind of mark.
+% This works because we only use \botmark / \topmark, not \firstmark.
+%
+% A mark contains a subexpression of the \ifcase ... \fi construct.
+% \get*marks macros below extract the needed part using \ifcase.
+%
+% Another complication is to let the user choose whether \thischapter
+% (\thissection) refers to the chapter (section) in effect at the top
+% of a page, or that at the bottom of a page.  The solution is
+% described on page 260 of The TeXbook.  It involves outputting two
+% marks for the sectioning macros, one before the section break, and
+% one after.  I won't pretend I can describe this better than DEK...
+\def\domark{%
+  \toks0=\expandafter{\lastchapterdefs}%
+  \toks2=\expandafter{\lastsectiondefs}%
+  \toks4=\expandafter{\prevchapterdefs}%
+  \toks6=\expandafter{\prevsectiondefs}%
+  \toks8=\expandafter{\lastcolordefs}%
+  \mark{%
+                   \the\toks0 \the\toks2
+      \noexpand\or \the\toks4 \the\toks6
+    \noexpand\else \the\toks8
+  }%
+}
+% \topmark doesn't work for the very first chapter (after the title
+% page or the contents), so we use \firstmark there -- this gets us
+% the mark with the chapter defs, unless the user sneaks in, e.g.,
+% @setcolor (or @url, or @link, etc.) between @contents and the very
+% first @chapter.
+\def\gettopheadingmarks{%
+  \ifcase0\topmark\fi
+  \ifx\thischapter\empty \ifcase0\firstmark\fi \fi
+}
+\def\getbottomheadingmarks{\ifcase1\botmark\fi}
+\def\getcolormarks{\ifcase2\topmark\fi}
+
+% Avoid "undefined control sequence" errors.
+\def\lastchapterdefs{}
+\def\lastsectiondefs{}
+\def\prevchapterdefs{}
+\def\prevsectiondefs{}
+\def\lastcolordefs{}
+
+% Main output routine.
+\chardef\PAGE = 255
+\output = {\onepageout{\pagecontents\PAGE}}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% \onepageout takes a vbox as an argument.  Note that \pagecontents
+% does insertions, but you have to call it yourself.
+\def\onepageout#1{%
+  \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}%
+  \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi
+  \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}%
+  %
+  {%
+    % Have to do this stuff outside the \shipout because we want it to
+    % take effect in \write's, yet the group defined by the \vbox ends
+    % before the \shipout runs.
+    %
+    \indexdummies         % don't expand commands in the output.
+    \normalturnoffactive  % \ in index entries must not stay \, e.g., if
+               % the page break happens to be in the middle of an example.
+               % We don't want .vr (or whatever) entries like this:
+               % \entry{{\tt \indexbackslash }acronym}{32}{\code {\acronym}}
+               % "\acronym" won't work when it's read back in;
+               % it needs to be
+               % {\code {{\tt \backslashcurfont }acronym}
+    \shipout\vbox{%
+      % Do this early so pdf references go to the beginning of the page.
+      \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi
+      %
+      \ifcropmarks \vbox to \outervsize\bgroup
+        \hsize = \outerhsize
+        \vskip-\topandbottommargin
+        \vtop to0pt{%
+          \line{\ewtop\hfil\ewtop}%
+          \nointerlineskip
+          \line{%
+            \vbox{\moveleft\cornerthick\nstop}%
+            \hfill
+            \vbox{\moveright\cornerthick\nstop}%
+          }%
+          \vss}%
+        \vskip\topandbottommargin
+        \line\bgroup
+          \hfil % center the page within the outer (page) hsize.
+          \ifodd\pageno\hskip\bindingoffset\fi
+          \vbox\bgroup
+      \fi
+      %
+      \unvbox\headlinebox
+      \pagebody{#1}%
+      \ifdim\ht\footlinebox > 0pt
+        % Only leave this space if the footline is nonempty.
+        % (We lessened \vsize for it in \oddfootingyyy.)
+        % The \baselineskip=24pt in plain's \makefootline has no effect.
+        \vskip 24pt
+        \unvbox\footlinebox
+      \fi
+      %
+      \ifcropmarks
+          \egroup % end of \vbox\bgroup
+        \hfil\egroup % end of (centering) \line\bgroup
+        \vskip\topandbottommargin plus1fill minus1fill
+        \boxmaxdepth = \cornerthick
+        \vbox to0pt{\vss
+          \line{%
+            \vbox{\moveleft\cornerthick\nsbot}%
+            \hfill
+            \vbox{\moveright\cornerthick\nsbot}%
+          }%
+          \nointerlineskip
+          \line{\ewbot\hfil\ewbot}%
+        }%
+      \egroup % \vbox from first cropmarks clause
+      \fi
+    }% end of \shipout\vbox
+  }% end of group with \indexdummies
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+  \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1\relax \unvbox#1\relax
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Here are the rules for the cropmarks.  Note that they are
+% offset so that the space between them is truly \outerhsize or \outervsize
+% (P. A. MacKay, 12 November, 1986)
+%
+\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong}
+\def\nstop{\vbox
+  {\hrule height\cornerthick depth\cornerlong width\cornerthick}}
+\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong}
+\def\nsbot{\vbox
+  {\hrule height\cornerlong depth\cornerthick width\cornerthick}}
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+%
+\def\parsearg{\parseargusing{}}
+\def\parseargusing#1#2{%
+  \def\argtorun{#2}%
+  \begingroup
+    \obeylines
+    \spaceisspace
+    #1%
+    \parseargline\empty% Insert the \empty token, see \finishparsearg below.
+}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    \argremovecomment #1\comment\ArgTerm%
+  }%
+}
+
+% First remove any @comment, then any @c comment.
+\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm}
+\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm}
+
+% Each occurrence of `\^^M' or `<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\foo{...}
+%      is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+%
+% Actually, I use \csname\string\foo\endcsname, ie. \\foo, as it is my
+% favourite TeX trick.  --kasal, 16nov03
+
+\def\parseargdef#1{%
+  \expandafter \doparseargdef \csname\string#1\endcsname #1%
+}
+\def\doparseargdef#1#2{%
+  \def#2{\parsearg#1}%
+  \def#1##1%
+}
+
+% Several utility definitions with active space:
+{
+  \obeyspaces
+  \gdef\obeyedspace{ }
+
+  % Make each space character in the input produce a normal interword
+  % space in the output.  Don't allow a line break at this space, as this
+  % is used only in environments like @example, where each line of input
+  % should produce a line of output anyway.
+  %
+  \gdef\sepspaces{\obeyspaces\let =\tie}
+
+  % If an index command is used in an @example environment, any spaces
+  % therein should become regular spaces in the raw index file, not the
+  % expansion of \tie (\leavevmode \penalty \@M \ ).
+  \gdef\unsepspaces{\let =\space}
+}
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+% Define the framework for environments in texinfo.tex.  It's used like this:
+%
+%   \envdef\foo{...}
+%   \def\Efoo{...}
+%
+% It's the responsibility of \envdef to insert \begingroup before the
+% actual body; @end closes the group after calling \Efoo.  \envdef also
+% defines \thisenv, so the current environment is known; @end checks
+% whether the environment name matches.  The \checkenv macro can also be
+% used to check whether the current environment is the one expected.
+%
+% Non-false conditionals (@iftex, @ifset) don't fit into this, so they
+% are not treated as environments; they don't open a group.  (The
+% implementation of @end takes care not to call \endgroup in this
+% special case.)
+
+
+% At run-time, environments start with this:
+\def\startenvironment#1{\begingroup\def\thisenv{#1}}
+% initialize
+\let\thisenv\empty
+
+% ... but they get defined via ``\envdef\foo{...}'':
+\long\def\envdef#1#2{\def#1{\startenvironment#1#2}}
+\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}}
+
+% Check whether we're in the right environment:
+\def\checkenv#1{%
+  \def\temp{#1}%
+  \ifx\thisenv\temp
+  \else
+    \badenverr
+  \fi
+}
+
+% Environment mismatch, #1 expected:
+\def\badenverr{%
+  \errhelp = \EMsimple
+  \errmessage{This command can appear only \inenvironment\temp,
+    not \inenvironment\thisenv}%
+}
+\def\inenvironment#1{%
+  \ifx#1\empty
+    out of any environment%
+  \else
+    in environment \expandafter\string#1%
+  \fi
+}
+
+% @end foo executes the definition of \Efoo.
+% But first, it executes a specialized version of \checkenv
+%
+\parseargdef\end{%
+  \if 1\csname iscond.#1\endcsname
+  \else
+    % The general wording of \badenverr may not be ideal, but... --kasal, 06nov03
+    \expandafter\checkenv\csname#1\endcsname
+    \csname E#1\endcsname
+    \endgroup
+  \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+%% Simple single-character @ commands
+
+% @@ prints an @
+% Kludge this until the fonts are right (grr).
+\def\@{{\tt\char64}}
+
+% This is turned off because it was never documented
+% and you can use @w{...} around a quote to suppress ligatures.
+%% Define @` and @' to be the same as ` and '
+%% but suppressing ligatures.
+%\def\`{{`}}
+%\def\'{{'}}
+
+% Used to generate quoted braces.
+\def\mylbrace {{\tt\char123}}
+\def\myrbrace {{\tt\char125}}
+\let\{=\mylbrace
+\let\}=\myrbrace
+\begingroup
+  % Definitions to produce \{ and \} commands for indices,
+  % and @{ and @} for the aux/toc files.
+  \catcode`\{ = \other \catcode`\} = \other
+  \catcode`\[ = 1 \catcode`\] = 2
+  \catcode`\! = 0 \catcode`\\ = \other
+  !gdef!lbracecmd[\{]%
+  !gdef!rbracecmd[\}]%
+  !gdef!lbraceatcmd[@{]%
+  !gdef!rbraceatcmd[@}]%
+!endgroup
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \c
+\let\dotaccent = \.
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \t
+\let\ubaraccent = \b
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\selectfonts\lllsize \underbar{o}}}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+  \def\temp{#1}%
+  \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi
+  \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi
+  \else \errmessage{@dotless can be used only with i or j}%
+  \fi\fi
+}
+
+% The \TeX{} logo, as in plain, but resetting the spacing so that a
+% period following counts as ending a sentence.  (Idea found in latex.)
+%
+\edef\TeX{\TeX \spacefactor=1000 }
+
+% @LaTeX{} logo.  Not quite the same results as the definition in
+% latex.ltx, since we use a different font for the raised A; it's most
+% convenient for us to use an explicitly smaller font, rather than using
+% the \scriptstyle font (since we don't reset \scriptstyle and
+% \scriptscriptstyle).
+%
+\def\LaTeX{%
+  L\kern-.36em
+  {\setbox0=\hbox{T}%
+   \vbox to \ht0{\hbox{\selectfonts\lllsize A}\vss}}%
+  \kern-.15em
+  \TeX
+}
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=\endofsentencespacefactor\space}
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=\endofsentencespacefactor\space}
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=\endofsentencespacefactor\space}
+
+% @frenchspacing on|off  says whether to put extra space after punctuation.
+%
+\def\onword{on}
+\def\offword{off}
+%
+\parseargdef\frenchspacing{%
+  \def\temp{#1}%
+  \ifx\temp\onword \plainfrenchspacing
+  \else\ifx\temp\offword \plainnonfrenchspacing
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @frenchspacing option `\temp', must be on/off}%
+  \fi\fi
+}
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large.  This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material.  In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom.  The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+  \ifnum\catcode`\^^M=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  \startsavinginserts
+  %
+  \setbox\groupbox = \vtop\bgroup
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it.  Thus, space below is not quite equal to space
+% above.  But it's pretty close.
+\def\Egroup{%
+    % To get correct interline space between the last line of the group
+    % and the first line afterwards, we have to propagate \prevdepth.
+    \endgraf % Not \par, as it may have been set to \lisppar.
+    \global\dimen1 = \prevdepth
+  \egroup           % End the \vtop.
+  % \dimen0 is the vertical size of the group's box.
+  \dimen0 = \ht\groupbox  \advance\dimen0 by \dp\groupbox
+  % \dimen2 is how much space is left on the page (more or less).
+  \dimen2 = \pageheight   \advance\dimen2 by -\pagetotal
+  % if the group doesn't fit on the current page, and it's a big big
+  % group, force a page break.
+  \ifdim \dimen0 > \dimen2
+    \ifdim \pagetotal < \vfilllimit\pageheight
+      \page
+    \fi
+  \fi
+  \box\groupbox
+  \prevdepth = \dimen1
+  \checkinserts
+}
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+% Old definition--didn't work.
+%\parseargdef\need{\par %
+%% This method tries to make TeX break the page naturally
+%% if the depth of the box does not fit.
+%{\baselineskip=0pt%
+%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak
+%\prevdepth=-1000pt
+%}}
+
+\parseargdef\need{%
+  % Ensure vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % If the @need value is less than one line space, it's useless.
+  \dimen0 = #1\mil
+  \dimen2 = \ht\strutbox
+  \advance\dimen2 by \dp\strutbox
+  \ifdim\dimen0 > \dimen2
+    %
+    % Do a \strut just to make the height of this box be normal, so the
+    % normal leading is inserted relative to the preceding line.
+    % And a page break here is fine.
+    \vtop to #1\mil{\strut\vfil}%
+    %
+    % TeX does not even consider page breaks if a penalty added to the
+    % main vertical list is 10000 or more.  But in order to see if the
+    % empty box we just added fits on the page, we must make it consider
+    % page breaks.  On the other hand, we don't want to actually break the
+    % page after the empty box.  So we use a penalty of 9999.
+    %
+    % There is an extremely small chance that TeX will actually break the
+    % page at this \penalty, if there are no other feasible breakpoints in
+    % sight.  (If the user is using lots of big @group commands, which
+    % almost-but-not-quite fill up a page, TeX will have a hard time doing
+    % good page breaking, for example.)  However, I could not construct an
+    % example where a page broke at this \penalty; if it happens in a real
+    % document, then we can reconsider our strategy.
+    \penalty9999
+    %
+    % Back up by the size of the box, whether we did a page break or not.
+    \kern -#1\mil
+    %
+    % Do not allow a page break right after this kern.
+    \nobreak
+  \fi
+}
+
+% @br   forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+  \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph.  For more general purposes, use the \margin insertion
+% class.  WHICH is `l' or `r'.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+  \nobreak
+  \kern-\strutdepth
+  \vtop to \strutdepth{%
+    \baselineskip=\strutdepth
+    \vss
+    % if you have multiple lines of stuff to put here, you'll need to
+    % make the vbox yourself of the appropriate size.
+    \ifx#1l%
+      \llap{\ignorespaces #2\hskip\inmarginspacing}%
+    \else
+      \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+    \fi
+    \null
+  }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+  \setbox0 = \hbox{\ignorespaces #2}%
+  \ifdim\wd0 > 0pt
+    \def\lefttext{#1}%  have both texts
+    \def\righttext{#2}%
+  \else
+    \def\lefttext{#1}%  have only one text
+    \def\righttext{#1}%
+  \fi
+  %
+  \ifodd\pageno
+    \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+  \else
+    \def\temp{\inleftmargin\lefttext}%
+  \fi
+  \temp
+}
+
+% @include FILE -- \input text of FILE.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+  \pushthisfilestack
+  \def\thisfile{#1}%
+  {%
+    \makevalueexpandable  % we want to expand any @value in FILE.
+    \turnoffactive        % and allow special characters in the expansion
+    \indexnofonts         % Allow `@@' and other weird things in file names.
+    \edef\temp{\noexpand\input #1 }%
+    %
+    % This trickery is to read FILE outside of a group, in case it makes
+    % definitions, etc.
+    \expandafter
+  }\temp
+  \popthisfilestack
+}
+\def\filenamecatcodes{%
+  \catcode`\\=\other
+  \catcode`~=\other
+  \catcode`^=\other
+  \catcode`_=\other
+  \catcode`|=\other
+  \catcode`<=\other
+  \catcode`>=\other
+  \catcode`+=\other
+  \catcode`-=\other
+  \catcode`\`=\other
+  \catcode`\'=\other
+}
+
+\def\pushthisfilestack{%
+  \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+  \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+  \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+  the stack of filenames is empty.}}
+
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+  \ifhmode
+    \let\next\centerH
+  \else
+    \let\next\centerV
+  \fi
+  \next{\hfil \ignorespaces#1\unskip \hfil}%
+}
+\def\centerH#1{%
+  {%
+    \hfil\break
+    \advance\hsize by -\leftskip
+    \advance\hsize by -\rightskip
+    \line{#1}%
+    \break
+  }%
+}
+\def\centerV#1{\line{\kern\leftskip #1\kern\rightskip}}
+
+% @sp n   outputs n lines of vertical space
+
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+\def\comment{\begingroup \catcode`\^^M=\other%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\commentxxx}
+{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}}
+
+\let\c=\comment
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% NCHARS can also be the word `asis' or `none'.
+% We cannot feasibly implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\parseargdef\paragraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \defaultparindent = 0pt
+    \else
+      \defaultparindent = #1em
+    \fi
+  \fi
+  \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\parseargdef\exampleindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \lispnarrowing = 0pt
+    \else
+      \lispnarrowing = #1em
+    \fi
+  \fi
+}
+
+% @firstparagraphindent WORD
+% If WORD is `none', then suppress indentation of the first paragraph
+% after a section heading.  If WORD is `insert', then do indent at such
+% paragraphs.
+%
+% The paragraph indentation is suppressed or not by calling
+% \suppressfirstparagraphindent, which the sectioning commands do.
+% We switch the definition of this back and forth according to WORD.
+% By default, we suppress indentation.
+%
+\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent}
+\def\insertword{insert}
+%
+\parseargdef\firstparagraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\noneword
+    \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent
+  \else\ifx\temp\insertword
+    \let\suppressfirstparagraphindent = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @firstparagraphindent option `\temp'}%
+  \fi\fi
+}
+
+% Here is how we actually suppress indentation.  Redefine \everypar to
+% \kern backwards by \parindent, and then reset itself to empty.
+%
+% We also make \indent itself not actually do anything until the next
+% paragraph.
+%
+\gdef\dosuppressfirstparagraphindent{%
+  \gdef\indent{%
+    \restorefirstparagraphindent
+    \indent
+  }%
+  \gdef\noindent{%
+    \restorefirstparagraphindent
+    \noindent
+  }%
+  \global\everypar = {%
+    \kern -\parindent
+    \restorefirstparagraphindent
+  }%
+}
+
+\gdef\restorefirstparagraphindent{%
+  \global \let \indent = \ptexindent
+  \global \let \noindent = \ptexnoindent
+  \global \everypar = {}%
+}
+
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}.  So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+  \catcode`\_ = \active
+  \gdef\mathunderscore{%
+    \catcode`\_=\active
+    \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+  }
+}
+% Another complication: we want \\ (and @\) to output a \ character.
+% FYI, plain.tex uses \\ as a temporary control sequence (why?), but
+% this is not advertised and we don't care.  Texinfo does not
+% otherwise define @\.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+  \tex
+  \mathunderscore
+  \let\\ = \mathbackslash
+  \mathactive
+  % make the texinfo accent commands work in math mode
+  \let\"=\ddot
+  \let\'=\acute
+  \let\==\bar
+  \let\^=\hat
+  \let\`=\grave
+  \let\u=\breve
+  \let\v=\check
+  \let\~=\tilde
+  \let\dotaccent=\dot
+  $\finishmath
+}
+\def\finishmath#1{#1$\endgroup}  % Close the group opened by \tex.
+
+% Some active characters (such as <) are spaced differently in math.
+% We have to reset their definitions in case the @math was an argument
+% to a command which sets the catcodes (such as @item or @section).
+%
+{
+  \catcode`^ = \active
+  \catcode`< = \active
+  \catcode`> = \active
+  \catcode`+ = \active
+  \catcode`' = \active
+  \gdef\mathactive{%
+    \let^ = \ptexhat
+    \let< = \ptexless
+    \let> = \ptexgtr
+    \let+ = \ptexplus
+    \let' = \ptexquoteright
+  }
+}
+
+% Some math mode symbols.
+\def\bullet{$\ptexbullet$}
+\def\geq{\ifmmode \ge\else $\ge$\fi}
+\def\leq{\ifmmode \le\else $\le$\fi}
+\def\minus{\ifmmode -\else $-$\fi}
+
+% @dots{} outputs an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in the cm
+% typewriter fonts as three actual period characters; on the other hand,
+% in other typewriter fonts three periods are wider than 1.5em.  So do
+% whichever is larger.
+%
+\def\dots{%
+  \leavevmode
+  \setbox0=\hbox{...}% get width of three periods
+  \ifdim\wd0 > 1.5em
+    \dimen0 = \wd0
+  \else
+    \dimen0 = 1.5em
+  \fi
+  \hbox to \dimen0{%
+    \hskip 0pt plus.25fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus.5fil
+  }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+  \dots
+  \spacefactor=\endofsentencespacefactor
+}
+
+% @comma{} is so commas can be inserted into text without messing up
+% Texinfo's parsing.
+%
+\let\comma = ,
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate (before @setfilename).
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% @setfilename is done at the beginning of every texinfo file.
+% So open here the files we need to have open while reading the input.
+% This makes it possible to make a .fmt file for texinfo.
+\def\setfilename{%
+   \fixbackslash  % Turn off hack to swallow `\input texinfo'.
+   \iflinks
+     \tryauxfile
+     % Open the new aux file.  TeX will close it automatically at exit.
+     \immediate\openout\auxfile=\jobname.aux
+   \fi % \openindices needs to do some work in any case.
+   \openindices
+   \let\setfilename=\comment % Ignore extra @setfilename cmds.
+   %
+   % If texinfo.cnf is present on the system, read it.
+   % Useful for site-wide @afourpaper, etc.
+   \openin 1 texinfo.cnf
+   \ifeof 1 \else \input texinfo.cnf \fi
+   \closein 1
+   %
+   \comment % Ignore the actual filename.
+}
+
+% Called from \setfilename.
+%
+\def\openindices{%
+  \newindex{cp}%
+  \newcodeindex{fn}%
+  \newcodeindex{vr}%
+  \newcodeindex{tp}%
+  \newcodeindex{ky}%
+  \newcodeindex{pg}%
+}
+
+% @bye.
+\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+\newtoks\toksA
+\newtoks\toksB
+\newtoks\toksC
+\newtoks\toksD
+\newbox\boxA
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set).  So we test for \relax and 0 as well as \undefined,
+% borrowed from ifpdf.sty.
+\ifx\pdfoutput\undefined
+\else
+  \ifx\pdfoutput\relax
+  \else
+    \ifcase\pdfoutput
+    \else
+      \pdftrue
+    \fi
+  \fi
+\fi
+
+% PDF uses PostScript string constants for the names of xref targets,
+% for display in the outlines, and in other places.  Thus, we have to
+% double any backslashes.  Otherwise, a name like "\node" will be
+% interpreted as a newline (\n), followed by o, d, e.  Not good.
+% http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html
+% (and related messages, the final outcome is that it is up to the TeX
+% user to double the backslashes and otherwise make the string valid, so
+% that's what we do).
+
+% double active backslashes.
+%
+{\catcode`\@=0 \catcode`\\=\active
+ @gdef@activebackslashdouble{%
+   @catcode`@\=@active
+   @let\=@doublebackslash}
+}
+
+% To handle parens, we must adopt a different approach, since parens are
+% not active characters.  hyperref.dtx (which has the same problem as
+% us) handles it with this amazing macro to replace tokens, with minor
+% changes for Texinfo.  It is included here under the GPL by permission
+% from the author, Heiko Oberdiek.
+%
+% #1 is the tokens to replace.
+% #2 is the replacement.
+% #3 is the control sequence with the string.
+%
+\def\HyPsdSubst#1#2#3{%
+  \def\HyPsdReplace##1#1##2\END{%
+    ##1%
+    \ifx\\##2\\%
+    \else
+      #2%
+      \HyReturnAfterFi{%
+        \HyPsdReplace##2\END
+      }%
+    \fi
+  }%
+  \xdef#3{\expandafter\HyPsdReplace#3#1\END}%
+}
+\long\def\HyReturnAfterFi#1\fi{\fi#1}
+
+% #1 is a control sequence in which to do the replacements.
+\def\backslashparens#1{%
+  \xdef#1{#1}% redefine it as its expansion; the definition is simply
+             % \lastnode when called from \setref -> \pdfmkdest.
+  \HyPsdSubst{(}{\realbackslash(}{#1}%
+  \HyPsdSubst{)}{\realbackslash)}{#1}%
+}
+
+\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
+with PDF output, and none of those formats could be found.  (.eps cannot
+be supported due to the design of the PDF format; use regular TeX (DVI
+output) for that.)}
+
+\ifpdf
+  %
+  % Color manipulation macros based on pdfcolor.tex,
+  % except using rgb instead of cmyk; the latter is said to render as a
+  % very dark gray on-screen and a very dark halftone in print, instead
+  % of actual black.
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  % k sets the color for filling (usual text, etc.);
+  % K sets the color for stroking (thin rules, e.g., normal _'s).
+  \def\pdfsetcolor#1{\pdfliteral{#1 rg  #1 RG}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\lastcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\lastcolordefs{}
+  %
+  \def\makefootline{%
+    \baselineskip24pt
+    \line{\pdfsetcolor{\maincolor}\the\footline}%
+  }
+  %
+  \def\makeheadline{%
+    \vbox to 0pt{%
+      \vskip-22.5pt
+      \line{%
+        \vbox to8.5pt{}%
+        % Extract \thiscolor definition from the marks.
+        \getcolormarks
+        % Typeset the headline with \maincolor, then restore the color.
+        \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+      }%
+      \vss
+    }%
+    \nointerlineskip
+  }
+  %
+  %
+  \pdfcatalog{/PageMode /UseOutlines}
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\dopdfimage#1#2#3{%
+    \def\imagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\imageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % pdftex (and the PDF format) support .png, .jpg, .pdf (among
+    % others).  Let's try in that order.
+    \let\pdfimgext=\empty
+    \begingroup
+      \openin 1 #1.png \ifeof 1
+        \openin 1 #1.jpg \ifeof 1
+          \openin 1 #1.jpeg \ifeof 1
+            \openin 1 #1.JPG \ifeof 1
+              \openin 1 #1.pdf \ifeof 1
+                \openin 1 #1.PDF \ifeof 1
+                  \errhelp = \nopdfimagehelp
+                  \errmessage{Could not find image file #1 for pdf}%
+                \else \gdef\pdfimgext{PDF}%
+                \fi
+              \else \gdef\pdfimgext{pdf}%
+              \fi
+            \else \gdef\pdfimgext{JPG}%
+            \fi
+          \else \gdef\pdfimgext{jpeg}%
+          \fi
+        \else \gdef\pdfimgext{jpg}%
+        \fi
+      \else \gdef\pdfimgext{png}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    % without \immediate, ancient pdftex seg faults when the same image is
+    % included twice.  (Version 3.14159-pre-1.0-unofficial-20010704.)
+    \ifnum\pdftexversion < 14
+      \immediate\pdfimage
+    \else
+      \immediate\pdfximage
+    \fi
+      \ifdim \wd0 >0pt width \imagewidth \fi
+      \ifdim \wd2 >0pt height \imageheight \fi
+      \ifnum\pdftexversion<13
+         #1.\pdfimgext
+       \else
+         {#1.\pdfimgext}%
+       \fi
+    \ifnum\pdftexversion < 14 \else
+      \pdfrefximage \pdflastximage
+    \fi}
+  %
+  \def\pdfmkdest#1{{%
+    % We have to set dummies so commands such as @code, and characters
+    % such as \, aren't expanded when present in a section title.
+    \indexnofonts
+    \turnoffactive
+    \activebackslashdouble
+    \makevalueexpandable
+    \def\pdfdestname{#1}%
+    \backslashparens\pdfdestname
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }}
+  %
+  % used to mark target names; must be expandable.
+  \def\pdfmkpgn#1{#1}
+  %
+  % by default, use a color that is dark enough to print on paper as
+  % nearly black, but still distinguishable for online viewing.
+  \def\urlcolor{\rgbDarkRed}
+  \def\linkcolor{\rgbDarkRed}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  % Adding outlines to PDF; macros for calculating structure of outlines
+  % come from Petr Olsak
+  \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+    \else \csname#1\endcsname \fi}
+  \def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+    \advance\tempnum by 1
+    \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+  %
+  % #1 is the section text, which is what will be displayed in the
+  % outline by the pdf viewer.  #2 is the pdf expression for the number
+  % of subentries (or empty, for subsubsections).  #3 is the node text,
+  % which might be empty if this toc entry had no corresponding node.
+  % #4 is the page number
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    % Generate a link to the node text if that exists; else, use the
+    % page number.  We could generate a destination for the section
+    % text in the case where a section has no node, but it doesn't
+    % seem worth the trouble, since most documents are normally structured.
+    \def\pdfoutlinedest{#3}%
+    \ifx\pdfoutlinedest\empty
+      \def\pdfoutlinedest{#4}%
+    \else
+      % Doubled backslashes in the name.
+      {\activebackslashdouble \xdef\pdfoutlinedest{#3}%
+       \backslashparens\pdfoutlinedest}%
+    \fi
+    %
+    % Also double the backslashes in the display string.
+    {\activebackslashdouble \xdef\pdfoutlinetext{#1}%
+     \backslashparens\pdfoutlinetext}%
+    %
+    \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      % Thanh's hack / proper braces in bookmarks
+      \edef\mylbrace{\iftrue \string{\else}\fi}\let\{=\mylbrace
+      \edef\myrbrace{\iffalse{\else\string}\fi}\let\}=\myrbrace
+      %
+      % Read toc silently, to get counts of subentries for \pdfoutline.
+      \def\numchapentry##1##2##3##4{%
+       \def\thischapnum{##2}%
+       \def\thissecnum{0}%
+       \def\thissubsecnum{0}%
+      }%
+      \def\numsecentry##1##2##3##4{%
+       \advancenumber{chap\thischapnum}%
+       \def\thissecnum{##2}%
+       \def\thissubsecnum{0}%
+      }%
+      \def\numsubsecentry##1##2##3##4{%
+       \advancenumber{sec\thissecnum}%
+       \def\thissubsecnum{##2}%
+      }%
+      \def\numsubsubsecentry##1##2##3##4{%
+       \advancenumber{subsec\thissubsecnum}%
+      }%
+      \def\thischapnum{0}%
+      \def\thissecnum{0}%
+      \def\thissubsecnum{0}%
+      %
+      % use \def rather than \let here because we redefine \chapentry et
+      % al. a second time, below.
+      \def\appentry{\numchapentry}%
+      \def\appsecentry{\numsecentry}%
+      \def\appsubsecentry{\numsubsecentry}%
+      \def\appsubsubsecentry{\numsubsubsecentry}%
+      \def\unnchapentry{\numchapentry}%
+      \def\unnsecentry{\numsecentry}%
+      \def\unnsubsecentry{\numsubsecentry}%
+      \def\unnsubsubsecentry{\numsubsubsecentry}%
+      \readdatafile{toc}%
+      %
+      % Read toc second time, this time actually producing the outlines.
+      % The `-' means take the \expnumber as the absolute number of
+      % subentries, which we calculated on our first read of the .toc above.
+      %
+      % We use the node names as the destinations.
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{% count is always zero
+        \dopdfoutline{##1}{}{##3}{##4}}%
+      %
+      % PDF outlines are displayed using system fonts, instead of
+      % document fonts.  Therefore we cannot use special characters,
+      % since the encoding is unknown.  For example, the eogonek from
+      % Latin 2 (0xea) gets translated to a | character.  Info from
+      % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
+      %
+      % xx to do this right, we have to translate 8-bit characters to
+      % their "best" equivalent, based on the @documentencoding.  Right
+      % now, I guess we'll just let the pdf reader have its way.
+      \indexnofonts
+      \setupdatafile
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  %
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \ifx\p\space\else\addtokens{\filename}{\PP}%
+        \advance\filenamelength by 1
+      \fi
+    \fi
+    \nextsp}
+  \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax}
+  \ifnum\pdftexversion < 14
+    \let \startlink \pdfannotlink
+  \else
+    \let \startlink \pdfstartlink
+  \fi
+  % make a live url in pdf output.
+  \def\pdfurl#1{%
+    \begingroup
+      % it seems we really need yet another set of dummies; have not
+      % tried to figure out what each command should do in the context
+      % of @url.  for now, just make @/ a no-op, that's the only one
+      % people have actually reported a problem with.
+      %
+      \normalturnoffactive
+      \def\@{@}%
+      \let\/=\empty
+      \makevalueexpandable
+      % do we want to go so far as to use \indexnofonts instead of just
+      % special-casing \var here?
+      \def\var##1{##1}%
+      %
+      \leavevmode\setcolor{\urlcolor}%
+      \startlink attr{/Border [0 0 0]}%
+        user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+    \endgroup}
+  \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+  \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+  \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+  \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+  \def\maketoks{%
+    \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+    \ifx\first0\adn0
+    \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+    \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+    \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+    \else
+      \ifnum0=\countA\else\makelink\fi
+      \ifx\first.\let\next=\done\else
+        \let\next=\maketoks
+        \addtokens{\toksB}{\the\toksD}
+        \ifx\first,\addtokens{\toksB}{\space}\fi
+      \fi
+    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+    \next}
+  \def\makelink{\addtokens{\toksB}%
+    {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+  \def\pdflink#1{%
+    \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\else
+  % non-pdf mode
+  \let\pdfmkdest = \gobble
+  \let\pdfurl = \gobble
+  \let\endlink = \relax
+  \let\setcolor = \gobble
+  \let\pdfsetcolor = \gobble
+  \let\pdfmakeoutlines = \relax
+\fi  % \ifx\pdfoutput
+
+
+\message{fonts,}
+
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+  \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+  \csname ten#1\endcsname  % change the current font
+}
+
+% Select #1 fonts with the current style.
+%
+\def\selectfonts#1{\csname #1fonts\endcsname \csname\curfontstyle\endcsname}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}
+
+% Unfortunately, we have to override this for titles and the like, since
+% in those cases "rm" is bold.  Sigh.
+\def\rmisbold{\rm\def\curfontstyle{bf}}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+\let\li = \sf % Sometimes we call it \li, not \sf.
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
+% Default leading.
+\newdimen\textleading  \textleading = 13.2pt
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+% can get a sort of poor man's double spacing by redefining this.
+\def\baselinefactor{1}
+%
+\def\setleading#1{%
+  \dimen0 = #1\relax
+  \normalbaselineskip = \baselinefactor\dimen0
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% PDF CMaps.  See also LaTeX's t1.cmap.
+%
+% do nothing with this by default.
+\expandafter\let\csname cmapOT1\endcsname\gobble
+\expandafter\let\csname cmapOT1IT\endcsname\gobble
+\expandafter\let\csname cmapOT1TT\endcsname\gobble
+
+% if we are producing pdf, and we have \pdffontattr, then define cmaps.
+% (\pdffontattr was introduced many years ago, but people still run
+% older pdftex's; it's easy to conditionalize, so we do.)
+\ifpdf \ifx\pdffontattr\undefined \else
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1-0)
+%%Title: (TeX-OT1-0 TeX OT1 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<23> <26> <0023>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+40 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1IT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1IT-0)
+%%Title: (TeX-OT1IT-0 TeX OT1IT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1IT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1IT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<25> <26> <0025>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+42 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<23> <0023>
+<24> <00A3>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1IT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1TT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1TT-0)
+%%Title: (TeX-OT1TT-0 TeX OT1TT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1TT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1TT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+5 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<21> <26> <0021>
+<28> <5F> <0028>
+<61> <7E> <0061>
+endbfrange
+32 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <2191>
+<0C> <2193>
+<0D> <0027>
+<0E> <00A1>
+<0F> <00BF>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<20> <2423>
+<27> <2019>
+<60> <2018>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1TT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+\fi\fi
+
+
+% Set the font macro #1 to the font named #2, adding on the
+% specified font prefix (normally `cm').
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (currently only OT1, OT1IT and OT1TT are allowed, pass
+% empty to omit).
+\def\setfont#1#2#3#4#5{%
+  \font#1=\fontprefix#2#3 scaled #4
+  \csname cmap#5\endcsname#1%
+}
+% This is what gets called when #5 of \setfont is empty.
+\let\cmap\gobble
+% emacs-page end of cmaps
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\undefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx}               %where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Definitions for a main text size of 11pt.  This is the default in
+% Texinfo.
+%
+\def\definetextfontsizexi{%
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1095}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}{OT1}
+\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
+\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\def\chapnominalsize{17pt}
+\setfont\chaprm\rmbshape{12}{\magstep2}{OT1}
+\setfont\chapit\itbshape{10}{\magstep3}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep3}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT}
+\setfont\chapsf\sfbshape{17}{1000}{OT1}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}{OT1}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+\def\chapecsize{1728}
+
+% Section fonts (14.4pt).
+\def\secnominalsize{14pt}
+\setfont\secrm\rmbshape{12}{\magstep1}{OT1}
+\setfont\secit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep2}{OT1}
+\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\secsf\sfbshape{12}{\magstep1}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}{OT1}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+\def\sececsize{1440}
+
+% Subsection fonts (13.15pt).
+\def\ssecnominalsize{13pt}
+\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1}
+\setfont\ssecit\itbshape{10}{1315}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1315}{OT1}
+\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1315}{OT1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+\def\ssececsize{1200}
+
+% Reduced fonts for @acro in text (10pt).
+\def\reducednominalsize{10pt}
+\setfont\reducedrm\rmshape{10}{1000}{OT1}
+\setfont\reducedtt\ttshape{10}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{1000}{OT1}
+\setfont\reducedit\itshape{10}{1000}{OT1IT}
+\setfont\reducedsl\slshape{10}{1000}{OT1}
+\setfont\reducedsf\sfshape{10}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{1000}{OT1}
+\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT}
+\font\reducedi=cmmi10
+\font\reducedsy=cmsy10
+\def\reducedecsize{1000}
+
+% reset the current fonts
+\textfonts
+\rm
+} % end of 11pt text font size definitions
+
+
+% Definitions to make the main text be 10pt Computer Modern, with
+% section, chapter, etc., sizes following suit.  This is for the GNU
+% Press printing of the Emacs 22 manual.  Maybe other manuals in the
+% future.  Used with @smallbook, which sets the leading to 12pt.
+%
+\def\definetextfontsizex{%
+% Text fonts (10pt).
+\def\textnominalsize{10pt}
+\edef\mainmagstep{1000}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1000}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstephalf}{OT1}
+\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
+\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
+\def\df{\let\tentt=\deftt \let\tenbf = \defbf \let\tenttsl=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter fonts (14.4pt).
+\def\chapnominalsize{14pt}
+\setfont\chaprm\rmbshape{12}{\magstep1}{OT1}
+\setfont\chapit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep2}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\chapsf\sfbshape{12}{\magstep1}{OT1}
+\let\chapbf\chaprm
+\setfont\chapsc\scbshape{10}{\magstep2}{OT1}
+\font\chapi=cmmi12 scaled \magstep1
+\font\chapsy=cmsy10 scaled \magstep2
+\def\chapecsize{1440}
+
+% Section fonts (12pt).
+\def\secnominalsize{12pt}
+\setfont\secrm\rmbshape{12}{1000}{OT1}
+\setfont\secit\itbshape{10}{\magstep1}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep1}{OT1}
+\setfont\sectt\ttbshape{12}{1000}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT}
+\setfont\secsf\sfbshape{12}{1000}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep1}{OT1}
+\font\seci=cmmi12
+\font\secsy=cmsy10 scaled \magstep1
+\def\sececsize{1200}
+
+% Subsection fonts (10pt).
+\def\ssecnominalsize{10pt}
+\setfont\ssecrm\rmbshape{10}{1000}{OT1}
+\setfont\ssecit\itbshape{10}{1000}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1000}{OT1}
+\setfont\ssectt\ttbshape{10}{1000}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT}
+\setfont\ssecsf\sfbshape{10}{1000}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1000}{OT1}
+\font\sseci=cmmi10
+\font\ssecsy=cmsy10
+\def\ssececsize{1000}
+
+% Reduced fonts for @acro in text (9pt).
+\def\reducednominalsize{9pt}
+\setfont\reducedrm\rmshape{9}{1000}{OT1}
+\setfont\reducedtt\ttshape{9}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{900}{OT1}
+\setfont\reducedit\itshape{9}{1000}{OT1IT}
+\setfont\reducedsl\slshape{9}{1000}{OT1}
+\setfont\reducedsf\sfshape{9}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{900}{OT1}
+\setfont\reducedttsl\ttslshape{10}{900}{OT1TT}
+\font\reducedi=cmmi9
+\font\reducedsy=cmsy9
+\def\reducedecsize{0900}
+
+% reduce space between paragraphs
+\divide\parskip by 2
+
+% reset the current fonts
+\textfonts
+\rm
+} % end of 10pt text font size definitions
+
+
+% We provide the user-level command
+%   @fonttextsize 10
+% (or 11) to redefine the text font size.  pt is assumed.
+%
+\def\xword{10}
+\def\xiword{11}
+%
+\parseargdef\fonttextsize{%
+  \def\textsizearg{#1}%
+  \wlog{doing @fonttextsize \textsizearg}%
+  %
+  % Set \globaldefs so that documents can use this inside @tex, since
+  % makeinfo 4.8 does not support it, but we need it nonetheless.
+  %
+ \begingroup \globaldefs=1
+  \ifx\textsizearg\xword \definetextfontsizex
+  \else \ifx\textsizearg\xiword \definetextfontsizexi
+  \else
+    \errhelp=\EMsimple
+    \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'}
+  \fi\fi
+ \endgroup
+}
+
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.  Since
+% texinfo doesn't allow for producing subscripts and superscripts except
+% in the main text, we don't bother to reset \scriptfont and
+% \scriptscriptfont (which would also require loading a lot more fonts).
+%
+\def\resetmathfonts{%
+  \textfont0=\tenrm \textfont1=\teni \textfont2=\tensy
+  \textfont\itfam=\tenit \textfont\slfam=\tensl \textfont\bffam=\tenbf
+  \textfont\ttfam=\tentt \textfont\sffam=\tensf
+}
+
+% The font-changing commands redefine the meanings of \tenSTYLE, instead
+% of just \STYLE.  We do this because \STYLE needs to also set the
+% current \fam for math mode.  Our \STYLE (e.g., \rm) commands hardwire
+% \tenSTYLE to set the current font.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower).  These relative commands are used in
+% the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+\def\textfonts{%
+  \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl
+  \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc
+  \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy
+  \let\tenttsl=\textttsl
+  \def\curfontsize{text}%
+  \def\lsize{reduced}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{\textleading}}
+\def\titlefonts{%
+  \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl
+  \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc
+  \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy
+  \let\tenttsl=\titlettsl
+  \def\curfontsize{title}%
+  \def\lsize{chap}\def\lllsize{subsec}%
+  \resetmathfonts \setleading{25pt}}
+\def\titlefont#1{{\titlefonts\rmisbold #1}}
+\def\chapfonts{%
+  \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl
+  \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc
+  \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy
+  \let\tenttsl=\chapttsl
+  \def\curfontsize{chap}%
+  \def\lsize{sec}\def\lllsize{text}%
+  \resetmathfonts \setleading{19pt}}
+\def\secfonts{%
+  \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl
+  \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc
+  \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy
+  \let\tenttsl=\secttsl
+  \def\curfontsize{sec}%
+  \def\lsize{subsec}\def\lllsize{reduced}%
+  \resetmathfonts \setleading{16pt}}
+\def\subsecfonts{%
+  \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl
+  \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc
+  \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy
+  \let\tenttsl=\ssecttsl
+  \def\curfontsize{ssec}%
+  \def\lsize{text}\def\lllsize{small}%
+  \resetmathfonts \setleading{15pt}}
+\let\subsubsecfonts = \subsecfonts
+\def\reducedfonts{%
+  \let\tenrm=\reducedrm \let\tenit=\reducedit \let\tensl=\reducedsl
+  \let\tenbf=\reducedbf \let\tentt=\reducedtt \let\reducedcaps=\reducedsc
+  \let\tensf=\reducedsf \let\teni=\reducedi \let\tensy=\reducedsy
+  \let\tenttsl=\reducedttsl
+  \def\curfontsize{reduced}%
+  \def\lsize{small}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{10.5pt}}
+\def\smallfonts{%
+  \let\tenrm=\smallrm \let\tenit=\smallit \let\tensl=\smallsl
+  \let\tenbf=\smallbf \let\tentt=\smalltt \let\smallcaps=\smallsc
+  \let\tensf=\smallsf \let\teni=\smalli \let\tensy=\smallsy
+  \let\tenttsl=\smallttsl
+  \def\curfontsize{small}%
+  \def\lsize{smaller}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{10.5pt}}
+\def\smallerfonts{%
+  \let\tenrm=\smallerrm \let\tenit=\smallerit \let\tensl=\smallersl
+  \let\tenbf=\smallerbf \let\tentt=\smallertt \let\smallcaps=\smallersc
+  \let\tensf=\smallersf \let\teni=\smalleri \let\tensy=\smallersy
+  \let\tenttsl=\smallerttsl
+  \def\curfontsize{smaller}%
+  \def\lsize{smaller}\def\lllsize{smaller}%
+  \resetmathfonts \setleading{9.5pt}}
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}{OT1}
+\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1}  % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}{OT1}
+\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+
+% Define these just so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Set the fonts to use with the @small... environments.
+\let\smallexamplefonts = \smallfonts
+
+% About \smallexamplefonts.  If we use \smallfonts (9pt), @smallexample
+% can fit this many characters:
+%   8.5x11=86   smallbook=72  a4=90  a5=69
+% If we use \scriptfonts (8pt), then we can fit this many characters:
+%   8.5x11=90+  smallbook=80  a4=90+  a5=77
+% For me, subjectively, the few extra characters that fit aren't worth
+% the additional smallness of 8pt.  So I'm making the default 9pt.
+%
+% By the way, for comparison, here's what fits with @example (10pt):
+%   8.5x11=71  smallbook=60  a4=75  a5=58
+% --karl, 24jan03.
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\definetextfontsizexi
+
+
+\message{markup,}
+
+% Check if we are currently using a typewriter font.  Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+% Markup style infrastructure.  \defmarkupstylesetup\INITMACRO will
+% define and register \INITMACRO to be called on markup style changes.
+% \INITMACRO can check \currentmarkupstyle for the innermost
+% style and the set of \ifmarkupSTYLE switches for all styles
+% currently in effect.
+\newif\ifmarkupvar
+\newif\ifmarkupsamp
+\newif\ifmarkupkey
+%\newif\ifmarkupfile % @file == @samp.
+%\newif\ifmarkupoption % @option == @samp.
+\newif\ifmarkupcode
+\newif\ifmarkupkbd
+%\newif\ifmarkupenv % @env == @code.
+%\newif\ifmarkupcommand % @command == @code.
+\newif\ifmarkuptex % @tex (and part of @math, for now).
+\newif\ifmarkupexample
+\newif\ifmarkupverb
+\newif\ifmarkupverbatim
+
+\let\currentmarkupstyle\empty
+
+\def\setupmarkupstyle#1{%
+  \csname markup#1true\endcsname
+  \def\currentmarkupstyle{#1}%
+  \markupstylesetup
+}
+
+\let\markupstylesetup\empty
+
+\def\defmarkupstylesetup#1{%
+  \expandafter\def\expandafter\markupstylesetup
+    \expandafter{\markupstylesetup #1}%
+  \def#1%
+}
+
+% Markup style setup for left and right quotes.
+\defmarkupstylesetup\markupsetuplq{%
+  \expandafter\let\expandafter \temp \csname markupsetuplq\currentmarkupstyle\endcsname
+  \ifx\temp\relax \markupsetuplqdefault \else \temp \fi
+}
+
+\defmarkupstylesetup\markupsetuprq{%
+  \expandafter\let\expandafter \temp \csname markupsetuprq\currentmarkupstyle\endcsname
+  \ifx\temp\relax \markupsetuprqdefault \else \temp \fi
+}
+
+{
+\catcode`\'=\active
+\catcode`\`=\active
+
+\gdef\markupsetuplqdefault{\let`\lq}
+\gdef\markupsetuprqdefault{\let'\rq}
+
+\gdef\markupsetcodequoteleft{\let`\codequoteleft}
+\gdef\markupsetcodequoteright{\let'\codequoteright}
+
+\gdef\markupsetnoligaturesquoteleft{\let`\noligaturesquoteleft}
+}
+
+\let\markupsetuplqcode \markupsetcodequoteleft
+\let\markupsetuprqcode \markupsetcodequoteright
+\let\markupsetuplqexample \markupsetcodequoteleft
+\let\markupsetuprqexample \markupsetcodequoteright
+\let\markupsetuplqverb \markupsetcodequoteleft
+\let\markupsetuprqverb \markupsetcodequoteright
+\let\markupsetuplqverbatim \markupsetcodequoteleft
+\let\markupsetuprqverbatim \markupsetcodequoteright
+
+\let\markupsetuplqsamp \markupsetnoligaturesquoteleft
+\let\markupsetuplqkbd \markupsetnoligaturesquoteleft
+
+% Allow an option to not replace quotes with a regular directed right
+% quote/apostrophe (char 0x27), but instead use the undirected quote
+% from cmtt (char 0x0d).  The undirected quote is ugly, so don't make it
+% the default, but it works for pasting with more pdf viewers (at least
+% evince), the lilypond developers report.  xpdf does work with the
+% regular 0x27.
+%
+\def\codequoteright{%
+  \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
+    \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+      '%
+    \else \char'15 \fi
+  \else \char'15 \fi
+}
+%
+% and a similar option for the left quote char vs. a grave accent.
+% Modern fonts display ASCII 0x60 as a grave accent, so some people like
+% the code environments to do likewise.
+%
+\def\codequoteleft{%
+  \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax
+    \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax
+      % [Knuth] pp. 380,381,391
+      % \relax disables Spanish ligatures ?` and !` of \tt font.
+      \relax`%
+    \else \char'22 \fi
+  \else \char'22 \fi
+}
+
+% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font.
+\def\noligaturesquoteleft{\relax\lq}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+%% Add scribe-like font environments, plus @l for inline lisp (usually sans
+%% serif) and @ii for TeX italic
+
+% \smartitalic{ARG} outputs arg in italics, followed by an italic correction
+% unless the following character is such as not to need one.
+\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else
+                    \ptexslash\fi\fi\fi}
+\def\smartslanted#1{{\ifusingtt\ttsl\sl #1}\futurelet\next\smartitalicx}
+\def\smartitalic#1{{\ifusingtt\ttsl\it #1}\futurelet\next\smartitalicx}
+
+% like \smartslanted except unconditionally uses \ttsl.
+% @var is set to this for defun arguments.
+\def\ttslanted#1{{\ttsl #1}\futurelet\next\smartitalicx}
+
+% @cite is like \smartslanted except unconditionally use \sl.  We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitalicx}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\def\var#1{{\setupmarkupstyle{var}\smartslanted{#1}}}
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}}              % roman font
+\def\sc#1{{\smallcaps#1}}       % smallcaps font
+\def\ii#1{{\it #1}}             % italic font
+
+% @b, explicit bold.  Also @strong.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+  \def\plainfrenchspacing{%
+    \sfcode\dotChar  =\@m \sfcode\questChar=\@m \sfcode\exclamChar=\@m
+    \sfcode\colonChar=\@m \sfcode\semiChar =\@m \sfcode\commaChar =\@m
+    \def\endofsentencespacefactor{1000}% for @. and friends
+  }
+  \def\plainnonfrenchspacing{%
+    \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000
+    \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250
+    \def\endofsentencespacefactor{3000}% for @. and friends
+  }
+\catcode`@=\other
+\def\endofsentencespacefactor{3000}% default
+
+% @t, explicit typewriter.
+\def\t#1{%
+  {\tt \rawbackslash \plainfrenchspacing #1}%
+  \null
+}
+
+% @samp.
+\def\samp#1{{\setupmarkupstyle{samp}\lq\tclose{#1}\rq\null}}
+
+% definition of @key that produces a lozenge.  Doesn't adjust to text size.
+%\setfont\keyrm\rmshape{8}{1000}{OT1}
+%\font\keysy=cmsy9
+%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+%  \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+%    \vbox{\hrule\kern-0.4pt
+%     \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+%    \kern-0.4pt\hrule}%
+%  \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+
+% definition of @key with no lozenge.  If the current font is already
+% monospace, don't change it; that way, we respect @kbdinputstyle.  But
+% if it isn't monospace, then use \tt.
+%
+\def\key#1{{\setupmarkupstyle{key}%
+  \nohyphenation
+  \ifmonospace\else\tt\fi
+  #1}\null}
+
+% ctrl is no longer a Texinfo command.
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @file, @option are the same as @samp.
+\let\file=\samp
+\let\option=\samp
+
+% @code is a modification of @t,
+% which makes spaces the same size as normal in the surrounding text.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \rawbackslash
+    \plainfrenchspacing
+    #1%
+  }%
+  \null
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash.
+%  -- rms.
+{
+  \catcode`\-=\active \catcode`\_=\active
+  \catcode`\'=\active \catcode`\`=\active
+  \global\let'=\rq \global\let`=\lq  % default definitions
+  %
+  \global\def\code{\begingroup
+    \setupmarkupstyle{code}%
+    % The following should really be moved into \setupmarkupstyle handlers.
+    \catcode\dashChar=\active  \catcode\underChar=\active
+    \ifallowcodebreaks
+     \let-\codedash
+     \let_\codeunder
+    \else
+     \let-\realdash
+     \let_\realunder
+    \fi
+    \codex
+  }
+}
+
+\def\realdash{-}
+\def\codedash{-\discretionary{}{}{}}
+\def\codeunder{%
+  % this is all so @math{@code{var_name}+1} can work.  In math mode, _
+  % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.)
+  % will therefore expand the active definition of _, which is us
+  % (inside @code that is), therefore an endless loop.
+  \ifusingtt{\ifmmode
+               \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_.
+             \else\normalunderscore \fi
+             \discretionary{}{}{}}%
+            {\_}%
+}
+\def\codex #1{\tclose{#1}\endgroup}
+
+% An additional complication: the above will allow breaks after, e.g.,
+% each of the four underscores in __typeof__.  This is undesirable in
+% some manuals, especially if they don't have long identifiers in
+% general.  @allowcodebreaks provides a way to control this.
+%
+\newif\ifallowcodebreaks  \allowcodebreakstrue
+
+\def\keywordtrue{true}
+\def\keywordfalse{false}
+
+\parseargdef\allowcodebreaks{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\keywordtrue
+    \allowcodebreakstrue
+  \else\ifx\txiarg\keywordfalse
+    \allowcodebreaksfalse
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @allowcodebreaks option `\txiarg'}%
+  \fi\fi
+}
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\setupmarkupstyle{kbd}\def\look{#1}\expandafter\kbdfoo\look??\par}}
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+%   `example' (@kbd uses ttsl only inside of @example and friends),
+%   or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\worddistinct
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+  \else\ifx\txiarg\wordexample
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+  \else\ifx\txiarg\wordcode
+    \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @kbdinputstyle option `\txiarg'}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+\def\xkey{\key}
+\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}%
+\ifx\one\xkey\ifx\threex\three \key{#2}%
+\else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+\else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi}
+
+% For @indicateurl, @env, @command quotes seem unnecessary, so use \code.
+\let\indicateurl=\code
+\let\env=\code
+\let\command=\code
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow   (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% @uref (abbreviation for `urlref') takes an optional (comma-separated)
+% second argument specifying the text to display and an optional third
+% arg as text to display instead of (rather than in addition to) the url
+% itself.  First (mandatory) arg is the url.  Perhaps eventually put in
+% a hypertex \special here.
+%
+\def\uref#1{\douref #1,,,\finish}
+\def\douref#1,#2,#3,#4\finish{\begingroup
+  \unsepspaces
+  \pdfurl{#1}%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0 > 0pt
+      \ifpdf
+        \unhbox0             % PDF: 2nd arg given, show only it
+      \else
+        \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url
+      \fi
+    \else
+      \code{#1}% only url given, so show it
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdf
+  \def\email#1{\doemail#1,,\finish}
+  \def\doemail#1,#2,#3\finish{\begingroup
+    \unsepspaces
+    \pdfurl{mailto:#1}%
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+    \endlink
+  \endgroup}
+\else
+  \let\email=\uref
+\fi
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+% @l was never documented to mean ``switch to the Lisp font'',
+% and it is not used as such in any manual I can find.  We need it for
+% Polish suppressed-l.  --karl, 22sep96.
+%\def\l#1{{\li #1}\null}
+
+% @acronym for "FBI", "NATO", and the like.
+% We print this one point size smaller, since it's intended for
+% all-uppercase.
+%
+\def\acronym#1{\doacronym #1,,\finish}
+\def\doacronym#1,#2,#3\finish{%
+  {\selectfonts\lsize #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+  {\plainfrenchspacing #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+}
+
+
+\message{glyphs,}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+%
+% Since these characters are used in examples, they should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+%
+\def\point{$\star$}
+\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}}
+\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% The @error{} command.
+% Adapted from the TeXbook's \boxit.
+%
+\newbox\errorbox
+%
+{\tentt \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \reducedsf error\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{%
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{{\it\$}}
+
+% @euro{} comes from a separate font, depending on the current style.
+% We use the free feym* fonts from the eurosym package by Henrik
+% Theiling, which support regular, slanted, bold and bold slanted (and
+% "outlined" (blackboard board, sort of) versions, which we don't need).
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
+%
+% Although only regular is the truly official Euro symbol, we ignore
+% that.  The Euro is designed to be slightly taller than the regular
+% font height.
+%
+% feymr - regular
+% feymo - slanted
+% feybr - bold
+% feybo - bold slanted
+%
+% There is no good (free) typewriter version, to my knowledge.
+% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide.
+% Hmm.
+%
+% Also doesn't work in math.  Do we need to do math with euro symbols?
+% Hope not.
+%
+%
+\def\euro{{\eurofont e}}
+\def\eurofont{%
+  % We set the font at each command, rather than predefining it in
+  % \textfonts and the other font-switching commands, so that
+  % installations which never need the symbol don't have to have the
+  % font installed.
+  %
+  % There is only one designed size (nominal 10pt), so we always scale
+  % that to the current nominal size.
+  %
+  % By the way, simply using "at 1em" works for cmr10 and the like, but
+  % does not work for cmbx10 and other extended/shrunken fonts.
+  %
+  \def\eurosize{\csname\curfontsize nominalsize\endcsname}%
+  %
+  \ifx\curfontstyle\bfstylename
+    % bold:
+    \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize
+  \else
+    % regular:
+    \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize
+  \fi
+  \thiseurofont
+}
+
+% Glyphs from the EC fonts.  We don't use \let for the aliases, because
+% sometimes we redefine the original macro, and the alias should reflect
+% the redefinition.
+%
+% Use LaTeX names for the Icelandic letters.
+\def\DH{{\ecfont \char"D0}} % Eth
+\def\dh{{\ecfont \char"F0}} % eth
+\def\TH{{\ecfont \char"DE}} % Thorn
+\def\th{{\ecfont \char"FE}} % thorn
+%
+\def\guillemetleft{{\ecfont \char"13}}
+\def\guillemotleft{\guillemetleft}
+\def\guillemetright{{\ecfont \char"14}}
+\def\guillemotright{\guillemetright}
+\def\guilsinglleft{{\ecfont \char"0E}}
+\def\guilsinglright{{\ecfont \char"0F}}
+\def\quotedblbase{{\ecfont \char"12}}
+\def\quotesinglbase{{\ecfont \char"0D}}
+%
+% This positioning is not perfect (see the ogonek LaTeX package), but
+% we have the precomposed glyphs for the most common cases.  We put the
+% tests to use those glyphs in the single \ogonek macro so we have fewer
+% dummy definitions to worry about for index entries, etc.
+%
+% ogonek is also used with other letters in Lithuanian (IOU), but using
+% the precomposed glyphs for those is not so easy since they aren't in
+% the same EC font.
+\def\ogonek#1{{%
+  \def\temp{#1}%
+  \ifx\temp\macrocharA\Aogonek
+  \else\ifx\temp\macrochara\aogonek
+  \else\ifx\temp\macrocharE\Eogonek
+  \else\ifx\temp\macrochare\eogonek
+  \else
+    \ecfont \setbox0=\hbox{#1}%
+    \ifdim\ht0=1ex\accent"0C #1%
+    \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}%
+    \fi
+  \fi\fi\fi\fi
+  }%
+}
+\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A}
+\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a}
+\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E}
+\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e}
+%
+% Use the ec* fonts (cm-super in outline format) for non-CM glyphs.
+\def\ecfont{%
+  % We can't distinguish serif/sans and italic/slanted, but this
+  % is used for crude hacks anyway (like adding French and German
+  % quotes to documents typeset with CM, where we lose kerning), so
+  % hopefully nobody will notice/care.
+  \edef\ecsize{\csname\curfontsize ecsize\endcsname}%
+  \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}%
+  \ifx\curfontstyle\bfstylename
+    % bold:
+    \font\thisecfont = ecb\ifusingit{i}{x}\ecsize \space at \nominalsize
+  \else
+    % regular:
+    \font\thisecfont = ec\ifusingit{ti}{rm}\ecsize \space at \nominalsize
+  \fi
+  \thisecfont
+}
+
+% @registeredsymbol - R in a circle.  The font for the R should really
+% be smaller yet, but lllsize is the best we can do for now.
+% Adapted from the plain.tex definition of \copyright.
+%
+\def\registeredsymbol{%
+  $^{{\ooalign{\hfil\raise.07ex\hbox{\selectfonts\lllsize R}%
+               \hfil\crcr\Orb}}%
+    }$%
+}
+
+% @textdegree - the normal degrees sign.
+%
+\def\textdegree{$^\circ$}
+
+% Laurent Siebenmann reports \Orb undefined with:
+%  Textures 1.7.7 (preloaded format=plain 93.10.14)  (68K)  16 APR 2004 02:38
+% so we'll define it if necessary.
+%
+\ifx\Orb\undefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+% Quotes.
+\chardef\quotedblleft="5C
+\chardef\quotedblright=`\"
+\chardef\quoteleft=`\`
+\chardef\quoteright=`\'
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% Do an implicit @contents or @shortcontents after @end titlepage if the
+% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage.
+%
+\newif\ifsetcontentsaftertitlepage
+ \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue
+\newif\ifsetshortcontentsaftertitlepage
+ \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue
+
+\parseargdef\shorttitlepage{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+        \endgroup\page\hbox{}\page}
+
+\envdef\titlepage{%
+  % Open one extra group, as we want to close it in the middle of \Etitlepage.
+  \begingroup
+    \parindent=0pt \textfonts
+    % Leave some space at the very top of the page.
+    \vglue\titlepagetopglue
+    % No rule at page bottom unless we print one at the top with @title.
+    \finishedtitlepagetrue
+    %
+    % Most title ``pages'' are actually two pages long, with space
+    % at the top of the second.  We don't want the ragged left on the second.
+    \let\oldpage = \page
+    \def\page{%
+      \iffinishedtitlepage\else
+        \finishtitlepage
+      \fi
+      \let\page = \oldpage
+      \page
+      \null
+    }%
+}
+
+\def\Etitlepage{%
+    \iffinishedtitlepage\else
+       \finishtitlepage
+    \fi
+    % It is important to do the page break before ending the group,
+    % because the headline and footline are only empty inside the group.
+    % If we use the new definition of \page, we always get a blank page
+    % after the title page, which we certainly don't want.
+    \oldpage
+  \endgroup
+  %
+  % Need this before the \...aftertitlepage checks so that if they are
+  % in effect the toc pages will come out with page numbers.
+  \HEADINGSon
+  %
+  % If they want short, they certainly want long too.
+  \ifsetshortcontentsaftertitlepage
+    \shortcontents
+    \contents
+    \global\let\shortcontents = \relax
+    \global\let\contents = \relax
+  \fi
+  %
+  \ifsetcontentsaftertitlepage
+    \contents
+    \global\let\contents = \relax
+    \global\let\shortcontents = \relax
+  \fi
+}
+
+\def\finishtitlepage{%
+  \vskip4pt \hrule height 2pt width \hsize
+  \vskip\titlepagebottomglue
+  \finishedtitlepagetrue
+}
+
+%%% Macros to be used within @titlepage:
+
+\let\subtitlerm=\tenrm
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+  \checkenv\titlepage
+  \leftline{\titlefonts\rmisbold #1}
+  % print a rule at the page bottom also.
+  \finishedtitlepagefalse
+  \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+  \checkenv\titlepage
+  {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+  \def\temp{\quotation}%
+  \ifx\thisenv\temp
+    \def\quotationauthor{#1}% printed in \Equotation.
+  \else
+    \checkenv\titlepage
+    \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+    {\secfonts\rmisbold \leftline{#1}}%
+  \fi
+}
+
+
+%%% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline    % headline on even pages
+\newtoks\oddheadline     % headline on odd pages
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make TeX use those variables
+\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline
+                            \else \the\evenheadline \fi}}
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish}
+\def\evenheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish}
+\def\oddheadingyyy #1\|#2\|#3\|#4\finish{%
+\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish}
+\def\evenfootingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish}
+\def\oddfootingyyy #1\|#2\|#3\|#4\finish{%
+  \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  %
+  % Leave some space for the footline.  Hopefully ok to assume
+  % @evenfooting will not be used by itself.
+  \global\advance\pageheight by -12pt
+  \global\advance\vsize by -12pt
+}
+
+\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+
+% @evenheadingmarks top     \thischapter <- chapter at the top of a page
+% @evenheadingmarks bottom  \thischapter <- chapter at the bottom of a page
+%
+% The same set of arguments for:
+%
+% @oddheadingmarks
+% @evenfootingmarks
+% @oddfootingmarks
+% @everyheadingmarks
+% @everyfootingmarks
+
+\def\evenheadingmarks{\headingmarks{even}{heading}}
+\def\oddheadingmarks{\headingmarks{odd}{heading}}
+\def\evenfootingmarks{\headingmarks{even}{footing}}
+\def\oddfootingmarks{\headingmarks{odd}{footing}}
+\def\everyheadingmarks#1 {\headingmarks{even}{heading}{#1}
+                          \headingmarks{odd}{heading}{#1} }
+\def\everyfootingmarks#1 {\headingmarks{even}{footing}{#1}
+                          \headingmarks{odd}{footing}{#1} }
+% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
+\def\headingmarks#1#2#3 {%
+  \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname
+  \global\expandafter\let\csname get#1#2marks\endcsname \temp
+}
+
+\everyheadingmarks bottom
+\everyfootingmarks bottom
+
+% @headings double      turns headings on for double-sided printing.
+% @headings single      turns headings on for single-sided printing.
+% @headings off         turns them off.
+% @headings on          same as @headings double, retained for compatibility.
+% @headings after       turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\def\headings #1 {\csname HEADINGS#1\endcsname}
+
+\def\HEADINGSoff{%
+\global\evenheadline={\hfil} \global\evenfootline={\hfil}
+\global\oddheadline={\hfil} \global\oddfootline={\hfil}}
+\HEADINGSoff
+% When we turn headings on, set the page number to 1.
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\global\pageno=1
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% This produces Day Month Year style of output.
+% Only define if not already defined, in case a txi-??.tex file has set
+% up a different format (e.g., txi-cs.tex does this).
+\ifx\today\undefined
+\def\today{%
+  \number\day\space
+  \ifcase\month
+  \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+  \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+  \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+  \fi
+  \space\number\year}
+\fi
+
+% @settitle line...  specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemindicate{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  However, if
+    % what follows is an environment such as @example, there will be no
+    % \parskip glue; then the negative vskip we just inserted would
+    % cause the example and the item to crash together.  So we use this
+    % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+    % \parskip glue after all.  Section titles are handled this way also.
+    %
+    \penalty 10001
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.
+    \noindent
+    % Do this with kerns and \unhbox so that if there is a footnote in
+    % the item text, it can migrate to the main vertical list and
+    % eventually be printed.
+    \nobreak\kern-\tableindent
+    \dimen0 = \itemmax  \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+    \unhbox0
+    \nobreak\kern\dimen0
+    \endgroup
+    \itemxneedsnegativevskiptrue
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+  \let\itemindex\gobble
+  \tablecheck{table}%
+}
+\envdef\ftable{%
+  \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+  \tablecheck{ftable}%
+}
+\envdef\vtable{%
+  \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+  \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+  \ifnum \the\catcode`\^^M=\active
+    \endgroup
+    \errmessage{This command won't work in this context; perhaps the problem is
+      that we are \inenvironment\thisenv}%
+    \def\next{\doignore{#1}}%
+  \else
+    \let\next\tablex
+  \fi
+  \next
+}
+\def\tablex#1{%
+  \def\itemindicate{#1}%
+  \parsearg\tabley
+}
+\def\tabley#1{%
+  {%
+    \makevalueexpandable
+    \edef\temp{\noexpand\tablez #1\space\space\space}%
+    \expandafter
+  }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+  \aboveenvbreak
+  \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+  \ifnum 0#2>0 \tableindent=#2\mil \fi
+  \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+  \itemmax=\tableindent
+  \advance \itemmax by -\itemmargin
+  \advance \leftskip by \tableindent
+  \exdentamount=\tableindent
+  \parindent = 0pt
+  \parskip = \smallskipamount
+  \ifdim \parskip=0pt \parskip=2pt \fi
+  \let\item = \internalBitem
+  \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+  \aboveenvbreak
+  \itemmax=\itemindent
+  \advance\itemmax by -\itemmargin
+  \advance\leftskip by \itemindent
+  \exdentamount=\itemindent
+  \parindent=0pt
+  \parskip=\smallskipamount
+  \ifdim\parskip=0pt \parskip=2pt \fi
+  %
+  % Try typesetting the item mark that if the document erroneously says
+  % something like @itemize @samp (intending @table), there's an error
+  % right away at the @itemize.  It's not the best error message in the
+  % world, but it's better than leaving it to the @item.  This means if
+  % the user wants an empty mark, they have to say @w{} not just @w.
+  \def\itemcontents{#1}%
+  \setbox0 = \hbox{\itemcontents}%
+  %
+  % @itemize with no arg is equivalent to @itemize @bullet.
+  \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi
+  %
+  \let\item=\itemizeitem
+}
+
+% Definition of @item while inside @itemize and @enumerate.
+%
+\def\itemizeitem{%
+  \advance\itemno by 1  % for enumerations
+  {\let\par=\endgraf \smallbreak}% reasonable place to break
+  {%
+   % If the document has an @itemize directly after a section title, a
+   % \nobreak will be last on the list, and \sectionheading will have
+   % done a \vskip-\parskip.  In that case, we don't want to zero
+   % parskip, or the item text will crash with the heading.  On the
+   % other hand, when there is normal text preceding the item (as there
+   % usually is), we do want to zero parskip, or there would be too much
+   % space.  In that case, we won't have a \nobreak before.  At least
+   % that's the theory.
+   \ifnum\lastpenalty<10000 \parskip=0in \fi
+   \noindent
+   \hbox to 0pt{\hss \itemcontents \kern\itemmargin}%
+   %
+   \vadjust{\penalty 1200}}% not good to break after first line of item.
+  \flushcr
+}
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\envparseargdef\enumerate{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <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 resets \everytab so we don't have to
+% undo it ourselves.
+\def\headitemfont{\b}% for people to use in the template row; not changeable
+\def\headitem{%
+  \checkenv\multitable
+  \crcr
+  \global\everytab={\bf}% can't use \headitemfont since the parsing differs
+  \the\everytab % for the first item
+}%
+%
+% A \tab used to include \hskip1sp.  But then the space in a template
+% line is not enough.  That is bad.  So let's go back to just `&' until
+% we again encounter the problem the 1sp was intended to solve.
+%                                      --karl, nathan@acm.org, 20apr99.
+\def\tab{\checkenv\multitable &\the\everytab}%
+
+% @multitable ... @end multitable definitions:
+%
+\newtoks\everytab  % insert after every tab.
+%
+\envdef\multitable{%
+  \vskip\parskip
+  \startsavinginserts
+  %
+  % @item within a multitable starts a normal row.
+  % We use \def instead of \let so that if one of the multitable entries
+  % contains an @itemize, we don't choke on the \item (seen as \crcr aka
+  % \endtemplate) expanding \doitemize.
+  \def\item{\crcr}%
+  %
+  \tolerance=9500
+  \hbadness=9500
+  \setmultitablespacing
+  \parskip=\multitableparskip
+  \parindent=\multitableparindent
+  \overfullrule=0pt
+  \global\colcount=0
+  %
+  \everycr = {%
+    \noalign{%
+      \global\everytab={}%
+      \global\colcount=0 % Reset the column counter.
+      % Check for saved footnotes, etc.
+      \checkinserts
+      % Keeps underfull box messages off when table breaks over pages.
+      %\filbreak
+       % Maybe so, but it also creates really weird page breaks when the
+       % table breaks over pages. Wouldn't \vfil be better?  Wait until the
+       % problem manifests itself, so it can be fixed for real --karl.
+    }%
+  }%
+  %
+  \parsearg\domultitable
+}
+\def\domultitable#1{%
+  % To parse everything between @multitable and @item:
+  \setuptable#1 \endsetuptable
+  %
+  % This preamble sets up a generic column definition, which will
+  % be used as many times as user calls for columns.
+  % \vtop will set a single line and will also let text wrap and
+  % continue for many paragraphs if desired.
+  \halign\bgroup &%
+    \global\advance\colcount by 1
+    \multistrut
+    \vtop{%
+      % Use the current \colcount to find the correct column width:
+      \hsize=\expandafter\csname col\the\colcount\endcsname
+      %
+      % In order to keep entries from bumping into each other
+      % we will add a \leftskip of \multitablecolspace to all columns after
+      % the first one.
+      %
+      % If a template has been used, we will add \multitablecolspace
+      % to the width of each template entry.
+      %
+      % If the user has set preamble in terms of percent of \hsize we will
+      % use that dimension as the width of the column, and the \leftskip
+      % will keep entries from bumping into each other.  Table will start at
+      % left margin and final column will justify at right margin.
+      %
+      % Make sure we don't inherit \rightskip from the outer environment.
+      \rightskip=0pt
+      \ifnum\colcount=1
+       % The first column will be indented with the surrounding text.
+       \advance\hsize by\leftskip
+      \else
+       \ifsetpercent \else
+         % If user has not set preamble in terms of percent of \hsize
+         % we will advance \hsize by \multitablecolspace.
+         \advance\hsize by \multitablecolspace
+       \fi
+       % In either case we will make \leftskip=\multitablecolspace:
+      \leftskip=\multitablecolspace
+      \fi
+      % Ignoring space at the beginning and end avoids an occasional spurious
+      % blank line, when TeX decides to break the line at the space before the
+      % box from the multistrut, so the strut ends up on a line by itself.
+      % For example:
+      % @multitable @columnfractions .11 .89
+      % @item @code{#}
+      % @tab Legal holiday which is valid in major parts of the whole country.
+      % Is automatically provided with highlighting sequences respectively
+      % marking characters.
+      \noindent\ignorespaces##\unskip\multistrut
+    }\cr
+}
+\def\Emultitable{%
+  \crcr
+  \egroup % end the \halign
+  \global\setpercentfalse
+}
+
+\def\setmultitablespacing{%
+  \def\multistrut{\strut}% just use the standard line spacing
+  %
+  % Compute \multitablelinespace (if not defined by user) for use in
+  % \multitableparskip calculation.  We used define \multistrut based on
+  % this, but (ironically) that caused the spacing to be off.
+  % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
+\ifdim\multitablelinespace=0pt
+\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
+\global\advance\multitablelinespace by-\ht0
+\fi
+%% Test to see if parskip is larger than space between lines of
+%% table. If not, do nothing.
+%%        If so, set to same dimension as multitablelinespace.
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+                                      %% than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller
+                                      %% than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @ifnotxml always succeed.  They currently do nothing; we don't
+% attempt to check whether the conditionals are properly nested.  But we
+% have to remember that they are conditionals, so that @end doesn't
+% attempt to close an environment group.
+%
+\def\makecond#1{%
+  \expandafter\let\csname #1\endcsname = \relax
+  \expandafter\let\csname iscond.#1\endcsname = 1
+}
+\makecond{iftex}
+\makecond{ifnotdocbook}
+\makecond{ifnothtml}
+\makecond{ifnotinfo}
+\makecond{ifnotplaintext}
+\makecond{ifnotxml}
+
+% Ignore @ignore, @ifhtml, @ifinfo, and the like.
+%
+\def\direntry{\doignore{direntry}}
+\def\documentdescription{\doignore{documentdescription}}
+\def\docbook{\doignore{docbook}}
+\def\html{\doignore{html}}
+\def\ifdocbook{\doignore{ifdocbook}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\ifplaintext{\doignore{ifplaintext}}
+\def\ifxml{\doignore{ifxml}}
+\def\ignore{\doignore{ignore}}
+\def\menu{\doignore{menu}}
+\def\xml{\doignore{xml}}
+
+% Ignore text until a line `@end #1', keeping track of nested conditionals.
+%
+% A count to remember the depth of nesting.
+\newcount\doignorecount
+
+\def\doignore#1{\begingroup
+  % Scan in ``verbatim'' mode:
+  \obeylines
+  \catcode`\@ = \other
+  \catcode`\{ = \other
+  \catcode`\} = \other
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \spaceisspace
+  %
+  % Count number of #1's that we've seen.
+  \doignorecount = 0
+  %
+  % Swallow text until we reach the matching `@end #1'.
+  \dodoignore{#1}%
+}
+
+{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source.
+  \obeylines %
+  %
+  \gdef\dodoignore#1{%
+    % #1 contains the command name as a string, e.g., `ifinfo'.
+    %
+    % Define a command to find the next `@end #1'.
+    \long\def\doignoretext##1^^M@end #1{%
+      \doignoretextyyy##1^^M@#1\_STOP_}%
+    %
+    % And this command to find another #1 command, at the beginning of a
+    % line.  (Otherwise, we would consider a line `@c @ifset', for
+    % example, to count as an @ifset for nesting.)
+    \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}%
+    %
+    % And now expand that command.
+    \doignoretext ^^M%
+  }%
+}
+
+\def\doignoreyyy#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty                      % Nothing found.
+    \let\next\doignoretextzzz
+  \else                                        % Found a nested condition, ...
+    \advance\doignorecount by 1
+    \let\next\doignoretextyyy          % ..., look for another.
+    % If we're here, #1 ends with ^^M\ifinfo (for example).
+  \fi
+  \next #1% the token \_STOP_ is present just after this macro.
+}
+
+% We have to swallow the remaining "\_STOP_".
+%
+\def\doignoretextzzz#1{%
+  \ifnum\doignorecount = 0     % We have just found the outermost @end.
+    \let\next\enddoignore
+  \else                                % Still inside a nested condition.
+    \advance\doignorecount by -1
+    \let\next\doignoretext      % Look for the next @end.
+  \fi
+  \next
+}
+
+% Finish off ignored text.
+{ \obeylines%
+  % Ignore anything after the last `@end #1'; this matters in verbatim
+  % environments, where otherwise the newline after an ignored conditional
+  % would result in a blank line in the output.
+  \gdef\enddoignore#1^^M{\endgroup\ignorespaces}%
+}
+
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+% We rely on the fact that \parsearg sets \catcode`\ =10.
+%
+\parseargdef\set{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  {%
+    \makevalueexpandable
+    \def\temp{#2}%
+    \edef\next{\gdef\makecsname{SET#1}}%
+    \ifx\temp\empty
+      \next{}%
+    \else
+      \setzzz#2\endsetzzz
+    \fi
+  }%
+}
+% Remove the trailing space \setxxx inserted.
+\def\setzzz#1 \endsetzzz{\next{#1}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\parseargdef\clear{%
+  {%
+    \makevalueexpandable
+    \global\expandafter\let\csname SET#1\endcsname=\relax
+  }%
+}
+
+% @value{foo} gets the text saved in variable foo.
+\def\value{\begingroup\makevalueexpandable\valuexxx}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+{
+  \catcode`\- = \active \catcode`\_ = \active
+  %
+  \gdef\makevalueexpandable{%
+    \let\value = \expandablevalue
+    % We don't want these characters active, ...
+    \catcode`\-=\other \catcode`\_=\other
+    % ..., but we might end up with active ones in the argument if
+    % we're called from @code, as @code{@value{foo-bar_}}, though.
+    % So \let them to their normal equivalents.
+    \let-\realdash \let_\normalunderscore
+  }
+}
+
+% We have this subroutine so that we can handle at least some @value's
+% properly in indexes (we call \makevalueexpandable in \indexdummies).
+% The command has to be fully expandable (if the variable is set), since
+% the result winds up in the index file.  This means that if the
+% variable's value contains other Texinfo commands, it's almost certain
+% it will fail (although perhaps we could fix that with sufficient work
+% to do a one-level expansion on the result, instead of complete).
+%
+\def\expandablevalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    {[No value for ``#1'']}%
+    \message{Variable `#1', used in @value, is not set.}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get special treatment of `@end ifset,' call \makeond and the redefine.
+%
+\makecond{ifset}
+\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}}
+\def\doifset#1#2{%
+  {%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname SET#2\endcsname\relax
+      #1% If not set, redefine \next.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifsetfail{\doignore{ifset}}
+
+% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @dircategory CATEGORY  -- specify a category of the dir file
+% which this file should belong to.  Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named foo.
+% It automatically defines \fooindex such that
+% \fooindex ...rest of line... puts an entry in the index foo.
+% It also defines \fooindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is foo.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1 % Open the file
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%     % Define @#1index
+    \noexpand\doindex{#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+%
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+%
+\def\defcodeindex{\parsearg\newcodeindex}
+%
+\def\newcodeindex#1{%
+  \iflinks
+    \expandafter\newwrite \csname#1indfile\endcsname
+    \openout \csname#1indfile\endcsname \jobname.#1
+  \fi
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}%
+}
+
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+%
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+%
+\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}}
+\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}}
+
+% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
+% #3 the target index (bar).
+\def\dosynindex#1#2#3{%
+  % Only do \closeout if we haven't already done it, else we'll end up
+  % closing the target index.
+  \expandafter \ifx\csname donesynindex#2\endcsname \relax
+    % The \closeout helps reduce unnecessary open files; the limit on the
+    % Acorn RISC OS is a mere 16 files.
+    \expandafter\closeout\csname#2indfile\endcsname
+    \expandafter\let\csname donesynindex#2\endcsname = 1
+  \fi
+  % redefine \fooindfile:
+  \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
+  \expandafter\let\csname#2indfile\endcsname=\temp
+  % redefine \fooindex:
+  \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}%
+}
+
+% Define \doindex, the driver for all \fooindex macros.
+% Argument #1 is generated by the calling \fooindex macro,
+%  and it is "foo", the name of the index.
+
+% \doindex just uses \parsearg; it calls \doind for the actual work.
+% This is because \doind is more useful to call from other macros.
+
+% There is also \dosubind {index}{topic}{subtopic}
+% which makes an entry in a two-level index such as the operation index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer}
+\def\singleindexer #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer}
+\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}}
+
+% Take care of Texinfo commands that can appear in an index entry.
+% Since there are some commands we want to expand, and others we don't,
+% we have to laboriously prevent expansion for those that we don't.
+%
+\def\indexdummies{%
+  \escapechar = `\\     % use backslash in output files.
+  \def\@{@}% change to @@ when we switch to @ as escape char in index files.
+  \def\ {\realbackslash\space }%
+  %
+  % Need these in case \tex is in effect and \{ is a \delimiter again.
+  % But can't use \lbracecmd and \rbracecmd because texindex assumes
+  % braces and backslashes are used only as delimiters.
+  \let\{ = \mylbrace
+  \let\} = \myrbrace
+  %
+  % I don't entirely understand this, but when an index entry is
+  % generated from a macro call, the \endinput which \scanmacro inserts
+  % causes processing to be prematurely terminated.  This is,
+  % apparently, because \indexsorttmp is fully expanded, and \endinput
+  % is an expandable command.  The redefinition below makes \endinput
+  % disappear altogether for that purpose -- although logging shows that
+  % processing continues to some further point.  On the other hand, it
+  % seems \endinput does not hurt in the printed index arg, since that
+  % is still getting written without apparent harm.
+  %
+  % Sample source (mac-idx3.tex, reported by Graham Percival to
+  % help-texinfo, 22may06):
+  % @macro funindex {WORD}
+  % @findex xyz
+  % @end macro
+  % ...
+  % @funindex commtest
+  %
+  % The above is not enough to reproduce the bug, but it gives the flavor.
+  %
+  % Sample whatsit resulting:
+  % .@write3{\entry{xyz}{@folio }{@code {xyz@endinput }}}
+  %
+  % So:
+  \let\endinput = \empty
+  %
+  % Do the redefinitions.
+  \commondummies
+}
+
+% For the aux and toc files, @ is the escape character.  So we want to
+% redefine everything using @ as the escape character (instead of
+% \realbackslash, still used for index files).  When everything uses @,
+% this will be simpler.
+%
+\def\atdummies{%
+  \def\@{@@}%
+  \def\ {@ }%
+  \let\{ = \lbraceatcmd
+  \let\} = \rbraceatcmd
+  %
+  % Do the redefinitions.
+  \commondummies
+  \otherbackslash
+}
+
+% Called from \indexdummies and \atdummies.
+%
+\def\commondummies{%
+  %
+  % \definedummyword defines \#1 as \string\#1\space, thus effectively
+  % preventing its expansion.  This is used only for control% words,
+  % not control letters, because the \space would be incorrect for
+  % control characters, but is needed to separate the control word
+  % from whatever follows.
+  %
+  % For control letters, we have \definedummyletter, which omits the
+  % space.
+  %
+  % These can be used both for control words that take an argument and
+  % those that do not.  If it is followed by {arg} in the input, then
+  % that will dutifully get written to the index (or wherever).
+  %
+  \def\definedummyword  ##1{\def##1{\string##1\space}}%
+  \def\definedummyletter##1{\def##1{\string##1}}%
+  \let\definedummyaccent\definedummyletter
+  %
+  \commondummiesnofonts
+  %
+  \definedummyletter\_%
+  %
+  % Non-English letters.
+  \definedummyword\AA
+  \definedummyword\AE
+  \definedummyword\DH
+  \definedummyword\L
+  \definedummyword\O
+  \definedummyword\OE
+  \definedummyword\TH
+  \definedummyword\aa
+  \definedummyword\ae
+  \definedummyword\dh
+  \definedummyword\exclamdown
+  \definedummyword\l
+  \definedummyword\o
+  \definedummyword\oe
+  \definedummyword\ordf
+  \definedummyword\ordm
+  \definedummyword\questiondown
+  \definedummyword\ss
+  \definedummyword\th
+  %
+  % Although these internal commands shouldn't show up, sometimes they do.
+  \definedummyword\bf
+  \definedummyword\gtr
+  \definedummyword\hat
+  \definedummyword\less
+  \definedummyword\sf
+  \definedummyword\sl
+  \definedummyword\tclose
+  \definedummyword\tt
+  %
+  \definedummyword\LaTeX
+  \definedummyword\TeX
+  %
+  % Assorted special characters.
+  \definedummyword\bullet
+  \definedummyword\comma
+  \definedummyword\copyright
+  \definedummyword\registeredsymbol
+  \definedummyword\dots
+  \definedummyword\enddots
+  \definedummyword\equiv
+  \definedummyword\error
+  \definedummyword\euro
+  \definedummyword\guillemetleft
+  \definedummyword\guillemetright
+  \definedummyword\guilsinglleft
+  \definedummyword\guilsinglright
+  \definedummyword\expansion
+  \definedummyword\minus
+  \definedummyword\ogonek
+  \definedummyword\pounds
+  \definedummyword\point
+  \definedummyword\print
+  \definedummyword\quotedblbase
+  \definedummyword\quotedblleft
+  \definedummyword\quotedblright
+  \definedummyword\quoteleft
+  \definedummyword\quoteright
+  \definedummyword\quotesinglbase
+  \definedummyword\result
+  \definedummyword\textdegree
+  %
+  % We want to disable all macros so that they are not expanded by \write.
+  \macrolist
+  %
+  \normalturnoffactive
+  %
+  % Handle some cases of @value -- where it does not contain any
+  % (non-fully-expandable) commands.
+  \makevalueexpandable
+}
+
+% \commondummiesnofonts: common to \commondummies and \indexnofonts.
+%
+\def\commondummiesnofonts{%
+  % Control letters and accents.
+  \definedummyletter\!%
+  \definedummyaccent\"%
+  \definedummyaccent\'%
+  \definedummyletter\*%
+  \definedummyaccent\,%
+  \definedummyletter\.%
+  \definedummyletter\/%
+  \definedummyletter\:%
+  \definedummyaccent\=%
+  \definedummyletter\?%
+  \definedummyaccent\^%
+  \definedummyaccent\`%
+  \definedummyaccent\~%
+  \definedummyword\u
+  \definedummyword\v
+  \definedummyword\H
+  \definedummyword\dotaccent
+  \definedummyword\ogonek
+  \definedummyword\ringaccent
+  \definedummyword\tieaccent
+  \definedummyword\ubaraccent
+  \definedummyword\udotaccent
+  \definedummyword\dotless
+  %
+  % Texinfo font commands.
+  \definedummyword\b
+  \definedummyword\i
+  \definedummyword\r
+  \definedummyword\sc
+  \definedummyword\t
+  %
+  % Commands that take arguments.
+  \definedummyword\acronym
+  \definedummyword\cite
+  \definedummyword\code
+  \definedummyword\command
+  \definedummyword\dfn
+  \definedummyword\email
+  \definedummyword\emph
+  \definedummyword\env
+  \definedummyword\file
+  \definedummyword\kbd
+  \definedummyword\key
+  \definedummyword\math
+  \definedummyword\option
+  \definedummyword\pxref
+  \definedummyword\ref
+  \definedummyword\samp
+  \definedummyword\strong
+  \definedummyword\tie
+  \definedummyword\uref
+  \definedummyword\url
+  \definedummyword\var
+  \definedummyword\verb
+  \definedummyword\w
+  \definedummyword\xref
+}
+
+% \indexnofonts is used when outputting the strings to sort the index
+% by, and when constructing control sequence names.  It eliminates all
+% control sequences and just writes whatever the best ASCII sort string
+% would be for a given command (usually its argument).
+%
+\def\indexnofonts{%
+  % Accent commands should become @asis.
+  \def\definedummyaccent##1{\let##1\asis}%
+  % We can just ignore other control letters.
+  \def\definedummyletter##1{\let##1\empty}%
+  % Hopefully, all control words can become @asis.
+  \let\definedummyword\definedummyaccent
+  %
+  \commondummiesnofonts
+  %
+  % Don't no-op \tt, since it isn't a user-level command
+  % and is used in the definitions of the active chars like <, >, |, etc.
+  % Likewise with the other plain tex font commands.
+  %\let\tt=\asis
+  %
+  \def\ { }%
+  \def\@{@}%
+  % how to handle braces?
+  \def\_{\normalunderscore}%
+  %
+  % Non-English letters.
+  \def\AA{AA}%
+  \def\AE{AE}%
+  \def\DH{DZZ}%
+  \def\L{L}%
+  \def\OE{OE}%
+  \def\O{O}%
+  \def\TH{ZZZ}%
+  \def\aa{aa}%
+  \def\ae{ae}%
+  \def\dh{dzz}%
+  \def\exclamdown{!}%
+  \def\l{l}%
+  \def\oe{oe}%
+  \def\ordf{a}%
+  \def\ordm{o}%
+  \def\o{o}%
+  \def\questiondown{?}%
+  \def\ss{ss}%
+  \def\th{zzz}%
+  %
+  \def\LaTeX{LaTeX}%
+  \def\TeX{TeX}%
+  %
+  % Assorted special characters.
+  % (The following {} will end up in the sort string, but that's ok.)
+  \def\bullet{bullet}%
+  \def\comma{,}%
+  \def\copyright{copyright}%
+  \def\dots{...}%
+  \def\enddots{...}%
+  \def\equiv{==}%
+  \def\error{error}%
+  \def\euro{euro}%
+  \def\expansion{==>}%
+  \def\guillemetleft{<<}%
+  \def\guillemetright{>>}%
+  \def\guilsinglleft{<}%
+  \def\guilsinglright{>}%
+  \def\minus{-}%
+  \def\point{.}%
+  \def\pounds{pounds}%
+  \def\print{-|}%
+  \def\quotedblbase{"}%
+  \def\quotedblleft{"}%
+  \def\quotedblright{"}%
+  \def\quoteleft{`}%
+  \def\quoteright{'}%
+  \def\quotesinglbase{,}%
+  \def\registeredsymbol{R}%
+  \def\result{=>}%
+  \def\textdegree{o}%
+  %
+  % We need to get rid of all macros, leaving only the arguments (if present).
+  % Of course this is not nearly correct, but it is the best we can do for now.
+  % makeinfo does not expand macros in the argument to @deffn, which ends up
+  % writing an index entry, and texindex isn't prepared for an index sort entry
+  % that starts with \.
+  %
+  % Since macro invocations are followed by braces, we can just redefine them
+  % to take a single TeX argument.  The case of a macro invocation that
+  % goes to end-of-line is not handled.
+  %
+  \macrolist
+}
+
+\let\indexbackslash=0  %overridden during \printindex.
+\let\SETmarginindex=\relax % put index entries in margin (undocumented)?
+
+% Most index entries go through here, but \dosubind is the general case.
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{\dosubind{#1}{#2}{}}
+
+% Workhorse for all \fooindexes.
+% #1 is name of index, #2 is stuff to put there, #3 is subentry --
+% empty if called from \doind, as we usually are (the main exception
+% is with most defuns, which call us directly).
+%
+\def\dosubind#1#2#3{%
+  \iflinks
+  {%
+    % Store the main index entry text (including the third arg).
+    \toks0 = {#2}%
+    % If third arg is present, precede it with a space.
+    \def\thirdarg{#3}%
+    \ifx\thirdarg\empty \else
+      \toks0 = \expandafter{\the\toks0 \space #3}%
+    \fi
+    %
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \safewhatsit\dosubindwrite
+  }%
+  \fi
+}
+
+% Write the entry in \toks0 to the index file:
+%
+\def\dosubindwrite{%
+  % Put the index entry in the margin if desired.
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \the\toks0}}%
+  \fi
+  %
+  % Remember, we are within a group.
+  \indexdummies % Must do this here, since \bf, etc expand at this stage
+  \def\backslashcurfont{\indexbackslash}% \indexbackslash isn't defined now
+      % so it will be output as is; and it will print as backslash.
+  %
+  % Process the index entry with all font commands turned off, to
+  % get the string to sort by.
+  {\indexnofonts
+   \edef\temp{\the\toks0}% need full expansion
+   \xdef\indexsorttmp{\temp}%
+  }%
+  %
+  % Set up the complete index entry, with both the sort key and
+  % the original text, including any font commands.  We write
+  % three arguments to \entry to the .?? file (four in the
+  % subentry case), texindex reduces to two when writing the .??s
+  % sorted result.
+  \edef\temp{%
+    \write\writeto{%
+      \string\entry{\indexsorttmp}{\noexpand\folio}{\the\toks0}}%
+  }%
+  \temp
+}
+
+% Take care of unwanted page breaks/skips around a whatsit:
+%
+% If a skip is the last thing on the list now, preserve it
+% by backing up by \lastskip, doing the \write, then inserting
+% the skip again.  Otherwise, the whatsit generated by the
+% \write or \pdfdest will make \lastskip zero.  The result is that
+% sequences like this:
+% @end defun
+% @tindex whatever
+% @defun ...
+% will have extra space inserted, because the \medbreak in the
+% start of the @defun won't see the skip inserted by the @end of
+% the previous defun.
+%
+% But don't do any of this if we're not in vertical mode.  We
+% don't want to do a \vskip and prematurely end a paragraph.
+%
+% Avoid page breaks due to these extra skips, too.
+%
+% But wait, there is a catch there:
+% We'll have to check whether \lastskip is zero skip.  \ifdim is not
+% sufficient for this purpose, as it ignores stretch and shrink parts
+% of the skip.  The only way seems to be to check the textual
+% representation of the skip.
+%
+% The following is almost like \def\zeroskipmacro{0.0pt} except that
+% the ``p'' and ``t'' characters have catcode \other, not 11 (letter).
+%
+\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname}
+%
+\newskip\whatsitskip
+\newcount\whatsitpenalty
+%
+% ..., ready, GO:
+%
+\def\safewhatsit#1{%
+\ifhmode
+  #1%
+\else
+  % \lastskip and \lastpenalty cannot both be nonzero simultaneously.
+  \whatsitskip = \lastskip
+  \edef\lastskipmacro{\the\lastskip}%
+  \whatsitpenalty = \lastpenalty
+  %
+  % If \lastskip is nonzero, that means the last item was a
+  % skip.  And since a skip is discardable, that means this
+  % -\whatsitskip glue we're inserting is preceded by a
+  % non-discardable item, therefore it is not a potential
+  % breakpoint, therefore no \nobreak needed.
+  \ifx\lastskipmacro\zeroskipmacro
+  \else
+    \vskip-\whatsitskip
+  \fi
+  %
+  #1%
+  %
+  \ifx\lastskipmacro\zeroskipmacro
+    % If \lastskip was zero, perhaps the last item was a penalty, and
+    % perhaps it was >=10000, e.g., a \nobreak.  In that case, we want
+    % to re-insert the same penalty (values >10000 are used for various
+    % signals); since we just inserted a non-discardable item, any
+    % following glue (such as a \parskip) would be a breakpoint.  For example:
+    %
+    %   @deffn deffn-whatever
+    %   @vindex index-whatever
+    %   Description.
+    % would allow a break between the index-whatever whatsit
+    % and the "Description." paragraph.
+    \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi
+  \else
+    % On the other hand, if we had a nonzero \lastskip,
+    % this make-up glue would be preceded by a non-discardable item
+    % (the whatsit from the \write), so we must insert a \nobreak.
+    \nobreak\vskip\whatsitskip
+  \fi
+\fi
+}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+\def\cindexsub {\begingroup\obeylines\cindexsub}
+{\obeylines %
+\gdef\cindexsub "#1" #2^^M{\endgroup %
+\dosubind{cp}{#2}{#1}}}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\parseargdef\printindex{\begingroup
+  \dobreak \chapheadingskip{10000}%
+  %
+  \smallfonts \rm
+  \tolerance = 9500
+  \plainfrenchspacing
+  \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+  %
+  % See if the index file exists and is nonempty.
+  % Change catcode of @ here so that if the index file contains
+  % \initial {@}
+  % as its first line, TeX doesn't complain about mismatched braces
+  % (because it thinks @} is a control sequence).
+  \catcode`\@ = 11
+  \openin 1 \jobname.#1s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    \putwordIndexNonexistent
+  \else
+    %
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \temp
+    \ifeof 1
+      \putwordIndexIsEmpty
+    \else
+      % Index files are almost Texinfo source, but we use \ as the escape
+      % character.  It would be better to use @, but that's too big a change
+      % to make right now.
+      \def\indexbackslash{\backslashcurfont}%
+      \catcode`\\ = 0
+      \escapechar = `\\
+      \begindoublecolumns
+      \input \jobname.#1s
+      \enddoublecolumns
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+\def\initial#1{{%
+  % Some minor font changes for the special characters.
+  \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt
+  %
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  %
+  % We like breaks before the index initials, so insert a bonus.
+  \nobreak
+  \vskip 0pt plus 3\baselineskip
+  \penalty 0
+  \vskip 0pt plus -3\baselineskip
+  %
+  % Typeset the initial.  Making this add up to a whole number of
+  % baselineskips increases the chance of the dots lining up from column
+  % to column.  It still won't often be perfect, because of the stretch
+  % we need before each entry, but it's better.
+  %
+  % No shrink because it confuses \balancecolumns.
+  \vskip 1.67\baselineskip plus .5\baselineskip
+  \leftline{\secbf #1}%
+  % Do our best not to break after the initial.
+  \nobreak
+  \vskip .33\baselineskip plus .1\baselineskip
+}}
+
+% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
+% then page number (#2) flushed to the right margin.  It is used for index
+% and table of contents entries.  The paragraph is indented by \leftskip.
+%
+% A straightforward implementation would start like this:
+%      \def\entry#1#2{...
+% But this freezes the catcodes in the argument, and can cause problems to
+% @code, which sets - active.  This problem was fixed by a kludge---
+% ``-'' was active throughout whole index, but this isn't really right.
+%
+% The right solution is to prevent \entry from swallowing the whole text.
+%                                 --kasal, 21nov03
+\def\entry{%
+  \begingroup
+    %
+    % Start a new paragraph if necessary, so our assignments below can't
+    % affect previous text.
+    \par
+    %
+    % Do not fill out the last line with white space.
+    \parfillskip = 0in
+    %
+    % No extra space above this paragraph.
+    \parskip = 0in
+    %
+    % Do not prefer a separate line ending with a hyphen to fewer lines.
+    \finalhyphendemerits = 0
+    %
+    % \hangindent is only relevant when the entry text and page number
+    % don't both fit on one line.  In that case, bob suggests starting the
+    % dots pretty far over on the line.  Unfortunately, a large
+    % indentation looks wrong when the entry text itself is broken across
+    % lines.  So we use a small indentation and put up with long leaders.
+    %
+    % \hangafter is reset to 1 (which is the value we want) at the start
+    % of each paragraph, so we need not do anything with that.
+    \hangindent = 2em
+    %
+    % When the entry text needs to be broken, just fill out the first line
+    % with blank space.
+    \rightskip = 0pt plus1fil
+    %
+    % A bit of stretch before each entry for the benefit of balancing
+    % columns.
+    \vskip 0pt plus1pt
+    %
+    % Swallow the left brace of the text (first parameter):
+    \afterassignment\doentry
+    \let\temp =
+}
+\def\doentry{%
+    \bgroup % Instead of the swallowed brace.
+      \noindent
+      \aftergroup\finishentry
+      % And now comes the text of the entry.
+}
+\def\finishentry#1{%
+    % #1 is the page number.
+    %
+    % The following is kludged to not output a line of dots in the index if
+    % there are no page numbers.  The next person who breaks this will be
+    % cursed by a Unix daemon.
+    \setbox\boxA = \hbox{#1}%
+    \ifdim\wd\boxA = 0pt
+      \ %
+    \else
+      %
+      % If we must, put the page number on a line of its own, and fill out
+      % this line with blank space.  (The \hfil is overwhelmed with the
+      % fill leaders glue in \indexdotfill if the page number does fit.)
+      \hfil\penalty50
+      \null\nobreak\indexdotfill % Have leaders before the page number.
+      %
+      % The `\ ' here is removed by the implicit \unskip that TeX does as
+      % part of (the primitive) \par.  Without it, a spurious underfull
+      % \hbox ensues.
+      \ifpdf
+       \pdfgettoks#1.%
+       \ \the\toksA
+      \else
+       \ #1%
+      \fi
+    \fi
+    \par
+  \endgroup
+}
+
+% Like plain.tex's \dotfill, except uses up at least 1 em.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1fill}
+
+\def\primary #1{\line{#1\hfil}}
+
+\newskip\secondaryindent \secondaryindent=0.5cm
+\def\secondary#1#2{{%
+  \parfillskip=0in
+  \parskip=0in
+  \hangindent=1in
+  \hangafter=1
+  \noindent\hskip\secondaryindent\hbox{#1}\indexdotfill
+  \ifpdf
+    \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph.
+  \else
+    #2
+  \fi
+  \par
+}}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % Grab any single-column material above us.
+  \output = {%
+    %
+    % Here is a possibility not foreseen in manmac: if we accumulate a
+    % whole lot of material, we might end up calling this \output
+    % routine twice in a row (see the doublecol-lose test, which is
+    % essentially a couple of indexes with @setchapternewpage off).  In
+    % that case we just ship out what is in \partialpage with the normal
+    % output routine.  Generally, \partialpage will be empty when this
+    % runs and this will be a no-op.  See the indexspread.tex test case.
+    \ifvoid\partialpage \else
+      \onepageout{\pagecontents\partialpage}%
+    \fi
+    %
+    \global\setbox\partialpage = \vbox{%
+      % Unvbox the main output page.
+      \unvbox\PAGE
+      \kern-\topskip \kern\baselineskip
+    }%
+  }%
+  \eject % run that output routine to set \partialpage
+  %
+  % Use the double-column output routine for subsequent pages.
+  \output = {\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it in one place.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +-<1pt)
+  % as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Double the \vsize as well.  (We don't need a separate register here,
+  % since nobody clobbers \vsize.)
+  \vsize = 2\vsize
+}
+
+% The double-column output routine for all double-column pages except
+% the last.
+%
+\def\doublecolumnout{%
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  \advance\dimen@ by -\ht\partialpage
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@
+  \onepageout\pagesofar
+  \unvbox255
+  \penalty\outputpenalty
+}
+%
+% Re-output the contents of the output page -- any previous material,
+% followed by the two boxes we just split, in box0 and box2.
+\def\pagesofar{%
+  \unvbox\partialpage
+  %
+  \hsize = \doublecolumnhsize
+  \wd0=\hsize \wd2=\hsize
+  \hbox to\pagewidth{\box0\hfil\box2}%
+}
+%
+% All done with double columns.
+\def\enddoublecolumns{%
+  % The following penalty ensures that the page builder is exercised
+  % _before_ we change the output routine.  This is necessary in the
+  % following situation:
+  %
+  % The last section of the index consists only of a single entry.
+  % Before this section, \pagetotal is less than \pagegoal, so no
+  % break occurs before the last section starts.  However, the last
+  % section, consisting of \initial and the single \entry, does not
+  % fit on the page and has to be broken off.  Without the following
+  % penalty the page builder will not be exercised until \eject
+  % below, and by that time we'll already have changed the output
+  % routine to the \balancecolumns version, so the next-to-last
+  % double-column page will be processed with \balancecolumns, which
+  % is wrong:  The two columns will go to the main vertical list, with
+  % the broken-off section in the recent contributions.  As soon as
+  % the output routine finishes, TeX starts reconsidering the page
+  % break.  The two columns and the broken-off section both fit on the
+  % page, because the two columns now take up only half of the page
+  % goal.  When TeX sees \eject from below which follows the final
+  % section, it invokes the new output routine that we've set after
+  % \balancecolumns below; \onepageout will try to fit the two columns
+  % and the final section into the vbox of \pageheight (see
+  % \pagebody), causing an overfull box.
+  %
+  % Note that glue won't work here, because glue does not exercise the
+  % page builder, unlike penalties (see The TeXbook, pp. 280-281).
+  \penalty0
+  %
+  \output = {%
+    % Split the last of the double-column material.  Leave it on the
+    % current page, no automatic page break.
+    \balancecolumns
+    %
+    % If we end up splitting too much material for the current page,
+    % though, there will be another page break right after this \output
+    % invocation ends.  Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.  (We hope \balancecolumns will never be
+    % called on to balance too much material, but if it is, this makes
+    % the output somewhat more palatable.)
+    \global\output = {\onepageout{\pagecontents\PAGE}}%
+  }%
+  \eject
+  \endgroup % started in \begindoublecolumns
+  %
+  % \pagegoal was set to the doubled \vsize above, since we restarted
+  % the current page.  We're now back to normal single-column
+  % typesetting, so reset \pagegoal to the normal \vsize (after the
+  % \endgroup where \vsize got restored).
+  \pagegoal = \vsize
+}
+%
+% Called at the end of the double column material.
+\def\balancecolumns{%
+  \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \advance\dimen@ by \topskip
+  \advance\dimen@ by-\baselineskip
+  \divide\dimen@ by 2 % target to split to
+  %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}%
+  \splittopskip = \topskip
+  % Loop until we get a decent breakpoint.
+  {%
+    \vbadness = 10000
+    \loop
+      \global\setbox3 = \copy0
+      \global\setbox1 = \vsplit3 to \dimen@
+    \ifdim\ht3>\dimen@
+      \global\advance\dimen@ by 1pt
+    \repeat
+  }%
+  %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}%
+  \setbox0=\vbox to\dimen@{\unvbox1}%
+  \setbox2=\vbox to\dimen@{\unvbox3}%
+  %
+  \pagesofar
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% \unnumberedno is an oxymoron, of course.  But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number".  We avoid collisions with chapter
+% numbers by starting them at 10000.  (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno        \secno=0
+\newcount\subsecno     \subsecno=0
+\newcount\subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno  \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+  \ifnum\appendixno=`A A%
+  \else\ifnum\appendixno=`B B%
+  \else\ifnum\appendixno=`C C%
+  \else\ifnum\appendixno=`D D%
+  \else\ifnum\appendixno=`E E%
+  \else\ifnum\appendixno=`F F%
+  \else\ifnum\appendixno=`G G%
+  \else\ifnum\appendixno=`H H%
+  \else\ifnum\appendixno=`I I%
+  \else\ifnum\appendixno=`J J%
+  \else\ifnum\appendixno=`K K%
+  \else\ifnum\appendixno=`L L%
+  \else\ifnum\appendixno=`M M%
+  \else\ifnum\appendixno=`N N%
+  \else\ifnum\appendixno=`O O%
+  \else\ifnum\appendixno=`P P%
+  \else\ifnum\appendixno=`Q Q%
+  \else\ifnum\appendixno=`R R%
+  \else\ifnum\appendixno=`S S%
+  \else\ifnum\appendixno=`T T%
+  \else\ifnum\appendixno=`U U%
+  \else\ifnum\appendixno=`V V%
+  \else\ifnum\appendixno=`W W%
+  \else\ifnum\appendixno=`X X%
+  \else\ifnum\appendixno=`Y Y%
+  \else\ifnum\appendixno=`Z Z%
+  % The \the is necessary, despite appearances, because \appendixletter is
+  % expanded while writing the .toc file.  \char\appendixno is not
+  % expandable, thus it is written literally, thus all appendixes come out
+  % with the same letter (or @) in the toc without it.
+  \else\char\the\appendixno
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines these (using marks) as the number+name, number
+% and name of the chapter.  Page headings and footings can use
+% these.  @section does likewise.
+\def\thischapter{}
+\def\thischapternum{}
+\def\thischaptername{}
+\def\thissection{}
+\def\thissectionnum{}
+\def\thissectionname{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\let\up=\raisesections % original BFox name
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+\let\down=\lowersections % original BFox name
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achive this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unmlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+  % Compute the abs. sec. level:
+  \absseclevel=#2
+  \advance\absseclevel by \secbase
+  % Make sure \absseclevel doesn't fall outside the range:
+  \ifnum \absseclevel < 0
+    \absseclevel = 0
+  \else
+    \ifnum \absseclevel > 3
+      \absseclevel = 3
+    \fi
+  \fi
+  % The heading type:
+  \def\headtype{#1}%
+  \if \headtype U%
+    \ifnum \absseclevel < \unmlevel
+      \chardef\unmlevel = \absseclevel
+    \fi
+  \else
+    % Check for appendix sections:
+    \ifnum \absseclevel = 0
+      \edef\chapheadtype{\headtype}%
+    \else
+      \if \headtype A\if \chapheadtype N%
+       \errmessage{@appendix... within a non-appendix chapter}%
+      \fi\fi
+    \fi
+    % Check for numbered within unnumbered:
+    \ifnum \absseclevel > \unmlevel
+      \def\headtype{U}%
+    \else
+      \chardef\unmlevel = 3
+    \fi
+  \fi
+  % Now print the heading:
+  \if \headtype U%
+    \ifcase\absseclevel
+       \unnumberedzzz{#3}%
+    \or \unnumberedseczzz{#3}%
+    \or \unnumberedsubseczzz{#3}%
+    \or \unnumberedsubsubseczzz{#3}%
+    \fi
+  \else
+    \if \headtype A%
+      \ifcase\absseclevel
+         \appendixzzz{#3}%
+      \or \appendixsectionzzz{#3}%
+      \or \appendixsubseczzz{#3}%
+      \or \appendixsubsubseczzz{#3}%
+      \fi
+    \else
+      \ifcase\absseclevel
+         \chapterzzz{#3}%
+      \or \seczzz{#3}%
+      \or \numberedsubseczzz{#3}%
+      \or \numberedsubsubseczzz{#3}%
+      \fi
+    \fi
+  \fi
+  \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered.  Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v.  By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+  % section resetting is \global in case the chapter is in a group, such
+  % as an @include file.
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\chapno by 1
+  %
+  % Used for \float.
+  \gdef\chaplevelprefix{\the\chapno.}%
+  \resetallfloatnos
+  %
+  % \putwordChapter can contain complex things in translations.
+  \toks0=\expandafter{\putwordChapter}%
+  \message{\the\toks0 \space \the\chapno}%
+  %
+  % Write the actual heading.
+  \chapmacro{#1}{Ynumbered}{\the\chapno}%
+  %
+  % So @section and the like are numbered underneath this chapter.
+  \global\let\section = \numberedsec
+  \global\let\subsection = \numberedsubsec
+  \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz
+%
+\def\appendixzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\appendixno by 1
+  \gdef\chaplevelprefix{\appendixletter.}%
+  \resetallfloatnos
+  %
+  % \putwordAppendix can contain complex things in translations.
+  \toks0=\expandafter{\putwordAppendix}%
+  \message{\the\toks0 \space \appendixletter}%
+  %
+  \chapmacro{#1}{Yappendix}{\appendixletter}%
+  %
+  \global\let\section = \appendixsec
+  \global\let\subsection = \appendixsubsec
+  \global\let\subsubsection = \appendixsubsubsec
+}
+
+\outer\parseargdef\unnumbered{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz
+\def\unnumberedzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\unnumberedno by 1
+  %
+  % Since an unnumbered has no number, no prefix for figures.
+  \global\let\chaplevelprefix = \empty
+  \resetallfloatnos
+  %
+  % This used to be simply \message{#1}, but TeX fully expands the
+  % argument to \message.  Therefore, if #1 contained @-commands, TeX
+  % expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+  % expanded @cite (which turns out to cause errors because \cite is meant
+  % to be executed, not expanded).
+  %
+  % Anyway, we don't want the fully-expanded definition of @cite to appear
+  % as a result of the \message, we just want `@cite' itself.  We use
+  % \the<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{%
+  % Well, we could do the following in a group, but that would break
+  % an assumption that \chapmacro is called at the outermost level.
+  % Thus we are safer this way:                --kasal, 24feb04
+  \let\centerparametersmaybe = \centerparameters
+  \unnmhead0{#1}%
+  \let\centerparametersmaybe = \relax
+}
+
+% @top is like @unnumbered.
+\let\top\unnumbered
+
+% Sections.
+\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz
+\def\seczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%
+}
+
+\outer\parseargdef\appendixsection{\apphead1{#1}} % normally calls appendixsectionzzz
+\def\appendixsectionzzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}} % normally calls unnumberedseczzz
+\def\unnumberedseczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+\outer\parseargdef\numberedsubsec{\numhead2{#1}} % normally calls numberedsubseczzz
+\def\numberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+\outer\parseargdef\appendixsubsec{\apphead2{#1}} % normally calls appendixsubseczzz
+\def\appendixsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}} %normally calls unnumberedsubseczzz
+\def\unnumberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}} % normally numberedsubsubseczzz
+\def\numberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynumbered}%
+                 {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}} % normally appendixsubsubseczzz
+\def\appendixsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}} %normally unnumberedsubsubseczzz
+\def\unnumberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+% NOTE on use of \vbox for chapter headings, section headings, and such:
+%       1) We use \vbox rather than the earlier \line to permit
+%          overlong headings to fold.
+%       2) \hyphenpenalty is set to 10000 because hyphenation in a
+%          heading is obnoxious; this forbids it.
+%       3) Likewise, headings look best if no \parindent is used, and
+%          if justification is not attempted.  Hence \raggedright.
+
+\def\majorheading{%
+  {\advance\chapheadingskip by 10pt \chapbreak }%
+  \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+  {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                    \parindent=0pt\ptexraggedright
+                    \rmisbold #1\hfill}}%
+  \bigskip \par\penalty 200\relax
+  \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+%%% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+%%% Define plain chapter starts, and page on/off switching for it
+% Parameter controlling skip before chapter headings (if needed)
+
+\newskip\chapheadingskip
+
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\def\chappager{\par\vfill\supereject}
+% Because \domark is called before \chapoddpage, the filler page will
+% get the headings for the next chapter, which is wrong.  But we don't
+% care -- we just disable all headings on the filler page.
+\def\chapoddpage{%
+  \chappager
+  \ifodd\pageno \else
+    \begingroup
+      \evenheadline={\hfil}\evenfootline={\hfil}%
+      \oddheadline={\hfil}\oddfootline={\hfil}%
+      \hbox to 0pt{}%
+      \chappager
+    \endgroup
+  \fi
+}
+
+\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\let\pagealignmacro=\chappager}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\let\pagealignmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\let\pagealignmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+\def\Yappendixkeyword{Yappendix}
+%
+\def\chapmacro#1#2#3{%
+  % Insert the first mark before the heading break (see notes for \domark).
+  \let\prevchapterdefs=\lastchapterdefs
+  \let\prevsectiondefs=\lastsectiondefs
+  \gdef\lastsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}%
+                        \gdef\thissection{}}%
+  %
+  \def\temptype{#2}%
+  \ifx\temptype\Ynothingkeyword
+    \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{\thischaptername}}%
+  \else\ifx\temptype\Yomitfromtockeyword
+    \gdef\lastchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{}}%
+  \else\ifx\temptype\Yappendixkeyword
+    \toks0={#1}%
+    \xdef\lastchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\appendixletter}%
+      % \noexpand\putwordAppendix avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordAppendix{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \else
+    \toks0={#1}%
+    \xdef\lastchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\the\chapno}%
+      % \noexpand\putwordChapter avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordChapter{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \fi\fi\fi
+  %
+  % Output the mark.  Pass it through \safewhatsit, to take care of
+  % the preceding space.
+  \safewhatsit\domark
+  %
+  % Insert the chapter heading break.
+  \pchapsepmacro
+  %
+  % Now the second mark, after the heading break.  No break points
+  % between here and the heading.
+  \let\prevchapterdefs=\lastchapterdefs
+  \let\prevsectiondefs=\lastsectiondefs
+  \domark
+  %
+  {%
+    \chapfonts \rmisbold
+    %
+    % Have to define \lastsection before calling \donoderef, because the
+    % xref code eventually uses it.  On the other hand, it has to be called
+    % after \pchapsepmacro, or the headline will change too soon.
+    \gdef\lastsection{#1}%
+    %
+    % Only insert the separating space if we have a chapter/appendix
+    % number, and don't print the unnumbered ``number''.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unnchap}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      \setbox0 = \hbox{}% contents like unnumbered, but no toc entry
+      \def\toctype{omit}%
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{\putwordAppendix{} #3\enspace}%
+      \def\toctype{app}%
+    \else
+      \setbox0 = \hbox{#3\enspace}%
+      \def\toctype{numchap}%
+    \fi\fi\fi
+    %
+    % Write the toc entry for this chapter.  Must come before the
+    % \donoderef, because we include the current node name in the toc
+    % entry, and \donoderef resets it to empty.
+    \writetocentry{\toctype}{#1}{#3}%
+    %
+    % For pdftex, we have to write out the node definition (aka, make
+    % the pdfdest) after any page break, but before the actual text has
+    % been typeset.  If the destination for the pdf outline is after the
+    % text, then jumping from the outline may wind up with the text not
+    % being visible, for instance under high magnification.
+    \donoderef{#2}%
+    %
+    % Typeset the actual heading.
+    \nobreak % Avoid page breaks at the interline glue.
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright
+          \hangindent=\wd0 \centerparametersmaybe
+          \unhbox0 #1\par}%
+  }%
+  \nobreak\bigskip % no page break after a chapter title
+  \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+  \advance\rightskip by 3\rightskip
+  \leftskip = \rightskip
+  \parfillskip = 0pt
+}
+
+
+% I don't think this chapter style is supported any more, so I'm not
+% updating it with the new noderef stuff.  We'll see.  --karl, 11aug03.
+%
+\def\setchapterstyle #1 {\csname CHAPF#1\endcsname}
+%
+\def\unnchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt\ptexraggedright
+                       \rmisbold #1\hfill}}\bigskip \par\nobreak
+}
+\def\chfopen #1#2{\chapoddpage {\chapfonts
+\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}%
+\par\penalty 5000 %
+}
+\def\centerchfopen #1{%
+\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000
+                       \parindent=0pt
+                       \hfill {\rmisbold #1}\hfill}}\bigskip \par\nobreak
+}
+\def\CHAPFopen{%
+  \global\let\chapmacro=\chfopen
+  \global\let\centerchapmacro=\centerchfopen}
+
+
+% Section titles.  These macros combine the section number parts and
+% call the generic \sectionheading to do the printing.
+%
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip{-1000}}
+
+% Subsection titles.
+\newskip\subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}}
+
+% Subsubsection titles.
+\def\subsubsecheadingskip{\subsecheadingskip}
+\def\subsubsecheadingbreak{\subsecheadingbreak}
+
+
+% Print any size, any type, section title.
+%
+% #1 is the text, #2 is the section level (sec/subsec/subsubsec), #3 is
+% the section type for xrefs (Ynumbered, Ynothing, Yappendix), #4 is the
+% section number.
+%
+\def\seckeyword{sec}
+%
+\def\sectionheading#1#2#3#4{%
+  {%
+    % Switch to the right set of fonts.
+    \csname #2fonts\endcsname \rmisbold
+    %
+    \def\sectionlevel{#2}%
+    \def\temptype{#3}%
+    %
+    % Insert first mark before the heading break (see notes for \domark).
+    \let\prevsectiondefs=\lastsectiondefs
+    \ifx\temptype\Ynothingkeyword
+      \ifx\sectionlevel\seckeyword
+        \gdef\lastsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}%
+                              \gdef\thissection{\thissectionname}}%
+      \fi
+    \else\ifx\temptype\Yomitfromtockeyword
+      % Don't redefine \thissection.
+    \else\ifx\temptype\Yappendixkeyword
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\lastsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \else
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\lastsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \fi\fi\fi
+    %
+    % Go into vertical mode.  Usually we'll already be there, but we
+    % don't want the following whatsit to end up in a preceding paragraph
+    % if the document didn't happen to have a blank line.
+    \par
+    %
+    % Output the mark.  Pass it through \safewhatsit, to take care of
+    % the preceding space.
+    \safewhatsit\domark
+    %
+    % Insert space above the heading.
+    \csname #2headingbreak\endcsname
+    %
+    % Now the second mark, after the heading break.  No break points
+    % between here and the heading.
+    \let\prevsectiondefs=\lastsectiondefs
+    \domark
+    %
+    % Only insert the space after the number if we have a section number.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unn}%
+      \gdef\lastsection{#1}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      % for @headings -- no section number, don't include in toc,
+      % and don't redefine \lastsection.
+      \setbox0 = \hbox{}%
+      \def\toctype{omit}%
+      \let\sectionlevel=\empty
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{app}%
+      \gdef\lastsection{#1}%
+    \else
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{num}%
+      \gdef\lastsection{#1}%
+    \fi\fi\fi
+    %
+    % Write the toc entry (before \donoderef).  See comments in \chapmacro.
+    \writetocentry{\toctype\sectionlevel}{#1}{#4}%
+    %
+    % Write the node reference (= pdf destination for pdftex).
+    % Again, see comments in \chapmacro.
+    \donoderef{#3}%
+    %
+    % Interline glue will be inserted when the vbox is completed.
+    % That glue will be a valid breakpoint for the page, since it'll be
+    % preceded by a whatsit (usually from the \donoderef, or from the
+    % \writetocentry if there was no node).  We don't want to allow that
+    % break, since then the whatsits could end up on page n while the
+    % section is on page n+1, thus toc/etc. are wrong.  Debian bug 276000.
+    \nobreak
+    %
+    % Output the actual section heading.
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright
+          \hangindent=\wd0  % zero if no section number
+          \unhbox0 #1}%
+  }%
+  % Add extra space after the heading -- half of whatever came above it.
+  % Don't allow stretch, though.
+  \kern .5 \csname #2headingskip\endcsname
+  %
+  % Do not let the kern be a potential breakpoint, as it would be if it
+  % was followed by glue.
+  \nobreak
+  %
+  % We'll almost certainly start a paragraph next, so don't let that
+  % glue accumulate.  (Not a breakpoint because it's preceded by a
+  % discardable item.)
+  \vskip-\parskip
+  %
+  % This is purely so the last item on the list is a known \penalty >
+  % 10000.  This is so \startdefun can avoid allowing breakpoints after
+  % section headings.  Otherwise, it would insert a valid breakpoint between:
+  %
+  %   @section sec-whatever
+  %   @deffn def-whatever
+  \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this.  The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything.  This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+  \edef\writetoctype{#1}%
+  \ifx\writetoctype\omitkeyword \else
+    \iftocfileopened\else
+      \immediate\openout\tocfile = \jobname.toc
+      \global\tocfileopenedtrue
+    \fi
+    %
+    \iflinks
+      {\atdummies
+       \edef\temp{%
+         \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}%
+       \temp
+      }%
+    \fi
+  \fi
+  %
+  % Tell \shipout to create a pdf destination on each page, if we're
+  % writing pdf.  These are used in the table of contents.  We can't
+  % just write one on every page because the title pages are numbered
+  % 1 and 2 (the page numbers aren't printed), and so are the first
+  % two pages of the document.  Thus, we'd have two destinations named
+  % `1', and two named `2'.
+  \ifpdf \global\pdfmakepagedesttrue \fi
+}
+
+
+% These characters do not print properly in the Computer Modern roman
+% fonts, so we must take special care.  This is more or less redundant
+% with the Texinfo input format setup at the end of this file.
+%
+\def\activecatcodes{%
+  \catcode`\"=\active
+  \catcode`\$=\active
+  \catcode`\<=\active
+  \catcode`\>=\active
+  \catcode`\\=\active
+  \catcode`\^=\active
+  \catcode`\_=\active
+  \catcode`\|=\active
+  \catcode`\~=\active
+}
+
+
+% Read the toc file, which is essentially Texinfo input.
+\def\readtocfile{%
+  \setupdatafile
+  \activecatcodes
+  \input \tocreadfilename
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Prepare to read what we've written to \tocfile.
+%
+\def\startcontents#1{%
+  % If @setchapternewpage on, and @headings double, the contents should
+  % start on an odd page, unlike chapters.  Thus, we maintain
+  % \contentsalignmacro in parallel with \pagealignmacro.
+  % From: Torbjorn Granlund <tege@matematik.su.se>
+  \contentsalignmacro
+  \immediate\closeout\tocfile
+  %
+  % Don't need to put `Contents' or `Short Contents' in the headline.
+  % It is abundantly clear what they are.
+  \chapmacro{#1}{Yomitfromtoc}{}%
+  %
+  \savepageno = \pageno
+  \begingroup                  % Set up to handle contents files properly.
+    \raggedbottom              % Worry more about breakpoints than the bottom.
+    \advance\hsize by -\contentsrightmargin % Don't use the full line length.
+    %
+    % Roman numerals for page numbers.
+    \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+}
+
+% redefined for the two-volume lispref.  We always output on
+% \jobname.toc even if this is redefined.
+%
+\def\tocreadfilename{\jobname.toc}
+
+% Normal (long) toc.
+%
+\def\contents{%
+  \startcontents{\putwordTOC}%
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+    \ifeof 1 \else
+      \pdfmakeoutlines
+    \fi
+    \closein 1
+  \endgroup
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+}
+
+% And just the chapters.
+\def\summarycontents{%
+  \startcontents{\putwordShortTOC}%
+    %
+    \let\numchapentry = \shortchapentry
+    \let\appentry = \shortchapentry
+    \let\unnchapentry = \shortunnchapentry
+    % We want a true roman here for the page numbers.
+    \secfonts
+    \let\rm=\shortcontrm \let\bf=\shortcontbf
+    \let\sl=\shortcontsl \let\tt=\shortconttt
+    \rm
+    \hyphenpenalty = 10000
+    \advance\baselineskip by 1pt % Open it up a little.
+    \def\numsecentry##1##2##3##4{}
+    \let\appsecentry = \numsecentry
+    \let\unnsecentry = \numsecentry
+    \let\numsubsecentry = \numsecentry
+    \let\appsubsecentry = \numsecentry
+    \let\unnsubsecentry = \numsecentry
+    \let\numsubsubsecentry = \numsecentry
+    \let\appsubsubsecentry = \numsecentry
+    \let\unnsubsubsecentry = \numsecentry
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \closein 1
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+  \endgroup
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+}
+\let\shortcontents = \summarycontents
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g., `A' for an appendix, or `3' for a chapter.
+%
+\def\shortchaplabel#1{%
+  % This space should be enough, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % But use \hss just in case.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in by \shortchapentry above.)
+  %
+  % We'd like to right-justify chapter numbers, but that looks strange
+  % with appendix letters.  And right-justifying numbers and
+  % left-justifying letters looks strange when there is less than 10
+  % chapters.  Have to read the whole toc once to know how many chapters
+  % there are before deciding ...
+  \hbox to 1em{#1\hss}%
+}
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+%
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+  % We use M since it's probably the widest letter.
+  \setbox0 = \hbox{\putwordAppendix{} M}%
+  \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\labelspace#1}{#4}}
+
+% Unnumbered chapters.
+\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}}
+\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}}
+
+% Sections.
+\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}}
+\let\appsecentry=\numsecentry
+\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}}
+
+% Subsections.
+\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsecentry=\numsubsecentry
+\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}}
+
+% And subsubsections.
+\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsubsecentry=\numsubsubsecentry
+\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}}
+
+% This parameter controls the indentation of the various levels.
+% Same as \defaultparindent.
+\newdimen\tocindent \tocindent = 15pt
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+   \begingroup
+     \chapentryfonts
+     \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+% We use the same \entry macro as for the index entries.
+\let\tocentry = \entry
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\def\subsecentryfonts{\textfonts}
+\def\subsubsecentryfonts{\textfonts}
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% @tex ... @end tex    escapes into raw Tex temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain tex @ character.
+
+\envdef\tex{%
+  \setupmarkupstyle{tex}%
+  \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+  \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+  \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie
+  \catcode `\%=14
+  \catcode `\+=\other
+  \catcode `\"=\other
+  \catcode `\|=\other
+  \catcode `\<=\other
+  \catcode `\>=\other
+  \catcode`\`=\other
+  \catcode`\'=\other
+  \escapechar=`\\
+  %
+  \let\b=\ptexb
+  \let\bullet=\ptexbullet
+  \let\c=\ptexc
+  \let\,=\ptexcomma
+  \let\.=\ptexdot
+  \let\dots=\ptexdots
+  \let\equiv=\ptexequiv
+  \let\!=\ptexexclam
+  \let\i=\ptexi
+  \let\indent=\ptexindent
+  \let\noindent=\ptexnoindent
+  \let\{=\ptexlbrace
+  \let\+=\tabalign
+  \let\}=\ptexrbrace
+  \let\/=\ptexslash
+  \let\*=\ptexstar
+  \let\t=\ptext
+  \expandafter \let\csname top\endcsname=\ptextop  % outer
+  \let\frenchspacing=\plainfrenchspacing
+  %
+  \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+  \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+  \def\@{@}%
+}
+% There is no need to define \Etex.
+
+% Define @lisp ... @end lisp.
+% @lisp environment forms a group so it can rebind things,
+% including the definition of @end lisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip.
+%
+\def\aboveenvbreak{{%
+  % =10000 instead of <10000 because of a special case in \itemzzz and
+  % \sectionheading, q.v.
+  \ifnum \lastpenalty=10000 \else
+    \advance\envskipamount by \parskip
+    \endgraf
+    \ifdim\lastskip<\envskipamount
+      \removelastskip
+      % it's not a good place to break if the last penalty was \nobreak
+      % or better ...
+      \ifnum\lastpenalty<10000 \penalty-50 \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+\let\afterenvbreak = \aboveenvbreak
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins; it will
+% also clear it, so that its embedded environments do the narrowing again.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+\font\circle=lcircle10
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+\circthick=\fontdimen8\circle
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+        \ctl\leaders\hrule height\circthick\hfil\ctr
+        \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+        \cbl\leaders\hrule height\circthick\hfil\cbr
+        \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+\envdef\cartouche{%
+  \ifhmode\par\fi  % can't be in the midst of a paragraph.
+  \startsavinginserts
+  \lskip=\leftskip \rskip=\rightskip
+  \leftskip=0pt\rightskip=0pt % we want these *outside*.
+  \cartinner=\hsize \advance\cartinner by-\lskip
+  \advance\cartinner by-\rskip
+  \cartouter=\hsize
+  \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+                               % side, and for 6pt waste from
+                               % each corner char, and rule thickness
+  \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+  % Flag to tell @lisp, etc., not to narrow margin.
+  \let\nonarrowing = t%
+  \vbox\bgroup
+      \baselineskip=0pt\parskip=0pt\lineskip=0pt
+      \carttop
+      \hbox\bgroup
+         \hskip\lskip
+         \vrule\kern3pt
+         \vbox\bgroup
+             \kern3pt
+             \hsize=\cartinner
+             \baselineskip=\normbskip
+             \lineskip=\normlskip
+             \parskip=\normpskip
+             \vskip -\parskip
+             \comment % For explanation, see the end of \def\group.
+}
+\def\Ecartouche{%
+              \ifhmode\par\fi
+             \kern3pt
+         \egroup
+         \kern3pt\vrule
+         \hskip\rskip
+      \egroup
+      \cartbot
+  \egroup
+  \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\newdimen\nonfillparindent
+\def\nonfillstart{%
+  \aboveenvbreak
+  \hfuzz = 12pt % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  % Turn off paragraph indentation but redefine \indent to emulate
+  % the normal \indent.
+  \nonfillparindent=\parindent
+  \parindent = 0pt
+  \let\indent\nonfillindent
+  %
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+  \let\exdent=\nofillexdent
+}
+
+\begingroup
+\obeyspaces
+% We want to swallow spaces (but not other tokens) after the fake
+% @indent in our nonfill-environments, where spaces are normally
+% active and set to @tie, resulting in them not being ignored after
+% @indent.
+\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}%
+\gdef\nonfillindentcheck{%
+\ifx\temp %
+\expandafter\nonfillindentgobble%
+\else%
+\leavevmode\nonfillindentbox%
+\fi%
+}%
+\endgroup
+\def\nonfillindentgobble#1{\nonfillindent}
+\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}}
+
+% If you want all examples etc. small: @set dispenvsize small.
+% If you want even small examples the full size: @set dispenvsize nosmall.
+% This affects the following displayed environments:
+%    @example, @display, @format, @lisp
+%
+\def\smallword{small}
+\def\nosmallword{nosmall}
+\let\SETdispenvsize\relax
+\def\setnormaldispenv{%
+  \ifx\SETdispenvsize\smallword
+    % end paragraph for sake of leading, in case document has no blank
+    % line.  This is redundant with what happens in \aboveenvbreak, but
+    % we need to do it before changing the fonts, and it's inconvenient
+    % to change the fonts afterward.
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+\def\setsmalldispenv{%
+  \ifx\SETdispenvsize\nosmallword
+  \else
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+
+% We often define two environments, @foo and @smallfoo.
+% Let's do it by one command:
+\def\makedispenv #1#2{
+  \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}
+  \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}
+  \expandafter\let\csname E#1\endcsname \afterenvbreak
+  \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two synonyms:
+\def\maketwodispenvs #1#2#3{
+  \makedispenv{#1}{#3}
+  \makedispenv{#2}{#3}
+}
+
+% @lisp: indented, narrowed, typewriter font; @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvs {lisp}{example}{%
+  \nonfillstart
+  \tt\setupmarkupstyle{example}%
+  \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+  \gobble       % eat return
+}
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenv {display}{%
+  \nonfillstart
+  \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenv{format}{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \advance\leftskip by 0pt plus 1fill
+  \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification.  From plain.tex.
+\envdef\raggedright{%
+  \rightskip0pt plus2em \spaceskip.3333em \xspaceskip.5em\relax
+}
+\let\Eraggedright\par
+
+\envdef\raggedleft{%
+  \parindent=0pt \leftskip0pt plus2em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedleft\par
+
+\envdef\raggedcenter{%
+  \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedcenter\par
+
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.  We keep \parskip nonzero in general, since
+% we're doing normal filling.  So, when using \aboveenvbreak and
+% \afterenvbreak, temporarily make \parskip 0.
+%
+\def\quotationstart{%
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \parindent=0pt
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \advance\rightskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+  \parsearg\quotationlabel
+}
+
+\envdef\quotation{%
+  \setnormaldispenv
+  \quotationstart
+}
+
+\envdef\smallquotation{%
+  \setsmalldispenv
+  \quotationstart
+}
+\let\Esmallquotation = \Equotation
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+  \par
+  \ifx\quotationauthor\undefined\else
+    % indent a bit.
+    \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+  \fi
+  {\parskip=0pt \afterenvbreak}%
+}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty \else
+    {\bf #1: }%
+  \fi
+}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<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
+%
+\def\starttabbox{\setbox0=\hbox\bgroup}
+%
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabexpand{%
+    \catcode`\^^I=\active
+    \def^^I{\leavevmode\egroup
+      \dimen0=\wd0 % the width so far, or since the previous tab
+      \divide\dimen0 by\tabw
+      \multiply\dimen0 by\tabw % compute previous multiple of \tabw
+      \advance\dimen0 by\tabw  % advance to next multiple of \tabw
+      \wd0=\dimen0 \box0 \starttabbox
+    }%
+  }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  % Easiest (and conventionally used) font for verbatim
+  \tt
+  \def\par{\leavevmode\egroup\box0\endgraf}%
+  \tabexpand
+  \setupmarkupstyle{verbatim}%
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count
+  % must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+  \everypar{\starttabbox}%
+}
+
+% Do the @verb magic: verbatim text is quoted by unique
+% delimiter characters.  Before first delimiter expect a
+% right brace, after last delimiter expect closing brace:
+%
+%    \def\doverb'{'<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{#2\noexpand\end\gobble verbatim}%
+  % We really want {...\end verbatim} in the body of the macro, but
+  % without the active space; thus we have to use \xdef and \gobble.
+\endgroup
+%
+\envdef\verbatim{%
+    \setupverbatim\doverbatim
+}
+\let\Everbatim = \afterenvbreak
+
+
+% @verbatiminclude FILE - insert text of file in verbatim environment.
+%
+\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude}
+%
+\def\doverbatiminclude#1{%
+  {%
+    \makevalueexpandable
+    \setupverbatim
+    \indexnofonts       % Allow `@@' and other weird things in file names.
+    \input #1
+    \afterenvbreak
+  }%
+}
+
+% @copying ... @end copying.
+% Save the text away for @insertcopying later.
+%
+% We save the uninterpreted tokens, rather than creating a box.
+% Saving the text in a box would be much easier, but then all the
+% typesetting commands (@smallbook, font changes, etc.) have to be done
+% beforehand -- and a) we want @copying to be done first in the source
+% file; b) letting users define the frontmatter in as flexible order as
+% possible is very desirable.
+%
+\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
+\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+%
+\def\insertcopying{%
+  \begingroup
+    \parindent = 0pt  % paragraph indentation looks wrong on title page
+    \scanexp\copyingtext
+  \endgroup
+}
+
+
+\message{defuns,}
+% @defun etc.
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+\newcount\defunpenalty
+
+% Start the processing of @deffn:
+\def\startdefun{%
+  \ifnum\lastpenalty<10000
+    \medbreak
+    \defunpenalty=10003 % Will keep this @deffn together with the
+                        % following @def command, see below.
+  \else
+    % If there are two @def commands in a row, we'll have a \nobreak,
+    % which is there to keep the function description together with its
+    % header.  But if there's nothing but headers, we need to allow a
+    % break somewhere.  Check specifically for penalty 10002, inserted
+    % by \printdefunline, instead of 10000, since the sectioning
+    % commands also insert a nobreak penalty, and we don't want to allow
+    % a break between a section heading and a defun.
+    %
+    % As a minor refinement, we avoid "club" headers by signalling
+    % with penalty of 10003 after the very first @deffn in the
+    % sequence (see above), and penalty of 10002 after any following
+    % @def command.
+    \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi
+    %
+    % Similarly, after a section heading, do not allow a break.
+    % But do insert the glue.
+    \medskip  % preceded by discardable penalty, so not a breakpoint
+  \fi
+  %
+  \parindent=0in
+  \advance\leftskip by \defbodyindent
+  \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+  % First, check whether we are in the right environment:
+  \checkenv#1%
+  %
+  % As above, allow line break if we have multiple x headers in a row.
+  % It's not a great place, though.
+  \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi
+  %
+  % And now, it's time to reuse the body of the original defun:
+  \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+  \begingroup
+    % call \deffnheader:
+    #1#2 \endheader
+    % common ending:
+    \interlinepenalty = 10000
+    \advance\rightskip by 0pt plus 1fil
+    \endgraf
+    \nobreak\vskip -\parskip
+    \penalty\defunpenalty  % signal to \startdefun and \dodefunx
+    % Some of the @defun-type tags do not enable magic parentheses,
+    % rendering the following check redundant.  But we don't optimize.
+    \checkparencounts
+  \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remaining is to define \deffnheader.
+%
+\def\makedefun#1{%
+  \expandafter\let\csname E#1\endcsname = \Edefun
+  \edef\temp{\noexpand\domakedefun
+    \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+  \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+  \envdef#1{%
+    \startdefun
+    \parseargusing\activeparens{\printdefunline#3}%
+  }%
+  \def#2{\dodefunx#1}%
+  \def#3%
+}
+
+%%% Untyped functions:
+
+% @deffn category name args
+\makedefun{deffn}{\deffngeneral{}}
+
+% @deffn category class name args
+\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
+
+% \defopon {category on}class name args
+\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deffngeneral {subind}category name args
+%
+\def\deffngeneral#1#2 #3 #4\endheader{%
+  % Remember that \dosubind{fn}{foo}{} is equivalent to \doind{fn}{foo}.
+  \dosubind{fn}{\code{#3}}{#1}%
+  \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+}
+
+%%% Typed functions:
+
+% @deftypefn category type name args
+\makedefun{deftypefn}{\deftypefngeneral{}}
+
+% @deftypeop category class type name args
+\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
+
+% \deftypeopon {category on}class type name args
+\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypefngeneral {subind}category type name args
+%
+\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{fn}{\code{#4}}{#1}%
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+%%% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{vr}{\code{#4}}{#1}%
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+%%% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+%%% Type:
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+  \doind{tp}{\code{#2}}%
+  \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+  % Get the values of \leftskip and \rightskip as they were outside the @def...
+  \advance\leftskip by -\defbodyindent
+  %
+  % How we'll format the type name.  Putting it in brackets helps
+  % distinguish it from the body text that may end up on the next line
+  % just below it.
+  \def\temp{#1}%
+  \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+  %
+  % Figure out line sizes for the paragraph shape.
+  % The first line needs space for \box0; but if \rightskip is nonzero,
+  % we need only space for the part of \box0 which exceeds it:
+  \dimen0=\hsize  \advance\dimen0 by -\wd0  \advance\dimen0 by \rightskip
+  % The continuations:
+  \dimen2=\hsize  \advance\dimen2 by -\defargsindent
+  % (plain.tex says that \dimen1 should be used only as global.)
+  \parshape 2 0in \dimen0 \defargsindent \dimen2
+  %
+  % Put the type name to the right margin.
+  \noindent
+  \hbox to 0pt{%
+    \hfil\box0 \kern-\hsize
+    % \hsize has to be shortened this way:
+    \kern\leftskip
+    % Intentionally do not respect \rightskip, since we need the space.
+  }%
+  %
+  % Allow all lines to be underfull without complaint:
+  \tolerance=10000 \hbadness=10000
+  \exdentamount=\defbodyindent
+  {%
+    % defun fonts. We use typewriter by default (used to be bold) because:
+    % . we're printing identifiers, they should be in tt in principle.
+    % . in languages with many accents, such as Czech or French, it's
+    %   common to leave accents off identifiers.  The result looks ok in
+    %   tt, but exceedingly strange in rm.
+    % . we don't want -- and --- to be treated as ligatures.
+    % . this still does not fix the ?` and !` ligatures, but so far no
+    %   one has made identifiers using them :).
+    \df \tt
+    \def\temp{#2}% return value type
+    \ifx\temp\empty\else \tclose{\temp} \fi
+    #3% output function name
+  }%
+  {\rm\enskip}% hskip 0.5 em of \tenrm
+  %
+  \boldbrax
+  % arguments will be output next, if any.
+}
+
+% Print arguments in slanted roman (not ttsl), inconsistently with using
+% tt for the name.  This is because literal text is sometimes needed in
+% the argument list (groff manual), and ttsl and tt are not very
+% distinguishable.  Prevent hyphenation at `-' chars.
+%
+\def\defunargs#1{%
+  % use sl by default (not ttsl),
+  % tt for the names.
+  \df \sl \hyphenchar\font=0
+  %
+  % On the other hand, if an argument has two dashes (for instance), we
+  % want a way to get ttsl.  Let's try @var for that.
+  \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}%
+  #1%
+  \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+  \catcode`\(=\active \catcode`\)=\active
+  \catcode`\[=\active \catcode`\]=\active
+  \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+  \activeparens
+  \global\let(=\lparen \global\let)=\rparen
+  \global\let[=\lbrack \global\let]=\rbrack
+  \global\let& = \&
+
+  \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+  \gdef\magicamp{\let&=\amprm}
+}
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#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\undefined
+  \newwrite\macscribble
+  \def\scantokens#1{%
+    \toks0={#1}%
+    \immediate\openout\macscribble=\jobname.tmp
+    \immediate\write\macscribble{\the\toks0}%
+    \immediate\closeout\macscribble
+    \input \jobname.tmp
+  }
+\fi
+
+\def\scanmacro#1{%
+  \begingroup
+    \newlinechar`\^^M
+    \let\xeatspaces\eatspaces
+    % Undo catcode changes of \startcontents and \doprintindex
+    % When called from @insertcopying or (short)caption, we need active
+    % backslash to get it printed correctly.  Previously, we had
+    % \catcode`\\=\other instead.  We'll see whether a problem appears
+    % with macro expansion.                            --kasal, 19aug04
+    \catcode`\@=0 \catcode`\\=\active \escapechar=`\@
+    % ... and \example
+    \spaceisspace
+    %
+    % Append \endinput to make sure that TeX does not see the ending newline.
+    % I've verified that it is necessary both for e-TeX and for ordinary TeX
+    %                                                  --kasal, 29nov03
+    \scantokens{#1\endinput}%
+  \endgroup
+}
+
+\def\scanexp#1{%
+  \edef\temp{\noexpand\scanmacro{#1}}%
+  \temp
+}
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+
+% List of all defined macros in the form
+%    \definedummyword\macro1\definedummyword\macro2...
+% Currently is also contains all @aliases; the list can be split
+% if there is a need.
+\def\macrolist{}
+
+% Add the macro to \macrolist
+\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname}
+\def\addtomacrolistxxx#1{%
+     \toks0 = \expandafter{\macrolist\definedummyword#1}%
+     \xdef\macrolist{\the\toks0}%
+}
+
+% Utility routines.
+% This does \let #1 = #2, with \csnames; that is,
+%   \let \csname#1\endcsname = \csname#2\endcsname
+% (except of course we have to play expansion games).
+%
+\def\cslet#1#2{%
+  \expandafter\let
+  \csname#1\expandafter\endcsname
+  \csname#2\endcsname
+}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=\other \catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \.
+
+% Non-ASCII encodings make 8-bit characters active, so un-activate
+% them to avoid their expansion.  Must do this non-globally, to
+% confine the change to the current group.
+
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by  making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+
+\def\scanctxt{%
+  \catcode`\"=\other
+  \catcode`\+=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\@=\other
+  \catcode`\^=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\~=\other
+  \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi
+}
+
+\def\scanargctxt{%
+  \scanctxt
+  \catcode`\\=\other
+  \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{%
+  \scanctxt
+  \catcode`\{=\other
+  \catcode`\}=\other
+  \catcode`\^^M=\other
+  \usembodybackslash
+}
+
+\def\macroargctxt{%
+  \scanctxt
+  \catcode`\\=\other
+}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+  \getargs{#1}%           now \macname is the macname and \argl the arglist
+  \ifx\argl\empty       % no arguments
+     \paramno=0%
+  \else
+     \expandafter\parsemargdef \argl;%
+  \fi
+  \if1\csname ismacro.\the\macname\endcsname
+     \message{Warning: redefining \the\macname}%
+  \else
+     \expandafter\ifx\csname \the\macname\endcsname \relax
+     \else \errmessage{Macro name \the\macname\space already defined}\fi
+     \global\cslet{macsave.\the\macname}{\the\macname}%
+     \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+     \addtomacrolist{\the\macname}%
+  \fi
+  \begingroup \macrobodyctxt
+  \ifrecursive \expandafter\parsermacbody
+  \else \expandafter\parsemacbody
+  \fi}
+
+\parseargdef\unmacro{%
+  \if1\csname ismacro.#1\endcsname
+    \global\cslet{#1}{macsave.#1}%
+    \global\expandafter\let \csname ismacro.#1\endcsname=0%
+    % Remove the macro name from \macrolist:
+    \begingroup
+      \expandafter\let\csname#1\endcsname \relax
+      \let\definedummyword\unmacrodo
+      \xdef\macrolist{\macrolist}%
+    \endgroup
+  \else
+    \errmessage{Macro #1 not defined}%
+  \fi
+}
+
+% Called by \do from \dounmacro on each macro.  The idea is to omit any
+% macro definitions that have been changed to \relax.
+%
+\def\unmacrodo#1{%
+  \ifx #1\relax
+    % remove this
+  \else
+    \noexpand\definedummyword \noexpand#1%
+  \fi
+}
+
+% This makes use of the obscure feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname #1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+
+% Parse the optional {params} list.  Set up \paramno and \paramlist
+% so \defmacro knows what to do.  Define \macarg.blah for each blah
+% in the params list, to be ##N where N is the position in that list.
+% That gets used by \mbodybackslash (above).
+
+% We need to get `macro parameter char #' into several definitions.
+% The technique used is stolen from LaTeX:  let \hash be something
+% unexpandable, insert that wherever you need a #, and then redefine
+% it to # just before using the token list produced.
+%
+% The same technique is used to protect \eatspaces till just before
+% the macro is used.
+
+\def\parsemargdef#1;{\paramno=0\def\paramlist{}%
+        \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,}
+\def\parsemargdefxxx#1,{%
+  \if#1;\let\next=\relax
+  \else \let\next=\parsemargdefxxx
+    \advance\paramno by 1%
+    \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+        {\xeatspaces{\hash\the\paramno}}%
+    \edef\paramlist{\paramlist\hash\the\paramno,}%
+  \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+
+% This defines the macro itself. There are six cases: recursive and
+% nonrecursive macros of zero, one, and many arguments.
+% Much magic with \expandafter here.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in; @include reads the file inside a group.
+\def\defmacro{%
+  \let\hash=##% convert placeholders to macro parameter chars
+  \ifrecursive
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\scanmacro{\temp}}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline
+         \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+         \egroup\noexpand\scanmacro{\temp}}%
+    \else % many
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\csname\the\macname xx\endcsname}%
+      \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+        \csname\the\macname xxx\endcsname
+          \paramlist{\egroup\noexpand\scanmacro{\temp}}%
+    \fi
+  \else
+    \ifcase\paramno
+    % 0
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \or % 1
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \noexpand\braceorline
+         \expandafter\noexpand\csname\the\macname xxx\endcsname}%
+      \expandafter\xdef\csname\the\macname xxx\endcsname##1{%
+        \egroup
+        \noexpand\norecurse{\the\macname}%
+        \noexpand\scanmacro{\temp}\egroup}%
+    \else % many
+      \expandafter\xdef\csname\the\macname\endcsname{%
+         \bgroup\noexpand\macroargctxt
+         \expandafter\noexpand\csname\the\macname xx\endcsname}%
+      \expandafter\xdef\csname\the\macname xx\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+      \csname\the\macname xxx\endcsname
+      \paramlist{%
+          \egroup
+          \noexpand\norecurse{\the\macname}%
+          \noexpand\scanmacro{\temp}\egroup}%
+    \fi
+  \fi}
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+% \braceorline decides whether the next nonwhitespace character is a
+% {.  If so it reads up to the closing }, if not, it reads the whole
+% line.  Whatever was read is then fed to the next control sequence
+% as an argument (by \parsebrace or \parsearg)
+\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup\else
+    \expandafter\parsearg
+  \fi \macnamexxx}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign.  Just make them active and then expand them all to nothing.
+\def\alias{\parseargusing\obeyspaces\aliasxxx}
+\def\aliasxxx #1{\aliasyyy#1\relax}
+\def\aliasyyy #1=#2\relax{%
+  {%
+    \expandafter\let\obeyedspace=\empty
+    \addtomacrolist{#1}%
+    \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}%
+  }%
+  \next
+}
+
+
+\message{cross references,}
+
+\newwrite\auxfile
+\newif\ifhavexrefs    % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+% @node's only job in TeX is to define \lastnode, which is used in
+% cross-references.  The @node line might or might not have commas, and
+% might or might not have spaces before the first comma, like:
+% @node foo , bar , ...
+% We don't want such trailing spaces in the node name.
+%
+\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse}
+%
+% also remove a trailing comma, in case of something like this:
+% @node Help-Cross,  ,  , Cross-refs
+\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse}
+\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}}
+
+\let\nwnode=\node
+\let\lastnode=\empty
+
+% Write a cross-reference definition for the current node.  #1 is the
+% type (Ynumbered, Yappendix, Ynothing).
+%
+\def\donoderef#1{%
+  \ifx\lastnode\empty\else
+    \setref{\lastnode}{#1}%
+    \global\let\lastnode=\empty
+  \fi
+}
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\newcount\savesfregister
+%
+\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
+\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
+\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
+% anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name taken from \lastsection,
+%                 or the anchor name.
+% 2) NAME-snt   - section number and type, passed as the SNT arg, or
+%                 empty for anchors.
+% 3) NAME-pg    - the page number.
+%
+% This is called from \donoderef, \anchor, and \dofloat.  In the case of
+% floats, there is an additional part, which is not written here:
+% 4) NAME-lof   - the text as it should appear in a @listoffloats.
+%
+\def\setref#1#2{%
+  \pdfmkdest{#1}%
+  \iflinks
+    {%
+      \atdummies  % preserve commands, but don't expand them
+      \edef\writexrdef##1##2{%
+       \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+         ##1}{##2}}% these are parameters of \writexrdef
+      }%
+      \toks0 = \expandafter{\lastsection}%
+      \immediate \writexrdef{title}{\the\toks0 }%
+      \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+      \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, during \shipout
+    }%
+  \fi
+}
+
+% @xref, @pxref, and @ref generate cross-references.  For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual.  All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \unsepspaces
+  \def\printedmanual{\ignorespaces #5}%
+  \def\printedrefname{\ignorespaces #3}%
+  \setbox1=\hbox{\printedmanual\unskip}%
+  \setbox0=\hbox{\printedrefname\unskip}%
+  \ifdim \wd0 = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax
+      % Use the node name inside the square brackets.
+      \def\printedrefname{\ignorespaces #1}%
+    \else
+      % Use the actual chapter/section title appear inside
+      % the square brackets.  Use the real section title if we have it.
+      \ifdim \wd1 > 0pt
+        % It is in another manual, so we don't have it.
+        \def\printedrefname{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We know the real title if we have the xref values.
+          \def\printedrefname{\refx{#1-title}{}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printedrefname{\ignorespaces #1}%
+        \fi%
+      \fi
+    \fi
+  \fi
+  %
+  % Make link in pdf output.
+  \ifpdf
+    {\indexnofonts
+     \turnoffactive
+     % This expands tokens, so do it after making catcode changes, so _
+     % etc. don't get their TeX definitions.
+     \getfilename{#4}%
+     %
+     % See comments at \activebackslashdouble.
+     {\activebackslashdouble \xdef\pdfxrefdest{#1}%
+      \backslashparens\pdfxrefdest}%
+     %
+     \leavevmode
+     \startlink attr{/Border [0 0 0]}%
+     \ifnum\filenamelength>0
+       goto file{\the\filename.pdf} name{\pdfxrefdest}%
+     \else
+       goto name{\pdfmkpgn{\pdfxrefdest}}%
+     \fi
+    }%
+    \setcolor{\linkcolor}%
+  \fi
+  %
+  % Float references are printed completely differently: "Figure 1.2"
+  % instead of "[somenode], p.3".  We distinguish them by the
+  % LABEL-title being set to a magic string.
+  {%
+    % Have to otherify everything special to allow the \csname to
+    % include an _ in the xref name, etc.
+    \indexnofonts
+    \turnoffactive
+    \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+      \csname XR#1-title\endcsname
+  }%
+  \iffloat\Xthisreftitle
+    % If the user specified the print name (third arg) to the ref,
+    % print it instead of our usual "Figure 1.2".
+    \ifdim\wd0 = 0pt
+      \refx{#1-snt}{}%
+    \else
+      \printedrefname
+    \fi
+    %
+    % if the user also gave the printed manual name (fifth arg), append
+    % "in MANUALNAME".
+    \ifdim \wd1 > 0pt
+      \space \putwordin{} \cite{\printedmanual}%
+    \fi
+  \else
+    % node/anchor (non-float) references.
+    %
+    % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not
+    % insert empty discretionaries after hyphens, which means that it will
+    % not find a line break at a hyphen in a node names.  Since some manuals
+    % are best written with fairly long node names, containing hyphens, this
+    % is a loss.  Therefore, we give the text of the node name again, so it
+    % is as if TeX is seeing it for the first time.
+    \ifdim \wd1 > 0pt
+      \putwordSection{} ``\printedrefname'' \putwordin{} \cite{\printedmanual}%
+    \else
+      % _ (for example) has to be the character _ for the purposes of the
+      % control sequence corresponding to the node, but it has to expand
+      % into the usual \leavevmode...\vrule stuff for purposes of
+      % printing. So we \turnoffactive for the \refx-snt, back on for the
+      % printing, back off for the \refx-pg.
+      {\turnoffactive
+       % Only output a following space if the -snt ref is nonempty; for
+       % @unnumbered and @anchor, it won't be.
+       \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}%
+       \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+      }%
+      % output the `[mynode]' via a macro so it can be overridden.
+      \xrefprintnodename\printedrefname
+      %
+      % But we always want a comma and a space:
+      ,\space
+      %
+      % output the `page 3'.
+      \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output.  It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents.  Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+  \ifnum\secno=0
+    \putwordChapter@tie \the\chapno
+  \else \ifnum\subsecno=0
+    \putwordSection@tie \the\chapno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+\def\Yappendix{%
+  \ifnum\secno=0
+     \putwordAppendix@tie @char\the\appendixno{}%
+  \else \ifnum\subsecno=0
+     \putwordSection@tie @char\the\appendixno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie
+      @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+
+% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME.
+% If its value is nonempty, SUFFIX is output afterward.
+%
+\def\refx#1#2{%
+  {%
+    \indexnofonts
+    \otherbackslash
+    \expandafter\global\expandafter\let\expandafter\thisrefX
+      \csname XR#1\endcsname
+  }%
+  \ifx\thisrefX\relax
+    % If not defined, say something at least.
+    \angleleft un\-de\-fined\angleright
+    \iflinks
+      \ifhavexrefs
+        \message{\linenumber Undefined cross reference `#1'.}%
+      \else
+        \ifwarnedxrefs\else
+          \global\warnedxrefstrue
+          \message{Cross reference values unknown; you must run TeX again.}%
+        \fi
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \thisrefX
+  \fi
+  #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file.  Usually it's
+% just a \def (we prepend XR to the control sequence name to avoid
+% collisions).  But if this is a float type, we have more work to do.
+%
+\def\xrdef#1#2{%
+  {% The node name might contain 8-bit characters, which in our current
+   % implementation are changed to commands like @'e.  Don't let these
+   % mess up the control sequence name.
+    \indexnofonts
+    \turnoffactive
+    \xdef\safexrefname{#1}%
+  }%
+  %
+  \expandafter\gdef\csname XR\safexrefname\endcsname{#2}% remember this xref
+  %
+  % Was that xref control sequence that we just defined for a float?
+  \expandafter\iffloat\csname XR\safexrefname\endcsname
+    % it was a float, and we have the (safe) float type in \iffloattype.
+    \expandafter\let\expandafter\floatlist
+      \csname floatlist\iffloattype\endcsname
+    %
+    % Is this the first time we've seen this float type?
+    \expandafter\ifx\floatlist\relax
+      \toks0 = {\do}% yes, so just \do
+    \else
+      % had it before, so preserve previous elements in list.
+      \toks0 = \expandafter{\floatlist\do}%
+    \fi
+    %
+    % Remember this xref in the control sequence \floatlistFLOATTYPE,
+    % for later use in \listoffloats.
+    \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0
+      {\safexrefname}}%
+  \fi
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+%
+\def\tryauxfile{%
+  \openin 1 \jobname.aux
+  \ifeof 1 \else
+    \readdatafile{aux}%
+    \global\havexrefstrue
+  \fi
+  \closein 1
+}
+
+\def\setupdatafile{%
+  \catcode`\^^@=\other
+  \catcode`\^^A=\other
+  \catcode`\^^B=\other
+  \catcode`\^^C=\other
+  \catcode`\^^D=\other
+  \catcode`\^^E=\other
+  \catcode`\^^F=\other
+  \catcode`\^^G=\other
+  \catcode`\^^H=\other
+  \catcode`\^^K=\other
+  \catcode`\^^L=\other
+  \catcode`\^^N=\other
+  \catcode`\^^P=\other
+  \catcode`\^^Q=\other
+  \catcode`\^^R=\other
+  \catcode`\^^S=\other
+  \catcode`\^^T=\other
+  \catcode`\^^U=\other
+  \catcode`\^^V=\other
+  \catcode`\^^W=\other
+  \catcode`\^^X=\other
+  \catcode`\^^Z=\other
+  \catcode`\^^[=\other
+  \catcode`\^^\=\other
+  \catcode`\^^]=\other
+  \catcode`\^^^=\other
+  \catcode`\^^_=\other
+  % It was suggested to set the catcode of ^ to 7, which would allow ^^e4 etc.
+  % in xref tags, i.e., node names.  But since ^^e4 notation isn't
+  % supported in the main text, it doesn't seem desirable.  Furthermore,
+  % that is not enough: for node names that actually contain a ^
+  % character, we would end up writing a line like this: 'xrdef {'hat
+  % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first
+  % argument, and \hat is not an expandable control sequence.  It could
+  % all be worked out, but why?  Either we support ^^ or we don't.
+  %
+  % The other change necessary for this was to define \auxhat:
+  % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter
+  % and then to call \auxhat in \setq.
+  %
+  \catcode`\^=\other
+  %
+  % Special characters.  Should be turned off anyway, but...
+  \catcode`\~=\other
+  \catcode`\[=\other
+  \catcode`\]=\other
+  \catcode`\"=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\$=\other
+  \catcode`\#=\other
+  \catcode`\&=\other
+  \catcode`\%=\other
+  \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+  %
+  % This is to support \ in node names and titles, since the \
+  % characters end up in a \csname.  It's easier than
+  % leaving it active and making its active definition an actual \
+  % character.  What I don't understand is why it works in the *value*
+  % of the xrdef.  Seems like it should be a catcode12 \, and that
+  % should not typeset properly.  But it works, so I'm moving on for
+  % now.  --karl, 15jan04.
+  \catcode`\\=\other
+  %
+  % Make the characters 128-255 be printing characters.
+  {%
+    \count1=128
+    \def\loop{%
+      \catcode\count1=\other
+      \advance\count1 by 1
+      \ifnum \count1<256 \loop \fi
+    }%
+  }%
+  %
+  % @ is our escape character in .aux files, and we need braces.
+  \catcode`\{=1
+  \catcode`\}=2
+  \catcode`\@=0
+}
+
+\def\readdatafile#1{%
+\begingroup
+  \setupdatafile
+  \input\jobname.#1
+\endgroup}
+
+
+\message{insertions,}
+% including footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for info output only.
+\let\footnotestyle=\comment
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \let\indent=\ptexindent
+  \let\noindent=\ptexnoindent
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \dofootnote
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset (and anything else that uses
+% \parseargline) fails inside footnotes because the tokens are fixed when
+% the footnote is read.  --karl, 16nov96.
+%
+\gdef\dofootnote{%
+  \insert\footins\bgroup
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \hsize=\pagewidth
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  \smallfonts \rm
+  %
+  % Because we use hanging indentation in footnotes, a @noindent appears
+  % to exdent this text, so make it be a no-op.  makeinfo does not use
+  % hanging indentation so @noindent can still be needed within footnote
+  % text after an @example or the like (not that this is good style).
+  \let\noindent = \relax
+  %
+  % Hang the footnote text off the number.  Use \everypar in case the
+  % footnote extends for more than one paragraph.
+  \everypar = {\hang}%
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+% In case a @footnote appears in a vbox, save the footnote text and create
+% the real \insert just after the vbox finished.  Otherwise, the insertion
+% would be lost.
+% Similarly, if a @footnote appears inside an alignment, save the footnote
+% text to a box and make the \insert when a row of the table is finished.
+% And the same can be done for other insert classes.  --kasal, 16nov03.
+
+% Replace the \insert primitive by a cheating macro.
+% Deeper inside, just make sure that the saved insertions are not spilled
+% out prematurely.
+%
+\def\startsavinginserts{%
+  \ifx \insert\ptexinsert
+    \let\insert\saveinsert
+  \else
+    \let\checkinserts\relax
+  \fi
+}
+
+% This \insert replacement works for both \insert\footins{foo} and
+% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}.
+%
+\def\saveinsert#1{%
+  \edef\next{\noexpand\savetobox \makeSAVEname#1}%
+  \afterassignment\next
+  % swallow the left brace
+  \let\temp =
+}
+\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}}
+\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1}
+
+\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi}
+
+\def\placesaveins#1{%
+  \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname
+    {\box#1}%
+}
+
+% eat @SAVE -- beware, all of them have catcode \other:
+{
+  \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials  %  ;-)
+  \gdef\gobblesave @SAVE{}
+}
+
+% initialization:
+\def\newsaveins #1{%
+  \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}%
+  \next
+}
+\def\newsaveinsX #1{%
+  \csname newbox\endcsname #1%
+  \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts
+    \checksaveins #1}%
+}
+
+% initialize:
+\let\checkinserts\empty
+\newsaveins\footins
+\newsaveins\margin
+
+
+% @image.  We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front.  If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+  % Do not bother showing banner with epsf.tex v2.7k (available in
+  % doc/epsf.tex and on ctan).
+  \def\epsfannounce{\toks0 = }%
+  \input epsf.tex
+\fi
+\closein 1
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+  work.  It is also included in the Texinfo distribution, or you can get
+  it from ftp://tug.org/tex/epsf.tex.}
+%
+\def\image#1{%
+  \ifx\epsfbox\undefined
+    \ifwarnednoepsf \else
+      \errhelp = \noepsfhelp
+      \errmessage{epsf.tex not found, images will be ignored}%
+      \global\warnednoepsftrue
+    \fi
+  \else
+    \imagexxx #1,,,,,\finish
+  \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing this stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+  \catcode`\^^M = 5     % in case we're inside an example
+  \normalturnoffactive  % allow _ et al. in names
+  % If the image is by itself, center it.
+  \ifvmode
+    \imagevmodetrue
+    \nobreak\medskip
+    % Usually we'll have text after the image which will insert
+    % \parskip glue, so insert it here too to equalize the space
+    % above and below.
+    \nobreak\vskip\parskip
+    \nobreak
+  \fi
+  %
+  % Leave vertical mode so that indentation from an enclosing
+  % environment such as @quotation is respected.  On the other hand, if
+  % it's at the top level, we don't want the normal paragraph indentation.
+  \noindent
+  %
+  % Output the image.
+  \ifpdf
+    \dopdfimage{#1}{#2}{#3}%
+  \else
+    % \epsfbox itself resets \epsf?size at each figure.
+    \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+    \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+    \epsfbox{#1.eps}%
+  \fi
+  %
+  \ifimagevmode \medskip \fi  % space after the standalone image
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc.  We don't actually implement floating yet, we always include the
+% float "here".  But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc.  Can't contain commas.  If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label.  Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored.  It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+  \let\thiscaption=\empty
+  \let\thisshortcaption=\empty
+  %
+  % don't lose footnotes inside @float.
+  %
+  % BEWARE: when the floats start float, we have to issue warning whenever an
+  % insert appears inside a float which could possibly float. --kasal, 26may04
+  %
+  \startsavinginserts
+  %
+  % We can't be used inside a paragraph.
+  \par
+  %
+  \vtop\bgroup
+    \def\floattype{#1}%
+    \def\floatlabel{#2}%
+    \def\floatloc{#3}% we do nothing with this yet.
+    %
+    \ifx\floattype\empty
+      \let\safefloattype=\empty
+    \else
+      {%
+        % the floattype might have accents or other special characters,
+        % but we need to use it in a control sequence name.
+        \indexnofonts
+        \turnoffactive
+        \xdef\safefloattype{\floattype}%
+      }%
+    \fi
+    %
+    % If label is given but no type, we handle that as the empty type.
+    \ifx\floatlabel\empty \else
+      % We want each FLOATTYPE to be numbered separately (Figure 1,
+      % Table 1, Figure 2, ...).  (And if no label, no number.)
+      %
+      \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+      \global\advance\floatno by 1
+      %
+      {%
+        % This magic value for \lastsection is output by \setref as the
+        % XREFLABEL-title value.  \xrefX uses it to distinguish float
+        % labels (which have a completely different output format) from
+        % node and anchor labels.  And \xrdef uses it to construct the
+        % lists of floats.
+        %
+        \edef\lastsection{\floatmagic=\safefloattype}%
+        \setref{\floatlabel}{Yfloat}%
+      }%
+    \fi
+    %
+    % start with \parskip glue, I guess.
+    \vskip\parskip
+    %
+    % Don't suppress indentation if a float happens to start a section.
+    \restorefirstparagraphindent
+}
+
+% we have these possibilities:
+% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap
+% @float Foo,lbl & no caption:    Foo 1.1
+% @float Foo & @caption{Cap}:     Foo: Cap
+% @float Foo & no caption:        Foo
+% @float ,lbl & Caption{Cap}:     1.1: Cap
+% @float ,lbl & no caption:       1.1
+% @float & @caption{Cap}:         Cap
+% @float & no caption:
+%
+\def\Efloat{%
+    \let\floatident = \empty
+    %
+    % In all cases, if we have a float type, it comes first.
+    \ifx\floattype\empty \else \def\floatident{\floattype}\fi
+    %
+    % If we have an xref label, the number comes next.
+    \ifx\floatlabel\empty \else
+      \ifx\floattype\empty \else % if also had float type, need tie first.
+        \appendtomacro\floatident{\tie}%
+      \fi
+      % the number.
+      \appendtomacro\floatident{\chaplevelprefix\the\floatno}%
+    \fi
+    %
+    % Start the printed caption with what we've constructed in
+    % \floatident, but keep it separate; we need \floatident again.
+    \let\captionline = \floatident
+    %
+    \ifx\thiscaption\empty \else
+      \ifx\floatident\empty \else
+       \appendtomacro\captionline{: }% had ident, so need a colon between
+      \fi
+      %
+      % caption text.
+      \appendtomacro\captionline{\scanexp\thiscaption}%
+    \fi
+    %
+    % If we have anything to print, print it, with space before.
+    % Eventually this needs to become an \insert.
+    \ifx\captionline\empty \else
+      \vskip.5\parskip
+      \captionline
+      %
+      % Space below caption.
+      \vskip\parskip
+    \fi
+    %
+    % If have an xref label, write the list of floats info.  Do this
+    % after the caption, to avoid chance of it being a breakpoint.
+    \ifx\floatlabel\empty \else
+      % Write the text that goes in the lof to the aux file as
+      % \floatlabel-lof.  Besides \floatident, we include the short
+      % caption if specified, else the full caption if specified, else nothing.
+      {%
+        \atdummies
+        %
+        % since we read the caption text in the macro world, where ^^M
+        % is turned into a normal character, we have to scan it back, so
+        % we don't write the literal three characters "^^M" into the aux file.
+       \scanexp{%
+         \xdef\noexpand\gtemp{%
+           \ifx\thisshortcaption\empty
+             \thiscaption
+           \else
+             \thisshortcaption
+           \fi
+         }%
+       }%
+        \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+         \ifx\gtemp\empty \else : \gtemp \fi}}%
+      }%
+    \fi
+  \egroup  % end of \vtop
+  %
+  % place the captured inserts
+  %
+  % BEWARE: when the floats start floating, we have to issue warning
+  % whenever an insert appears inside a float which could possibly
+  % float. --kasal, 26may04
+  %
+  \checkinserts
+}
+
+% Append the tokens #2 to the definition of macro #1, not expanding either.
+%
+\def\appendtomacro#1#2{%
+  \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+
+% @caption, @shortcaption
+%
+\def\caption{\docaption\thiscaption}
+\def\shortcaption{\docaption\thisshortcaption}
+\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\defcaption#1#2{\egroup \def#1{#2}}
+
+% The parameter is the control sequence identifying the counter we are
+% going to use.  Create it if it doesn't exist and assign it to \floatno.
+\def\getfloatno#1{%
+  \ifx#1\relax
+      % Haven't seen this figure type before.
+      \csname newcount\endcsname #1%
+      %
+      % Remember to reset this floatno at the next chap.
+      \expandafter\gdef\expandafter\resetallfloatnos
+        \expandafter{\resetallfloatnos #1=0 }%
+  \fi
+  \let\floatno#1%
+}
+
+% \setref calls this to get the XREFLABEL-snt value.  We want an @xref
+% to the FLOATLABEL to expand to "Figure 3.1".  We call \setref when we
+% first read the @float command.
+%
+\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}%
+
+% Magic string used for the XREFLABEL-title value, so \xrefX can
+% distinguish floats from other xref types.
+\def\floatmagic{!!float!!}
+
+% #1 is the control sequence we are passed; we expand into a conditional
+% which is true if #1 represents a float ref.  That is, the magic
+% \lastsection value which we \setref above.
+%
+\def\iffloat#1{\expandafter\doiffloat#1==\finish}
+%
+% #1 is (maybe) the \floatmagic string.  If so, #2 will be the
+% (safe) float type for this float.  We set \iffloattype to #2.
+%
+\def\doiffloat#1=#2=#3\finish{%
+  \def\temp{#1}%
+  \def\iffloattype{#2}%
+  \ifx\temp\floatmagic
+}
+
+% @listoffloats FLOATTYPE - print a list of floats like a table of contents.
+%
+\parseargdef\listoffloats{%
+  \def\floattype{#1}% floattype
+  {%
+    % the floattype might have accents or other special characters,
+    % but we need to use it in a control sequence name.
+    \indexnofonts
+    \turnoffactive
+    \xdef\safefloattype{\floattype}%
+  }%
+  %
+  % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE.
+  \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax
+    \ifhavexrefs
+      % if the user said @listoffloats foo but never @float foo.
+      \message{\linenumber No `\safefloattype' floats to list.}%
+    \fi
+  \else
+    \begingroup
+      \leftskip=\tocindent  % indent these entries like a toc
+      \let\do=\listoffloatsdo
+      \csname floatlist\safefloattype\endcsname
+    \endgroup
+  \fi
+}
+
+% This is called on each entry in a list of floats.  We're passed the
+% xref label, in the form LABEL-title, which is how we save it in the
+% aux file.  We strip off the -title and look up \XRLABEL-lof, which
+% has the text we're supposed to typeset here.
+%
+% Figures without xref labels will not be included in the list (since
+% they won't appear in the aux file).
+%
+\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish}
+\def\listoffloatsdoentry#1-title\finish{{%
+  % Can't fully expand XR#1-lof because it can contain anything.  Just
+  % pass the control sequence.  On the other hand, XR#1-pg is just the
+  % page number, and we want to fully expand that so we can get a link
+  % in pdf output.
+  \toksA = \expandafter{\csname XR#1-lof\endcsname}%
+  %
+  % use the same \entry macro we use to generate the TOC and index.
+  \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
+  \writeentry
+}}
+
+
+\message{localization,}
+
+% For single-language documents, @documentlanguage is usually given very
+% early, just after @documentencoding.  Single argument is the language
+% (de) or locale (de_DE) abbreviation.
+%
+{
+  \catcode`\_ = \active
+  \globaldefs=1
+\parseargdef\documentlanguage{\begingroup
+  \let_=\normalunderscore  % normal _ character for filenames
+  \tex % read txi-??.tex file in plain TeX.
+    % Read the file by the name they passed if it exists.
+    \openin 1 txi-#1.tex
+    \ifeof 1
+      \documentlanguagetrywithoutunderscore{#1_\finish}%
+    \else
+      \globaldefs = 1  % everything in the txi-LL files needs to persist
+      \input txi-#1.tex
+    \fi
+    \closein 1
+  \endgroup % end raw TeX
+\endgroup}
+%
+% If they passed de_DE, and txi-de_DE.tex doesn't exist,
+% try txi-de.tex.
+%
+\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{%
+  \openin 1 txi-#1.tex
+  \ifeof 1
+    \errhelp = \nolanghelp
+    \errmessage{Cannot read language file txi-#1.tex}%
+  \else
+    \globaldefs = 1  % everything in the txi-LL files needs to persist
+    \input txi-#1.tex
+  \fi
+  \closein 1
+}
+}% end of special _ catcode
+%
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty.  Maybe you need to install it?  Putting it in the current
+directory should work if nowhere else does.}
+
+% This macro is called from txi-??.tex files; the first argument is the
+% \language name to set (without the "\lang@" prefix), the second and
+% third args are \{left,right}hyphenmin.
+%
+% The language names to pass are determined when the format is built.
+% See the etex.log file created at that time, e.g.,
+% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log.
+%
+% With TeX Live 2008, etex now includes hyphenation patterns for all
+% available languages.  This means we can support hyphenation in
+% Texinfo, at least to some extent.  (This still doesn't solve the
+% accented characters problem.)
+%
+\catcode`@=11
+\def\txisetlanguage#1#2#3{%
+  % do not set the language if the name is undefined in the current TeX.
+  \expandafter\ifx\csname lang@#1\endcsname \relax
+    \message{no patterns for #1}%
+  \else
+    \global\language = \csname lang@#1\endcsname
+  \fi
+  % but there is no harm in adjusting the hyphenmin values regardless.
+  \global\lefthyphenmin = #2\relax
+  \global\righthyphenmin = #3\relax
+}
+
+% Helpers for encodings.
+% Set the catcode of characters 128 through 255 to the specified number.
+%
+\def\setnonasciicharscatcode#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \global\catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+\def\setnonasciicharscatcodenonglobal#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+% @documentencoding sets the definition of non-ASCII characters
+% according to the specified encoding.
+%
+\parseargdef\documentencoding{%
+  % Encoding being declared for the document.
+  \def\declaredencoding{\csname #1.enc\endcsname}%
+  %
+  % Supported encodings: names converted to tokens in order to be able
+  % to compare them with \ifx.
+  \def\ascii{\csname US-ASCII.enc\endcsname}%
+  \def\latnine{\csname ISO-8859-15.enc\endcsname}%
+  \def\latone{\csname ISO-8859-1.enc\endcsname}%
+  \def\lattwo{\csname ISO-8859-2.enc\endcsname}%
+  \def\utfeight{\csname UTF-8.enc\endcsname}%
+  %
+  \ifx \declaredencoding \ascii
+     \asciichardefs
+  %
+  \else \ifx \declaredencoding \lattwo
+     \setnonasciicharscatcode\active
+     \lattwochardefs
+  %
+  \else \ifx \declaredencoding \latone
+     \setnonasciicharscatcode\active
+     \latonechardefs
+  %
+  \else \ifx \declaredencoding \latnine
+     \setnonasciicharscatcode\active
+     \latninechardefs
+  %
+  \else \ifx \declaredencoding \utfeight
+     \setnonasciicharscatcode\active
+     \utfeightchardefs
+  %
+  \else
+    \message{Unknown document encoding #1, ignoring.}%
+  %
+  \fi % utfeight
+  \fi % latnine
+  \fi % latone
+  \fi % lattwo
+  \fi % ascii
+}
+
+% A message to be logged when using a character that isn't available
+% the default font encoding (OT1).
+%
+\def\missingcharmsg#1{\message{Character missing in OT1 encoding: #1.}}
+
+% Take account of \c (plain) vs. \, (Texinfo) difference.
+\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi}
+
+% First, make active non-ASCII characters in order for them to be
+% correctly categorized when TeX reads the replacement text of
+% macros containing the character definitions.
+\setnonasciicharscatcode\active
+%
+% Latin1 (ISO-8859-1) character definitions.
+\def\latonechardefs{%
+  \gdef^^a0{~}
+  \gdef^^a1{\exclamdown}
+  \gdef^^a2{\missingcharmsg{CENT SIGN}}
+  \gdef^^a3{{\pounds}}
+  \gdef^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdef^^a5{\missingcharmsg{YEN SIGN}}
+  \gdef^^a6{\missingcharmsg{BROKEN BAR}}
+  \gdef^^a7{\S}
+  \gdef^^a8{\"{}}
+  \gdef^^a9{\copyright}
+  \gdef^^aa{\ordf}
+  \gdef^^ab{\guillemetleft}
+  \gdef^^ac{$\lnot$}
+  \gdef^^ad{\-}
+  \gdef^^ae{\registeredsymbol}
+  \gdef^^af{\={}}
+  %
+  \gdef^^b0{\textdegree}
+  \gdef^^b1{$\pm$}
+  \gdef^^b2{$^2$}
+  \gdef^^b3{$^3$}
+  \gdef^^b4{\'{}}
+  \gdef^^b5{$\mu$}
+  \gdef^^b6{\P}
+  %
+  \gdef^^b7{$^.$}
+  \gdef^^b8{\cedilla\ }
+  \gdef^^b9{$^1$}
+  \gdef^^ba{\ordm}
+  %
+  \gdef^^bb{\guilletright}
+  \gdef^^bc{$1\over4$}
+  \gdef^^bd{$1\over2$}
+  \gdef^^be{$3\over4$}
+  \gdef^^bf{\questiondown}
+  %
+  \gdef^^c0{\`A}
+  \gdef^^c1{\'A}
+  \gdef^^c2{\^A}
+  \gdef^^c3{\~A}
+  \gdef^^c4{\"A}
+  \gdef^^c5{\ringaccent A}
+  \gdef^^c6{\AE}
+  \gdef^^c7{\cedilla C}
+  \gdef^^c8{\`E}
+  \gdef^^c9{\'E}
+  \gdef^^ca{\^E}
+  \gdef^^cb{\"E}
+  \gdef^^cc{\`I}
+  \gdef^^cd{\'I}
+  \gdef^^ce{\^I}
+  \gdef^^cf{\"I}
+  %
+  \gdef^^d0{\DH}
+  \gdef^^d1{\~N}
+  \gdef^^d2{\`O}
+  \gdef^^d3{\'O}
+  \gdef^^d4{\^O}
+  \gdef^^d5{\~O}
+  \gdef^^d6{\"O}
+  \gdef^^d7{$\times$}
+  \gdef^^d8{\O}
+  \gdef^^d9{\`U}
+  \gdef^^da{\'U}
+  \gdef^^db{\^U}
+  \gdef^^dc{\"U}
+  \gdef^^dd{\'Y}
+  \gdef^^de{\TH}
+  \gdef^^df{\ss}
+  %
+  \gdef^^e0{\`a}
+  \gdef^^e1{\'a}
+  \gdef^^e2{\^a}
+  \gdef^^e3{\~a}
+  \gdef^^e4{\"a}
+  \gdef^^e5{\ringaccent a}
+  \gdef^^e6{\ae}
+  \gdef^^e7{\cedilla c}
+  \gdef^^e8{\`e}
+  \gdef^^e9{\'e}
+  \gdef^^ea{\^e}
+  \gdef^^eb{\"e}
+  \gdef^^ec{\`{\dotless i}}
+  \gdef^^ed{\'{\dotless i}}
+  \gdef^^ee{\^{\dotless i}}
+  \gdef^^ef{\"{\dotless i}}
+  %
+  \gdef^^f0{\dh}
+  \gdef^^f1{\~n}
+  \gdef^^f2{\`o}
+  \gdef^^f3{\'o}
+  \gdef^^f4{\^o}
+  \gdef^^f5{\~o}
+  \gdef^^f6{\"o}
+  \gdef^^f7{$\div$}
+  \gdef^^f8{\o}
+  \gdef^^f9{\`u}
+  \gdef^^fa{\'u}
+  \gdef^^fb{\^u}
+  \gdef^^fc{\"u}
+  \gdef^^fd{\'y}
+  \gdef^^fe{\th}
+  \gdef^^ff{\"y}
+}
+
+% Latin9 (ISO-8859-15) encoding character definitions.
+\def\latninechardefs{%
+  % Encoding is almost identical to Latin1.
+  \latonechardefs
+  %
+  \gdef^^a4{\euro}
+  \gdef^^a6{\v S}
+  \gdef^^a8{\v s}
+  \gdef^^b4{\v Z}
+  \gdef^^b8{\v z}
+  \gdef^^bc{\OE}
+  \gdef^^bd{\oe}
+  \gdef^^be{\"Y}
+}
+
+% Latin2 (ISO-8859-2) character definitions.
+\def\lattwochardefs{%
+  \gdef^^a0{~}
+  \gdef^^a1{\ogonek{A}}
+  \gdef^^a2{\u{}}
+  \gdef^^a3{\L}
+  \gdef^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdef^^a5{\v L}
+  \gdef^^a6{\'S}
+  \gdef^^a7{\S}
+  \gdef^^a8{\"{}}
+  \gdef^^a9{\v S}
+  \gdef^^aa{\cedilla S}
+  \gdef^^ab{\v T}
+  \gdef^^ac{\'Z}
+  \gdef^^ad{\-}
+  \gdef^^ae{\v Z}
+  \gdef^^af{\dotaccent Z}
+  %
+  \gdef^^b0{\textdegree}
+  \gdef^^b1{\ogonek{a}}
+  \gdef^^b2{\ogonek{ }}
+  \gdef^^b3{\l}
+  \gdef^^b4{\'{}}
+  \gdef^^b5{\v l}
+  \gdef^^b6{\'s}
+  \gdef^^b7{\v{}}
+  \gdef^^b8{\cedilla\ }
+  \gdef^^b9{\v s}
+  \gdef^^ba{\cedilla s}
+  \gdef^^bb{\v t}
+  \gdef^^bc{\'z}
+  \gdef^^bd{\H{}}
+  \gdef^^be{\v z}
+  \gdef^^bf{\dotaccent z}
+  %
+  \gdef^^c0{\'R}
+  \gdef^^c1{\'A}
+  \gdef^^c2{\^A}
+  \gdef^^c3{\u A}
+  \gdef^^c4{\"A}
+  \gdef^^c5{\'L}
+  \gdef^^c6{\'C}
+  \gdef^^c7{\cedilla C}
+  \gdef^^c8{\v C}
+  \gdef^^c9{\'E}
+  \gdef^^ca{\ogonek{E}}
+  \gdef^^cb{\"E}
+  \gdef^^cc{\v E}
+  \gdef^^cd{\'I}
+  \gdef^^ce{\^I}
+  \gdef^^cf{\v D}
+  %
+  \gdef^^d0{\DH}
+  \gdef^^d1{\'N}
+  \gdef^^d2{\v N}
+  \gdef^^d3{\'O}
+  \gdef^^d4{\^O}
+  \gdef^^d5{\H O}
+  \gdef^^d6{\"O}
+  \gdef^^d7{$\times$}
+  \gdef^^d8{\v R}
+  \gdef^^d9{\ringaccent U}
+  \gdef^^da{\'U}
+  \gdef^^db{\H U}
+  \gdef^^dc{\"U}
+  \gdef^^dd{\'Y}
+  \gdef^^de{\cedilla T}
+  \gdef^^df{\ss}
+  %
+  \gdef^^e0{\'r}
+  \gdef^^e1{\'a}
+  \gdef^^e2{\^a}
+  \gdef^^e3{\u a}
+  \gdef^^e4{\"a}
+  \gdef^^e5{\'l}
+  \gdef^^e6{\'c}
+  \gdef^^e7{\cedilla c}
+  \gdef^^e8{\v c}
+  \gdef^^e9{\'e}
+  \gdef^^ea{\ogonek{e}}
+  \gdef^^eb{\"e}
+  \gdef^^ec{\v e}
+  \gdef^^ed{\'\i}
+  \gdef^^ee{\^\i}
+  \gdef^^ef{\v d}
+  %
+  \gdef^^f0{\dh}
+  \gdef^^f1{\'n}
+  \gdef^^f2{\v n}
+  \gdef^^f3{\'o}
+  \gdef^^f4{\^o}
+  \gdef^^f5{\H o}
+  \gdef^^f6{\"o}
+  \gdef^^f7{$\div$}
+  \gdef^^f8{\v r}
+  \gdef^^f9{\ringaccent u}
+  \gdef^^fa{\'u}
+  \gdef^^fb{\H u}
+  \gdef^^fc{\"u}
+  \gdef^^fd{\'y}
+  \gdef^^fe{\cedilla t}
+  \gdef^^ff{\dotaccent{}}
+}
+
+% UTF-8 character definitions.
+%
+% This code to support UTF-8 is based on LaTeX's utf8.def, with some
+% changes for Texinfo conventions.  It is included here under the GPL by
+% permission from Frank Mittelbach and the LaTeX team.
+%
+\newcount\countUTFx
+\newcount\countUTFy
+\newcount\countUTFz
+
+\gdef\UTFviiiTwoOctets#1#2{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\endcsname}
+%
+\gdef\UTFviiiThreeOctets#1#2#3{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname}
+%
+\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname}
+
+\gdef\UTFviiiDefined#1{%
+  \ifx #1\relax
+    \message{\linenumber Unicode char \string #1 not defined for Texinfo}%
+  \else
+    \expandafter #1%
+  \fi
+}
+
+\begingroup
+  \catcode`\~13
+  \catcode`\"12
+
+  \def\UTFviiiLoop{%
+    \global\catcode\countUTFx\active
+    \uccode`\~\countUTFx
+    \uppercase\expandafter{\UTFviiiTmp}%
+    \advance\countUTFx by 1
+    \ifnum\countUTFx < \countUTFy
+      \expandafter\UTFviiiLoop
+    \fi}
+
+  \countUTFx = "C2
+  \countUTFy = "E0
+  \def\UTFviiiTmp{%
+    \xdef~{\noexpand\UTFviiiTwoOctets\string~}}
+  \UTFviiiLoop
+
+  \countUTFx = "E0
+  \countUTFy = "F0
+  \def\UTFviiiTmp{%
+    \xdef~{\noexpand\UTFviiiThreeOctets\string~}}
+  \UTFviiiLoop
+
+  \countUTFx = "F0
+  \countUTFy = "F4
+  \def\UTFviiiTmp{%
+    \xdef~{\noexpand\UTFviiiFourOctets\string~}}
+  \UTFviiiLoop
+\endgroup
+
+\begingroup
+  \catcode`\"=12
+  \catcode`\<=12
+  \catcode`\.=12
+  \catcode`\,=12
+  \catcode`\;=12
+  \catcode`\!=12
+  \catcode`\~=13
+
+  \gdef\DeclareUnicodeCharacter#1#2{%
+    \countUTFz = "#1\relax
+    \wlog{\space\space defining Unicode char U+#1 (decimal \the\countUTFz)}%
+    \begingroup
+      \parseXMLCharref
+      \def\UTFviiiTwoOctets##1##2{%
+        \csname u8:##1\string ##2\endcsname}%
+      \def\UTFviiiThreeOctets##1##2##3{%
+        \csname u8:##1\string ##2\string ##3\endcsname}%
+      \def\UTFviiiFourOctets##1##2##3##4{%
+        \csname u8:##1\string ##2\string ##3\string ##4\endcsname}%
+      \expandafter\expandafter\expandafter\expandafter
+       \expandafter\expandafter\expandafter
+       \gdef\UTFviiiTmp{#2}%
+    \endgroup}
+
+  \gdef\parseXMLCharref{%
+    \ifnum\countUTFz < "A0\relax
+      \errhelp = \EMsimple
+      \errmessage{Cannot define Unicode char value < 00A0}%
+    \else\ifnum\countUTFz < "800\relax
+      \parseUTFviiiA,%
+      \parseUTFviiiB C\UTFviiiTwoOctets.,%
+    \else\ifnum\countUTFz < "10000\relax
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiB E\UTFviiiThreeOctets.{,;}%
+    \else
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiA!%
+      \parseUTFviiiB F\UTFviiiFourOctets.{!,;}%
+    \fi\fi\fi
+  }
+
+  \gdef\parseUTFviiiA#1{%
+    \countUTFx = \countUTFz
+    \divide\countUTFz by 64
+    \countUTFy = \countUTFz
+    \multiply\countUTFz by 64
+    \advance\countUTFx by -\countUTFz
+    \advance\countUTFx by 128
+    \uccode `#1\countUTFx
+    \countUTFz = \countUTFy}
+
+  \gdef\parseUTFviiiB#1#2#3#4{%
+    \advance\countUTFz by "#10\relax
+    \uccode `#3\countUTFz
+    \uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
+\endgroup
+
+\def\utfeightchardefs{%
+  \DeclareUnicodeCharacter{00A0}{\tie}
+  \DeclareUnicodeCharacter{00A1}{\exclamdown}
+  \DeclareUnicodeCharacter{00A3}{\pounds}
+  \DeclareUnicodeCharacter{00A8}{\"{ }}
+  \DeclareUnicodeCharacter{00A9}{\copyright}
+  \DeclareUnicodeCharacter{00AA}{\ordf}
+  \DeclareUnicodeCharacter{00AB}{\guillemetleft}
+  \DeclareUnicodeCharacter{00AD}{\-}
+  \DeclareUnicodeCharacter{00AE}{\registeredsymbol}
+  \DeclareUnicodeCharacter{00AF}{\={ }}
+
+  \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}
+  \DeclareUnicodeCharacter{00B4}{\'{ }}
+  \DeclareUnicodeCharacter{00B8}{\cedilla{ }}
+  \DeclareUnicodeCharacter{00BA}{\ordm}
+  \DeclareUnicodeCharacter{00BB}{\guillemetright}
+  \DeclareUnicodeCharacter{00BF}{\questiondown}
+
+  \DeclareUnicodeCharacter{00C0}{\`A}
+  \DeclareUnicodeCharacter{00C1}{\'A}
+  \DeclareUnicodeCharacter{00C2}{\^A}
+  \DeclareUnicodeCharacter{00C3}{\~A}
+  \DeclareUnicodeCharacter{00C4}{\"A}
+  \DeclareUnicodeCharacter{00C5}{\AA}
+  \DeclareUnicodeCharacter{00C6}{\AE}
+  \DeclareUnicodeCharacter{00C7}{\cedilla{C}}
+  \DeclareUnicodeCharacter{00C8}{\`E}
+  \DeclareUnicodeCharacter{00C9}{\'E}
+  \DeclareUnicodeCharacter{00CA}{\^E}
+  \DeclareUnicodeCharacter{00CB}{\"E}
+  \DeclareUnicodeCharacter{00CC}{\`I}
+  \DeclareUnicodeCharacter{00CD}{\'I}
+  \DeclareUnicodeCharacter{00CE}{\^I}
+  \DeclareUnicodeCharacter{00CF}{\"I}
+
+  \DeclareUnicodeCharacter{00D0}{\DH}
+  \DeclareUnicodeCharacter{00D1}{\~N}
+  \DeclareUnicodeCharacter{00D2}{\`O}
+  \DeclareUnicodeCharacter{00D3}{\'O}
+  \DeclareUnicodeCharacter{00D4}{\^O}
+  \DeclareUnicodeCharacter{00D5}{\~O}
+  \DeclareUnicodeCharacter{00D6}{\"O}
+  \DeclareUnicodeCharacter{00D8}{\O}
+  \DeclareUnicodeCharacter{00D9}{\`U}
+  \DeclareUnicodeCharacter{00DA}{\'U}
+  \DeclareUnicodeCharacter{00DB}{\^U}
+  \DeclareUnicodeCharacter{00DC}{\"U}
+  \DeclareUnicodeCharacter{00DD}{\'Y}
+  \DeclareUnicodeCharacter{00DE}{\TH}
+  \DeclareUnicodeCharacter{00DF}{\ss}
+
+  \DeclareUnicodeCharacter{00E0}{\`a}
+  \DeclareUnicodeCharacter{00E1}{\'a}
+  \DeclareUnicodeCharacter{00E2}{\^a}
+  \DeclareUnicodeCharacter{00E3}{\~a}
+  \DeclareUnicodeCharacter{00E4}{\"a}
+  \DeclareUnicodeCharacter{00E5}{\aa}
+  \DeclareUnicodeCharacter{00E6}{\ae}
+  \DeclareUnicodeCharacter{00E7}{\cedilla{c}}
+  \DeclareUnicodeCharacter{00E8}{\`e}
+  \DeclareUnicodeCharacter{00E9}{\'e}
+  \DeclareUnicodeCharacter{00EA}{\^e}
+  \DeclareUnicodeCharacter{00EB}{\"e}
+  \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}
+  \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}
+  \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}
+  \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}
+
+  \DeclareUnicodeCharacter{00F0}{\dh}
+  \DeclareUnicodeCharacter{00F1}{\~n}
+  \DeclareUnicodeCharacter{00F2}{\`o}
+  \DeclareUnicodeCharacter{00F3}{\'o}
+  \DeclareUnicodeCharacter{00F4}{\^o}
+  \DeclareUnicodeCharacter{00F5}{\~o}
+  \DeclareUnicodeCharacter{00F6}{\"o}
+  \DeclareUnicodeCharacter{00F8}{\o}
+  \DeclareUnicodeCharacter{00F9}{\`u}
+  \DeclareUnicodeCharacter{00FA}{\'u}
+  \DeclareUnicodeCharacter{00FB}{\^u}
+  \DeclareUnicodeCharacter{00FC}{\"u}
+  \DeclareUnicodeCharacter{00FD}{\'y}
+  \DeclareUnicodeCharacter{00FE}{\th}
+  \DeclareUnicodeCharacter{00FF}{\"y}
+
+  \DeclareUnicodeCharacter{0100}{\=A}
+  \DeclareUnicodeCharacter{0101}{\=a}
+  \DeclareUnicodeCharacter{0102}{\u{A}}
+  \DeclareUnicodeCharacter{0103}{\u{a}}
+  \DeclareUnicodeCharacter{0104}{\ogonek{A}}
+  \DeclareUnicodeCharacter{0105}{\ogonek{a}}
+  \DeclareUnicodeCharacter{0106}{\'C}
+  \DeclareUnicodeCharacter{0107}{\'c}
+  \DeclareUnicodeCharacter{0108}{\^C}
+  \DeclareUnicodeCharacter{0109}{\^c}
+  \DeclareUnicodeCharacter{0118}{\ogonek{E}}
+  \DeclareUnicodeCharacter{0119}{\ogonek{e}}
+  \DeclareUnicodeCharacter{010A}{\dotaccent{C}}
+  \DeclareUnicodeCharacter{010B}{\dotaccent{c}}
+  \DeclareUnicodeCharacter{010C}{\v{C}}
+  \DeclareUnicodeCharacter{010D}{\v{c}}
+  \DeclareUnicodeCharacter{010E}{\v{D}}
+
+  \DeclareUnicodeCharacter{0112}{\=E}
+  \DeclareUnicodeCharacter{0113}{\=e}
+  \DeclareUnicodeCharacter{0114}{\u{E}}
+  \DeclareUnicodeCharacter{0115}{\u{e}}
+  \DeclareUnicodeCharacter{0116}{\dotaccent{E}}
+  \DeclareUnicodeCharacter{0117}{\dotaccent{e}}
+  \DeclareUnicodeCharacter{011A}{\v{E}}
+  \DeclareUnicodeCharacter{011B}{\v{e}}
+  \DeclareUnicodeCharacter{011C}{\^G}
+  \DeclareUnicodeCharacter{011D}{\^g}
+  \DeclareUnicodeCharacter{011E}{\u{G}}
+  \DeclareUnicodeCharacter{011F}{\u{g}}
+
+  \DeclareUnicodeCharacter{0120}{\dotaccent{G}}
+  \DeclareUnicodeCharacter{0121}{\dotaccent{g}}
+  \DeclareUnicodeCharacter{0124}{\^H}
+  \DeclareUnicodeCharacter{0125}{\^h}
+  \DeclareUnicodeCharacter{0128}{\~I}
+  \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}
+  \DeclareUnicodeCharacter{012A}{\=I}
+  \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}
+  \DeclareUnicodeCharacter{012C}{\u{I}}
+  \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}
+
+  \DeclareUnicodeCharacter{0130}{\dotaccent{I}}
+  \DeclareUnicodeCharacter{0131}{\dotless{i}}
+  \DeclareUnicodeCharacter{0132}{IJ}
+  \DeclareUnicodeCharacter{0133}{ij}
+  \DeclareUnicodeCharacter{0134}{\^J}
+  \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}
+  \DeclareUnicodeCharacter{0139}{\'L}
+  \DeclareUnicodeCharacter{013A}{\'l}
+
+  \DeclareUnicodeCharacter{0141}{\L}
+  \DeclareUnicodeCharacter{0142}{\l}
+  \DeclareUnicodeCharacter{0143}{\'N}
+  \DeclareUnicodeCharacter{0144}{\'n}
+  \DeclareUnicodeCharacter{0147}{\v{N}}
+  \DeclareUnicodeCharacter{0148}{\v{n}}
+  \DeclareUnicodeCharacter{014C}{\=O}
+  \DeclareUnicodeCharacter{014D}{\=o}
+  \DeclareUnicodeCharacter{014E}{\u{O}}
+  \DeclareUnicodeCharacter{014F}{\u{o}}
+
+  \DeclareUnicodeCharacter{0150}{\H{O}}
+  \DeclareUnicodeCharacter{0151}{\H{o}}
+  \DeclareUnicodeCharacter{0152}{\OE}
+  \DeclareUnicodeCharacter{0153}{\oe}
+  \DeclareUnicodeCharacter{0154}{\'R}
+  \DeclareUnicodeCharacter{0155}{\'r}
+  \DeclareUnicodeCharacter{0158}{\v{R}}
+  \DeclareUnicodeCharacter{0159}{\v{r}}
+  \DeclareUnicodeCharacter{015A}{\'S}
+  \DeclareUnicodeCharacter{015B}{\'s}
+  \DeclareUnicodeCharacter{015C}{\^S}
+  \DeclareUnicodeCharacter{015D}{\^s}
+  \DeclareUnicodeCharacter{015E}{\cedilla{S}}
+  \DeclareUnicodeCharacter{015F}{\cedilla{s}}
+
+  \DeclareUnicodeCharacter{0160}{\v{S}}
+  \DeclareUnicodeCharacter{0161}{\v{s}}
+  \DeclareUnicodeCharacter{0162}{\cedilla{t}}
+  \DeclareUnicodeCharacter{0163}{\cedilla{T}}
+  \DeclareUnicodeCharacter{0164}{\v{T}}
+
+  \DeclareUnicodeCharacter{0168}{\~U}
+  \DeclareUnicodeCharacter{0169}{\~u}
+  \DeclareUnicodeCharacter{016A}{\=U}
+  \DeclareUnicodeCharacter{016B}{\=u}
+  \DeclareUnicodeCharacter{016C}{\u{U}}
+  \DeclareUnicodeCharacter{016D}{\u{u}}
+  \DeclareUnicodeCharacter{016E}{\ringaccent{U}}
+  \DeclareUnicodeCharacter{016F}{\ringaccent{u}}
+
+  \DeclareUnicodeCharacter{0170}{\H{U}}
+  \DeclareUnicodeCharacter{0171}{\H{u}}
+  \DeclareUnicodeCharacter{0174}{\^W}
+  \DeclareUnicodeCharacter{0175}{\^w}
+  \DeclareUnicodeCharacter{0176}{\^Y}
+  \DeclareUnicodeCharacter{0177}{\^y}
+  \DeclareUnicodeCharacter{0178}{\"Y}
+  \DeclareUnicodeCharacter{0179}{\'Z}
+  \DeclareUnicodeCharacter{017A}{\'z}
+  \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}
+  \DeclareUnicodeCharacter{017C}{\dotaccent{z}}
+  \DeclareUnicodeCharacter{017D}{\v{Z}}
+  \DeclareUnicodeCharacter{017E}{\v{z}}
+
+  \DeclareUnicodeCharacter{01C4}{D\v{Z}}
+  \DeclareUnicodeCharacter{01C5}{D\v{z}}
+  \DeclareUnicodeCharacter{01C6}{d\v{z}}
+  \DeclareUnicodeCharacter{01C7}{LJ}
+  \DeclareUnicodeCharacter{01C8}{Lj}
+  \DeclareUnicodeCharacter{01C9}{lj}
+  \DeclareUnicodeCharacter{01CA}{NJ}
+  \DeclareUnicodeCharacter{01CB}{Nj}
+  \DeclareUnicodeCharacter{01CC}{nj}
+  \DeclareUnicodeCharacter{01CD}{\v{A}}
+  \DeclareUnicodeCharacter{01CE}{\v{a}}
+  \DeclareUnicodeCharacter{01CF}{\v{I}}
+
+  \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}
+  \DeclareUnicodeCharacter{01D1}{\v{O}}
+  \DeclareUnicodeCharacter{01D2}{\v{o}}
+  \DeclareUnicodeCharacter{01D3}{\v{U}}
+  \DeclareUnicodeCharacter{01D4}{\v{u}}
+
+  \DeclareUnicodeCharacter{01E2}{\={\AE}}
+  \DeclareUnicodeCharacter{01E3}{\={\ae}}
+  \DeclareUnicodeCharacter{01E6}{\v{G}}
+  \DeclareUnicodeCharacter{01E7}{\v{g}}
+  \DeclareUnicodeCharacter{01E8}{\v{K}}
+  \DeclareUnicodeCharacter{01E9}{\v{k}}
+
+  \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}
+  \DeclareUnicodeCharacter{01F1}{DZ}
+  \DeclareUnicodeCharacter{01F2}{Dz}
+  \DeclareUnicodeCharacter{01F3}{dz}
+  \DeclareUnicodeCharacter{01F4}{\'G}
+  \DeclareUnicodeCharacter{01F5}{\'g}
+  \DeclareUnicodeCharacter{01F8}{\`N}
+  \DeclareUnicodeCharacter{01F9}{\`n}
+  \DeclareUnicodeCharacter{01FC}{\'{\AE}}
+  \DeclareUnicodeCharacter{01FD}{\'{\ae}}
+  \DeclareUnicodeCharacter{01FE}{\'{\O}}
+  \DeclareUnicodeCharacter{01FF}{\'{\o}}
+
+  \DeclareUnicodeCharacter{021E}{\v{H}}
+  \DeclareUnicodeCharacter{021F}{\v{h}}
+
+  \DeclareUnicodeCharacter{0226}{\dotaccent{A}}
+  \DeclareUnicodeCharacter{0227}{\dotaccent{a}}
+  \DeclareUnicodeCharacter{0228}{\cedilla{E}}
+  \DeclareUnicodeCharacter{0229}{\cedilla{e}}
+  \DeclareUnicodeCharacter{022E}{\dotaccent{O}}
+  \DeclareUnicodeCharacter{022F}{\dotaccent{o}}
+
+  \DeclareUnicodeCharacter{0232}{\=Y}
+  \DeclareUnicodeCharacter{0233}{\=y}
+  \DeclareUnicodeCharacter{0237}{\dotless{j}}
+
+  \DeclareUnicodeCharacter{02DB}{\ogonek{ }}
+
+  \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}
+  \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}
+  \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}
+  \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}
+  \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}
+  \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}
+  \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}
+  \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}
+  \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}
+  \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}
+  \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}
+  \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}
+
+  \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}
+  \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}
+
+  \DeclareUnicodeCharacter{1E20}{\=G}
+  \DeclareUnicodeCharacter{1E21}{\=g}
+  \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}
+  \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}
+  \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}
+  \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}
+  \DeclareUnicodeCharacter{1E26}{\"H}
+  \DeclareUnicodeCharacter{1E27}{\"h}
+
+  \DeclareUnicodeCharacter{1E30}{\'K}
+  \DeclareUnicodeCharacter{1E31}{\'k}
+  \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}
+  \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}
+  \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}
+  \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}
+  \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}
+  \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}
+  \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}
+  \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}
+  \DeclareUnicodeCharacter{1E3E}{\'M}
+  \DeclareUnicodeCharacter{1E3F}{\'m}
+
+  \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}
+  \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}
+  \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}
+  \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}
+  \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}
+  \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}
+  \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}
+  \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}
+  \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}
+  \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}
+
+  \DeclareUnicodeCharacter{1E54}{\'P}
+  \DeclareUnicodeCharacter{1E55}{\'p}
+  \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}
+  \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}
+  \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}
+  \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}
+  \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}
+  \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}
+  \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}
+  \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}
+
+  \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}
+  \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}
+  \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}
+  \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}
+  \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}
+  \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}
+  \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}
+  \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}
+  \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}
+  \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}
+
+  \DeclareUnicodeCharacter{1E7C}{\~V}
+  \DeclareUnicodeCharacter{1E7D}{\~v}
+  \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}
+  \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}
+
+  \DeclareUnicodeCharacter{1E80}{\`W}
+  \DeclareUnicodeCharacter{1E81}{\`w}
+  \DeclareUnicodeCharacter{1E82}{\'W}
+  \DeclareUnicodeCharacter{1E83}{\'w}
+  \DeclareUnicodeCharacter{1E84}{\"W}
+  \DeclareUnicodeCharacter{1E85}{\"w}
+  \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}
+  \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}
+  \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}
+  \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}
+  \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}
+  \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}
+  \DeclareUnicodeCharacter{1E8C}{\"X}
+  \DeclareUnicodeCharacter{1E8D}{\"x}
+  \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}
+  \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}
+
+  \DeclareUnicodeCharacter{1E90}{\^Z}
+  \DeclareUnicodeCharacter{1E91}{\^z}
+  \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}
+  \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}
+  \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}
+  \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}
+  \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}
+  \DeclareUnicodeCharacter{1E97}{\"t}
+  \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}
+  \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}
+
+  \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}
+  \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}
+
+  \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}
+  \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}
+  \DeclareUnicodeCharacter{1EBC}{\~E}
+  \DeclareUnicodeCharacter{1EBD}{\~e}
+
+  \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}
+  \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}
+  \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}
+  \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}
+
+  \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}
+  \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}
+
+  \DeclareUnicodeCharacter{1EF2}{\`Y}
+  \DeclareUnicodeCharacter{1EF3}{\`y}
+  \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}
+
+  \DeclareUnicodeCharacter{1EF8}{\~Y}
+  \DeclareUnicodeCharacter{1EF9}{\~y}
+
+  \DeclareUnicodeCharacter{2013}{--}
+  \DeclareUnicodeCharacter{2014}{---}
+  \DeclareUnicodeCharacter{2018}{\quoteleft}
+  \DeclareUnicodeCharacter{2019}{\quoteright}
+  \DeclareUnicodeCharacter{201A}{\quotesinglbase}
+  \DeclareUnicodeCharacter{201C}{\quotedblleft}
+  \DeclareUnicodeCharacter{201D}{\quotedblright}
+  \DeclareUnicodeCharacter{201E}{\quotedblbase}
+  \DeclareUnicodeCharacter{2022}{\bullet}
+  \DeclareUnicodeCharacter{2026}{\dots}
+  \DeclareUnicodeCharacter{2039}{\guilsinglleft}
+  \DeclareUnicodeCharacter{203A}{\guilsinglright}
+  \DeclareUnicodeCharacter{20AC}{\euro}
+
+  \DeclareUnicodeCharacter{2192}{\expansion}
+  \DeclareUnicodeCharacter{21D2}{\result}
+
+  \DeclareUnicodeCharacter{2212}{\minus}
+  \DeclareUnicodeCharacter{2217}{\point}
+  \DeclareUnicodeCharacter{2261}{\equiv}
+}% end of \utfeightchardefs
+
+
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+   \relax
+}
+
+% Make non-ASCII characters printable again for compatibility with
+% existing Texinfo documents that may use them, even without declaring a
+% document encoding.
+%
+\setnonasciicharscatcode \other
+
+
+\message{formatting,}
+
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be so finicky about underfull hboxes, either.
+\hbadness = 2000
+
+% Following George Bush, get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+  \ifx\emergencystretch\thisisundefined
+    % Allow us to assign to \emergencystretch anyway.
+    \def\emergencystretch{\dimen0}%
+  \else
+    \emergencystretch = .15\hsize
+  \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth;
+% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip;
+% 7) physical page height; 8) physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading.  The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+  \voffset = #3\relax
+  \topskip = #6\relax
+  \splittopskip = \topskip
+  %
+  \vsize = #1\relax
+  \advance\vsize by \topskip
+  \outervsize = \vsize
+  \advance\outervsize by 2\topandbottommargin
+  \pageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \pagewidth = \hsize
+  %
+  \normaloffset = #4\relax
+  \bindingoffset = #5\relax
+  %
+  \ifpdf
+    \pdfpageheight #7\relax
+    \pdfpagewidth #8\relax
+    % if we don't reset these, they will remain at "1 true in" of
+    % whatever layout pdftex was dumped with.
+    \pdfhorigin = 1 true in
+    \pdfvorigin = 1 true in
+  \fi
+  %
+  \setleading{\textleading}
+  %
+  \parindent = \defaultparindent
+  \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % If page is nothing but text, make it come out even.
+  \internalpagesizes{607.2pt}{6in}% that's 46 lines
+                    {\voffset}{.25in}%
+                    {\bindingoffset}{36pt}%
+                    {11in}{8.5in}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.25 trim size.
+\def\smallbook{{\globaldefs = 1
+  \parskip = 2pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.5in}{5in}%
+                    {-.2in}{0in}%
+                    {\bindingoffset}{16pt}%
+                    {9.25in}{7in}%
+  %
+  \lispnarrowing = 0.3in
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = .5cm
+}}
+
+% Use @smallerbook to reset parameters for 6x9 trim size.
+% (Just testing, parameters still in flux.)
+\def\smallerbook{{\globaldefs = 1
+  \parskip = 1.5pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.4in}{4.8in}%
+                    {-.2in}{-.4in}%
+                    {0pt}{14pt}%
+                    {9in}{6in}%
+  %
+  \lispnarrowing = 0.25in
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = .4cm
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % Double-side printing via postscript on Laserjet 4050
+  % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm.
+  % To change the settings for a different printer or situation, adjust
+  % \normaloffset until the front-side and back-side texts align.  Then
+  % do the same for \bindingoffset.  You can set these for testing in
+  % your texinfo source file like this:
+  % @tex
+  % \global\normaloffset = -6mm
+  % \global\bindingoffset = 10mm
+  % @end tex
+  \internalpagesizes{673.2pt}{160mm}% that's 51 lines
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{44pt}%
+                    {297mm}{210mm}%
+  %
+  \tolerance = 700
+  \hfuzz = 1pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = 5mm
+}}
+
+% Use @afivepaper to print on European A5 paper.
+% From romildo@urano.iceb.ufop.br, 2 July 2000.
+% He also recommends making @example and @lisp be small.
+\def\afivepaper{{\globaldefs = 1
+  \parskip = 2pt plus 1pt minus 0.1pt
+  \textleading = 12.5pt
+  %
+  \internalpagesizes{160mm}{120mm}%
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{8pt}%
+                    {210mm}{148mm}%
+  %
+  \lispnarrowing = 0.2in
+  \tolerance = 800
+  \hfuzz = 1.2pt
+  \contentsrightmargin = 0pt
+  \defbodyindent = 2mm
+  \tableindent = 12mm
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.
+\def\afourlatex{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{237mm}{150mm}%
+                    {\voffset}{4.6mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  %
+  % Must explicitly reset to 0 because we call \afourpaper.
+  \globaldefs = 0
+}}
+
+% Use @afourwide to print on A4 paper in landscape format.
+\def\afourwide{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{241mm}{165mm}%
+                    {\voffset}{-2.95mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  \globaldefs = 0
+}}
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\parseargdef\pagesizes{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+  \globaldefs = 1
+  %
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{\textleading}%
+  %
+  \dimen0 = #1\relax
+  \advance\dimen0 by \voffset
+  %
+  \dimen2 = \hsize
+  \advance\dimen2 by \normaloffset
+  %
+  \internalpagesizes{#1}{\hsize}%
+                    {\voffset}{\normaloffset}%
+                    {\bindingoffset}{44pt}%
+                    {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+
+\message{and turning on texinfo input format.}
+
+% DEL is a comment character, in case @c does not suffice.
+\catcode`\^^? = 14
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other
+\catcode`\~=\other
+\catcode`\^=\other
+\catcode`\_=\other
+\catcode`\|=\other
+\catcode`\<=\other
+\catcode`\>=\other
+\catcode`\+=\other
+\catcode`\$=\other
+\def\normaldoublequote{"}
+\def\normaltilde{~}
+\def\normalcaret{^}
+\def\normalunderscore{_}
+\def\normalverticalbar{|}
+\def\normalless{<}
+\def\normalgreater{>}
+\def\normalplus{+}
+\def\normaldollar{$}%$ font-lock fix
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font.  Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts.  But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Turn off all special characters except @
+% (and those which the user can use as if they were ordinary).
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active
+\def~{{\tt\char126}}
+\chardef\hat=`\^
+\catcode`\^=\active
+\def^{{\tt \hat}}
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+\let\realunder=_
+% Subroutine for the previous macro.
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+
+\catcode`\|=\active
+\def|{{\tt\char124}}
+\chardef \less=`\<
+\catcode`\<=\active
+\def<{{\tt \less}}
+\chardef \gtr=`\>
+\catcode`\>=\active
+\def>{{\tt \gtr}}
+\catcode`\+=\active
+\def+{{\tt \char 43}}
+\catcode`\$=\active
+\def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have \everyjob (or @setfilename) turn them on.
+% \otherifyactive is called near the end of this file.
+\def\otherifyactive{\catcode`+=\other \catcode`\_=\other}
+
+% Used sometimes to turn off (effectively) the active characters even after
+% parsing them.
+\def\turnoffactive{%
+  \normalturnoffactive
+  \otherbackslash
+}
+
+\catcode`\@=0
+
+% \backslashcurfont outputs one backslash character in current font,
+% as in \char`\\.
+\global\chardef\backslashcurfont=`\\
+\global\let\rawbackslashxx=\backslashcurfont  % let existing .??s files work
+
+% \realbackslash is an actual character `\' with catcode other, and
+% \doublebackslash is two of them (for the pdf outlines).
+{\catcode`\\=\other @gdef@realbackslash{\} @gdef@doublebackslash{\\}}
+
+% In texinfo, backslash is an active character; it prints the backslash
+% in fixed width font.
+\catcode`\\=\active
+@def@normalbackslash{{@tt@backslashcurfont}}
+% On startup, @fixbackslash assigns:
+%  @let \ = @normalbackslash
+
+% \rawbackslash defines an active \ to do \backslashcurfont.
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other.
+@gdef@rawbackslash{@let\=@backslashcurfont}
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.
+%
+@def@normalturnoffactive{%
+  @let\=@normalbackslash
+  @let"=@normaldoublequote
+  @let~=@normaltilde
+  @let^=@normalcaret
+  @let_=@normalunderscore
+  @let|=@normalverticalbar
+  @let<=@normalless
+  @let>=@normalgreater
+  @let+=@normalplus
+  @let$=@normaldollar %$ font-lock fix
+  @markupsetuplqdefault
+  @markupsetuprqdefault
+  @unsepspaces
+}
+
+% Make _ and + \other characters, temporarily.
+% This is canceled by @fixbackslash.
+@otherifyactive
+
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+%
+@gdef@eatinput input texinfo{@fixbackslash}
+@global@let\ = @eatinput
+
+% On the other hand, perhaps the file did not have a `\input texinfo'. Then
+% the first `\' in the file would cause an error. This macro tries to fix
+% that, assuming it is called before the first `\' could plausibly occur.
+% Also turn back on active characters that might appear in the input
+% file name, in case not using a pre-dumped format.
+%
+@gdef@fixbackslash{%
+  @ifx\@eatinput @let\ = @normalbackslash @fi
+  @catcode`+=@active
+  @catcode`@_=@active
+}
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These look ok in all fonts, so just make them not special.
+@catcode`@& = @other
+@catcode`@# = @other
+@catcode`@% = @other
+
+@c Finally, make ` and ' active, so that txicodequoteundirected and
+@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}.  If we
+@c don't make ` and ' active, @code will not get them as active chars.
+@c Do this last of all since we use ` in the previous @catcode assignments.
+@catcode`@'=@active
+@catcode`@`=@active
+@markupsetuplqdefault
+@markupsetuprqdefault
+
+@c Local variables:
+@c eval: (add-hook 'write-file-hooks 'time-stamp)
+@c page-delimiter: "^\\\\message"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@ignore
+   arch-tag: e1b36e32-c96e-4135-a41a-0b2efa2ea115
+@end ignore
diff --git a/tty.c b/tty.c
new file mode 100644 (file)
index 0000000..25950f2
--- /dev/null
+++ b/tty.c
@@ -0,0 +1,222 @@
+/*  Copyright 1997,2001,2002,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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
+#define FAIL (-1)
+#define DONE 0
+static Terminal in_orig;
+
+/*--------------- Signal Handler routines -------------*/
+
+static void tty_time_out(int dummy)
+{
+       int exit_code;
+       signal(SIGALRM, SIG_IGN);
+       if(tty && need_tty_reset)
+               restore_tty (&in_orig); 
+#ifdef future
+       if (fail_on_timeout)
+               exit_code=SHFAIL;
+       else {
+               if (default_choice && mode_defined) {
+                       if (yes_no) {
+                               if ('Y' == default_choice)
+                                       exit_code=0;
+                               else
+                                       exit_code=1;
+                       } else
+                               exit_code=default_choice-minc+1;
+               } else
+                       exit_code=DONE;
+       }
+#else
+       exit_code = DONE;
+#endif
+       exit(exit_code);
+}
+
+static void cleanup_tty(void)
+{ 
+       if(tty && need_tty_reset) {
+               restore_tty (&in_orig);
+               setup_signal();
+       }
+}
+
+static void set_raw_tty(int mode)
+{
+       Terminal in_raw;
+
+       if(mode != tty_mode && mode != -1) {
+               if(!handlerIsSet) {
+                       /* Determine existing TTY settings */
+                       gtty (STDIN, &in_orig);
+                       need_tty_reset = 1;
+
+                       /* Restore original TTY settings on exit */
+                       atexit(cleanup_tty);
+                       handlerIsSet = 1;
+               }
+
+
+               setup_signal();
+               signal (SIGALRM, tty_time_out);
+       
+               /* Change STDIN settings to raw */
+
+               gtty (STDIN, &in_raw);
+               if(mode) {
+#ifdef USE_SGTTY
+                       in_raw.sg_flags |= CBREAK;
+#else
+                       in_raw.c_lflag &= ~ICANON;
+                       in_raw.c_cc[VMIN]=1;
+                       in_raw.c_cc[VTIME]=0;                   
+#endif
+                       stty (STDIN, &in_raw);
+               } else {
+#ifdef USE_SGTTY
+                       in_raw.sg_flags &= ~CBREAK;
+#else
+                       in_raw.c_lflag |= ICANON;
+#endif
+                       stty (STDIN, &in_raw);
+               }
+               tty_mode = mode;
+               discard_input(STDIN);
+       }
+}
+#endif
+
+FILE *opentty(int mode)
+{
+       if(notty)
+               return NULL;
+       if (tty == NULL) {
+               ttyfd = open("/dev/tty", O_RDONLY);
+               if(ttyfd >= 0) {
+                       tty = fdopen(ttyfd, "r");
+               }
+       }
+       if  (tty == NULL){
+               if ( !isatty(0) ){
+                       notty = 1;
+                       return NULL;
+               }
+               ttyfd = 0;
+               tty = stdin;
+       }
+#ifdef USE_RAWTERM
+       if(mtools_raw_tty)
+               set_raw_tty(mode);
+#endif
+       return tty;
+}
+
+int ask_confirmation(const char *format, ...)
+{
+       char ans[10];
+       va_list ap;
+
+       if(!opentty(-1))
+               return 0;
+
+       while (1) {
+               va_start(ap, format);
+               vfprintf(stderr, format, ap);
+               va_end(ap);
+               fflush(stderr);
+               fflush(opentty(-1));
+               if (mtools_raw_tty) {
+                       ans[0] = fgetc(opentty(1));
+                       fputs("\n", stderr);
+               } else {
+                       if(fgets(ans,9, opentty(0)) == NULL)
+                               /* Treat end-of-file as no */
+                               ans[0] = 'n';
+               }
+               if (ans[0] == 'y' || ans[0] == 'Y')
+                       return 0;
+               if (ans[0] == 'n' || ans[0] == 'N')
+                       return -1;
+       }
+}
diff --git a/unixdir.c b/unixdir.c
new file mode 100644 (file)
index 0000000..ea16caa
--- /dev/null
+++ b/unixdir.c
@@ -0,0 +1,166 @@
+/*  Copyright 1998-2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 */
+};
+
+#ifdef HAVE_FCHDIR
+#define FCHDIR_MODE
+#endif
+
+int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); 
+int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, 
+             int follow_dir_link);
+
+int unix_dir_loop(Stream_t *Stream, MainParam_t *mp)
+{
+       DeclareThis(Dir_t);
+       struct dirent *entry;
+       char *newName;
+       int ret=0;
+
+#ifdef FCHDIR_MODE
+       int fd;
+
+       fd = open(".", O_RDONLY);
+       if(chdir(This->pathname) < 0) {
+               fprintf(stderr, "Could not chdir into %s (%s)\n",
+                       This->pathname, strerror(errno));
+               return -1;
+       }
+#endif
+       while((entry=readdir(This->dir)) != NULL) {
+               if(got_signal)
+                       break;
+               if(isSpecial(entry->d_name))
+                       continue;
+#ifndef FCHDIR_MODE
+               newName = malloc(strlen(This->pathname) + 1 + 
+                                strlen(entry->d_name) + 1);
+               if(!newName) {
+                       ret = ERROR_ONE;
+                       break;
+               }
+               strcpy(newName, This->pathname);
+               strcat(newName, "/");
+               strcat(newName, entry->d_name);
+#else
+               newName = entry->d_name;
+#endif
+               ret |= unix_loop(Stream, mp, newName, 0);
+#ifndef FCHDIR_MODE
+               free(newName);
+#endif
+       }
+#ifdef FCHDIR_MODE
+       if(fchdir(fd) < 0)
+               perror("Could not chdir back to ..");
+       close(fd);
+#endif
+       return ret;
+}
+
+Stream_t *OpenDir(Stream_t *Stream, const char *filename)
+{
+       Dir_t *This;
+
+       This = New(Dir_t);
+       
+       This->Class = &DirClass;
+       This->Next = 0;
+       This->refs = 1;
+       This->Buffer = 0;
+       This->pathname = malloc(strlen(filename)+1);
+       if(This->pathname == NULL) {
+               Free(This);
+               return NULL;
+       }
+       strcpy(This->pathname, filename);
+
+       if(MT_STAT(filename, &This->statbuf) < 0) {
+               Free(This->pathname);
+               Free(This);
+               return NULL;
+       }
+
+       This->dir = opendir(filename);
+       if(!This->dir) {
+               Free(This->pathname);
+               Free(This);
+               return NULL;
+       }
+
+       return (Stream_t *) This;
+}
diff --git a/version.texi b/version.texi
new file mode 100644 (file)
index 0000000..395eb53
--- /dev/null
@@ -0,0 +1,3 @@
+@set EDITION 4.0.12
+@set VERSION 4.0.12
+@set UPDATED November 2009
diff --git a/vfat.c b/vfat.c
new file mode 100644 (file)
index 0000000..05a26a1
--- /dev/null
+++ b/vfat.c
@@ -0,0 +1,826 @@
+/*  Copyright 1995 David C. Niemi
+ *  Copyright 1996-2003,2005,2007-2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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 "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 */
+}
+
+
+static dirCacheEntry_t *vfat_lookup_loop_common(doscp_t *cp,
+                                               direntry_t *direntry,
+                                               dirCache_t *cache,
+                                               int lookForFreeSpace,
+                                               int *io_error)
+{
+       wchar_t newfile[13];
+       int initpos = direntry->entry + 1;
+       struct vfat_state vfat;
+       wchar_t *longname;
+       int error;
+
+       /* not yet cached */
+       *io_error = 0;
+       clear_vfat(&vfat);
+       while(1) {
+               ++direntry->entry;
+               if(!dir_read(direntry, &error)){
+                       if(error) {
+                           *io_error = error;
+                           return NULL;
+                       }
+                       addFreeEntry(cache, initpos, direntry->entry);
+                       return addEndEntry(cache, direntry->entry);
+               }
+               
+               if (direntry->dir.name[0] == '\0'){
+                               /* the end of the directory */
+                       if(lookForFreeSpace)
+                               continue;
+                       return addEndEntry(cache, direntry->entry);
+               }
+               if(direntry->dir.name[0] != DELMARK &&
+                  direntry->dir.attr == 0x0f)
+                       parse_vses(direntry, &vfat);
+               else
+                       /* the main entry */
+                       break;
+       }
+       
+       /* If we get here, it's a short name FAT entry, maybe erased.
+        * thus we should make sure that the vfat structure will be
+        * cleared before the next loop run */
+       
+       /* deleted file */
+       if (direntry->dir.name[0] == DELMARK) {
+               return addFreeEntry(cache, initpos,
+                                   direntry->entry + 1);
+       }
+
+       check_vfat(&vfat, &direntry->dir);
+       if(!vfat.present)
+               vfat.subentries = 0;
+
+       /* mark space between last entry and this one as free */
+       addFreeEntry(cache, initpos,
+                    direntry->entry - vfat.subentries);
+
+       if (direntry->dir.attr & 0x8){
+               /* Read entry as a label */
+               wchar_t *ptr = newfile;
+               ptr += dos_to_wchar(cp, direntry->dir.name, ptr, 8);
+               ptr += dos_to_wchar(cp, direntry->dir.ext, ptr, 3);
+               *ptr = '\0';
+       } else
+               unix_name(cp,
+                         direntry->dir.name,
+                         direntry->dir.ext,
+                         direntry->dir.Case,
+                         newfile);
+
+       if(vfat.present)
+               longname = vfat.name;
+       else
+               longname = 0;
+
+       return addUsedEntry(cache, direntry->entry - vfat.subentries,
+                           direntry->entry + 1, longname,
+                           newfile, &direntry->dir);
+}
+
+static __inline__ dirCacheEntry_t *vfat_lookup_loop_for_read(doscp_t *cp,
+                                                            direntry_t *direntry,
+                                                            dirCache_t *cache,
+                                                            int *io_error)
+{
+       int initpos = direntry->entry + 1;
+       dirCacheEntry_t *dce;
+
+       *io_error = 0;
+       dce = cache->entries[initpos];
+       if(dce) {
+               direntry->entry = dce->endSlot - 1;
+               return dce;
+       } else {
+               return vfat_lookup_loop_common(cp,
+                                              direntry, cache, 0, io_error);
+       }
+}
+
+
+typedef enum result_t {
+       RES_NOMATCH,
+       RES_MATCH,
+       RES_END,
+       RES_ERROR
+} result_t;
+
+
+/*
+ * 0 does not match
+ * 1 matches
+ * 2 end
+ */
+static result_t checkNameForMatch(struct direntry_t *direntry,
+                                 dirCacheEntry_t *dce,
+                                 const wchar_t *filename,
+                                 int length,
+                                 int flags)
+{
+       switch(dce->type) {
+               case DCET_FREE:
+                       return RES_NOMATCH;
+               case DCET_END:
+                       return RES_END;
+               case DCET_USED:
+                       break;
+               default:
+                       fprintf(stderr, "Unexpected entry type %d\n",
+                               dce->type);
+                       return RES_ERROR;
+       }
+
+       direntry->dir = dce->dir;
+
+       /* make sure the entry is of an accepted type */
+       if((direntry->dir.attr & 0x8) && !(flags & ACCEPT_LABEL))
+               return RES_NOMATCH;
+
+
+       /*---------- multiple files ----------*/
+       if(!((flags & MATCH_ANY) ||
+            (dce->longName &&
+             match(dce->longName, filename, direntry->name, 0, length)) ||
+            match(dce->shortName, filename, direntry->name, 1, length))) {
+
+               return RES_NOMATCH;
+       }
+
+       /* entry of non-requested type, has to come after name
+        * checking because of clash handling */
+       if(IS_DIR(direntry) && !(flags & ACCEPT_DIR)) {
+               if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) {
+                       char tmp[4*13+1];
+                       wchar_to_native(dce->shortName,tmp,13);
+                       fprintf(stderr, "Skipping \"%s\", is a directory\n",
+                               tmp);
+               }
+               return RES_NOMATCH;
+       }
+
+       if(!(direntry->dir.attr & (ATTR_LABEL | ATTR_DIR)) &&
+          !(flags & ACCEPT_PLAIN)) {
+               if(!(flags & (ACCEPT_LABEL|MATCH_ANY|NO_MSG))) {
+                       char tmp[4*13+1];
+                       wchar_to_native(dce->shortName,tmp,13);
+                       fprintf(stderr,
+                               "Skipping \"%s\", is not a directory\n",
+                               tmp);
+               }
+               return RES_NOMATCH;
+       }
+
+       return RES_MATCH;
+}
+
+
+/*
+ * vfat_lookup looks for filenames in directory dir.
+ * if a name if found, it is returned in outname
+ * if applicable, the file is opened and its stream is returned in File
+ */
+
+int vfat_lookup(direntry_t *direntry, const char *filename, int length,
+               int flags, char *shortname, char *longname)
+{
+       dirCacheEntry_t *dce;
+       result_t result;
+       dirCache_t *cache;
+       int io_error;
+       wchar_t wfilename[MAX_VNAMELEN+1];
+       wchar_t *wfilenamep = wfilename;
+       doscp_t *cp = GET_DOSCONVERT(direntry->Dir);
+
+       if(length == -1 && filename)
+               length = strlen(filename);
+
+       if(filename != NULL)
+               length = native_to_wchar(filename, wfilename, MAX_VNAMELEN,
+                                        filename+length, 0);
+       else {
+               wfilenamep = NULL;
+               length = 0;
+       }
+
+       if (direntry->entry == -2)
+               return -1;
+
+       cache = allocDirCache(direntry->Dir, direntry->entry+1);
+       if(!cache) {
+               fprintf(stderr, "Out of memory error in vfat_lookup [0]\n");
+               exit(1);
+       }
+
+       do {
+               dce = vfat_lookup_loop_for_read(cp, direntry, cache, &io_error);
+               if(!dce) {
+                       if (io_error)
+                               return -2;
+                       fprintf(stderr, "Out of memory error in vfat_lookup\n");
+                       exit(1);
+               }
+               result = checkNameForMatch(direntry, dce,
+                                          wfilename,
+                                          length, flags);
+       } while(result == RES_NOMATCH);
+
+       if(result == RES_MATCH){
+               if(longname){
+                       if(dce->longName)
+                               wchar_to_native(dce->longName,
+                                               longname, MAX_VNAMELEN);
+                       else
+                               *longname ='\0';
+               }
+               if(shortname)
+                       wchar_to_native(dce->shortName, shortname, 12);
+               direntry->beginSlot = dce->beginSlot;
+               direntry->endSlot = dce->endSlot-1;
+               return 0; /* file found */
+       } else {
+               direntry->entry = -2;
+               return -1; /* no file found */
+       }
+}
+
+static __inline__ dirCacheEntry_t *vfat_lookup_loop_for_insert(doscp_t *cp,
+                                                              direntry_t *direntry,
+                                                              int initpos,
+                                                              dirCache_t *cache)
+{
+       dirCacheEntry_t *dce;
+       int io_error;
+
+       dce = cache->entries[initpos];
+       if(dce && dce->type != DCET_END) {
+               return dce;
+       } else {
+               direntry->entry = initpos - 1;
+               dce = vfat_lookup_loop_common(cp,
+                                             direntry, cache, 1, &io_error);
+               if(!dce) {
+                       if (io_error) {
+                               return NULL;
+                       }
+                       fprintf(stderr,
+                               "Out of memory error in vfat_lookup_loop\n");
+                       exit(1);
+               }
+               return cache->entries[initpos];
+       }
+}
+
+static void accountFreeSlots(struct scan_state *ssp, dirCacheEntry_t *dce)
+{
+       if(ssp->got_slots)
+               return;
+
+       if(ssp->free_end != dce->beginSlot) {
+               ssp->free_start = dce->beginSlot;
+       }
+       ssp->free_end = dce->endSlot;
+
+       if(ssp->free_end - ssp->free_start >= ssp->size_needed) {
+               ssp->got_slots = 1;
+               ssp->slot = ssp->free_start + ssp->size_needed - 1;
+       }
+}
+
+static void clear_scan(wchar_t *longname, int use_longname,
+                      struct scan_state *s)
+{
+       s->shortmatch = s->longmatch = s->slot = -1;
+       s->free_end = s->got_slots = s->free_start = 0;
+
+       if (use_longname)
+               s->size_needed = 1 +
+                       (wcslen(longname) + VSE_NAMELEN - 1)/VSE_NAMELEN;
+       else
+                s->size_needed = 1;
+}
+
+/* lookup_for_insert replaces the old scandir function.  It directly
+ * calls into vfat_lookup_loop, thus eliminating the overhead of the
+ * normal vfat_lookup
+ */
+int lookupForInsert(Stream_t *Dir,
+                   struct direntry_t *direntry,
+                   dos_name_t *dosname,
+                   char *longname,
+                   struct scan_state *ssp,
+                   int ignore_entry,
+                   int source_entry,
+                   int pessimisticShortRename,
+                   int use_longname)
+{
+       direntry_t entry;
+       int ignore_match;
+       dirCacheEntry_t *dce;
+       dirCache_t *cache;
+       int pos; /* position _before_ the next answered entry */
+       wchar_t shortName[13];
+       wchar_t wlongname[MAX_VNAMELEN+1];
+       doscp_t *cp = GET_DOSCONVERT(Dir);
+
+       native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, 0, 0);
+       clear_scan(wlongname, use_longname, ssp);
+
+       ignore_match = (ignore_entry == -2 );
+
+       initializeDirentry(&entry, Dir);
+       ssp->match_free = 0;
+
+       /* hash bitmap of already encountered names.  Speeds up batch appends
+        * to huge directories, because in the best case, we only need to scan
+        * the new entries rather than the whole directory */
+       cache = allocDirCache(Dir, 1);
+       if(!cache) {
+               fprintf(stderr, "Out of memory error in lookupForInsert\n");
+               exit(1);
+       }
+
+       if(!ignore_match)
+               unix_name(cp, dosname->base, dosname->ext, 0, shortName);
+
+       pos = cache->nrHashed;
+       if(source_entry >= 0 ||
+          (pos && isHashed(cache, wlongname))) {
+               pos = 0;
+       } else if(pos && !ignore_match && isHashed(cache, shortName)) {
+               if(pessimisticShortRename) {
+                       ssp->shortmatch = -2;
+                       return 1;
+               }
+               pos = 0;
+       } else if(growDirCache(cache, pos) < 0) {
+               fprintf(stderr, "Out of memory error in vfat_looup [0]\n");
+               exit(1);
+       }
+       do {
+               dce = vfat_lookup_loop_for_insert(cp, &entry, pos, cache);
+               switch(dce->type) {
+                       case DCET_FREE:
+                               accountFreeSlots(ssp, dce);
+                               break;
+                       case DCET_USED:
+                               if(!(dce->dir.attr & 0x8) &&
+                                  (signed int)dce->endSlot-1 == source_entry)
+                                  accountFreeSlots(ssp, dce);
+
+                               /* labels never match, neither does the
+                                * ignored entry */
+                               if( (dce->dir.attr & 0x8) ||
+                                   ((signed int)dce->endSlot-1==ignore_entry))
+                                       break;
+
+                               /* check long name */
+                               if((dce->longName &&
+                                   !wcscasecmp(dce->longName, wlongname)) ||
+                                  (dce->shortName &&
+                                   !wcscasecmp(dce->shortName, wlongname))) {
+                                       ssp->longmatch = dce->endSlot - 1;
+                                       /* long match is a reason for
+                                        * immediate stop */
+                                       direntry->beginSlot = dce->beginSlot;
+                                       direntry->endSlot = dce->endSlot-1;
+                                       return 1;
+                               }
+
+                               /* Long name or not, always check for
+                                * short name match */
+                               if (!ignore_match &&
+                                   !wcscasecmp(shortName, dce->shortName))
+                                       ssp->shortmatch = dce->endSlot - 1;
+                               break;
+                       case DCET_END:
+                               break;
+               }
+               pos = dce->endSlot;
+       } while(dce->type != DCET_END);
+       if (ssp->shortmatch > -1)
+               return 1;
+       ssp->max_entry = dce->beginSlot;
+       if (ssp->got_slots)
+               return 6;       /* Success */
+
+       /* Need more room.  Can we grow the directory? */
+       if(!isRootDir(Dir))             
+               return 5;       /* OK, try to grow the directory */
+
+       fprintf(stderr, "No directory slots\n");
+       return -1;
+}
+
+
+
+/* End vfat.c */
diff --git a/vfat.h b/vfat.h
new file mode 100644 (file)
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 (file)
index 0000000..f0db3b3
--- /dev/null
+++ b/xdf_io.c
@@ -0,0 +1,710 @@
+/*  Copyright 1994,1996-2003,2005,2007,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <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;
+
+
+struct {
+  unsigned char track_size;
+  unsigned int track0_size:7;
+  unsigned int rootskip:1;
+  unsigned char rate;
+  sector_map_t map[9];
+} xdf_table[]= {
+  {
+    19, 16, 0, 0,
+    {  {0,3},  {0,6},  {1,2},  {0,2},  {1,6},  {1,3},  {0,0} }
+  },
+  {
+    23, 19, 0, 0,
+    {  {0,3},  {0,4},  {1,6},  {0,2},  {1,2},  {0,6},  {1,4},  {1,3},  {0,0} }
+  },
+  {
+    46, 37, 1, 0x43,
+    {  {0,3},  {0,4},  {0,5},  {0,7},  {1,3},  {1,4},  {1,5},  {1,7},  {0,0} }
+  },
+  {
+    24, 20, 1, 0,
+    {  {0,5},  {1,6},  {0,6},  {1, 5} }
+  },
+  {
+    48, 41, 1, 0,
+    {  {0,6},  {1,7},  {0,7},  {1, 6} }
+  }
+};
+
+#define NUMBER(x) (sizeof(x)/sizeof(x[0]))
+
+typedef struct {
+       unsigned char begin; /* where it begins */
+       unsigned char end;       
+       unsigned char sector;
+       unsigned char sizecode;
+
+       unsigned int dirty:1;
+       unsigned int phantom:2;
+       unsigned int valid:1;
+       unsigned int head:1;
+} TrackMap_t;
+
+
+
+typedef struct Xdf_t {
+       Class_t *Class;
+       int refs;
+       Stream_t *Next;
+       Stream_t *Buffer;
+
+       int fd;
+       char *buffer;
+       
+       int current_track;
+       
+       sector_map_t *map;
+
+       int track_size;
+       int track0_size;
+       int sector_size;
+       int FatSize;
+       int RootDirSize;
+       TrackMap_t *track_map;
+
+       unsigned char last_sector;
+       unsigned char rate;
+
+       unsigned int stretch:1;
+       unsigned int rootskip:1;
+       signed  int drive:4;
+} Xdf_t;
+
+typedef struct {
+       unsigned char head;
+       unsigned char sector;
+       unsigned char ptr;
+} Compactify_t;
+
+
+static int analyze_reply(RawRequest_t *raw_cmd, int do_print)
+{
+       int ret, bytes, newbytes;
+
+       bytes = 0;
+       while(1) {
+               ret = analyze_one_reply(raw_cmd, &newbytes, do_print);
+               bytes += newbytes;
+               switch(ret) {
+                       case 0:
+                               return bytes;
+                       case 1:
+                               raw_cmd++;
+                               break;
+                       case -1:
+                               if(bytes)
+                                       return bytes;
+                               else
+                                       return 0;
+               }
+       }
+}
+                               
+
+
+static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr,
+                   const char *message, int retries)
+{
+       int j;
+       int ret=-1;
+       
+       if(!nr)
+               return 0;
+       for (j=0; j< retries; j++){
+               switch(send_one_cmd(fd, raw_cmd, message)) {
+                       case -1:
+                               return -1;
+                       case 1:
+                               j++;
+                               continue;
+                       case 0:
+                               break;
+               }
+               if((ret=analyze_reply(raw_cmd, j)) > 0)
+                       return ret; /* ok */
+       }
+       if(j > 1 && j == retries) {
+               fprintf(stderr,"Too many errors, giving up\n");
+               return 0;
+       }
+       return -1;
+}
+
+
+
+#define REC (This->track_map[ptr])
+#define END(x) (This->track_map[(x)].end)
+#define BEGIN(x) (This->track_map[(x)].begin)
+
+static int add_to_request(Xdf_t *This, int ptr,
+                         RawRequest_t *request, int *nr,
+                         int direction, Compactify_t *compactify)
+{
+#if 0
+       if(direction == MT_WRITE) {
+               printf("writing %d: %d %d %d %d [%02x]\n", 
+                      ptr, This->current_track,
+                      REC.head, REC.sector, REC.sizecode,
+                      *(This->buffer + ptr * This->sector_size));
+       } else
+                       printf(" load %d.%d\n", This->current_track, ptr);
+#endif
+       if(REC.phantom) {
+               if(direction== MT_READ)                 
+                       memset(This->buffer + ptr * This->sector_size, 0,
+                              128 << REC.sizecode);
+               return 0;
+       }
+       
+       if(*nr &&
+          RR_SIZECODE(request+(*nr)-1) == REC.sizecode &&         
+          compactify->head == REC.head &&
+          compactify->ptr + 1 == ptr &&
+          compactify->sector +1 == REC.sector) {
+               RR_SETSIZECODE(request+(*nr)-1, REC.sizecode);
+       } else {
+               if(*nr)
+                       RR_SETCONT(request+(*nr)-1);
+               RR_INIT(request+(*nr));
+               RR_SETDRIVE(request+(*nr), This->drive);
+               RR_SETRATE(request+(*nr), This->rate);
+               RR_SETTRACK(request+(*nr), This->current_track);
+               RR_SETPTRACK(request+(*nr), 
+                            This->current_track << This->stretch);
+               RR_SETHEAD(request+(*nr), REC.head);
+               RR_SETSECTOR(request+(*nr), REC.sector);
+               RR_SETSIZECODE(request+(*nr), REC.sizecode);
+               RR_SETDIRECTION(request+(*nr), direction);
+               RR_SETDATA(request+(*nr),
+                          (caddr_t) This->buffer + ptr * This->sector_size);
+               (*nr)++;
+       }
+       compactify->ptr = ptr;
+       compactify->head = REC.head;
+       compactify->sector = REC.sector;
+       return 0;
+}
+
+
+static void add_to_request_if_invalid(Xdf_t *This, int ptr,
+                                    RawRequest_t *request, int *nr,
+                                    Compactify_t *compactify)
+{
+       if(!REC.valid)
+               add_to_request(This, ptr, request, nr, MT_READ, compactify);
+
+}
+
+
+static void adjust_bounds(Xdf_t *This, off_t *begin, off_t *end)
+{
+       /* translates begin and end from byte to sectors */
+       *begin = *begin / This->sector_size;
+       *end = (*end + This->sector_size - 1) / This->sector_size;
+}
+
+
+static __inline__ int try_flush_dirty(Xdf_t *This)
+{
+       int ptr, nr, bytes;
+       RawRequest_t requests[100];
+       Compactify_t compactify;
+
+       if(This->current_track < 0)
+               return 0;
+       
+       nr = 0;
+       for(ptr=0; ptr < This->last_sector; ptr=REC.end)
+               if(REC.dirty)
+                       add_to_request(This, ptr,
+                                      requests, &nr,
+                                      MT_WRITE, &compactify);
+#if 1
+       bytes = send_cmd(This->fd,requests, nr, "writing", 4);
+       if(bytes < 0)
+               return bytes;
+#else
+       bytes = 0xffffff;
+#endif
+       for(ptr=0; ptr < This->last_sector; ptr=REC.end)
+               if(REC.dirty) {
+                       if(bytes >= REC.end - REC.begin) {
+                               bytes -= REC.end - REC.begin;
+                               REC.dirty = 0;
+                       } else
+                               return 1;
+               }
+       return 0;
+}
+
+
+
+static int flush_dirty(Xdf_t *This)
+{      
+       int ret;
+
+       while((ret = try_flush_dirty(This))) {
+               if(ret < 0)                    
+                       return ret;
+       }
+       return 0;
+}
+
+
+static int load_data(Xdf_t *This, off_t begin, off_t end, int retries)
+{
+       int ptr, nr, bytes;
+       RawRequest_t requests[100];
+       Compactify_t compactify;
+
+       adjust_bounds(This, &begin, &end);
+       
+       ptr = begin;
+       nr = 0;
+       for(ptr=REC.begin; ptr < end ; ptr = REC.end)
+               add_to_request_if_invalid(This, ptr, requests, &nr,
+                                         &compactify);
+       bytes = send_cmd(This->fd,requests, nr, "reading", retries);
+       if(bytes < 0)
+               return bytes;
+       ptr = begin;
+       for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
+               if(!REC.valid) {
+                       if(bytes >= REC.end - REC.begin) {
+                               bytes -= REC.end - REC.begin;
+                               REC.valid = 1;
+                       } else if(ptr > begin)
+                               return ptr * This->sector_size;
+                       else
+                               return -1;
+               }
+       }
+       return end * This->sector_size;
+}
+
+static void mark_dirty(Xdf_t *This, off_t begin, off_t end)
+{
+       int ptr;
+
+       adjust_bounds(This, &begin, &end);
+       
+       ptr = begin;
+       for(ptr=REC.begin; ptr < end ; ptr = REC.end) {
+               REC.valid = 1;
+               if(!REC.phantom)
+                       REC.dirty = 1;
+       }
+}
+
+
+static int load_bounds(Xdf_t *This, off_t begin, off_t end)
+{
+       off_t lbegin, lend;
+       int endp1, endp2;
+
+       lbegin = begin;
+       lend = end;
+
+       adjust_bounds(This, &lbegin, &lend);    
+
+       if(begin != BEGIN(lbegin) * This->sector_size &&
+          end != BEGIN(lend) * This->sector_size &&
+          lend < END(END(lbegin)))
+               /* contiguous end & begin, load them in one go */
+               return load_data(This, begin, end, 4);
+
+       if(begin != BEGIN(lbegin) * This->sector_size) {
+               endp1 = load_data(This, begin, begin, 4);
+               if(endp1 < 0)
+                       return endp1;
+       }
+
+       if(end != BEGIN(lend) * This->sector_size) {
+               endp2 = load_data(This, end, end, 4);
+               if(endp2 < 0)
+                       return BEGIN(lend) * This->sector_size;
+       }
+       return lend * This->sector_size;
+}
+
+
+static int fill_t0(Xdf_t *This, int ptr, int size, int *sector, int *head)
+{
+       int n;
+
+       for(n = 0; n < size; ptr++,n++) {
+               REC.head = *head;
+               REC.sector = *sector + 129;
+               REC.phantom = 0;
+               (*sector)++;
+               if(!*head && *sector >= This->track0_size - 8) {
+                       *sector = 0;
+                       *head = 1;
+               }
+       }
+       return ptr;
+}
+
+
+static int fill_phantoms(Xdf_t *This, int ptr, int size)
+{
+       int n;
+
+       for(n = 0; n < size; ptr++,n++)
+               REC.phantom = 1;
+       return ptr;
+}
+
+static void decompose(Xdf_t *This, int where, int len, off_t *begin, 
+                                         off_t *end, int boot)
+{
+       int ptr, track;
+       sector_map_t *map;
+       int lbegin, lend;
+       
+       track = where / This->track_size / 1024;
+       
+       *begin = where - track * This->track_size * 1024;
+       *end = where + len - track * This->track_size * 1024;
+       maximize(*end, This->track_size * 1024);
+
+       if(This->current_track == track && !boot)
+               /* already OK, return immediately */
+               return;
+       if(!boot)
+               flush_dirty(This);
+       This->current_track = track;
+
+       if(track) {
+               for(ptr=0, map=This->map; map->size; map++) {
+                       /* iterate through all sectors */
+                       lbegin = ptr;
+                       lend = ptr + (128 << map->size) / This->sector_size;
+                       for( ; ptr < lend ; ptr++) {
+                               REC.begin = lbegin;
+                               REC.end = lend;
+                               
+                               REC.head = map->head;
+                               REC.sector = map->size + 128;
+                               REC.sizecode = map->size;
+                               
+                               REC.valid = 0;
+                               REC.dirty = 0;
+                               REC.phantom = 0;
+                       }
+               }
+               REC.begin = REC.end = ptr;
+       } else {
+               int sector, head;
+
+               head = 0;
+               sector = 0;
+
+               for(ptr=boot; ptr < 2 * This->track_size; ptr++) {
+                       REC.begin = ptr;
+                       REC.end = ptr+1;
+                       
+                       REC.sizecode = 2;
+                       
+                       REC.valid = 0;
+                       REC.dirty = 0;
+               }
+
+               /* boot & 1st fat */
+               ptr=fill_t0(This, 0, 1 + This->FatSize, &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);
+       if(len2 < 0)
+               return len2;
+       len2 -= begin;
+       maximize(len, len2);
+       memcpy(buf, This->buffer + begin, len);
+       return end - begin;
+}
+
+static int xdf_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
+{      
+       off_t begin, end;
+       size_t len2;
+       DeclareThis(Xdf_t);
+
+       decompose(This, truncBytes32(where), len, &begin, &end, 0);
+       len2 = load_bounds(This, begin, end);
+       if(len2 < 0)
+               return len2;
+       maximize(end, (off_t)len2);
+       len2 -= begin;
+       maximize(len, (off_t)len2);
+       memcpy(This->buffer + begin, buf, len);
+       mark_dirty(This, begin, end);
+       return end - begin;
+}
+
+static int xdf_flush(Stream_t *Stream)
+{
+       DeclareThis(Xdf_t);
+
+       return flush_dirty(This);       
+}
+
+static int xdf_free(Stream_t *Stream)
+{
+       DeclareThis(Xdf_t);
+       Free(This->track_map);
+       Free(This->buffer);
+       return close(This->fd);
+}
+
+
+static int check_geom(struct device *dev, int media, union bootsector *boot)
+{
+       int sect;
+
+       if(media >= 0xfc && media <= 0xff)
+               return 1; /* old DOS */
+
+       if (!IS_MFORMAT_ONLY(dev)) {
+           if(compare(dev->sectors, 19) &&
+              compare(dev->sectors, 23) &&
+              compare(dev->sectors, 24) &&
+              compare(dev->sectors, 46) &&
+              compare(dev->sectors, 48))
+               return 1;
+           
+           /* check against contradictory info from configuration file */
+           if(compare(dev->heads, 2))
+               return 1;
+       }
+
+       /* check against info from boot */
+       if(boot) {
+               sect = WORD(nsect);
+               if((sect != 19 && sect != 23 && sect != 24 &&
+                   sect != 46 && sect != 48) ||
+                  (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)) || 
+                  WORD(nheads) !=2)
+                   return 1;
+       }
+       return 0;
+}
+
+static void set_geom(union bootsector *boot, struct device *dev)
+{
+       /* fill in config info to be returned to user */
+       dev->heads = 2;
+       dev->use_2m = 0xff;
+       if(boot) {
+               dev->sectors = WORD(nsect);
+               if(WORD(psect))
+                       dev->tracks = WORD(psect) / dev->sectors / 2;
+       }
+}
+
+static int config_geom(Stream_t *Stream, struct device *dev, 
+                      struct device *orig_dev, int media,
+                      union bootsector *boot)
+{
+       if(check_geom(dev, media, boot))
+               return 1;
+       set_geom(boot,dev);
+       return 0;
+}
+
+static Class_t XdfClass = {
+       xdf_read, 
+       xdf_write, 
+       xdf_flush, 
+       xdf_free, 
+       config_geom, 
+       0, /* get_data */
+       0 /* pre-allocate */
+};
+
+Stream_t *XdfOpen(struct device *dev, char *name,
+                 int mode, char *errmsg, struct xdf_info *info)
+{
+       Xdf_t *This;
+       off_t begin, end;
+       union bootsector *boot;
+       unsigned int type;
+
+       if(dev && (!SHOULD_USE_XDF(dev) || check_geom(dev, 0, 0)))
+               return NULL;
+
+       This = New(Xdf_t);
+       if (!This)
+               return NULL;
+
+       This->Class = &XdfClass;
+       This->sector_size = 512;
+       This->stretch = 0;
+
+       precmd(dev);
+       This->fd = open(name, mode | dev->mode | O_EXCL | O_NDELAY);
+       if(This->fd < 0) {
+#ifdef HAVE_SNPRINTF
+               snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno));
+#else
+               sprintf(errmsg,"xdf floppy: open: \"%s\"", strerror(errno));
+#endif
+               goto exit_0;
+       }
+       closeExec(This->fd);
+
+       This->drive = GET_DRIVE(This->fd);
+       if(This->drive < 0)
+               goto exit_1;
+
+       /* allocate buffer */
+       This->buffer = (char *) malloc(96 * 512);
+       if (!This->buffer)
+               goto exit_1;
+
+       This->current_track = -1;
+       This->track_map = (TrackMap_t *)
+               calloc(96, sizeof(TrackMap_t));
+       if(!This->track_map)
+               goto exit_2;
+
+       /* lock the device on writes */
+       if (lock_dev(This->fd, mode == O_RDWR, dev)) {
+#ifdef HAVE_SNPRINTF
+               snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:", 
+                       dev->name);
+#else
+               sprintf(errmsg,"xdf floppy: device \"%s\" busy:", 
+                       dev->name);
+#endif
+               goto exit_3;
+       }
+
+       /* Before reading the boot sector, assume dummy values suitable
+        * for reading at least the boot sector */
+       This->track_size = 11;
+       This->track0_size = 6;
+       This->rate = 0;
+       This->FatSize = 9;
+       This->RootDirSize = 1;
+       decompose(This, 0, 512, &begin, &end, 0);
+       if (load_data(This, 0, 1, 1) < 0 ) {
+               This->rate = 0x43;
+               if(load_data(This, 0, 1, 1) < 0)
+                       goto exit_3;
+       }
+
+       boot = (union bootsector *) This->buffer;
+       This->FatSize = WORD(fatlen);
+       This->RootDirSize = WORD(dirents)/16;
+       This->track_size = WORD(nsect);
+       for(type=0; type < NUMBER(xdf_table); type++) {
+               if(xdf_table[type].track_size == This->track_size) {
+                       This->map = xdf_table[type].map;
+                       This->track0_size = xdf_table[type].track0_size;
+                       This->rootskip = xdf_table[type].rootskip;
+                       This->rate = xdf_table[type].rate;
+                       break;
+               }
+       }
+       if(type == NUMBER(xdf_table))
+               goto exit_3;
+
+       if(info) {
+               info->RootDirSize = This->RootDirSize;
+               info->FatSize = This->FatSize;
+               info->BadSectors = 5;
+       }
+       decompose(This, 0, 512, &begin, &end, 1);
+
+       This->refs = 1;
+       This->Next = 0;
+       This->Buffer = 0;
+       if(dev)
+               set_geom(boot, dev);
+       return (Stream_t *) This;
+
+exit_3:
+       Free(This->track_map);
+exit_2:
+       Free(This->buffer);
+exit_1:
+       close(This->fd);
+exit_0:
+       Free(This);
+       return NULL;
+}
+
+#endif
+
+/* Algorithms can't be patented */
+
diff --git a/xdf_io.h b/xdf_io.h
new file mode 100644 (file)
index 0000000..db5d52c
--- /dev/null
+++ b/xdf_io.h
@@ -0,0 +1,33 @@
+#ifndef MTOOLS_XDFIO_H
+#define MTOOLS_XDFIO_H
+
+/*  Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ *  This file is part of mtools.
+ *
+ *  Mtools is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Mtools is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msdos.h"
+#include "stream.h"
+
+struct xdf_info {
+  int FatSize;
+  int RootDirSize;
+  int BadSectors;
+};
+
+Stream_t *XdfOpen(struct device *dev, char *name,
+                 int mode, char *errmsg, struct xdf_info *info);
+
+#endif