summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2013-01-09 19:04:18 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2013-01-09 19:04:18 +0000
commitaf0c3edb9706e470b45a9c8dd6debcc9e2d543c2 (patch)
tree340ee9c0f1b504061d4206d05d9fcc265c1302eb
downloadmtools-af0c3edb9706e470b45a9c8dd6debcc9e2d543c2.tar.gz
-rw-r--r--COPYING674
-rw-r--r--INSTALL30
-rw-r--r--Makefile.Be49
-rw-r--r--Makefile.in335
-rw-r--r--NEWS1094
-rw-r--r--README76
-rw-r--r--README.BEBOX126
-rw-r--r--Release.notes230
-rw-r--r--aclocal.m434
-rw-r--r--buffer.c387
-rw-r--r--buffer.h28
-rwxr-xr-xbuildMingw.sh16
-rw-r--r--byte_dword.h63
-rw-r--r--charsetConv.c428
-rw-r--r--cleanconfig20
-rw-r--r--codepage.h42
-rw-r--r--codepages.c117
-rw-r--r--config.c806
-rwxr-xr-xconfig.guess1533
-rw-r--r--config.h.Be56
-rw-r--r--config.h.in406
-rwxr-xr-xconfig.sub1693
-rwxr-xr-xconfigure7234
-rw-r--r--configure-stamp0
-rw-r--r--configure.in395
-rw-r--r--copyfile.c73
-rw-r--r--debian/changelog164
-rw-r--r--debian/compat1
-rw-r--r--debian/control31
-rw-r--r--debian/floppyd.files1
-rw-r--r--debian/floppyd.manpages2
-rw-r--r--debian/mcheck.133
-rw-r--r--debian/mtools.conf25
-rw-r--r--debian/mtools.dirs1
-rw-r--r--debian/mtools.files1
-rw-r--r--debian/mtools.manpages33
-rwxr-xr-xdebian/rules64
-rw-r--r--devices.c1109
-rw-r--r--devices.h187
-rw-r--r--dirCache.c367
-rw-r--r--dirCache.h53
-rw-r--r--dirCacheP.h14
-rw-r--r--directory.c143
-rw-r--r--direntry.c166
-rw-r--r--expand.c108
-rw-r--r--fat.c997
-rw-r--r--fat_free.c72
-rw-r--r--fat_size_calculation.tex228
-rw-r--r--file.c723
-rw-r--r--file.h28
-rw-r--r--file_name.c220
-rw-r--r--file_name.h44
-rw-r--r--file_read.c55
-rw-r--r--filter.c173
-rw-r--r--floppyd.1255
-rw-r--r--floppyd.c1297
-rw-r--r--floppyd_installtest.194
-rw-r--r--floppyd_installtest.c330
-rw-r--r--floppyd_io.c679
-rw-r--r--floppyd_io.h65
-rw-r--r--force_io.c63
-rw-r--r--fs.h43
-rw-r--r--fsP.h103
-rw-r--r--hash.c220
-rw-r--r--htable.h32
-rw-r--r--init.c426
-rwxr-xr-xinstall-sh238
-rw-r--r--llong.c96
-rw-r--r--llong.h110
-rw-r--r--lockdev.h77
-rw-r--r--lz.142
-rw-r--r--mainloop.c671
-rw-r--r--mainloop.h101
-rw-r--r--man-warning-end.texi46
-rw-r--r--man-warning.texi12
-rw-r--r--man/floppyd.1257
-rw-r--r--man/floppyd_installtest.196
-rw-r--r--man/mattrib.1133
-rw-r--r--man/mbadblocks.198
-rw-r--r--man/mcat.1103
-rw-r--r--man/mcd.1116
-rw-r--r--man/mclasserase.1115
-rw-r--r--man/mcopy.1183
-rw-r--r--man/mdel.199
-rw-r--r--man/mdeltree.1100
-rw-r--r--man/mdir.1121
-rw-r--r--man/mdu.199
-rw-r--r--man/mformat.1282
-rw-r--r--man/minfo.1101
-rw-r--r--man/mkmanifest.1181
-rw-r--r--man/mlabel.1117
-rw-r--r--man/mmd.195
-rw-r--r--man/mmount.199
-rw-r--r--man/mmove.1101
-rw-r--r--man/mpartition.1187
-rw-r--r--man/mrd.1100
-rw-r--r--man/mren.1107
-rw-r--r--man/mshowfat.194
-rw-r--r--man/mtools.1555
-rw-r--r--man/mtools.5633
-rw-r--r--man/mtoolstest.193
-rw-r--r--man/mtype.1113
-rw-r--r--man/mzip.1155
-rw-r--r--match.c158
-rw-r--r--mattrib.1128
-rw-r--r--mattrib.c258
-rw-r--r--mbadblocks.1115
-rw-r--r--mbadblocks.c282
-rw-r--r--mcat.1100
-rw-r--r--mcat.c162
-rw-r--r--mcd.1111
-rw-r--r--mcd.c62
-rw-r--r--mclasserase.1112
-rw-r--r--mclasserase.c351
-rw-r--r--mcomp.144
-rw-r--r--mcopy.1177
-rw-r--r--mcopy.c631
-rw-r--r--mdel.196
-rw-r--r--mdel.c208
-rw-r--r--mdeltree.196
-rw-r--r--mdir.1118
-rw-r--r--mdir.c617
-rw-r--r--mdoctorfat.c183
-rw-r--r--mdu.195
-rw-r--r--mdu.c140
-rw-r--r--mformat.1290
-rw-r--r--mformat.c1382
-rw-r--r--minfo.199
-rw-r--r--minfo.c233
-rw-r--r--misc.c262
-rw-r--r--missFuncs.c477
-rw-r--r--mk_direntry.c709
-rwxr-xr-xmkdosboot34
-rwxr-xr-xmkinstalldirs50
-rw-r--r--mkmanifest.1180
-rw-r--r--mkmanifest.c112
-rwxr-xr-xmkmanpages147
-rw-r--r--mlabel.1118
-rw-r--r--mlabel.c331
-rw-r--r--mmd.191
-rw-r--r--mmd.c199
-rw-r--r--mmount.196
-rw-r--r--mmount.c107
-rw-r--r--mmove.199
-rw-r--r--mmove.c323
-rw-r--r--mpartition.1184
-rw-r--r--mpartition.c742
-rw-r--r--mrd.195
-rw-r--r--mren.1105
-rw-r--r--msdos.h279
-rw-r--r--mshortname.195
-rw-r--r--mshortname.c76
-rw-r--r--mshowfat.196
-rw-r--r--mshowfat.c110
-rw-r--r--mtools.1521
-rw-r--r--mtools.5539
-rw-r--r--mtools.c201
-rw-r--r--mtools.conf80
-rw-r--r--mtools.h287
-rw-r--r--mtools.info2801
-rw-r--r--mtools.spec192
-rw-r--r--mtools.texi2638
-rw-r--r--mtools.tmpl.1521
-rw-r--r--mtools.tmpl.5539
-rw-r--r--mtoolsDirentry.h71
-rw-r--r--mtoolsPaths.h47
-rw-r--r--mtoolstest.190
-rw-r--r--mtype.1114
-rw-r--r--mxtar.148
-rw-r--r--mzip.1147
-rw-r--r--mzip.c552
-rw-r--r--nameclash.h75
-rw-r--r--partition.h49
-rw-r--r--patchlevel.c24
-rw-r--r--plain_io.c805
-rw-r--r--plain_io.h38
-rw-r--r--precmd.c48
-rw-r--r--privileges.c211
-rw-r--r--privtest.c26
-rw-r--r--read_dword.h41
-rwxr-xr-xscripts/add-disk47
-rwxr-xr-xscripts/amuFormat.sh103
-rwxr-xr-xscripts/download81
-rw-r--r--scripts/format.dat41
-rwxr-xr-xscripts/mcheck61
-rwxr-xr-xscripts/mcomp28
-rwxr-xr-xscripts/mxtar25
-rwxr-xr-xscripts/tgz86
-rwxr-xr-xscripts/uz92
-rw-r--r--scsi.c322
-rw-r--r--scsi.h37
-rw-r--r--signal.c134
-rw-r--r--stream.c87
-rw-r--r--stream.h107
-rw-r--r--streamcache.c79
-rw-r--r--strip-pp.sed20
-rw-r--r--subdir.c44
-rw-r--r--sysconfdir.texi1
-rw-r--r--sysincludes.h607
-rw-r--r--texinfo.tex10075
-rw-r--r--tgz.156
-rw-r--r--tty.c222
-rw-r--r--unixdir.c166
-rw-r--r--uz.143
-rw-r--r--version.texi3
-rw-r--r--vfat.c831
-rw-r--r--vfat.h110
-rw-r--r--xdf_io.c710
-rw-r--r--xdf_io.h33
209 files changed, 66842 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..db7bbb4
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,30 @@
+% Copyright 1996,1997,1999,2001,2002 Alain Knaff.
+
+% This documentation is for Mtools which is a collection of tools to
+% allow Unix systems to manipulate MS-DOS files.
+
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.3 or
+% any later version published by the Free Software Foundation; with no
+% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+% Texts. A copy of the license is included in the section entitled
+% ``GNU Free Documentation License''.
+
+Installation of mtools is now pretty straightforward:
+
+ 1. Run ./configure
+ 2. Run make
+
+ Configuration options:
+
+ * Use ./configure --enable-vold to compile mtools to use Solaris'
+vold instead of directly accessing the floppy disk
+ * Use ./configure --disable-xdf to disable support for Xdf disks on Linux
+ * Use ./configure --enable-new-vold to compile mtools to use the *new*
+vold for Solaris. With this, you no longer need precmd=volcheck, and
+users don't need to type "eject" before pushing the button.
+
+Further doc can be found in the manpages, and in the texinfo doc. The
+texinfo doc contains the same info as the manpages, but is more up to
+date. To generate a printable doc, make dvi. To generate an info file,
+make info.
diff --git a/Makefile.Be b/Makefile.Be
new file mode 100644
index 0000000..8dee7d3
--- /dev/null
+++ b/Makefile.Be
@@ -0,0 +1,49 @@
+# Copyright 1997 Marco Nelissen
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+#
+# Makefile for Mtools
+#
+# check the Configure file for some examples of device-specific setups
+# Berkeley flavors of Unix should include -DBSD in the CFLAGS. Pick
+# a lock method... either -DLOCKF, -DFLOCK, or -DFCNTL and put that
+# string in the CFLAGS line below.
+
+#
+# rudimentary makefile for building mtools 3.1 on the BeOS
+#
+
+CC=mwcc -O7
+
+OBJS=buffer.o codepage.o codepages.o config.o copyfile.o devices.o \
+directory.o expand.o fat.o fat_free.o file.o file_name.o file_read.o \
+filter.o force_io.o hash.o init.o match.o mainloop.o mattrib.o mbadblocks.o \
+mcd.o mcopy.o mdel.o mdir.o mformat.o minfo.o misc.o missFuncs.o \
+mk_direntry.o mlabel.o mmd.o mmount.o mmove.o mpartition.o mzip.o mtools.o \
+parse.o plain_io.o precmd.o privileges.o scsi.o signal.o stream.o \
+streamcache.o subdir.o toupper.o tty.o vfat.o xdf_io.o
+
+all: mtools mkmanifest
+
+$(OBJS): config.h
+
+config.h: config.h.Be
+ cp config.h.Be config.h
+
+mtools: $(OBJS)
+ $(CC) -o mtools $(OBJS)
+
+mkmanifest: mkmanifest.o
+ $(CC) -o mkmanifest mkmanifest.c
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..1e2c12a
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,335 @@
+# Copyright 1996-2004,2006-2010 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+#
+# Makefile for Mtools
+#
+# check the Configure file for some examples of device-specific setups
+# Berkeley flavors of Unix should include -DBSD in the CFLAGS. Pick
+# a lock method... either -DLOCKF, -DFLOCK, or -DFCNTL and put that
+# string in the CFLAGS line below.
+
+# User specified flags
+USERCFLAGS =
+USERLDFLAGS =
+USERLDLIBS =
+
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+TEXI2PDF = texi2pdf
+TEXI2HTML = texi2html
+
+
+# do not edit below this line
+# =============================================================================
+
+SHELL = /bin/sh
+
+top_srcdir=@top_srcdir@
+srcdir=@srcdir@
+VPATH=@srcdir@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+infodir = @infodir@
+mandir = @mandir@
+sysconfdir = @sysconfdir@
+datarootdir = @datarootdir@
+
+CC = @CC@
+CXX = @CXX@
+MYCFLAGS = @CFLAGS@
+MYCXXFLAGS = @CXXFLAGS@
+CPPFLAGS = @CPPFLAGS@
+HOST_ID = @HOST_ID@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)\" $(HOST_ID)
+
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+SHLIB = @SHLIB@
+MACHDEPLIBS = @MACHDEPLIBS@
+LN_S = @LN_S@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_INFO = @INSTALL_INFO@
+
+.SUFFIXES:
+.SUFFIXES: .o .c
+.SUFFIXES: .o .c
+
+MAN1 = floppyd.1 floppyd_installtest.1 mattrib.1 mbadblocks.1 mcat.1 mcd.1 \
+mclasserase.1 mcopy.1 mdel.1 mdeltree.1 mdir.1 mdu.1 mformat.1 minfo.1 \
+mkmanifest.1 mlabel.1 mmd.1 mmount.1 mmove.1 mpartition.1 \
+mrd.1 mren.1 mshortname.1 mshowfat.1 mtoolstest.1 mtools.1 mtype.1 mzip.1
+MAN1EXT = 1
+MAN1DIR = $(DESTDIR)$(mandir)/man${MAN1EXT}
+MAN5 = mtools.5
+MAN5EXT = 5
+MAN5DIR = $(DESTDIR)$(mandir)/man${MAN5EXT}
+
+# all files in this directory included in the distribution
+DIST = \
+COPYING Changelog INSTALL Makefile Makefile.in README Release.notes \
+buffer.c buffer.h charsetConv.c codepage.h codepages.c config.c \
+config.guess config.h.in config.log config.sub configure configure.in \
+copyfile.c devices.c devices.h dirCache.c dirCache.h directory.c direntry.c \
+expand.c fat.c \
+fat_free.c file.c file.h file_name.h file_name.c files filter.c floppyd.1 \
+floppyd.c floppyd_io.c floppyd_io.h force_io.c fs.h fsP.h \
+getopt.h hash.c htable.h init.c llong.c mainloop.c match.c mattrib.1 \
+mattrib.c mbadblocks.1 mbadblocks.c mcat.1 mcat.c mcd.1 mcd.c mclasserase.c \
+mcopy.1 \
+mcopy.c mdel.1 mdel.c mdeltree.1 mdir.1 mdir.c mdu.c mdu.1 mformat.1 \
+mformat.c minfo.c \
+misc.c tty.c scsi.c missFuncs.c mk_direntry.c mkmanifest.1 mkmanifest.c \
+mlabel.1 mlabel.c mmd.1 mmd.c mmount.1 mmount.c mmove.1 mmove.c \
+mpartition.1 mpartition.c mrd.1 \
+mren.1 msdos.h mshortname.1 mshowfat.1 mtoolstest.1 mtools.1 mtools.5 mtools.c \
+mtools.conf mtools.h mtype.1 nameclash.h patchlevel.c \
+plain_io.c plain_io.h precmd.c privileges.c scripts signal.c stream.c stream.h \
+streamcache.c streamcache.h subdir.c 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 mshortname.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
+
+OBJS3 = floppyd.o llong.o
+
+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 \
+mshortname.c mshowfat.c mzip.c mtools.c plain_io.c precmd.c privileges.c \
+scsi.c signal.c stream.c streamcache.c subdir.c unixdir.c tty.o vfat.c \
+xdf_io.c mkmanifest.c
+
+
+SCRIPTS = mcheck mxtar uz tgz mcomp amuFormat.sh
+
+LINKS=mattrib mcat mcd mclasserase mcopy mdel mdeltree mdir mdu mformat minfo \
+mlabel mmd mmount mmove mpartition mrd mren mtype mtoolstest mshortname \
+mshowfat mbadblocks mzip
+
+X_CFLAGS = @X_CFLAGS@
+X_LIBS = @X_LIBS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+CFLAGS = $(CPPFLAGS) $(DEFS) $(MYCFLAGS) -fno-strict-aliasing -I. @extraincludedir@ -I@srcdir@ $(USERCFLAGS)
+CXXFLAGS = $(CPPFLAGS) $(DEFS) $(MYCXXFLAGS) -I. @extraincludedir@ -I@srcdir@ $(USERCFLAGS)
+LINK = $(CC) $(LDFLAGS) $(USERLDFLAGS) @extralibdir@
+ALLLIBS = $(USERLDLIBS) $(MACHDEPLIBS) $(SHLIB) $(LIBS)
+X_LDFLAGS = $(X_EXTRA_LIBS) $(X_LIBS) -lXau -lX11 $(LIBS)
+X_CCFLAGS = $(X_CFLAGS) $(CFLAGS)
+
+all: mtools $(LINKS) mkmanifest @FLOPPYD@ mtools.1 mtools.5
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $<
+
+#%.o: %.cpp
+# $(CXX) $(CXXFLAGS) -c $<
+
+mtools: $(OBJS1)
+ $(LINK) $(OBJS1) -o $@ $(ALLLIBS)
+
+mkmanifest: $(OBJS2)
+ $(LINK) $(OBJS2) -o $@ $(ALLLIBS)
+
+floppyd.o: floppyd.c
+ $(CC) $(X_CCFLAGS) -c $?
+
+floppyd: $(OBJS3)
+ $(LINK) $(OBJS3) -o $@ $(X_LDFLAGS)
+floppyd_installtest: $(OBJS4)
+ $(LINK) $(OBJS4) -o $@ $(ALLLIBS)
+
+
+$(LINKS): mtools
+ rm -f $@ && $(LN_S) mtools $@
+
+mostlyclean:
+ -rm -f *~ *.orig *.o a.out core 2>/dev/null
+
+clean: mostlyclean
+ -rm -f mtools $(LINKS) floppyd floppyd_installtest mkmanifest *.info* *.dvi *.html 2>/dev/null
+
+
+texclean:
+ -rm -f mtools.aux mtools.toc mtools.log
+ -rm -f mtools.cps mtools.pgs mtools.vrs
+ -rm -f mtools.cp mtools.fn mtools.ky
+ -rm -f mtools.pg mtools.tp mtools.vr
+
+info: mtools.info
+%.info: %.texi sysconfdir.texi
+ $(MAKEINFO) -I$(srcdir) $< --no-split --output=$@
+
+dvi: mtools.dvi
+%.dvi: %.texi sysconfdir.texi
+ $(TEXI2DVI) $<
+
+ps: mtools.ps
+%.ps: %.dvi
+ dvips -f < $< > $@
+
+pdf: mtools.pdf
+%.pdf: %.texi sysconfdir.texi
+ $(TEXI2PDF) $<
+
+mtools.1: mtools.tmpl.1 Makefile
+ sed "s%SYSCONFDIR%$(sysconfdir)/%g" $(srcdir)/mtools.tmpl.1 >mtools.1
+
+mtools.5: mtools.tmpl.5 Makefile
+ sed "s%SYSCONFDIR%$(sysconfdir)/%g" $(srcdir)/mtools.tmpl.5 >mtools.5
+
+sysconfdir.texi:
+ echo "@set SYSCONFDIR $(sysconfdir)/" >sysconfdir.texi
+
+html: mtools.html mtools_toc.html
+%.html %_toc.html: %.texi sysconfdir.texi
+ $(TEXI2HTML) $<
+
+# Don't cd, to avoid breaking install-sh references.
+install-info: info
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(infodir)
+ if test -f mtools.info; then \
+ for i in mtools.info*; do \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/$$i; \
+ done; \
+ else \
+ for i in $(srcdir)/mtools.info*; do \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(infodir)/`echo $$i | sed 's|^$(srcdir)/||'`; \
+ done; \
+ fi; \
+ if [ -n "$(INSTALL_INFO)" ] ; then \
+ $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/mtools.info; \
+ fi
+
+uninstall-info:
+ cd $(DESTDIR)$(infodir) && rm -f mtools.info*
+
+install: $(DESTDIR)$(bindir)/mtools @BINFLOPPYD@ install-man install-links \
+ $(DESTDIR)$(bindir)/mkmanifest install-scripts install-info
+
+uninstall: uninstall-bin uninstall-man uninstall-links \
+ uninstall-scripts
+
+distclean: clean texclean
+ rm -f config.cache config.h config.status config.log Makefile
+maintainer-clean: distclean
+
+
+$(DESTDIR)$(bindir)/floppyd: floppyd
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) floppyd $(DESTDIR)$(bindir)/floppyd
+
+$(DESTDIR)$(bindir)/floppyd_installtest: floppyd_installtest
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) floppyd_installtest $(DESTDIR)$(bindir)/floppyd_installtest
+
+$(DESTDIR)$(bindir)/mtools: mtools
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) mtools $(DESTDIR)$(bindir)/mtools
+
+$(DESTDIR)$(bindir)/mkmanifest: mkmanifest
+ $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+ $(INSTALL_PROGRAM) mkmanifest $(DESTDIR)$(bindir)/mkmanifest
+
+#$(ETCDIR)/mtools: mtools.etc
+# cp mtools.etc $(ETCDIR)/mtools
+
+install-links: $(DESTDIR)$(bindir)/mtools
+ @for j in $(LINKS); do \
+ rm -f $(DESTDIR)$(bindir)/$$j ; \
+ $(LN_S) mtools $(DESTDIR)$(bindir)/$$j ; \
+ echo $(DESTDIR)$(bindir)/$$j ; \
+ done
+
+## "z" is the older version of "gz"; the name is just *too* short
+install-scripts: $(DESTDIR)$(bindir)/mtools
+ @$(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir)
+ @for j in $(SCRIPTS) ; do \
+ $(INSTALL_PROGRAM) $(srcdir)/scripts/$$j $(DESTDIR)$(bindir)/$$j ; \
+ echo $(DESTDIR)$(bindir)/$$j ; \
+ done
+ rm -f $(DESTDIR)$(bindir)/lz
+ cd $(DESTDIR)$(bindir) && $(LN_S) uz lz
+
+install-man:
+ @$(top_srcdir)/mkinstalldirs $(MAN1DIR)
+ @for j in $(MAN1); do \
+ $(INSTALL_DATA) $(srcdir)/$$j $(MAN1DIR)/$$j ; \
+ echo $(MAN1DIR)/$$j ; \
+ done
+ @$(top_srcdir)/mkinstalldirs $(MAN5DIR)
+ @for j in $(MAN5); do \
+ $(INSTALL_DATA) $(srcdir)/$$j $(MAN5DIR)/$$j ; \
+ echo $(MAN5DIR)/$$j ; \
+ done
+
+uninstall-bin:
+ @for j in mtools mkmanifest; do \
+ rm -f $(DESTDIR)$(bindir)/$$j ; \
+ echo $(DESTDIR)$(bindir)/$$j ; \
+ done
+
+uninstall-scripts:
+ @for j in $(SCRIPTS); do \
+ rm -f $(DESTDIR)$(bindir)/$$j ; \
+ echo $(DESTDIR)$(bindir)/$$j ; \
+ done
+
+uninstall-man:
+ @for j in $(MAN1); do \
+ rm -f $(MAN1DIR)/$$j ; \
+ echo $(MAN1DIR)/$$j ; \
+ done
+ @for j in $(MAN5); do \
+ rm -f $(MAN5DIR)/$$j ; \
+ echo $(MAN5DIR)/$$j ; \
+ done
+
+uninstall-links:
+ @for j in $(LINKS); \
+ do rm -f $(DESTDIR)$(bindir)/$$j ; \
+ echo $(DESTDIR)$(bindir)/$$j ; \
+ done
+
+depend: $(SRCS)
+ makedepend -- $(CFLAGS) -- $^
+
+check:
+ echo No self tests included
+# check target needed even if empty, in order to make life easyer for
+# automatic tools to install GNU soft
+
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..5b7b371
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,1094 @@
+v4_0_18
+ Fix for names of iconv encodings on AIX
+ Fix mt_size_t on NetBSD
+ Fixed compilation on Mingw
+ Fixed doc (especially mformat)
+ Fix mformat'ing of FAT12 filesystems with huge cluster sizes
+ Minfo prints image file name in mformat command line if an image
+ file name was given
+ Always generate gzip-compressed RPMs, in order to remain
+ compatible with older distributions
+ Fixed buffer overflow with drive letter in mclasserase
+v4_0_17
+ mbadblocks now takes a list of bad blocks (either as sectors
+ or as clusters)
+ mbadblocks now is able to do write scanning for bad blocks
+ mshowfat can show cluster of specific offset
+ Enable mtools to deal with very small sector sizes...
+ Fixed encoding of all-lowercase names (no need to mangle
+ these)
+ Consider every directory entry after an ENDMARK (0x00) to be deleted
+ After writing a new entry at end of a directory, be sure to also add
+ an ENDMARK (0x00)
+
+ Deal with possibility of a NULL pointer being returned by
+ localtime during timestamp conversion
+v4_0_16
+ configure.in fixes
+ fixed formatting of fat_size_calculation.tex document
+ compatibility with current autoconfig versions
+ Make it clear that label is limited to 11 characters
+ Fixed typo in initialization of FAT32 info sector
+v4_0_15
+ Added missing -i option to mshortname
+ Splitted .deb package into mtools and floppyd in order to
+ match Ubuntu
+v4_0_14
+ New mshortname command
+ Fix floppyd for disks bigger than 2 Gig
+ Remove obsolete -z flag
+ Remove now unsupported AC_USE_SYSTEM_EXTENSIONS
+ Fixed output formatting of mdir if MTOOLS_DOTTED_DIR is set
+ Mformat now correctly writes backup boot sector
+ Fixed signedness of serial number in mlabel
+ Fixed buffer size problem in mlabel
+ Make mlabel write backup boot sector if FAT32
+ Catch situation where both clear and new label are given to mlabel
+ Quote filename parameters to scripts
+ Mformat: Close file descriptor for boot sector
+ Added lzip support to scripts/uz
+ Added Tot_sectors option to mformat
+ Fixed hidden sector handling in mformat
+ Minfo generates mformat command lines containing new -T option
+ Mlabel prints error if label too long
+v4_0_13
+ Merged Debian patches
+v4_0_12
+ Mingw compatibility fixes
+v4_0_11
+ Fixed compiler warnings in mlabel.c and elsewhere
+ Fixed h flag in mattrib.c
+ Added missing error checking in floppyd and elsewhere
+
+v4_0_10
+ More copyright stuff...
+ Fixed issues with max filesize (was 2GB instead of 4GB, and
+ warned only after copying the beginning)
+v4_0_9
+ More copyright stuff
+v4_0_8
+ Corrected copyright attributions in the various files
+v4_0_7
+ Fixed conversion to native on OS/2
+ Fix parsing of --help flag
+v4_0_6
+ Fallback for missing wchar_t iconv codepage on OS/2
+ Fixes for LSEEK64 support
+ Support for --help that returns a 0 exit status
+v4_0_5
+ Make setpgrp() usage in floppyd conditional
+ Re-instate PACKED around structure (ARM)
+ LSEEK64
+
+v4_0_4
+ BSD support: SCSI, use getuserid/getgroupid in floppyd
+ Another attempt at putwc fix for OS/2
+ Further GNU fixes
+ Fallback for putwc if there is wchar (OS/2)
+v4_0_3
+ Fix multipart pathname parsing bug in vfat.c (forgot limited length)
+ Supplied fallback define for putwc
+ Copyright notices in all sources
+v4_0_2
+ Off-by-2 error in unix_name in file_name.c
+v4_0_1
+ Missing functions on Solaris
+v4_0_0
+ Offset for -i-specified image files
+v4_0_0_pre2
+ Use transliteration to represent characters which don't exist in
+ target set
+v4_0_0_pre1
+ Mtools-4 with Unicode support
+ Released 4.0.0_pre1
+v20071226
+ Debian build files
+ Fixed security issue with doctored file names
+ 64 bit compilation fixes
+v20070601
+ Fixed misc blunders...
+v20070531
+ Fixed lots of minor items raised by gcc4
+ Merged some of the BSD patches
+ New version of amuFormat.sh written in sh rather than csh
+ Support for config parameters after -i file
+ Released 3.9.11
+v20070411
+ Added sizecode printing on minfo
+ In mformat manpage, use same flag for sector number than printed in
+ minfo
+ Limit sizecode to 6, else it will overflow max sector size defined in
+ msdos.h
+v20070308
+ Applied mingw patch by Jamey Sharp and Josh Triplett
+v20070306
+ Fixed doc about /etc/default
+v20070305
+ Fixed mlabel on read-only disks
+v20060626
+ Merged Redhat/Fedora patches
+v20060531
+ #ifdef linux-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
index 0000000..9befffd
--- /dev/null
+++ b/README
@@ -0,0 +1,76 @@
+Compilation
+-----------
+
+ To compile mtools on Unix, first type ./configure, then make. To
+compile mtools on a Bebox, refer to README.BEBOX.
+
+Doc
+---
+
+ The most uptodate doc of this package is the texinfo doc. Type 'make
+info' to get online info doc, and 'make dvi ; dvips mtools.dvi' to get
+a printed copy. The info doc has a concept index. Make use of it.
+ You may get an info copy using the following command 'make info'.
+This can then be viewed using emacs' info mode, or using a standalone
+info viewer.
+ Man pages are still present, but contain less information.
+ If you do not have the necessary tools to view the texinfo doc, you
+may also find it on the World Wide Web at the following locations:
+ http://ftp.gnu.org/software/mtools/manual/mtools.html
+
+Compiler
+--------
+
+ Mtools should be compiled with an Ansi compiler, preferably gcc
+
+Authors
+-------
+
+Original code (versions through 2.0.7?) by Emmet P. Gray (Texas, USA).
+Viktor Dukhovni (at Princeton, USA) had major input into v2.0.
+
+Since 2.0.7: maintained primarily and until now by Alain Knaff
+(Luxembourg) and David Niemi (Reston, Virginia, USA).
+
+Please report bugs to the mtools mailing list at mtools@www.tux.org.
+Before reporting any problems, check whether they have already been
+fixed in the Alpha patches at http://mtools.linux.lu and
+http://www.tux.org/pub/knaff
+
+You may subscribe to the mtools mailing list by sending a message
+containing 'subscribe mtools' in its body to majordomo@www.tux.org
+
+Since March 3rd 2009, mtools is now officially a GNU package. Special
+thanks to Emmet P. Gray, the original developer of the program, who
+supported dubbing mtools a GNU package.
+
+Current Status
+--------------
+
+Stable release 4.0.x
+
+Copying
+-------
+Mtools is a GNU program published under GPL v3.0 (code) and GNU Free
+Documentation License.
+
+Most files of mtools bears a notice describing the copyright, and
+whether it is covered by GPL or GFDL
+
+GPL:
+
+debian/control Copyright 2007 Alain Knaff
+
+debian/changelog Copyright 2007-2009 Alain Knaff
+
+NEWS Copyright 1995 David C. Niemi
+ Copyright 1995-2009 Alain Knaff
+
+mtools.spec Copyright 2003-2005,2007-2009 Alain Knaff
+
+
+GFDL:
+
+README Copyright 1996-1998,2001,2002,2009 Alain Knaff.
+Release.notes Copyright 1995 Alain Knaff
+
diff --git a/README.BEBOX b/README.BEBOX
new file mode 100644
index 0000000..29e6bfa
--- /dev/null
+++ b/README.BEBOX
@@ -0,0 +1,126 @@
+% Copyright 1997 Marco Nelissen.
+% Copyright 1996-1998,2001,2002,2009 Alain Knaff.
+% This documentation is for Mtools which is a collection of tools to
+% allow Unix systems to manipulate MS-DOS files.
+
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.3 or
+% any later version published by the Free Software Foundation; with no
+% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+% Texts. A copy of the license is included in the section entitled
+% ``GNU Free Documentation License''.
+
+
+
+NOTE: THIS FILE ONLY REFERS TO THE BEBOX. IF YOU ARE USING UNIX,
+REFER TO README.
+
+
+This is mtools 3.6 for BeOS DR9. This release will no longer work on
+DR8, which should be no problem since everybody should have upgraded
+to DR9 by now. mtools 3.6 can be used as a replacement for the
+version 2.0.7 mtools supplied with BeOS. mtools 3.6 supports the VFAT
+filesystem (long filenames), which the Be-supplied tools do not.
+
+To install:
+
+- build the executables: type "make -f Makefile.Be" in the mtools
+ directory. Again, this instruction is only for the Bebox, not for any
+ kind of Unix. They should compile without any warnings or errors.
+
+ WARNING: do NOT rerun the configure script. Although DR9 bash will
+no longer lock up when running the configure script, the resulting
+files are not entirely correct, and mtools will fail to compile. I
+have hand-crafted a config.h that can be used to compile mtools. This
+will be used if you just type "make -f Makefile.Be"
+
+- copy the "mtools" executable (and perhaps also "mkmanifest") to /bin,
+ or to another directory in your path.
+
+Since all of the mtools-commands are contained within a single
+executable, you must either define aliases for each command, or create
+links for them.
+
+To create aliases, add the following lines to the file /boot/.profile
+
+alias mattrib="mtools -c mattrib"
+alias mbadblocks="mtools -c mbadblocks"
+alias mcd="mtools -c mcd"
+alias mcopy="mtools -c mcopy"
+alias mdel="mtools -c mdel"
+alias mdeltree="mtools -c mdeltree"
+alias mdir="mtools -c mdir"
+alias mformat="mtools -c mformat"
+alias minfo="mtools -c minfo"
+alias mlabel="mtools -c mlabel"
+alias mmd="mtools -c mmd"
+alias mmount="mtools -c mmount"
+alias mrd="mtools -c mrd"
+alias mmove="mtools -c mmove"
+alias mpartition="mtools -c mpartition"
+alias mren="mtools -c mren"
+alias mtoolstest="mtools -c mtoolstest"
+alias mtest="mtools -c mtest"
+alias mtype="mtools -c mtype"
+alias mzip="mtools -c mzip"
+
+ (then close and re-open all terminals and shells, or type
+". /boot/.profile" in each open terminal to activate the
+aliases. Optional: remove the old mtools from the /bin directory)
+
+
+To create links, open a shell, and type the following commands
+(assuming you copied the mtools executable to /bin):
+
+cd /bin
+rm mattrib mcd mcopy mdel mdir mformat mkmanifest mlabel mmd mrd mread mren mtype mwrite
+ln -s mtools mattrib
+ln -s mtools mbadblocks
+ln -s mtools mcd
+ln -s mtools mcopy
+ln -s mtools mdel
+ln -s mtools mdeltree
+ln -s mtools mdir
+ln -s mtools mformat
+ln -s mtools minfo
+ln -s mtools mlabel
+ln -s mtools mmd
+ln -s mtools mmount
+ln -s mtools mrd
+ln -s mtools mread
+ln -s mtools mmove
+ln -s mtools mpartition
+ln -s mtools mren
+ln -s mtools mtoolstest
+ln -s mtools mtest
+ln -s mtools mtype
+ln -s mtools mwrite
+ln -s mtools mzip
+
+
+Alternatively, make multiple copies of the "mtools" executable and use
+the names mdir, mdel etcetera.
+
+- if you want more than just floppy support, you need to make a configuration
+ file. An example mtools.conf.be is included in the distribution.
+ mtools looks in a number of standard places for its config file, such as:
+ /boot/.mtoolsrc
+ /boot/mtools.conf
+ /boot/system/mtools.conf
+ By defining the variable MTOOLSRC you can give the config file any name you
+ like and put it at any location.
+
+ You need to add something like "export MTOOLSRC=/conf/mtools.cfg" to
+ your .profile file.
+
+ Take care to remove or change the entries that you don't need. The provided
+ mtools.conf is for unix systems, with some BeOS settings at the end.
+ The sample entry for a ZIP disk on the BeOS has been provided by
+ Chris Herborth
+ (chrish@qnx.com).
+
+
+- enjoy!
+
+Marco Nelissen <marcone@xs4all.nl>
+Alain Knaff <alain@knaff.lu>
diff --git a/Release.notes b/Release.notes
new file mode 100644
index 0000000..f434b4a
--- /dev/null
+++ b/Release.notes
@@ -0,0 +1,230 @@
+[See Changelog for more recent changes]
+
+2.5.1 29 Aug 1995
+
+Bug fixes to allow compiling and running on SINIX-D 5.41, thanks to
+Martin Kraemer <Martin.Kraemer@mch.sni.de>.
+
+-----------------------------------------------------------------------------
+2.5 21 Aug 1995
+
+First public Alpha Test release of the newly rewritten Mtools.
+Summary of the many major changes:
+
+XDF support, ANSIfication, major restructuring, and debugging (Alain Knaff)
+VFAT support, new prompts for overwrites, and debugging (David Niemi)
+
+-----------------------------------------------------------------------------
+Patch #7alk ... 4 Dec 94
+
+This patch adds the following features:
+
+ 1) mbadblocks program to mark bad blocks
+ 2) uses fat_type field of boot block to find out the number
+ of fat bits.
+ 3) is able to format hard disk partitions (untested)
+ 4) sets _all_ standard fields in boot sector, even without 2m mode.
+ 5) adds boot code to the boot sector (which transfers booting to
+ the hard drive. In most cases, that's what the user wants.)
+
+-----------------------------------------------------------------------------
+Patch #7alk ... 4 Nov 94
+
+This patch adds the following features:
+
+ 1) Use even disk buffer size whenever possible to workaround a
+ bug in Linux blockdev code [???]
+ 2) Clearer error message on failed sanity check
+ 3) Removal of BOGUS Notes file
+
+-----------------------------------------------------------------------------
+Patch #7alk quinter, 2 Nov 94
+
+This patch adds the following features:
+
+ 1) O_EXCL flag when opening the device to ensure it is not mounted
+ 2) Sanity checks to avoid accessing non msdos disks
+Both features were suggested by Karl Eichwalder (ke@pertron.central.de)
+
+-----------------------------------------------------------------------------
+Patch #7alk quater, 1 Oct 94
+
+This patch adds the following features:
+
+ 1) disk serial number support.
+ 2) mcheck works for every drive.
+
+-----------------------------------------------------------------------------
+Patch #7alk ter, 10 Sep 94
+
+This patch adds the following features:
+
+ 1) mformat works again.
+ 2) mmount allows the user to pass arbitrary arguments to mount.
+ Floppy disks are no longer mounted by default on /mount/A /mount/B
+ etc.
+
+-----------------------------------------------------------------------------
+Patch #7alk bis, 18 jul 94
+
+This patch adds the following features:
+
+ 1) Support for variable sector sizes.
+ 2) Support for "2m" formats.
+ 3) Support for formatting 16-bit fat disks.
+ 4) Support for formatting ED disks (Their capacity is too big to
+ use a 12 bit FAT and 1 sector clusters. Either use bigger
+ clusters or a 16 bit FAT)
+ 5) Mcopying from one DOS drive to another works now. (It used to
+ call mktemp on a non-writable string)
+
+-----------------------------------------------------------------------------
+Patch #7alk, 16 feb 94
+
+This patch adds the following features:
+
+ 1) Mtools can now set the disk geometry on Linux. (Useful for
+ reading 1.72 Mb disks. This was already possible on unixpc and
+ SPARC )
+ 2) New mmount command. Reads the boot sector, sets the geometry
+ and finally mounts the disk. Only available for Linux.
+ 3) Mwrite can now write stdout to a DOS file: mwrite - a:test
+ 4) Mread now also acts as mtype: mread a:test -
+ 5) Mtools now tries 3 sources to get its drive geometry.
+ configuration: first ~/.mtoolsrc, then /etc/mtools, and finally
+ compiled-in. ( The two first are conditional on LOADDEVS being
+ defined ). LOADDEVS is now compatibles with the various geometry
+ setting routines (init_linux, init_sparc and init_unixpc).
+ 6) Bug fixes for -t mode of mwrite and mread. ( For certain file sizes
+ the trailing DOS end-of-file character wasn't correctly written.)
+ 7) Bug fixes for "drive probing code." (Now failure to lock onto a disk
+ causes always trial of the next configuration. Before, mtools used
+ to abort on certain cases). Similar fixes in mformat.
+ 8) Optimization/bug fix of cluster/fat repartition in mformat.c
+ 9) Made fat checking code optional. (1.72mb disks mformatted with old
+ mtools were almost always rejected) To bypass fat-checking set the
+ environment variable MTOOLS_FAT_COMPATIBILITY
+ 10) Mtools now opens /dev/tty to ask for confirmation messages. This
+ way, it doesn't interfere with mreading/mwriting from/to stdin/stdout.
+
+
+CAUTION: I only tested this with Sparc and Linux. Although I left #ifdefs
+for other OS's in devices.c, that doesn't mean that it works on these OS's.
+
+-----------------------------------------------------------------------------
+Patch #7+, 19 sep 93
+
+This patch merges in the mods against 2.05 under Linux. Two are the main
+changes: that all commands are linked as a single executable, which can
+be linked as different name, and that the device specs are no longer
+hardcompiled but are read dynamically from /etc/mtools (the latter change
+is conditional on LOADDEVS being defined).
+
+-----------------------------------------------------------------------------
+Patch #7, 6 Sep 92
+
+This patch will change the method of determining if the FAT encoding
+scheme in the devices.c file is correct. The method introduced by patch
+#6 was naive and easily fooled.
+
+A pre-processor variable called CHK_FAT has been added to the fat_read.c
+file just in case this new method isn't appropriate for all disks.
+
+-----------------------------------------------------------------------------
+Patch #6, 21 Aug 92
+
+This patch will add the following features:
+
+ 1) Mtools commands now use advisory locks to preclude two
+ processes from writing to the same DOS filesystem. You must
+ edit the Makefile to choose one of the 3 lock methods:
+ -DLOCKF, -DFLOCK, or -DFCNTL.
+ See the Configure file for more details.
+
+ 2) An error detection routine has been added to determine if the
+ FAT encoding scheme in the devices.c file is correct.
+
+ 3) Mtools commands now return exit codes with the following
+ meaning:
+ 0 = success
+ 1 = utter failure
+ 2 = partial success/failure. (at least one successful
+ operation, but at least one failure)
+
+It also corrects a bug when Mtools is used on machines that have 16 bit
+integers. However, machines with 16 bit integers are limited to FAT
+tables that are less than 64k in length.
+-------------------------------------------------------------------------------
+Patch #5, 25 Aug 91
+
+This patch will add a few new features:
+
+ 1) Mtools will now work properly on MSDOS partitions that are
+ greater than 32M.
+
+ 2) If the "current working directory" information (contained in
+ the $HOME/.mcwd file) is more than 6 hours old, Mtools will
+ issue a warning and ignore the old information.
+
+ 3) The mcopy command will now copy files between 2 MS-DOS file
+ systems (such as mcopy "a:*" b:).
+
+-------------------------------------------------------------------------------
+Patch #4, 11 Apr 91
+
+ This patch will fix a bug in the mmd command where directories
+ inherited the file name extension of the parent directory. It
+ also adds a feature that will allow the copying of zero length
+ files.
+
+-------------------------------------------------------------------------------
+Patch #3, 28 Nov 90
+
+ This patch will fix a bug where Mtools sometimes bypasses the
+ disk "cache" and reads/writes to the disk directly.
+
+-------------------------------------------------------------------------------
+Patch #2, 21 Nov 90
+
+ This patch will fix a bug in the folding of MS-DOS filenames to
+ lower case, and will fix a bug that could prevent the detection
+ of a full disk.
+
+-------------------------------------------------------------------------------
+Patch #1, 12 Oct 90
+
+ This patch will fix a few problems on Berkeley flavors of Unix,
+ and will fix the floating point exception bug when Mtools is
+ used with diskettes that have been formatted under very old DOS
+ (or formatted by some other non-DOS system).
+
+-------------------------------------------------------------------------------
+New in the v2.0 release....
+
+ 1) Support for multiple devices. Mtools now supports:
+ multiple floppy disks (A:, B:, etc)
+ DOS partitions on a hard disk
+ DOS "images" such as those VP/ix uses.
+
+ 2) Wildcards are supported anywhere in a pathname (not just
+ in the "filename" part as before)
+
+ 3) Reads and writes to slow devices are now "cylinder buffered"
+ when appropriate.
+
+ 4) Versions of CD, FORMAT, LABEL, and ATTRIB have been added.
+
+ 5) A Mtools.1 manual page has been added for an overview of Mtools.
+
+ 6) The mkmanifest command has been added. Although not an 'mtool'
+ command, it makes life easier when fixing up Unix filenames that
+ get clobbered by MS-DOS file name restrictions.
+
+ 7) The mkdfs program of the "fast-mtools" release for the Sun
+ SparcStation can be replaced with mformat.
+
+ 8) The Configure file has been included to help those who must add
+ devices to the devices.c file.
+
+ Many thanks to Viktor Dukhovni (viktor@math.princeton.edu) for
+ many of the ideas in the new release.
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..50b2e21
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,34 @@
+dnl Copyright 1997,2001-2003 Alain Knaff.
+dnl This file is part of mtools.
+dnl
+dnl Mtools is free software: you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation, either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl Mtools is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+dnl
+dnl Check for declaration of sys_errlist in one of stdio.h and errno.h.
+dnl Declaration of sys_errlist on BSD4.4 interferes with our declaration.
+dnl Reported by Keith Bostic.
+AC_DEFUN([CF_SYS_ERRLIST],
+[
+AC_MSG_CHECKING([declaration of sys_errlist])
+AC_CACHE_VAL(cf_cv_dcl_sys_errlist,[
+ AC_TRY_COMPILE([
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h> ],
+ [char *c = (char *) *sys_errlist],
+ [cf_cv_dcl_sys_errlist=yes],
+ [cf_cv_dcl_sys_errlist=no])])
+AC_MSG_RESULT($cf_cv_dcl_sys_errlist)
+test $cf_cv_dcl_sys_errlist = no || AC_DEFINE([DECL_SYS_ERRLIST],1,[Define when sys_errlist is defined in the standard include files])
+])dnl
+dnl
diff --git a/buffer.c b/buffer.c
new file mode 100644
index 0000000..ebefd1e
--- /dev/null
+++ b/buffer.c
@@ -0,0 +1,387 @@
+/* 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)
+{
+ if(_buf_flush(Buffer) < 0)
+ return -1;
+
+ /* start reading at the beginning of start's sector
+ * don't start reading too early, or we might not even reach
+ * start */
+ Buffer->current = ROUND_DOWN(start, Buffer->sectorSize);
+ Buffer->cur_size = 0;
+ return 0;
+}
+
+#undef OFFSET
+#define OFFSET (start - This->current)
+
+typedef enum position_t {
+ OUTSIDE,
+ APPEND,
+ INSIDE,
+ ERROR
+} position_t;
+
+static position_t isInBuffer(Buffer_t *This, mt_off_t start, size_t *len)
+{
+ if(start >= This->current &&
+ start < This->current + This->cur_size) {
+ maximize(*len, This->cur_size - OFFSET);
+ return INSIDE;
+ } else if(start == This->current + This->cur_size &&
+ This->cur_size < This->size &&
+ *len >= This->sectorSize) {
+ /* append to the buffer for this, three conditions have to
+ * be met:
+ * 1. The start falls exactly at the end of the currently
+ * loaded data
+ * 2. There is still space
+ * 3. We append at least one sector
+ */
+ maximize(*len, This->size - This->cur_size);
+ *len = ROUND_DOWN(*len, This->sectorSize);
+ return APPEND;
+ } else {
+ if(invalidate_buffer(This, start) < 0)
+ return ERROR;
+ maximize(*len, This->cylinderSize - OFFSET);
+ maximize(*len, This->cylinderSize - This->current % This->cylinderSize);
+ return OUTSIDE;
+ }
+}
+
+static int buf_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+ size_t length;
+ int offset;
+ char *disk_ptr;
+ int ret;
+ DeclareThis(Buffer_t);
+
+ if(!len)
+ return 0;
+
+ /*fprintf(stderr, "buf read %x %x %x\n", Stream, start, len);*/
+ switch(isInBuffer(This, start, &len)) {
+ case OUTSIDE:
+ case APPEND:
+ /* always load until the end of the cylinder */
+ length = This->cylinderSize -
+ (This->current + This->cur_size) % This->cylinderSize;
+ maximize(length, This->size - This->cur_size);
+
+ /* read it! */
+ ret=READS(This->Next,
+ This->buf + This->cur_size,
+ This->current + This->cur_size,
+ length);
+ if ( ret < 0 )
+ return ret;
+ This->cur_size += ret;
+ if (This->current+This->cur_size < start) {
+ fprintf(stderr, "Short buffer fill\n");
+ exit(1);
+ }
+ break;
+ case INSIDE:
+ /* nothing to do */
+ break;
+ case ERROR:
+ return -1;
+ }
+
+ offset = OFFSET;
+ disk_ptr = This->buf + offset;
+ maximize(len, This->cur_size - offset);
+ memcpy(buf, disk_ptr, len);
+ return len;
+}
+
+static int buf_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+ char *disk_ptr;
+ DeclareThis(Buffer_t);
+ size_t offset;
+
+ if(!len)
+ return 0;
+
+ This->ever_dirty = 1;
+
+#ifdef DEBUG
+ fprintf(stderr, "buf write %x %02x %08x %08x -- %08x %08x -- %08x\n",
+ Stream, (unsigned char) This->buf[0],
+ start, len, This->current, This->cur_size, This->size);
+ fprintf(stderr, "%d %d %d %x %x\n",
+ start == This->current + This->cur_size,
+ This->cur_size < This->size,
+ len >= This->sectorSize, len, This->sectorSize);
+#endif
+ switch(isInBuffer(This, start, &len)) {
+ case OUTSIDE:
+#ifdef DEBUG
+ fprintf(stderr, "outside\n");
+#endif
+ if(start % This->cylinderSize ||
+ len < This->sectorSize) {
+ size_t readSize;
+ int ret;
+
+ readSize = This->cylinderSize -
+ This->current % This->cylinderSize;
+
+ ret=READS(This->Next, This->buf, This->current, readSize);
+ /* read it! */
+ if ( ret < 0 )
+ return ret;
+ if(ret % This->sectorSize) {
+ fprintf(stderr, "Weird: read size (%d) not a multiple of sector size (%d)\n", ret, (int) This->sectorSize);
+ ret -= ret % This->sectorSize;
+ if(ret == 0) {
+ fprintf(stderr, "Nothing left\n");
+ exit(1);
+ }
+ }
+ This->cur_size = ret;
+ /* for dosemu. Autoextend size */
+ if(!This->cur_size) {
+ memset(This->buf,0,readSize);
+ This->cur_size = readSize;
+ }
+ offset = OFFSET;
+ break;
+ }
+ /* FALL THROUGH */
+ case APPEND:
+#ifdef DEBUG
+ fprintf(stderr, "append\n");
+#endif
+ len = ROUND_DOWN(len, This->sectorSize);
+ offset = OFFSET;
+ maximize(len, This->size - offset);
+ This->cur_size += len;
+ if(This->Next->Class->pre_allocate)
+ PRE_ALLOCATE(This->Next,
+ This->current + This->cur_size);
+ break;
+ case INSIDE:
+ /* nothing to do */
+#ifdef DEBUG
+ fprintf(stderr, "inside\n");
+#endif
+ offset = OFFSET;
+ maximize(len, This->cur_size - offset);
+ break;
+ case ERROR:
+ return -1;
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "Should not happen\n");
+#endif
+ exit(1);
+ }
+
+ disk_ptr = This->buf + offset;
+
+ /* extend if we write beyond end */
+ if(offset + len > This->cur_size) {
+ len -= (offset + len) % This->sectorSize;
+ This->cur_size = len + offset;
+ }
+
+ memcpy(disk_ptr, buf, len);
+ if(!This->dirty || offset < This->dirty_pos)
+ This->dirty_pos = ROUND_DOWN(offset, This->sectorSize);
+ if(!This->dirty || offset + len > This->dirty_end)
+ This->dirty_end = ROUND_UP(offset + len, This->sectorSize);
+
+ if(This->dirty_end > This->cur_size) {
+ fprintf(stderr,
+ "Internal error, dirty end too big dirty_end=%x cur_size=%x len=%x offset=%d sectorSize=%x\n",
+ (unsigned int) This->dirty_end,
+ (unsigned int) This->cur_size,
+ (unsigned int) len,
+ (int) offset, (int) This->sectorSize);
+ fprintf(stderr, "offset + len + grain - 1 = %x\n",
+ (int) (offset + len + This->sectorSize - 1));
+ fprintf(stderr, "ROUNDOWN(offset + len + grain - 1) = %x\n",
+ (int)ROUND_DOWN(offset + len + This->sectorSize - 1,
+ This->sectorSize));
+ fprintf(stderr, "This->dirty = %d\n", This->dirty);
+ exit(1);
+ }
+
+ This->dirty = 1;
+ return len;
+}
+
+static int buf_flush(Stream_t *Stream)
+{
+ int ret;
+ DeclareThis(Buffer_t);
+
+ if (!This->ever_dirty)
+ return 0;
+ ret = _buf_flush(This);
+ if(ret == 0)
+ This->ever_dirty = 0;
+ return ret;
+}
+
+
+static int buf_free(Stream_t *Stream)
+{
+ DeclareThis(Buffer_t);
+
+ if(This->buf)
+ free(This->buf);
+ This->buf = 0;
+ return 0;
+}
+
+static Class_t BufferClass = {
+ buf_read,
+ buf_write,
+ buf_flush,
+ buf_free,
+ 0, /* set_geom */
+ get_data_pass_through, /* get_data */
+ 0, /* pre-allocate */
+ get_dosConvert_pass_through /* dos convert */
+};
+
+Stream_t *buf_init(Stream_t *Next, int size,
+ int cylinderSize,
+ int sectorSize)
+{
+ Buffer_t *Buffer;
+ Stream_t *Stream;
+
+
+ if(size % cylinderSize != 0) {
+ fprintf(stderr, "size not multiple of cylinder size\n");
+ exit(1);
+ }
+ if(cylinderSize % sectorSize != 0) {
+ fprintf(stderr, "cylinder size not multiple of sector size\n");
+ exit(1);
+ }
+
+ if(Next->Buffer){
+ Next->refs--;
+ Next->Buffer->refs++;
+ return Next->Buffer;
+ }
+
+ Stream = (Stream_t *) malloc (sizeof(Buffer_t));
+ if(!Stream)
+ return 0;
+ Buffer = (Buffer_t *) Stream;
+ Buffer->buf = malloc(size);
+ if ( !Buffer->buf){
+ Free(Stream);
+ return 0;
+ }
+ Buffer->size = size;
+ Buffer->dirty = 0;
+ Buffer->cylinderSize = cylinderSize;
+ Buffer->sectorSize = sectorSize;
+
+ Buffer->ever_dirty = 0;
+ Buffer->dirty_pos = 0;
+ Buffer->dirty_end = 0;
+ Buffer->current = 0L;
+ Buffer->cur_size = 0; /* buffer currently empty */
+
+ Buffer->Next = Next;
+ Buffer->Class = &BufferClass;
+ Buffer->refs = 1;
+ Buffer->Buffer = 0;
+ Buffer->Next->Buffer = (Stream_t *) Buffer;
+ return Stream;
+}
+
diff --git a/buffer.h b/buffer.h
new file mode 100644
index 0000000..6c79258
--- /dev/null
+++ b/buffer.h
@@ -0,0 +1,28 @@
+#ifndef MTOOLS_BUFFER_H
+#define MTOOLS_BUFFER_H
+
+/* Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+
+Stream_t *buf_init(Stream_t *Next,
+ int size,
+ int cylinderSize,
+ int sectorSize);
+
+#endif
diff --git a/buildMingw.sh b/buildMingw.sh
new file mode 100755
index 0000000..3414f3d
--- /dev/null
+++ b/buildMingw.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# Build Mingw (Windows) executable
+#
+# For this you meed the mingw cross-compiler to be installed
+#
+# You may download the RPMs from http://mirzam.it.vu.nl/mingw/
+# All 4 RPM's are needed:
+# mingw-binutils
+# mingw-gcc-core
+# mingw-runtime
+# mingw-w32api
+
+dir=`dirname $0`
+$dir/configure --srcdir $dir --host i586-mingw32msvc --disable-floppyd
+make
diff --git a/byte_dword.h b/byte_dword.h
new file mode 100644
index 0000000..c7963ea
--- /dev/null
+++ b/byte_dword.h
@@ -0,0 +1,63 @@
+#ifndef BYTE_DWORD
+#define BYTE_DWORD
+
+/* Copyright 2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static Dword byte2dword(Byte* val)
+{
+ Dword l;
+ l = (val[0] << 24) + (val[1] << 16) + (val[2] << 8) + val[3];
+
+ return l;
+}
+
+UNUSED(static Qword byte2qword(Byte* val))
+{
+ Qword l;
+ l = val[0];
+ l = (l << 8) | val[1];
+ l = (l << 8) | val[2];
+ l = (l << 8) | val[3];
+ l = (l << 8) | val[4];
+ l = (l << 8) | val[5];
+ l = (l << 8) | val[6];
+ l = (l << 8) | val[7];
+ return l;
+}
+
+static void dword2byte(Dword parm, Byte* rval)
+{
+ rval[0] = (parm >> 24) & 0xff;
+ rval[1] = (parm >> 16) & 0xff;
+ rval[2] = (parm >> 8) & 0xff;
+ rval[3] = parm & 0xff;
+}
+
+UNUSED(static void qword2byte(Qword parm, Byte* rval))
+{
+ rval[0] = (parm >> 56) & 0xff;
+ rval[1] = (parm >> 48) & 0xff;
+ rval[2] = (parm >> 40) & 0xff;
+ rval[3] = (parm >> 32) & 0xff;
+ rval[4] = (parm >> 24) & 0xff;
+ rval[5] = (parm >> 16) & 0xff;
+ rval[6] = (parm >> 8) & 0xff;
+ rval[7] = parm & 0xff;
+}
+
+#endif
diff --git a/charsetConv.c b/charsetConv.c
new file mode 100644
index 0000000..0dc1b6d
--- /dev/null
+++ b/charsetConv.c
@@ -0,0 +1,428 @@
+/* Copyright 2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Various character set conversions used by mtools
+ */
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "file_name.h"
+
+
+#ifdef HAVE_ICONV_H
+#include <iconv.h>
+
+struct doscp_t {
+ iconv_t from;
+ iconv_t to;
+};
+
+static const char *wcharCp=NULL;
+
+static const char* wcharTries[] = {
+ "WCHAR_T",
+ "UTF-32BE", "UTF-32LE",
+ "UTF-16BE", "UTF-16LE",
+ "UTF-32", "UTF-16",
+ "UCS-4BE", "UCS-4LE",
+ "UCS-2BE", "UCS-2LE",
+ "UCS-4", "UCS-2"
+};
+
+static const char *asciiTries[] = {
+ "ASCII", "ASCII-GR", "ISO8859-1"
+};
+
+static const wchar_t *testString = L"ab";
+
+static int try(const char *testCp) {
+ size_t res;
+ char *inbuf = (char *)testString;
+ size_t inbufLen = 2*sizeof(wchar_t);
+ char outbuf[3];
+ char *outbufP = outbuf;
+ size_t outbufLen = 2*sizeof(char);
+ iconv_t test;
+ int i;
+
+ for(i=0; i < sizeof(asciiTries) / sizeof(asciiTries[0]); i++) {
+ test = iconv_open(asciiTries[i], testCp);
+ if(test != (iconv_t) -1)
+ break;
+ }
+ if(test == (iconv_t) -1)
+ goto fail0;
+ res = iconv(test,
+ &inbuf, &inbufLen,
+ &outbufP, &outbufLen);
+ if(res != 0 || outbufLen != 0 || inbufLen != 0)
+ goto fail;
+ if(memcmp(outbuf, "ab", 2))
+ goto fail;
+ /* fprintf(stderr, "%s ok\n", testCp); */
+ return 1;
+ fail:
+ iconv_close(test);
+ fail0:
+ /*fprintf(stderr, "%s fail\n", testCp);*/
+ return 0;
+}
+
+static const char *getWcharCp(void) {
+ unsigned int i;
+ if(wcharCp != NULL)
+ return wcharCp;
+ for(i=0; i< sizeof(wcharTries) / sizeof(wcharTries[0]); i++) {
+ if(try(wcharTries[i]))
+ return (wcharCp=wcharTries[i]);
+ }
+ fprintf(stderr, "No codepage found for wchar_t\n");
+ return NULL;
+}
+
+
+doscp_t *cp_open(int codepage)
+{
+ char dosCp[17];
+ doscp_t *ret;
+ iconv_t *from;
+ iconv_t *to;
+
+ if(codepage == 0)
+ codepage = mtools_default_codepage;
+ if(codepage < 0 || codepage > 9999) {
+ fprintf(stderr, "Bad codepage %d\n", codepage);
+ return NULL;
+ }
+
+ if(getWcharCp() == NULL)
+ return NULL;
+
+ sprintf(dosCp, "CP%d", codepage);
+ from = iconv_open(wcharCp, dosCp);
+ if(from == (iconv_t)-1) {
+ fprintf(stderr, "Error converting to codepage %d %s\n",
+ codepage, strerror(errno));
+ return NULL;
+ }
+
+ sprintf(dosCp, "CP%d//TRANSLIT", codepage);
+ to = iconv_open(dosCp, wcharCp);
+ if(to == (iconv_t)-1) {
+ /* Transliteration not supported? */
+ sprintf(dosCp, "CP%d", codepage);
+ to = iconv_open(dosCp, wcharCp);
+ }
+ if(to == (iconv_t)-1) {
+ iconv_close(from);
+ fprintf(stderr, "Error converting to codepage %d %s\n",
+ codepage, strerror(errno));
+ return NULL;
+ }
+
+ ret = New(doscp_t);
+ if(ret == NULL)
+ return ret;
+ ret->from = from;
+ ret->to = to;
+ return ret;
+}
+
+void cp_close(doscp_t *cp)
+{
+ iconv_close(cp->to);
+ iconv_close(cp->from);
+ free(cp);
+}
+
+int dos_to_wchar(doscp_t *cp, 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;
+ unsigned 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, generating at most len wchar
+ * characters. If end is supplied, stop conversion when source pointer
+ * exceeds end. Returns number of generated wchars
+ */
+int native_to_wchar(const char *native, wchar_t *wchar, size_t len,
+ const char *end, int *mangled)
+{
+ mbstate_t ps;
+ unsigned int i;
+ memset(&ps, 0, sizeof(ps));
+
+ for(i=0; i<len && (native < end || !end); i++) {
+ int r = mbrtowc(wchar+i, native, len, &ps);
+ if(r < 0) {
+ /* Unconvertible character. Just pretend it's Latin1
+ encoded (if valid Latin1 character) or 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) || (!end && *native && i == len)))
+ *mangled |= 3;
+ wchar[i]='\0';
+ return i;
+}
+
diff --git a/cleanconfig b/cleanconfig
new file mode 100644
index 0000000..1a4d69e
--- /dev/null
+++ b/cleanconfig
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Copyright 2001,2002,2005 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+# Removes all autoconfig related files
+rm -f config.sub config.guess configure config.h.in
diff --git a/codepage.h b/codepage.h
new file mode 100644
index 0000000..8775865
--- /dev/null
+++ b/codepage.h
@@ -0,0 +1,42 @@
+/* Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct Codepage_l {
+ int nr;
+ unsigned char tounix[128];
+} Codepage_t;
+
+
+typedef struct country_l {
+ int country;
+ int codepage;
+ int default_codepage;
+ int to_upper;
+} country_t;
+
+
+void init_codepage(void);
+unsigned char to_dos(unsigned char c);
+void to_unix(char *a, int n);
+char contents_to_unix(char a);
+
+extern Codepage_t *Codepage;
+extern char *mstoupper;
+extern country_t countries[];
+extern unsigned char toucase[][128];
+extern Codepage_t codepages[];
+extern char *country_string;
diff --git a/codepages.c b/codepages.c
new file mode 100644
index 0000000..5558724
--- /dev/null
+++ b/codepages.c
@@ -0,0 +1,117 @@
+/* Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "config.h"
+
+#ifndef HAVE_ICONV_H
+#include "codepage.h"
+
+Codepage_t codepages[]= {
+ { 437,
+ "ÇüéâäàåçêëèïîìÄÅ"
+ "ÉæÆôöòûùÿÖÜ¢£¥Pf"
+ "áíóúñѪº¿r¬½¼¡«»"
+ "_______________¬"
+ "________________"
+ "________________"
+ "abgpSsµtftodøØ_N"
+ "=±<>||÷~°··Vn²__"
+ },
+
+ { 819,
+ "________________"
+ "________________"
+ " ¡¢£¤¥¦§¨©ª«¬­®¯"
+ "°±²³´µ¶·¸¹º»¼½¾¿"
+ "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ"
+ "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß"
+ "àáâãäåæçèéêëìíîï"
+ "ðñòóôõö÷øùúûüýþÿ"
+ },
+
+ { 850,
+ "ÇüéâäàåçêëèïîìÄÅ"
+ "ÉæÆôöòûùÿÖÜø£Ø×_"
+ "áíóúñѪº¿®¬½¼¡«»"
+ "_____ÁÂÀ©____¢¥¬"
+ "______ãÃ_______¤"
+ "ðÐÉËÈiÍÎÏ____|I_"
+ "ÓßÔÒõÕµþÞÚÙýÝÞ¯´"
+ "­±_¾¶§÷¸°¨·¹³²__"
+ },
+
+ { 852,
+ "ÇüéâäucçlëÕõîZÄC"
+ "ÉLlôöLlSsÖÜTtL×c"
+ "áíóúAaZzEe zCs«»"
+ "_____ÁÂES____Zz¬"
+ "______Aa_______¤"
+ "ðÐDËdÑÍÎe_r__TU_"
+ "ÓßÔNnñSsRÚrUýÝt´"
+ "­~.~~§÷¸°¨·¹uRr_"
+ },
+
+ { 860,
+ "ÇüéâãàåçêëèÍõìÃÂ"
+ "ÉÀÈôõòÚùÌÕÜ¢£ÙPÓ"
+ "áíóúñѪº¿Ò¬½¼¡«»"
+ "_______________¬"
+ "________________"
+ "________________"
+ "abgpSsµtftodøØ_N"
+ "=±<>||÷~°··Vn²__"
+ },
+
+ { 863,
+ "ÇüéâÂà¶çêëèïî_À§"
+ "ÉÈÊôËÏûù¤ÔÜ¢£ÙÛf"
+ "|´óú¨ ³¯Îr¬½¼¾«»"
+ "_______________¬"
+ "________________"
+ "________________"
+ "abgpSsµtftodøØ_N"
+ "=±<>||÷~°··Vn²__"
+ },
+
+ { 865,
+ "ÇüéâäàåçêëèïîìÄÅ"
+ "ÉæÆôöòûùÿÖÜø£ØPf"
+ "áíóúñѪº¿r¬½¼¡«¤"
+ "_______________¬"
+ "________________"
+ "________________"
+ "abgpSsµtftodøØ_N"
+ "=±<>||÷~°··Vn²__",
+ },
+
+ /* Taiwanese (Chinese Complex Character) support */
+ { 950,
+ "€‚ƒ„…†‡ˆ‰Š‹ŒŽ"
+ "‘’“”•–—˜™š›œžŸ"
+ " ¡¢£¤¥¦§¨©ª«¬­®¯"
+ "°±²³´µ¶·¸¹º»¼½¾¿"
+ "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ"
+ "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß"
+ "àáâãäåæçèéêëìíîï"
+ "ðñòóôõö÷øùúûüýþÿ",
+ },
+
+
+ { 0 }
+};
+
+#endif
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..f086883
--- /dev/null
+++ b/config.c
@@ -0,0 +1,806 @@
+/* Copyright 1996-2005,2007-2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "sysincludes.h"
+#include "mtools.h"
+#include "codepage.h"
+#include "mtoolsPaths.h"
+
+/* global variables */
+/* they are not really harmful here, because there is only one configuration
+ * file per invocations */
+
+#define MAX_LINE_LEN 256
+
+/* scanner */
+static char buffer[MAX_LINE_LEN+1]; /* buffer for the whole line */
+static char *pos; /* position in line */
+static char *token; /* last scanned token */
+static size_t token_length; /* length of the token */
+static FILE *fp; /* file pointer for configuration file */
+static int linenumber; /* current line number. Only used for printing
+ * error messages */
+static int lastTokenLinenumber; /* line numnber for last token */
+static const char *filename=NULL; /* current file name. Used for printing
+ * error messages, and for storing in
+ * the device definition (mtoolstest) */
+static int file_nr=0;
+
+
+static 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)
+{
+ if(cur_dev == -1) {
+ trusted = 0;
+ return;
+ }
+ if(!devices[cur_dev].name)
+ syntax("missing filename", 0);
+ if(devices[cur_dev].tracks ||
+ devices[cur_dev].heads ||
+ devices[cur_dev].sectors) {
+ if(!devices[cur_dev].tracks ||
+ !devices[cur_dev].heads ||
+ !devices[cur_dev].sectors)
+ syntax("incomplete geometry: either indicate all of track/heads/sectors or none of them", 0);
+ if(!(devices[cur_dev].misc_flags &
+ (MFORMAT_ONLY_FLAG | FILTER_FLAG)))
+ syntax("if you supply a geometry, you also must supply one of the `mformat_only' or `filter' flags", 0);
+ }
+ devices[cur_dev].file_nr = file_nr;
+ devices[cur_dev].cfg_filename = filename;
+ if(! (flag_mask & PRIV_FLAG) && IS_SCSI(&devices[cur_dev]))
+ devices[cur_dev].misc_flags |= PRIV_FLAG;
+ if(!trusted && (devices[cur_dev].misc_flags & PRIV_FLAG)) {
+ fprintf(stderr,
+ "Warning: privileged flag ignored for drive %c: defined in file %s\n",
+ 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);
+
+void set_cmd_line_image(char *img) {
+ char *ofsp;
+
+ prepend();
+ devices[cur_dev].drive = ':';
+ default_drive = ':';
+
+ ofsp = strstr(img, "@@");
+ if (ofsp == NULL) {
+ /* no separator => no offset */
+ devices[cur_dev].name = strdup(img);
+ devices[cur_dev].offset = 0;
+ } else {
+ devices[cur_dev].name = strndup(img, ofsp - img);
+ devices[cur_dev].offset = str_to_offset(ofsp+2);
+ }
+
+ devices[cur_dev].fat_bits = 0;
+ devices[cur_dev].tracks = 0;
+ devices[cur_dev].heads = 0;
+ devices[cur_dev].sectors = 0;
+ if (strchr(devices[cur_dev].name, '|')) {
+ char *pipechar = strchr(devices[cur_dev].name, '|');
+ *pipechar = 0;
+ strncpy(buffer, pipechar+1, MAX_LINE_LEN);
+ buffer[MAX_LINE_LEN] = '\0';
+ fp = NULL;
+ filename = "{command line}";
+ linenumber = 0;
+ lastTokenLinenumber = 0;
+ pos = buffer;
+ token = 0;
+ 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 UNUSEDP)
+{
+ /* 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 100755
index 0000000..e3a2116
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1533 @@
+#! /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, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-06-10'
+
+# 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 -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # 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 ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[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 -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ 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 | genuineintel)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-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:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | 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 -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ 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"
+ ;;
+ 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.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ 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 ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ 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
index 0000000..fe08c4d
--- /dev/null
+++ b/config.h.Be
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1997 Marco Nelissen
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define PREFIX "/boot/system"
+#define HAVE_ATEXIT
+#define HAVE_FCNTL_H
+#define HAVE_GETOPT_H
+#define HAVE_LIMITS_H
+#define HAVE_SYS_IOCTL_H
+#define TIME_WITH_SYS_TIME 1
+#define HAVE_TERMIOS_H
+#define HAVE_SYS_PARAM_H
+#define HAVE_STRING_H
+#define HAVE_MEMORY_H
+#define HAVE_MALLOC_H
+#define HAVE_UTIME_H
+#define HAVE_SYS_WAIT_H
+#define HAVE_MEMCPY
+#define HAVE_MEMSET
+#define HAVE_STRERROR
+#define HAVE_STRNCASECMP
+#define HAVE_STRCASECMP
+#undef HAVE_GETPASS
+#define HAVE_STDLIB_H
+#define HAVE_STRCHR
+#define HAVE_STRRCHR
+#define HAVE_UNISTD_H
+#define RETSIGTYPE void
+#define HAVE_STRDUP
+#define HAVE_STRPBRK
+#define HAVE_STRSPN
+#define HAVE_STRTOUL
+#define HAVE_STRCSPN
+#define HAVE_RANDOM
+#define random rand
+#define HAVE_SRANDOM
+#define srandom srand
+#define INIT_NOOP
+#include <signal.h>
+#define SYSCONFDIR "/boot/system"
+#define USE_RAWTERM
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..330dabc
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,406 @@
+/* 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 the system has the type `caddr_t'. */
+#undef HAVE_CADDR_T
+
+/* Define to 1 if you have the `fchdir' function. */
+#undef HAVE_FCHDIR
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `flock' function. */
+#undef HAVE_FLOCK
+
+/* Define to 1 if you have the `getgroupid' function. */
+#undef HAVE_GETGROUPID
+
+/* Define to 1 if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define to 1 if you have the `getpass' function. */
+#undef HAVE_GETPASS
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the `getuserid' function. */
+#undef HAVE_GETUSERID
+
+/* Define to 1 if you have the `htons' function. */
+#undef HAVE_HTONS
+
+/* Define to 1 if you have the <iconv.h> header file. */
+#undef HAVE_ICONV_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `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 `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the `sun' library (-lsun). */
+#undef HAVE_LIBSUN
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+#undef HAVE_LINUX_FS_H
+
+/* Define to 1 if you have the <linux/unistd.h> header file. */
+#undef HAVE_LINUX_UNISTD_H
+
+/* Define to 1 if you have the `llseek' function. */
+#undef HAVE_LLSEEK
+
+/* Define when you have an LLSEEK prototype */
+#undef HAVE_LLSEEK_PROTOTYPE
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have the `lockf' function. */
+#undef HAVE_LOCKF
+
+/* Define when the compiler supports LOFF_T type */
+#undef HAVE_LOFF_T
+
+/* Define when the compiler supports LONG_LONG type */
+#undef HAVE_LONG_LONG
+
+/* Define to 1 if you have the `lseek64' function. */
+#undef HAVE_LSEEK64
+
+/* Define when you have an LSEEK64 prototype */
+#undef HAVE_LSEEK64_PROTOTYPE
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `media_oldaliases' function. */
+#undef HAVE_MEDIA_OLDALIASES
+
+/* Define to 1 if you have the `memcpy' function. */
+#undef HAVE_MEMCPY
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define when the compiler supports OFFSET_T type */
+#undef HAVE_OFFSET_T
+
+/* Define when the system has a 64 bit off_t type */
+#undef HAVE_OFF_T_64
+
+/* Define to 1 if you have the `on_exit' function. */
+#undef HAVE_ON_EXIT
+
+/* Define to 1 if you have the `putwc' function. */
+#undef HAVE_PUTWC
+
+/* Define to 1 if you have the `random' function. */
+#undef HAVE_RANDOM
+
+/* Define to 1 if you have the `setenv' function. */
+#undef HAVE_SETENV
+
+/* Define to 1 if you have the `seteuid' function. */
+#undef HAVE_SETEUID
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the `setpgrp' function. */
+#undef HAVE_SETPGRP
+
+/* Define to 1 if you have the `setresuid' function. */
+#undef HAVE_SETRESUID
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#undef HAVE_SGTTY_H
+
+/* Define to 1 if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the `snprintf' function. */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if you have the `srandom' function. */
+#undef HAVE_SRANDOM
+
+/* Define to 1 if you have the `stat64' function. */
+#undef HAVE_STAT64
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strcspn' function. */
+#undef HAVE_STRCSPN
+
+/* Define to 1 if you have the `strdup' function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strncasecmp' function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the `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 home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to 1 if the `setpgrp' function takes no argument. */
+#undef SETPGRP_VOID
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define when you want to include floppyd support */
+#undef USE_FLOPPYD
+
+/* Define on non Unix OS'es which don't have the concept of tty's */
+#undef USE_RAWTERM
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Define this if you want to use Xdf */
+#undef USE_XDF
+
+/* Define this if you use mtools together with the new Solaris' vold support
+ */
+#undef USING_NEW_VOLD
+
+/* Define this if you use mtools together with Solaris' vold */
+#undef USING_VOLD
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* 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 100755
index 0000000..eb0389a
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1693 @@
+#! /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, 2009
+# Free Software Foundation, Inc.
+
+timestamp='2009-06-11'
+
+# 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* | \
+ kopensolaris*-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
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ 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 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | 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[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ 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-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | 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[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ 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
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -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* | -cegcc* \
+ | -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
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -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
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..1810eff
--- /dev/null
+++ b/configure
@@ -0,0 +1,7234 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ # Preserve -v and -x to the replacement shell.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+ esac
+ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -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='mkdir -p "$as_dir"'
+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'"
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+PACKAGE_URL=
+
+ac_unique_file="buffer.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+HOST_ID
+SHLIB
+MACHDEPLIBS
+extralibdir
+extraincludedir
+BINFLOPPYD
+FLOPPYD
+X_EXTRA_LIBS
+X_LIBS
+X_PRE_LIBS
+X_CFLAGS
+XMKMF
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+INSTALL_INFO
+LN_S
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+EGREP
+GREP
+CPP
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_xdf
+enable_vold
+enable_new_vold
+enable_debug
+enable_raw_term
+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= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $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_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --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 (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ XMKMF Path to xmkmf, Makefile generator for X Window System
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid; break
+else
+ as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=$ac_mid; break
+else
+ as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid
+else
+ as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ return 1;
+ if (($2) < 0)
+ {
+ long int i = longval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%ld", i);
+ }
+ else
+ {
+ unsigned long int i = ulongval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%lu", i);
+ }
+ /* Do not output a trailing newline, as this causes \r\n confusion
+ on some platforms. */
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+ ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+ fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#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"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { 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
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { 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
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+if test $ac_cv_c_compiler_gnu = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC needs -traditional" >&5
+$as_echo_n "checking whether $CC needs -traditional... " >&6; }
+if ${ac_cv_prog_gcc_traditional+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_pattern="Autoconf.*'x'"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sgtty.h>
+Autoconf TIOCGETP
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+ ac_cv_prog_gcc_traditional=yes
+else
+ ac_cv_prog_gcc_traditional=no
+fi
+rm -f conftest*
+
+
+ if test $ac_cv_prog_gcc_traditional = no; then
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <termio.h>
+Autoconf TCGETA
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "$ac_pattern" >/dev/null 2>&1; then :
+ ac_cv_prog_gcc_traditional=yes
+fi
+rm -f conftest*
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gcc_traditional" >&5
+$as_echo "$ac_cv_prog_gcc_traditional" >&6; }
+ if test $ac_cv_prog_gcc_traditional = yes; then
+ CC="$CC -traditional"
+ fi
+fi
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+
+# Extract the first word of "install-info", so it can be a program name with args.
+set dummy install-info; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_INSTALL_INFO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $INSTALL_INFO in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_INSTALL_INFO="$INSTALL_INFO" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { 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:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_path_INSTALL_INFO" && ac_cv_path_INSTALL_INFO=""""
+ ;;
+esac
+fi
+INSTALL_INFO=$ac_cv_path_INSTALL_INFO
+if test -n "$INSTALL_INFO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL_INFO" >&5
+$as_echo "$INSTALL_INFO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+ MINIX=yes
+else
+ MINIX=
+fi
+
+
+ if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# define __EXTENSIONS__ 1
+ $ac_includes_default
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_safe_to_define___extensions__=yes
+else
+ ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+ $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+ $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$target_alias" = x; then
+ ac_cv_target=$ac_cv_host
+else
+ ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* 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
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+
+
+# Check whether --enable-xdf was given.
+if test "${enable_xdf+set}" = set; then :
+ enableval=$enable_xdf; if test x$enableval = xyes; then
+
+$as_echo "#define USE_XDF 1" >>confdefs.h
+
+fi
+else
+
+$as_echo "#define USE_XDF 1" >>confdefs.h
+
+fi
+
+
+
+# Check whether --enable-vold was given.
+if test "${enable_vold+set}" = set; then :
+ enableval=$enable_vold; if test x$enableval = xyes; then
+
+$as_echo "#define USING_VOLD 1" >>confdefs.h
+
+fi
+fi
+
+
+
+# Check whether --enable-new-vold was given.
+if test "${enable_new_vold+set}" = set; then :
+ enableval=$enable_new_vold; newVold=x$enableval
+if test x$enableval = xyes; then
+
+$as_echo "#define USING_NEW_VOLD 1" >>confdefs.h
+
+fi
+fi
+
+
+
+# Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+ enableval=$enable_debug; if test x$enableval = xyes; then
+
+$as_echo "#define DEBUG 1" >>confdefs.h
+
+fi
+fi
+
+
+
+# Check whether --enable-raw_term was given.
+if test "${enable_raw_term+set}" = set; then :
+ enableval=$enable_raw_term; if test x$enableval = xyes; then
+
+$as_echo "#define USE_RAWTERM 1" >>confdefs.h
+
+fi
+else
+
+$as_echo "#define USE_RAWTERM 1" >>confdefs.h
+
+fi
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwnam in -lsun" >&5
+$as_echo_n "checking for getpwnam in -lsun... " >&6; }
+if ${ac_cv_lib_sun_getpwnam+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsun $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char getpwnam ();
+int
+main ()
+{
+return getpwnam ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_sun_getpwnam=yes
+else
+ ac_cv_lib_sun_getpwnam=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sun_getpwnam" >&5
+$as_echo "$ac_cv_lib_sun_getpwnam" >&6; }
+if test "x$ac_cv_lib_sun_getpwnam" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSUN 1
+_ACEOF
+
+ LIBS="-lsun $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cam_open_device in -lcam" >&5
+$as_echo_n "checking for cam_open_device in -lcam... " >&6; }
+if ${ac_cv_lib_cam_cam_open_device+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcam $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cam_open_device ();
+int
+main ()
+{
+return cam_open_device ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_cam_cam_open_device=yes
+else
+ ac_cv_lib_cam_cam_open_device=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cam_cam_open_device" >&5
+$as_echo "$ac_cv_lib_cam_cam_open_device" >&6; }
+if test "x$ac_cv_lib_cam_cam_open_device" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCAM 1
+_ACEOF
+
+ LIBS="-lcam $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5
+$as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; }
+if ${ac_cv_header_sys_wait_h+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/wait.h>
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+int
+main ()
+{
+ int s;
+ wait (&s);
+ s = WIFEXITED (s) ? WEXITSTATUS (s) : 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_sys_wait_h=yes
+else
+ ac_cv_header_sys_wait_h=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5
+$as_echo "$ac_cv_header_sys_wait_h" >&6; }
+if test $ac_cv_header_sys_wait_h = yes; then
+
+$as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
+
+fi
+
+for ac_header in getopt.h sys/stat.h stdlib.h unistd.h linux/unistd.h \
+libc.h fcntl.h limits.h sys/file.h sys/ioctl.h sys/time.h strings.h string.h \
+sys/param.h memory.h malloc.h 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 linux/fs.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_header in termio.h sys/termio.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+
+done
+
+for ac_header in termios.h sys/termios.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+
+done
+
+
+ac_fn_c_check_type "$LINENO" "caddr_t" "ac_cv_type_caddr_t" "$ac_includes_default"
+if test "x$ac_cv_type_caddr_t" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_CADDR_T 1
+_ACEOF
+
+
+fi
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of size_t" >&5
+$as_echo_n "checking size of size_t... " >&6; }
+if ${ac_cv_sizeof_size_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (size_t))" "ac_cv_sizeof_size_t" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_size_t" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot compute sizeof (size_t)
+See \`config.log' for more details" "$LINENO" 5; }
+ else
+ ac_cv_sizeof_size_t=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_size_t" >&5
+$as_echo "$ac_cv_sizeof_size_t" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIZE_T $ac_cv_sizeof_size_t
+_ACEOF
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether llseek declared in unistd.h" >&5
+$as_echo_n "checking whether llseek declared in unistd.h... " >&6; }
+if ${mtools_cv_have_llseek_prototype+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <unistd.h>
+int
+main ()
+{
+extern int llseek(int);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ mtools_cv_have_llseek_prototype=no
+else
+ mtools_cv_have_llseek_prototype=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mtools_cv_have_llseek_prototype" >&5
+$as_echo "$mtools_cv_have_llseek_prototype" >&6; }
+if test "$mtools_cv_have_llseek_prototype" = yes; then
+
+$as_echo "#define HAVE_LLSEEK_PROTOTYPE 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether lseek64 declared in unistd.h" >&5
+$as_echo_n "checking whether lseek64 declared in unistd.h... " >&6; }
+if ${mtools_cv_have_lseek64_prototype+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include "sysincludes.h"
+#include <unistd.h>
+
+int
+main ()
+{
+extern int lseek64(int);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ mtools_cv_have_lseek64_prototype=no
+else
+ mtools_cv_have_lseek64_prototype=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mtools_cv_have_lseek64_prototype" >&5
+$as_echo "$mtools_cv_have_lseek64_prototype" >&6; }
+if test "$mtools_cv_have_lseek64_prototype" = yes; then
+
+$as_echo "#define HAVE_LSEEK64_PROTOTYPE 1" >>confdefs.h
+
+fi
+
+
+for ac_func in htons
+do :
+ ac_fn_c_check_func "$LINENO" "htons" "ac_cv_func_htons"
+if test "x$ac_cv_func_htons" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_HTONS 1
+_ACEOF
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* 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
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if ${ac_cv_c_inline+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = xyes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if ${ac_cv_header_time+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_time=yes
+else
+ ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if ${ac_cv_struct_tm+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+ int *p = &tm.tm_sec;
+ return !p;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_struct_tm=time.h
+else
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
+
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5
+$as_echo_n "checking return type of signal handlers... " >&6; }
+if ${ac_cv_type_signal+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <signal.h>
+
+int
+main ()
+{
+return *(signal (0, 0)) (0) == 1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_signal=int
+else
+ ac_cv_type_signal=void
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5
+$as_echo "$ac_cv_type_signal" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define RETSIGTYPE $ac_cv_type_signal
+_ACEOF
+
+
+for ac_func in strerror random srandom strchr strrchr lockf flock \
+strcasecmp strncasecmp strnlen atexit on_exit getpass memmove \
+strdup 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 \
+sigaction
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 64-bit off_t" >&5
+$as_echo_n "checking for 64-bit off_t... " >&6; }
+if ${sfs_cv_off_t_64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <unistd.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+switch (0) case 0: case (sizeof (off_t) <= 4):;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ sfs_cv_off_t_64=no
+else
+ sfs_cv_off_t_64=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sfs_cv_off_t_64" >&5
+$as_echo "$sfs_cv_off_t_64" >&6; }
+if test $sfs_cv_off_t_64 = yes; then
+
+$as_echo "#define HAVE_OFF_T_64 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports loff_t type" >&5
+$as_echo_n "checking whether ${CC} supports loff_t type... " >&6; }
+if ${ice_cv_have_loff_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main ()
+{
+loff_t a;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ice_cv_have_loff_t=yes
+else
+ ice_cv_have_loff_t=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ice_cv_have_loff_t" >&5
+$as_echo "$ice_cv_have_loff_t" >&6; }
+if test "$ice_cv_have_loff_t" = yes; then
+
+$as_echo "#define HAVE_LOFF_T 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports offset_t type" >&5
+$as_echo_n "checking whether ${CC} supports offset_t type... " >&6; }
+if ${ice_cv_have_offset_t+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main ()
+{
+offset_t a;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ice_cv_have_offset_t=yes
+else
+ ice_cv_have_offset_t=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ice_cv_have_offset_t" >&5
+$as_echo "$ice_cv_have_offset_t" >&6; }
+if test "$ice_cv_have_offset_t" = yes; then
+
+$as_echo "#define HAVE_OFFSET_T 1" >>confdefs.h
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC} supports long long type" >&5
+$as_echo_n "checking whether ${CC} supports long long type... " >&6; }
+if ${ice_cv_have_long_long+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+long long a;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ice_cv_have_long_long=yes
+else
+ ice_cv_have_long_long=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ice_cv_have_long_long" >&5
+$as_echo "$ice_cv_have_long_long" >&6; }
+if test "$ice_cv_have_long_long" = yes; then
+
+$as_echo "#define HAVE_LONG_LONG 1" >>confdefs.h
+
+fi
+
+
+
+for ac_func in utimes utime
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+ break
+fi
+done
+
+for ac_func in tzset gettimeofday
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking declaration of sys_errlist" >&5
+$as_echo_n "checking declaration of sys_errlist... " >&6; }
+if ${cf_cv_dcl_sys_errlist+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+int
+main ()
+{
+char *c = (char *) *sys_errlist
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cf_cv_dcl_sys_errlist=yes
+else
+ cf_cv_dcl_sys_errlist=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cf_cv_dcl_sys_errlist" >&5
+$as_echo "$cf_cv_dcl_sys_errlist" >&6; }
+test $cf_cv_dcl_sys_errlist = no ||
+$as_echo "#define DECL_SYS_ERRLIST 1" >>confdefs.h
+
+
+
+
+host_os0=`echo $host_os | sed 's/-/_/g'`
+host_os1=`echo $host_os0 | sed 's/\./_/g'`
+host_os2=`echo $host_os0 | sed 's/^\([^.]*\)\..*$/\1/g'`
+host_os3=`echo $host_os2 | sed 's/^\([^0-9]*\)[0-9]*$/\1/g'`
+host_cpu1=`echo $host_cpu | sed 's/\./_/g'`
+host_vendor1=`echo $host_vendor | sed 's/\./_/g'`
+HOST_ID="-DCPU_$host_cpu1 -DVENDOR_$host_vendor1 -DOS_$host_os1"
+if [ $host_os1 != $host_os2 ] ; then
+ HOST_ID="$HOST_ID -DOS_$host_os2"
+fi
+if [ $host_os1 != $host_os3 ] && [ $host_os2 != $host_os3 ] ; then
+ HOST_ID="$HOST_ID -DOS_$host_os3"
+fi
+
+my_host_os=`echo $host_os1 $host_os2 $host_os3 | sort -u`
+objs=`echo $srcdir/*.c | sed 's/\.c$/.o/' `
+if [ "X$GCC" = "Xyes" ] ; then
+ Wall=-Wall
+ if [ "$host_os3" = sunos ] ; then
+ Wall=""
+ fi
+ if [ "$host_os3" = ultrix ] ; then
+ Wall=""
+ fi
+ if [ "$host_os3" = linux ] ; then
+ CFLAGS="$CFLAGS -fno-strength-reduce"
+ fi
+ if [ "$host_os3" = aux ] ; then
+ CFLAGS="$CFLAGS -ZP"
+ MACHDEPLIBS="-lposix -UTIL"
+ fi
+ case "${host}" in
+ arm*-*-linux) CFLAGS="$CFLAGS -mstructure-size-boundary=8";;
+ esac
+ CFLAGS="$CFLAGS $Wall"
+else
+ if [ $host_os3 = hpux ] ; then
+ CPPFLAGS="$CPPFLAGS -Ae"
+ fi
+
+ if [ $host_os3 = xenix ] ; then
+ CFLAGS="$CFLAGS -M2e"
+ fi
+fi
+
+if [ $host_os3 = hpux ] ; then
+ LDFLAGS="$LDFLAGS -z"
+fi
+
+if [ $host_os3 = xenix ] ; then
+ LDFLAGS="$LDFLAGS -M2e -i -f 5000"
+fi
+
+if [ $host_os2 = sysv4 ] ; then
+ SHLIB="-lc -L/usr/ucblib -lucb"
+else
+ SHLIB=""
+fi
+
+if [ $host_os3 = isc ] ; then
+ CFLAGS="$CFLAGS -D_SYSV3"
+ SHLIB="-lc_s"
+fi
+
+if [ $host_os3 = solaris -a x$newVold = xxyes ] ; then
+ SHLIB="$SHLIB -s -lvolmgt"
+fi
+
+if [ $host_os3 = nextstep ] ; then
+ CFLAGS="$CFLAGS -DBSD"
+ SHLIB=""
+fi
+
+if [ -d /usr/5lib ] ; then
+ extralibdir=-L/usr/5lib
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5
+$as_echo_n "checking for X... " >&6; }
+
+
+# Check whether --with-x was given.
+if test "${with_x+set}" = set; then :
+ withval=$with_x;
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ case $x_includes,$x_libraries in #(
+ *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #(
+ *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=no ac_x_libraries=no
+rm -f -r conftest.dir
+if mkdir conftest.dir; then
+ cd conftest.dir
+ cat >Imakefile <<'_ACEOF'
+incroot:
+ @echo incroot='${INCROOT}'
+usrlibdir:
+ @echo usrlibdir='${USRLIBDIR}'
+libdir:
+ @echo libdir='${LIBDIR}'
+_ACEOF
+ if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+ for ac_var in incroot usrlibdir libdir; do
+ eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
+ done
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl dylib la dll; do
+ if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" &&
+ test -f "$ac_im_libdir/libX11.$ac_extension"; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case $ac_im_incroot in
+ /usr/include) ac_x_includes= ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
+ esac
+ case $ac_im_usrlibdir in
+ /usr/lib | /usr/lib64 | /lib | /lib64) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
+ esac
+ fi
+ cd ..
+ rm -f -r conftest.dir
+fi
+
+# Standard set of common directories for X headers.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ac_x_header_dirs='
+/usr/X11/include
+/usr/X11R7/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R7
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R7/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R7
+/usr/local/include/X11R6
+/usr/local/include/X11R5
+/usr/local/include/X11R4
+
+/usr/X386/include
+/usr/x386/include
+/usr/XFree86/include/X11
+
+/usr/include
+/usr/local/include
+/usr/unsupported/include
+/usr/athena/include
+/usr/local/x11r5/include
+/usr/lpp/Xamples/include
+
+/usr/openwin/include
+/usr/openwin/share/include'
+
+if test "$ac_x_includes" = no; then
+ # Guess where to find include files, by looking for Xlib.h.
+ # First, try using that file with no special directory specified.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ for ac_dir in $ac_x_header_dirs; do
+ if test -r "$ac_dir/X11/Xlib.h"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+done
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi # $ac_x_includes = no
+
+if test "$ac_x_libraries" = no; then
+ # Check for the libraries.
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS=$LIBS
+ LIBS="-lX11 $LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ LIBS=$ac_save_LIBS
+for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
+do
+ # Don't even attempt the hair of trying to link an X program!
+ for ac_extension in a so sl dylib la dll; do
+ if test -r "$ac_dir/libX11.$ac_extension"; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
+
+case $ac_x_includes,$ac_x_libraries in #(
+ no,* | *,no | *\'*)
+ # Didn't find X, or a directory has "'" in its name.
+ ac_cv_have_x="have_x=no";; #(
+ *)
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$ac_x_includes'\
+ ac_x_libraries='$ac_x_libraries'"
+esac
+fi
+;; #(
+ *) have_x=yes;;
+ esac
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5
+$as_echo "$have_x" >&6; }
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$x_includes'\
+ ac_x_libraries='$x_libraries'"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5
+$as_echo "libraries $x_libraries, headers $x_includes" >&6; }
+fi
+
+if test "$no_x" = yes; then
+ # Not all programs may use this symbol, but it does not hurt to define it.
+
+$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h
+
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ # It would also be nice to do this for all -L options, not just this one.
+ if test -n "$x_libraries"; then
+ X_LIBS="$X_LIBS -L$x_libraries"
+ # For Solaris; some versions of Sun CC require a space after -R and
+ # others require no space. Words are not sufficient . . . .
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5
+$as_echo_n "checking whether -R must be followed by a space... " >&6; }
+ ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+ ac_xsave_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ X_LIBS="$X_LIBS -R$x_libraries"
+else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ X_LIBS="$X_LIBS -R $x_libraries"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_c_werror_flag=$ac_xsave_c_werror_flag
+ LIBS=$ac_xsave_LIBS
+ fi
+
+ # Check for system-dependent libraries X programs must link with.
+ # Do this before checking for the system-independent R6 libraries
+ # (-lICE), since we may need -lsocket or whatever for X linking.
+
+ if test "$ISC" = yes; then
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+ else
+ # Martyn Johnson says this is needed for Ultrix, if the X
+ # libraries were built with DECnet support. And Karl Berry says
+ # the Alpha needs dnet_stub (dnet does not exist).
+ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet_stub $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_xsave_LIBS"
+
+ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+ # to get the SysV transport functions.
+ # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4)
+ # needs -lnsl.
+ # The nsl library prevents programs from opening the X display
+ # on Irix 5.2, according to T.E. Dickey.
+ # The functions gethostbyname, getservbyname, and inet_addr are
+ # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking.
+ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+ if test $ac_cv_lib_nsl_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bsd_gethostbyname=yes
+else
+ ac_cv_lib_bsd_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd"
+fi
+
+ fi
+ fi
+
+ # lieder@skyler.mavd.honeywell.com says without -lsocket,
+ # socket/setsockopt and other routines are undefined under SCO ODT
+ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
+ # on later versions), says Simon Leinen: it contains gethostby*
+ # variants that don't use the name server (or something). -lsocket
+ # must be given before -lnsl if both are needed. We assume that
+ # if connect needs -lnsl, so does gethostbyname.
+ ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_connect = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_connect+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_connect=yes
+else
+ ac_cv_lib_socket_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = xyes; then :
+ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+ fi
+
+ # Guillermo Gomez says -lposix is necessary on A/UX.
+ ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove"
+if test "x$ac_cv_func_remove" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_remove = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if ${ac_cv_lib_posix_remove+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+int
+main ()
+{
+return remove ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_posix_remove=yes
+else
+ ac_cv_lib_posix_remove=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+ fi
+
+ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+ ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat"
+if test "x$ac_cv_func_shmat" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_shmat = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if ${ac_cv_lib_ipc_shmat+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lipc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+int
+main ()
+{
+return shmat ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ipc_shmat=yes
+else
+ ac_cv_lib_ipc_shmat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+fi
+
+ fi
+ fi
+
+ # Check for libraries that X11R6 Xt/Xaw programs need.
+ ac_save_LDFLAGS=$LDFLAGS
+ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+ # check for ICE first), but we must link in the order -lSM -lICE or
+ # we get undefined symbols. So assume we have SM if we have ICE.
+ # These have to be linked with before -lX11, unlike the other
+ # libraries we check for below, so use a different variable.
+ # John Interrante, Karl Berry
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceConnectionNumber ();
+int
+main ()
+{
+return IceConnectionNumber ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+ ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then :
+ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+fi
+
+ LDFLAGS=$ac_save_LDFLAGS
+
+fi
+
+
+# Check whether --enable-floppyd was given.
+if test "${enable_floppyd+set}" = set; then :
+ enableval=$enable_floppyd; if test x$enableval != x; then
+ use_floppyd=$enableval
+fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5
+$as_echo_n "checking for main in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_main+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_main=yes
+else
+ ac_cv_lib_socket_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5
+$as_echo "$ac_cv_lib_socket_main" >&6; }
+if test "x$ac_cv_lib_socket_main" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSOCKET 1
+_ACEOF
+
+ LIBS="-lsocket $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lbsd" >&5
+$as_echo_n "checking for main in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_main+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bsd_main=yes
+else
+ ac_cv_lib_bsd_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_main" >&5
+$as_echo "$ac_cv_lib_bsd_main" >&6; }
+if test "x$ac_cv_lib_bsd_main" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBBSD 1
+_ACEOF
+
+ LIBS="-lbsd $LIBS"
+
+fi
+
+for ac_header in sys/socket.h arpa/inet.h netdb.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+if test X$use_floppyd = X -a X$no_x = X ; then
+ use_floppyd="yes"
+fi
+
+if test X$use_floppyd = Xyes; then
+ if test X$no_x = Xyes ; then
+ echo "Floppyd needs X support" >&2
+ echo "To compile without floppyd, use ./configure --disable-floppyd" >&2
+ exit 1
+ fi
+ FLOPPYD="floppyd floppyd_installtest"
+ BINFLOPPYD="\$(DESTDIR)\$(bindir)/floppyd \$(DESTDIR)\$(bindir)/floppyd_installtest"
+
+$as_echo "#define USE_FLOPPYD 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether setpgrp takes no argument" >&5
+$as_echo_n "checking whether setpgrp takes no argument... " >&6; }
+if ${ac_cv_func_setpgrp_void+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ as_fn_error $? "cannot check setpgrp when cross compiling" "$LINENO" 5
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+/* If this system has a BSD-style setpgrp which takes arguments,
+ setpgrp(1, 1) will fail with ESRCH and return -1, in that case
+ exit successfully. */
+ return setpgrp (1,1) != -1;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_setpgrp_void=no
+else
+ ac_cv_func_setpgrp_void=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setpgrp_void" >&5
+$as_echo "$ac_cv_func_setpgrp_void" >&6; }
+if test $ac_cv_func_setpgrp_void = yes; then
+
+$as_echo "#define SETPGRP_VOID 1" >>confdefs.h
+
+fi
+
+else
+ FLOPPYD=
+ BINFLOPPYD=
+fi
+
+
+
+
+
+
+
+
+
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -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
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+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
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.68,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS "
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+ ;;
+
+
+ esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure-stamp b/configure-stamp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/configure-stamp
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..b9f74b5
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,395 @@
+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 linux/fs.h)
+AC_CHECK_HEADERS(termio.h sys/termio.h, [break])
+AC_CHECK_HEADERS(termios.h sys/termios.h, [break])
+
+AC_CHECK_TYPES(caddr_t)
+AC_CHECK_SIZEOF(size_t)
+
+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 \
+sigaction)
+
+dnl
+dnl Check for 64-bit off_t
+dnl
+AC_DEFUN(SFS_CHECK_OFF_T_64,
+[AC_CACHE_CHECK(for 64-bit off_t, sfs_cv_off_t_64,
+AC_TRY_COMPILE([
+#include <unistd.h>
+#include <sys/types.h>
+],[
+switch (0) case 0: case (sizeof (off_t) <= 4):;
+], sfs_cv_off_t_64=no, sfs_cv_off_t_64=yes))
+if test $sfs_cv_off_t_64 = yes; then
+ AC_DEFINE([HAVE_OFF_T_64],1,[Define when the system has a 64 bit off_t type])
+fi])
+
+
+dnl ICE_CC_LOFF_T
+dnl -------------
+dnl
+dnl If the CC compiler supports `loff_t' type, define `HAVE_LOFF_T'.
+dnl
+AC_DEFUN(ICE_CC_LOFF_T,
+[
+AC_MSG_CHECKING(whether ${CC} supports loff_t type)
+AC_CACHE_VAL(ice_cv_have_loff_t,
+[
+AC_TRY_COMPILE([#include <sys/types.h>],[loff_t a;],
+ice_cv_have_loff_t=yes,
+ice_cv_have_loff_t=no)
+])
+AC_MSG_RESULT($ice_cv_have_loff_t)
+if test "$ice_cv_have_loff_t" = yes; then
+AC_DEFINE([HAVE_LOFF_T],1,[Define when the compiler supports LOFF_T type])
+fi
+])dnl
+
+
+dnl ICE_CC_OFFSET_T
+dnl -------------
+dnl
+dnl If the CC compiler supports `offset_t' type, define `HAVE_OFFSET_T'.
+dnl
+AC_DEFUN(ICE_CC_OFFSET_T,
+[
+AC_MSG_CHECKING(whether ${CC} supports offset_t type)
+AC_CACHE_VAL(ice_cv_have_offset_t,
+[
+AC_TRY_COMPILE([#include <sys/types.h>],[offset_t a;],
+ice_cv_have_offset_t=yes,
+ice_cv_have_offset_t=no)
+])
+AC_MSG_RESULT($ice_cv_have_offset_t)
+if test "$ice_cv_have_offset_t" = yes; then
+AC_DEFINE([HAVE_OFFSET_T],1,[Define when the compiler supports OFFSET_T type])
+fi
+])dnl
+
+dnl ICE_CC_LONG_LONG
+dnl -------------
+dnl
+dnl If the CC compiler supports `long long' type, define `HAVE_LONG_LONG'.
+dnl
+AC_DEFUN(ICE_CC_LONG_LONG,
+[
+AC_MSG_CHECKING(whether ${CC} supports long long type)
+AC_CACHE_VAL(ice_cv_have_long_long,
+[
+AC_TRY_COMPILE(,[long long a;],
+ice_cv_have_long_long=yes,
+ice_cv_have_long_long=no)
+])
+AC_MSG_RESULT($ice_cv_have_long_long)
+if test "$ice_cv_have_long_long" = yes; then
+AC_DEFINE([HAVE_LONG_LONG],1,[Define when the compiler supports LONG_LONG type])
+fi
+])dnl
+
+dnl ICE_CC_OFF64_T
+dnl -------------
+dnl
+dnl If the CC compiler supports `long long' type, define `HAVE_OFF64_T'.
+dnl
+AC_DEFUN(ICE_CC_OFF64_T,
+[
+AC_MSG_CHECKING(whether ${CC} supports off64_t type)
+AC_CACHE_VAL(ice_cv_have_off64_t,
+[
+AC_TRY_COMPILE(,[off64_t a;],
+ice_cv_have_off64_t=yes,
+ice_cv_have_off64_t=no)
+])
+AC_MSG_RESULT($ice_cv_have_off64_t)
+if test "$ice_cv_have_off64_t" = yes; then
+AC_DEFINE([HAVE_OFF64_T],1,[Define when the compiler supports OFF64_T type])
+fi
+])dnl
+
+
+SFS_CHECK_OFF_T_64
+ICE_CC_LOFF_T
+ICE_CC_OFFSET_T
+ICE_CC_LONG_LONG
+
+
+AC_CHECK_FUNCS(utimes utime, [break])
+AC_CHECK_FUNCS(tzset gettimeofday)
+
+CF_SYS_ERRLIST
+
+[
+host_os0=`echo $host_os | sed 's/-/_/g'`
+host_os1=`echo $host_os0 | sed 's/\./_/g'`
+host_os2=`echo $host_os0 | sed 's/^\([^.]*\)\..*$/\1/g'`
+host_os3=`echo $host_os2 | sed 's/^\([^0-9]*\)[0-9]*$/\1/g'`
+host_cpu1=`echo $host_cpu | sed 's/\./_/g'`
+host_vendor1=`echo $host_vendor | sed 's/\./_/g'`
+HOST_ID="-DCPU_$host_cpu1 -DVENDOR_$host_vendor1 -DOS_$host_os1"
+if [ $host_os1 != $host_os2 ] ; then
+ HOST_ID="$HOST_ID -DOS_$host_os2"
+fi
+if [ $host_os1 != $host_os3 ] && [ $host_os2 != $host_os3 ] ; then
+ HOST_ID="$HOST_ID -DOS_$host_os3"
+fi
+
+my_host_os=`echo $host_os1 $host_os2 $host_os3 | sort -u`
+objs=`echo $srcdir/*.c | sed 's/\.c$/.o/' `
+if [ "X$GCC" = "Xyes" ] ; then
+ Wall=-Wall
+ if [ "$host_os3" = sunos ] ; then
+ Wall=""
+ fi
+ if [ "$host_os3" = ultrix ] ; then
+ Wall=""
+ fi
+ if [ "$host_os3" = linux ] ; then
+ CFLAGS="$CFLAGS -fno-strength-reduce"
+ fi
+ if [ "$host_os3" = aux ] ; then
+ CFLAGS="$CFLAGS -ZP"
+ MACHDEPLIBS="-lposix -UTIL"
+ fi
+ case "${host}" in
+ arm*-*-linux) CFLAGS="$CFLAGS -mstructure-size-boundary=8";;
+ esac
+ CFLAGS="$CFLAGS $Wall"
+else
+ if [ $host_os3 = hpux ] ; then
+ CPPFLAGS="$CPPFLAGS -Ae"
+ fi
+
+ if [ $host_os3 = xenix ] ; then
+ CFLAGS="$CFLAGS -M2e"
+ fi
+fi
+
+if [ $host_os3 = hpux ] ; then
+ LDFLAGS="$LDFLAGS -z"
+fi
+
+if [ $host_os3 = xenix ] ; then
+ LDFLAGS="$LDFLAGS -M2e -i -f 5000"
+fi
+
+if [ $host_os2 = sysv4 ] ; then
+ SHLIB="-lc -L/usr/ucblib -lucb"
+else
+ SHLIB=""
+fi
+
+if [ $host_os3 = isc ] ; then
+ CFLAGS="$CFLAGS -D_SYSV3"
+ SHLIB="-lc_s"
+fi
+
+if [ $host_os3 = solaris -a x$newVold = xxyes ] ; then
+ SHLIB="$SHLIB -s -lvolmgt"
+fi
+
+if [ $host_os3 = nextstep ] ; then
+ CFLAGS="$CFLAGS -DBSD"
+ SHLIB=""
+fi
+
+if [ -d /usr/5lib ] ; then
+ extralibdir=-L/usr/5lib
+fi
+
+]
+
+AC_PATH_X
+AC_PATH_XTRA
+
+dnl Floppyd
+AC_ARG_ENABLE(floppyd,
+[ --enable-floppyd floppy daemon support],
+[if test x$enableval != x; then
+ use_floppyd=$enableval
+fi])
+
+AC_CHECK_LIB(socket,main)
+dnl AC_CHECK_LIB(nsl,getpwnam)
+AC_CHECK_LIB(bsd,main)
+AC_CHECK_HEADERS(sys/socket.h arpa/inet.h netdb.h)
+
+if test X$use_floppyd = X -a X$no_x = X ; then
+ use_floppyd="yes"
+fi
+
+if test X$use_floppyd = Xyes; then
+ if test X$no_x = Xyes ; then
+ echo "Floppyd needs X support" >&2
+ echo "To compile without floppyd, use ./configure --disable-floppyd" >&2
+ exit 1
+ fi
+ FLOPPYD="floppyd floppyd_installtest"
+ BINFLOPPYD="\$(DESTDIR)\$(bindir)/floppyd \$(DESTDIR)\$(bindir)/floppyd_installtest"
+ AC_DEFINE([USE_FLOPPYD],1,[Define when you want to include floppyd support])
+ AC_FUNC_SETPGRP
+else
+ FLOPPYD=
+ BINFLOPPYD=
+fi
+
+
+AC_SUBST(FLOPPYD)
+AC_SUBST(BINFLOPPYD)
+AC_SUBST(extraincludedir)
+AC_SUBST(extralibdir)
+AC_SUBST(MACHDEPLIBS)
+AC_SUBST(SHLIB)
+AC_SUBST(host_cpu)
+AC_SUBST(HOST_ID)
+AC_OUTPUT(Makefile)
diff --git a/copyfile.c b/copyfile.c
new file mode 100644
index 0000000..282c649
--- /dev/null
+++ b/copyfile.c
@@ -0,0 +1,73 @@
+/* Copyright 1996-1999,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..6a90040
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,164 @@
+mtools (4.0.18) stable; urgency=low
+ * Fix for names of iconv encodings on AIX
+ * Fix mt_size_t on NetBSD
+ * Fixed compilation on Mingw
+ * Fixed doc (especially mformat)
+ * Fix mformat'ing of FAT12 filesystems with huge cluster sizes
+ * Minfo prints image file name in mformat command line if an image
+ * file name was given
+ * Always generate gzip-compressed RPMs, in order to remain
+ * compatible with older distributions
+ * Fixed buffer overflow with drive letter in mclasserase
+ -- Alain Knaff <alain@knaff.lu> Wed, 9 Jan 2013 00:21:20 +0200
+mtools (4.0.17) stable; urgency=low
+
+ * mbadblocks now takes a list of bad blocks (either as sectors
+ or as clusters)
+ * mbadblocks now is able to do write scanning for bad blocks
+ * mshowfat can show cluster of specific offset
+ * Enable mtools to deal with very small sector sizes...
+ * Fixed encoding of all-lowercase names (no need to mangle
+ these)
+ * Consider every directory entry after an ENDMARK (0x00) to be deleted
+ * After writing a new entry at end of a directory, be sure to also add
+ an ENDMARK (0x00)
+ * Deal with possibility of a NULL pointer being returned by
+ localtime during timestamp conversion
+ -- Alain Knaff <alain@knaff.lu> Wed, 29 Jun 2011 00:21:20 +0200
+mtools (4.0.16) stable; urgency=low
+
+ * configure.in fixes
+ * fixed formatting of fat_size_calculation.tex document
+ * compatibility with current autoconfig versions
+ * Make it clear that label is limited to 11 characters
+ * Fixed typo in initialization of FAT32 info sector
+
+ -- Alain Knaff <alain@knaff.lu> Sat, 16 Apr 2011 18:00:30 +0200
+mtools (4.0.15) stable; urgency=low
+
+ * Added missing -i option to mshortname
+ * Splitted .deb package into mtools and floppyd in order to
+ match Ubuntu
+
+ -- Alain Knaff <alain@knaff.lu> Sun, 17 Oct 2010 19:42:46 +0200
+mtools (4.0.14) stable; urgency=low
+
+ * New mshortname command
+ * Fix floppyd for disks bigger than 2 Gig
+ * Remove obsolete -z flag
+ * Remove now unsupported AC_USE_SYSTEM_EXTENSIONS
+ * Fixed output formatting of mdir if MTOOLS_DOTTED_DIR is set
+ * Mformat now correctly writes backup boot sector
+ * Fixed signedness of serial number in mlabel
+ * Fixed buffer size problem in mlabel
+ * Make mlabel write backup boot sector if FAT32
+ * Catch situation where both clear and new label are given to mlabel
+ * Quote filename parameters to scripts
+ * Mformat: Close file descriptor for boot sector
+ * Added lzip support to scripts/uz
+ * Added Tot_sectors option to mformat
+ * Fixed hidden sector handling in mformat
+ * Minfo generates mformat command lines containing new -T option
+ * Mlabel prints error if label too long
+
+ -- Alain Knaff <alain@knaff.lu> Tue, 12 Oct 2010 00:19:48 +0200
+mtools (4.0.13) stable; urgency=low
+
+ * Merged Debian patches
+
+ -- Alain Knaff <alain@knaff.lu> Sun, 28 Feb 2010 15:33:45 +0100
+mtools (4.0.12) stable; urgency=low
+
+ * Mingw compatibility fixes
+
+ -- Alain Knaff <alain@knaff.lu> Tue, 3 Nov 2009 21:26:58 +0100
+mtools (4.0.11) stable; urgency=low
+
+ * Fixed compiler in mlabel.c and elsewhere
+ * Fixed h flag in mattrib.c
+ * Added missing error checking in floppyd and elsewhere
+
+ -- Alain Knaff <alain@knaff.lu> Sat, 29 Aug 2009 14:38:19 +0200
+mtools (4.0.10) stable; urgency=low
+
+ * More copyright stuff
+ * Fixed issues with max filesize (was 2GB instead of 4GB, and
+ warned only after copying the beginning)
+
+ -- Alain Knaff <alain@knaff.lu> Tue, 3 Mar 2009 22:14:04 +0100
+mtools (4.0.9) stable; urgency=low
+
+ * More copyright stuff
+
+ -- Alain Knaff <alain@knaff.lu> Mon, 2 Mar 2009 22:15:54 +0100
+mtools (4.0.8) stable; urgency=low
+
+ * Copyright notices
+
+ -- Alain Knaff <alain@knaff.lu> Sun, 1 Mar 2009 00:36:22 +0100
+mtools (4.0.7) stable; urgency=low
+
+ * Fixed conversion to native on OS/2
+ * Fix parsing of --help flag
+
+ -- Alain Knaff <alain@knaff.lu> Tue, 24 Feb 2009 19:55:46 +0100
+mtools (4.0.6) stable; urgency=low
+
+ * Fallback for missing wchar_t iconv codepage on OS/2
+ * Fixes for LSEEK64 support
+ * Support for --help that returns a 0 exit status
+
+ -- Alain Knaff <alain@knaff.lu> Sun, 22 Feb 2009 02:04:32 +0100
+mtools (4.0.5) stable; urgency=low
+
+ * Make setpgrp() usage in floppyd conditional
+ * Re-instate PACKED around structure (ARM)
+ * LSEEK64
+
+ -- Alain Knaff <alain@knaff.lu> Thu, 19 Feb 2009 23:55:04 +0100
+mtools (4.0.4) stable; urgency=low
+
+ * BSD support: SCSI, use getuserid/getgroupid in floppyd
+ * Another attempt at putwc fix for OS/2
+ * Further GNU fixes
+ * Fallback for putwc if there is wchar (OS/2)
+
+ -- Alain Knaff <alain@knaff.lu> Sun, 15 Feb 2009 16:18:32 +0100
+mtools (4.0.3) stable; urgency=low
+
+ * Fix multipart pathname parsing bug in vfat.c (forgot limited length)
+ * Supplied fallback define for putwc
+ * Copyright notices in all sources
+
+ -- Alain Knaff <alain@knaff.lu> Mon, 9 Feb 2009 21:46:01 +0100
+mtools (4.0.2) stable; urgency=low
+
+ * Fixed off-by-2 error in unix_name in file_name.c
+
+ -- Alain Knaff <alain@knaff.lu> Mon, 26 Jan 2009 22:58:06 +0100
+mtools (4.0.1) stable; urgency=low
+
+ * Missing functions on Solaris
+
+ -- Alain Knaff <alain@knaff.lu> Sun, 7 Dec 2008 21:38:55 +0100
+mtools (4.0.0) stable; urgency=low
+
+ * Offset for -i-specified image files
+
+ -- Alain Knaff <alain@knaff.lu> Sat, 29 Nov 2008 09:20:30 +0100
+mtools (4.0.0-pre2) stable; urgency=low
+
+ * Use transliteration to represent characters which don't exist in
+ target set
+
+ -- Alain Knaff <alain@knaff.lu> Tue, 18 Nov 2008 22:42:23 +0100
+mtools (4.0.0-pre1) stable; urgency=low
+
+ * Unicode support
+
+ -- Alain Knaff <alain@knaff.lu> Sat, 1 Nov 2008 20:52:58 +0100
+mtools (3.9.11-20071226) stable; urgency=low
+
+ * first release of debian package
+
+ -- Alain Knaff <alain@knaff.lu> Tue, 28 Aug 2007 23:23:37 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..ec00b44
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,31 @@
+Source: mtools
+Build-Depends: debhelper (>= 7), autotools-dev, libxt-dev, texinfo
+Section: otherosfs
+Priority: optional
+Maintainer: Alain Knaff <alain@knaff.lu>
+Homepage: http://www.mtools.linux.lu/
+
+Package: floppyd
+Priority: extra
+Architecture: any
+Replaces: mtools (<< 3.9.7)
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Suggests: mtools
+Description: Daemon for remote access to floppy drives
+ Floppyd is used as a server to grant access to the floppy drive to
+ clients running on a remote machine, just as an X server grants access
+ to the display to remote clients.
+
+Package: mtools
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Provides: mtools
+Suggests: floppyd
+Description: Tools for manipulating MSDOS files
+ Mtools is a collection of utilities to access MS-DOS disks from Unix
+ without mounting them. It supports Win'95 style long file names, OS/2
+ Xdf disks, ZIP/JAZ disks and 2m disks (store up to 1992k on a high
+ density 3 1/2 disk).
+ .
+ Also included in this package are commands to eject and manipulate
+ the write/password protection control of Zip disks.
diff --git a/debian/floppyd.files b/debian/floppyd.files
new file mode 100644
index 0000000..8383412
--- /dev/null
+++ b/debian/floppyd.files
@@ -0,0 +1 @@
+usr/bin/floppyd*
diff --git a/debian/floppyd.manpages b/debian/floppyd.manpages
new file mode 100644
index 0000000..427671f
--- /dev/null
+++ b/debian/floppyd.manpages
@@ -0,0 +1,2 @@
+floppyd.1
+floppyd_installtest.1
diff --git a/debian/mcheck.1 b/debian/mcheck.1
new file mode 100644
index 0000000..6eece5c
--- /dev/null
+++ b/debian/mcheck.1
@@ -0,0 +1,33 @@
+.\" mcheck (package: mtools) 2003-05-04
+.TH mcheck 1 "May 2003" "mtools"
+.SH NAME
+mcheck \- verify all files on an MS-DOS formatted disk
+.SH SYNOPSIS
+.PP
+.B mcheck
+[\fImsdosdrive\fR]
+.SH DESCRIPTION
+.\" Putting a newline after each sentence can generate better output.
+mcheck is a script that verifies all files on a MS-DOS formatted disk by
+reading them using
+.BR mtype (1)
+
+The optional argument specifies the MS-DOS drive letter of the disk
+to be checked. A: is used by default.
+
+.SH LICENSE
+Copyright (C) 1994 David C. Niemi (niemi@tuxers.net)
+
+The author requires that any copies or derived works include this
+copyright notice; no other restrictions are placed on its use.
+
+.SH AUTHOR
+mcheck was written by David C. Niemi <niemi@tuxers.net>
+
+This manual page was written by Rabin Vincent <r.vincent@iu-bremen.de>
+for the Debian GNU/Linux system (but may be used by others).
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR mdir (1),
+.BR mtype (1)
diff --git a/debian/mtools.conf b/debian/mtools.conf
new file mode 100644
index 0000000..4f6805c
--- /dev/null
+++ b/debian/mtools.conf
@@ -0,0 +1,25 @@
+# Debian default mtools.conf file.
+# "info mtools" or "man mtools.conf" for more detail.
+
+# # Linux floppy drives
+drive a: file="/dev/fd0" exclusive
+drive b: file="/dev/fd1" exclusive
+
+# # First SCSI hard disk partition
+# drive c: file="/dev/sda1"
+
+# # First IDE hard disk partition
+# drive c: file="/dev/hda1"
+
+# # dosemu hdimage.
+drive m: file="/var/lib/dosemu/hdimage.first" partition=1 offset=128
+
+# # dosemu floppy image
+drive n: file="/var/lib/dosemu/fdimage"
+
+# # SCSI zip disk
+# drive z: file="/dev/sda4"
+
+# # uncomment the following line to display all file names in lower
+# # case by default
+# mtools_lower_case=1
diff --git a/debian/mtools.dirs b/debian/mtools.dirs
new file mode 100644
index 0000000..ee19d5d
--- /dev/null
+++ b/debian/mtools.dirs
@@ -0,0 +1 @@
+etc
diff --git a/debian/mtools.files b/debian/mtools.files
new file mode 100644
index 0000000..e772481
--- /dev/null
+++ b/debian/mtools.files
@@ -0,0 +1 @@
+usr/bin
diff --git a/debian/mtools.manpages b/debian/mtools.manpages
new file mode 100644
index 0000000..be24a60
--- /dev/null
+++ b/debian/mtools.manpages
@@ -0,0 +1,33 @@
+lz.1
+mattrib.1
+mbadblocks.1
+mcat.1
+mcd.1
+mclasserase.1
+mcopy.1
+mdel.1
+mdeltree.1
+mdir.1
+mdu.1
+mformat.1
+minfo.1
+mkmanifest.1
+mlabel.1
+mmd.1
+mmount.1
+mmove.1
+mpartition.1
+mrd.1
+mren.1
+mshortname.1
+mshowfat.1
+mtools.1
+mtoolstest.1
+mtype.1
+mzip.1
+tgz.1
+uz.1
+mxtar.1
+mcomp.1
+mtools.5
+debian/mcheck.1
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..aaaea24
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,64 @@
+#!/usr/bin/make -f
+# rules for mtools package
+# by Luis Bustamante (luferbu@fluidsignal.com)
+
+export DH_VERBOSE=1
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+ cp -f /usr/share/misc/config.sub /usr/share/misc/config.guess .
+ ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr \
+ --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --sysconfdir=/etc
+ touch configure-stamp
+
+build: patch build-stamp
+build-stamp: configure-stamp
+ dh_testdir
+ $(MAKE)
+ touch build-stamp
+
+clean: unpatch
+ dh_testdir
+ dh_testroot
+ rm -rf build-stamp configure-stamp
+ rm -rf config.sub config.guess
+ [ ! -f Makefile ] || $(MAKE) distclean
+ dh_clean config.cache config.log config.status .#patchlevel.c.1.18 .#mtools.spec.1.4 .#mtools.texi.1.11 .#fat_size_calculation.tex.1.1
+
+install: build
+ dh_testdir
+ dh_testroot
+ dh_prep
+ dh_installdirs
+ $(MAKE) install prefix=$$( pwd )/debian/tmp/usr
+ install -m 644 debian/mtools.conf debian/mtools/etc/
+ dh_movefiles
+
+binary-indep:
+binary-arch: mtools
+binary: binary-indep binary-arch
+
+mtools: build install
+ dh_testdir
+ dh_testroot
+ dh_installdocs
+ dh_installexamples -pmtools mtools.conf
+ dh_installman
+ dh_installinfo -pmtools mtools.info
+ dh_undocumented -pmtools mcheck.1 mcomp.1 mxtar.1
+ dh_installchangelogs
+ dh_strip
+ dh_link -pmtools /usr/share/man/man5/mtools.5 /usr/share/man/man5/mtools.conf.5
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+.PHONY: build clean binary-indep binary-arch binary install \
+ mtools patch clean-build unpatch configure
diff --git a/devices.c b/devices.c
new file mode 100644
index 0000000..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
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
index 0000000..e1dad23
--- /dev/null
+++ b/dirCache.c
@@ -0,0 +1,367 @@
+/* Copyright 1998,2001-2003,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "sysincludes.h"
+#include "vfat.h"
+#include "dirCache.h"
+#include "dirCacheP.h"
+#include <assert.h>
+
+
+#define BITS_PER_INT (sizeof(unsigned int) * 8)
+
+
+static __inline__ 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;
+}
+
+/* Free a range of entries. The range being cleared is always aligned
+ * on the begin of an entry. Entries which are cleared entirely are
+ * free'd. Entries which are cleared half-way (can only happen at end)
+ * are "shortened" by moving its beginSlot
+ * If this was a range representing space after end-mark, return beginning
+ * of range if it had been shortened in its lifetime (which means that end
+ * mark must have moved => may need to be rewritten)
+ */
+static int freeDirCacheRange(dirCache_t *cache,
+ unsigned int beginSlot,
+ unsigned int endSlot)
+{
+ dirCacheEntry_t *entry;
+ unsigned int clearBegin;
+ unsigned int clearEnd;
+ unsigned int i;
+
+ if(endSlot < beginSlot) {
+ fprintf(stderr, "Bad slots %d %d in free range\n",
+ beginSlot, endSlot);
+ exit(1);
+ }
+
+ while(beginSlot < endSlot) {
+ entry = cache->entries[beginSlot];
+ if(!entry) {
+ beginSlot++;
+ continue;
+ }
+
+ /* Due to the way this is called, we _always_ de-allocate
+ * starting from beginning... */
+ assert(entry->beginSlot == beginSlot);
+
+ clearEnd = entry->endSlot;
+ if(clearEnd > endSlot)
+ clearEnd = endSlot;
+ clearBegin = beginSlot;
+
+ for(i = clearBegin; i <clearEnd; i++)
+ cache->entries[i] = 0;
+
+ entry->beginSlot = clearEnd;
+
+ if(entry->beginSlot == entry->endSlot) {
+ int needWriteEnd = 0;
+ if(entry->endMarkPos != -1 &&
+ entry->endMarkPos < beginSlot)
+ needWriteEnd = 1;
+
+ if(entry->longName)
+ free(entry->longName);
+ if(entry->shortName)
+ free(entry->shortName);
+ free(entry);
+ if(needWriteEnd) {
+ return beginSlot;
+ }
+ }
+
+ beginSlot = clearEnd;
+ }
+ return -1;
+}
+
+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;
+ entry->endMarkPos = -1;
+
+ freeDirCacheRange(cache, beginSlot, endSlot);
+ for(i=beginSlot; i<endSlot; i++) {
+ cache->entries[i] = entry;
+ }
+ return entry;
+}
+
+dirCacheEntry_t *addUsedEntry(dirCache_t *cache, 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;
+}
+
+/* Try to merge free slot at position "slot" with slot at previous position
+ * After successful merge, both will point to a same DCE (the one which used
+ * to be previous)
+ * Only does something if both of these slots are actually free
+ */
+static void mergeFreeSlots(dirCache_t *cache, int slot)
+{
+ dirCacheEntry_t *previous, *next;
+ unsigned int i;
+
+ if(slot == 0)
+ return;
+ previous = cache->entries[slot-1];
+ next = cache->entries[slot];
+ if(next && next->type == DCET_FREE &&
+ previous && previous->type == DCET_FREE) {
+ for(i=next->beginSlot; i < next->endSlot; i++)
+ cache->entries[i] = previous;
+ previous->endSlot = next->endSlot;
+ previous->endMarkPos = next->endMarkPos;
+ free(next);
+ }
+}
+
+/* Create a free range extending from beginSlot to endSlot, and try to merge
+ * it with any neighboring free ranges */
+dirCacheEntry_t *addFreeEndEntry(dirCache_t *cache,
+ unsigned int beginSlot,
+ unsigned int endSlot,
+ int isAtEnd)
+{
+ dirCacheEntry_t *entry;
+
+ if(beginSlot < cache->nrHashed)
+ cache->nrHashed = beginSlot;
+
+ if(endSlot < beginSlot) {
+ fprintf(stderr, "Bad slots %d %d in add free entry\n",
+ beginSlot, endSlot);
+ exit(1);
+ }
+
+ if(endSlot == beginSlot)
+ return 0;
+ entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_FREE);
+ if(isAtEnd)
+ entry->endMarkPos = beginSlot;
+ mergeFreeSlots(cache, beginSlot);
+ mergeFreeSlots(cache, endSlot);
+ return cache->entries[beginSlot];
+}
+
+dirCacheEntry_t *addFreeEntry(dirCache_t *cache,
+ unsigned int beginSlot,
+ unsigned int endSlot)
+{
+ return addFreeEndEntry(cache, beginSlot, endSlot, 0);
+}
+
+dirCacheEntry_t *addEndEntry(dirCache_t *cache, 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) {
+ int n;
+ n=freeDirCacheRange(cache, 0, cache->nr_entries);
+ if(n >= 0)
+ low_level_dir_write_end(Stream, n);
+ free(cache);
+ *dcp = 0;
+ }
+}
diff --git a/dirCache.h b/dirCache.h
new file mode 100644
index 0000000..bd9637b
--- /dev/null
+++ b/dirCache.h
@@ -0,0 +1,53 @@
+#ifndef MTOOLS_DIRCACHE_H
+#define MTOOLS_DIRCACHE_H
+
+/* Copyright 1997,1999,2001-2003,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+typedef enum {
+ DCET_FREE,
+ DCET_USED,
+ DCET_END
+} dirCacheEntryType_t;
+
+#define DC_BITMAP_SIZE 128
+
+typedef struct dirCacheEntry_t dirCacheEntry_t;
+
+typedef struct dirCache_t {
+ struct dirCacheEntry_t **entries;
+ 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 *addFreeEndEntry(dirCache_t *Stream,
+ unsigned int begin, unsigned int end,
+ int isAtEnd);
+dirCacheEntry_t *addEndEntry(dirCache_t *Stream, int pos);
+dirCacheEntry_t *lookupInDircache(dirCache_t *Stream, int pos);
+#endif
diff --git a/dirCacheP.h b/dirCacheP.h
new file mode 100644
index 0000000..1857ee4
--- /dev/null
+++ b/dirCacheP.h
@@ -0,0 +1,14 @@
+#ifndef DIRCACHEP_H
+#define DIRCACHEP_H
+
+struct dirCacheEntry_t {
+ dirCacheEntryType_t type;
+ unsigned int beginSlot;
+ unsigned int endSlot;
+ wchar_t *shortName;
+ wchar_t *longName;
+ struct directory dir;
+ int endMarkPos;
+} ;
+
+#endif /* DIRCACHEP_H */
diff --git a/directory.c b/directory.c
new file mode 100644
index 0000000..12c3ec0
--- /dev/null
+++ b/directory.c
@@ -0,0 +1,143 @@
+/* Copyright 1995 David C. Niemi
+ * Copyright 1996-2002,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "sysincludes.h"
+#include "msdos.h"
+#include "stream.h"
+#include "mtools.h"
+#include "file.h"
+#include "fs.h"
+#include "file_name.h"
+
+/* #define DEBUG */
+
+/*
+ * Read a directory entry into caller supplied buffer
+ */
+struct directory *dir_read(direntry_t *entry, int *error)
+{
+ int n;
+ *error = 0;
+ if((n=force_read(entry->Dir, (char *) (&entry->dir),
+ (mt_off_t) entry->entry * MDIR_SIZE,
+ MDIR_SIZE)) != MDIR_SIZE) {
+ if (n < 0) {
+ *error = -1;
+ }
+ return NULL;
+ }
+ return &entry->dir;
+}
+
+/*
+ * Make a subdirectory grow in length. Only subdirectories (not root)
+ * may grow. Returns a 0 on success, 1 on failure (disk full), or -1
+ * on error.
+ */
+
+int dir_grow(Stream_t *Dir, int size)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(FsPublic_t);
+ int ret;
+ 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);
+}
+
+void low_level_dir_write_end(Stream_t *Dir, int entry)
+{
+ char zero = ENDMARK;
+ force_write(Dir, &zero, (mt_off_t) entry * MDIR_SIZE, 1);
+}
+
+/*
+ * Make a directory entry. Builds a directory entry based on the
+ * name, attribute, starting cluster number, and size. Returns a pointer
+ * to a static directory structure.
+ */
+
+struct directory *mk_entry(const dos_name_t *dn, char attr,
+ unsigned int fat, size_t size, time_t date,
+ struct directory *ndir)
+{
+ struct tm *now;
+ time_t date2 = date;
+ unsigned char hour, min_hi, min_low, sec;
+ unsigned char year, month_hi, month_low, day;
+
+ now = localtime(&date2);
+ dosnameToDirentry(dn, ndir);
+ ndir->attr = attr;
+ ndir->ctime_ms = 0;
+ hour = now->tm_hour << 3;
+ min_hi = now->tm_min >> 3;
+ min_low = now->tm_min << 5;
+ sec = now->tm_sec / 2;
+ ndir->ctime[1] = ndir->time[1] = hour + min_hi;
+ ndir->ctime[0] = ndir->time[0] = min_low + sec;
+ year = (now->tm_year - 80) << 1;
+ month_hi = (now->tm_mon + 1) >> 3;
+ month_low = (now->tm_mon + 1) << 5;
+ day = now->tm_mday;
+ ndir -> adate[1] = ndir->cdate[1] = ndir->date[1] = year + month_hi;
+ ndir -> adate[0] = ndir->cdate[0] = ndir->date[0] = month_low + day;
+
+ set_word(ndir->start, fat & 0xffff);
+ set_word(ndir->startHi, fat >> 16);
+ set_dword(ndir->size, size);
+ return ndir;
+}
+
+/*
+ * Make a directory entry from base name. This is supposed to be used
+ * from places such as mmd for making special entries (".", "..", "/", ...)
+ * Thus it doesn't bother with character set conversions
+ */
+struct directory *mk_entry_from_base(const char *base, char attr,
+ unsigned int fat, size_t size, time_t date,
+ struct directory *ndir)
+{
+ struct dos_name_t dn;
+ strncpy(dn.base, base, 8);
+ strncpy(dn.ext, " ", 3);
+ return mk_entry(&dn, attr, fat, size, date, ndir);
+}
diff --git a/direntry.c b/direntry.c
new file mode 100644
index 0000000..c1d2ddd
--- /dev/null
+++ b/direntry.c
@@ -0,0 +1,166 @@
+/* Copyright 1997,2000-2003,2007-2010 Alain Knaff. This file is
+ * part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "stream.h"
+#include "file.h"
+#include "mtoolsDirentry.h"
+#include "file_name.h"
+
+void initializeDirentry(direntry_t *entry, Stream_t *Dir)
+{
+ 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);
+}
+
+static void _fprintShortPwd(FILE *f, direntry_t *entry, int recurs)
+{
+ if(entry->entry == -3) {
+ putc(getDrive(entry->Dir), f);
+ putc(':', f);
+ if(!recurs)
+ putc('/', f);
+ } else {
+ int i,j;
+ _fprintShortPwd(f, getDirentry(entry->Dir), 1);
+ putc('/',f);
+ for(i=7; i>=0 && entry->dir.name[i] == ' ';i--);
+ for(j=0; j<=i; j++)
+ putc(entry->dir.name[j],f);
+ for(i=2; i>=0 && entry->dir.ext[i] == ' ';i--);
+ if(i > 0)
+ putc('.',f);
+ for(j=0; j<=i; j++)
+ putc(entry->dir.ext[j],f);
+ }
+}
+
+void fprintShortPwd(FILE *f, direntry_t *entry)
+{
+ _fprintShortPwd(f, entry, 0);
+}
+
+char *getPwd(direntry_t *entry)
+{
+ int size;
+ char *ret;
+ char *end;
+
+ size = getPathLen(entry);
+ ret = malloc(size+1);
+ if(!ret)
+ return 0;
+ end = sprintPwd(entry, ret);
+ *end = '\0';
+ return ret;
+}
+
+int isSubdirOf(Stream_t *inside, Stream_t *outside)
+{
+ while(1) {
+ if(inside == outside) /* both are the same */
+ return 1;
+ if(getDirentry(inside)->entry == -3) /* root directory */
+ return 0;
+ /* look further up */
+ inside = getDirentry(inside)->Dir;
+ }
+}
diff --git a/expand.c b/expand.c
new file mode 100644
index 0000000..6b11f09
--- /dev/null
+++ b/expand.c
@@ -0,0 +1,108 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996-2002,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..16e32ab
--- /dev/null
+++ b/fat.c
@@ -0,0 +1,997 @@
+/* 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;
+
+ /*fprintf(stderr, "Fat write\n");*/
+
+ if (!This->fat_dirty)
+ return;
+
+ dups = This->num_fat;
+ if (This->fat_error)
+ dups = 1;
+
+
+ for(i=0; i<dups; i++){
+ j = 0;
+ for(slot=0;j<This->fat_len;slot++) {
+ if(!This->FatMap[slot].dirty) {
+ j += SECT_PER_ENTRY;
+ continue;
+ }
+ for(bit=0;
+ bit < SECT_PER_ENTRY && j<This->fat_len;
+ bit++,j++) {
+ if(!(This->FatMap[slot].dirty & (ONE << bit)))
+ continue;
+ ret = fatWriteSector(This,j,slot, bit, i);
+ if (ret < (int) This->sector_size){
+ if (ret < 0 ){
+ perror("error in fat_write");
+ exit(1);
+ } else {
+ fprintf(stderr,
+ "end of file in fat_write\n");
+ exit(1);
+ }
+ }
+ /* if last dupe, zero it out */
+ if(i==dups-1)
+ This->FatMap[slot].dirty &= ~(ONE<<bit);
+ }
+ }
+ }
+ /* write the info sector, if any */
+ if(This->infoSectorLoc && This->infoSectorLoc != MAX32) {
+ /* initialize info sector */
+ InfoSector_t *infoSector;
+ infoSector = (InfoSector_t *) safe_malloc(This->sector_size);
+ 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_word(infoSector->signature3, 0xaa55);
+ if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) !=
+ (signed int) This->sector_size)
+ fprintf(stderr,"Trouble writing the info sector\n");
+ free(infoSector);
+ }
+ This->fat_dirty = 0;
+ This->lastFatAccessMode = FAT_ACCESS_READ;
+}
+
+
+
+/*
+ * Zero-Fat
+ * Used by mformat.
+ */
+int zero_fat(Fs_t *Stream, int media_descriptor)
+{
+ unsigned int i, j;
+ unsigned int fat_start;
+ unsigned char *buf;
+
+ buf = malloc(Stream->sector_size);
+ if(!buf) {
+ perror("alloc fat sector buffer");
+ return -1;
+ }
+ for(i=0; i< Stream->num_fat; i++) {
+ fat_start = Stream->fat_start + i*Stream->fat_len;
+ for(j = 0; j < Stream->fat_len; j++) {
+ if(j <= 1)
+ memset(buf, 0, Stream->sector_size);
+ if(!j) {
+ buf[0] = media_descriptor;
+ buf[2] = buf[1] = 0xff;
+ if(Stream->fat_bits > 12)
+ buf[3] = 0xff;
+ if(Stream->fat_bits > 16) {
+ buf[4] = 0xff;
+ buf[5] = 0xff;
+ buf[6] = 0xff;
+ buf[7] = 0x0f;
+ }
+ }
+
+ if(forceWriteSector(Stream, (char *)buf,
+ fat_start + j, 1) !=
+ (signed int) Stream->sector_size) {
+ fprintf(stderr,
+ "Trouble initializing a FAT sector\n");
+ free(buf);
+ return -1;
+ }
+ }
+ }
+
+ free(buf);
+ Stream->FatMap = GetFatMap(Stream);
+ if (Stream->FatMap == NULL) {
+ perror("alloc fat map");
+ return -1;
+ }
+ return 0;
+}
+
+
+void set_fat12(Fs_t *This)
+{
+ This->fat_bits = 12;
+ This->end_fat = 0xfff;
+ This->last_fat = 0xff6;
+ This->fat_decode = fat12_decode;
+ This->fat_encode = fat12_encode;
+}
+
+static char word_endian_test[] = { 0x34, 0x12 };
+
+void set_fat16(Fs_t *This)
+{
+ This->fat_bits = 16;
+ This->end_fat = 0xffff;
+ This->last_fat = 0xfff6;
+
+ if(sizeof(unsigned short) == 2 &&
+ * (unsigned short *) word_endian_test == 0x1234) {
+ This->fat_decode = fast_fat16_decode;
+ This->fat_encode = fast_fat16_encode;
+ } else {
+ This->fat_decode = fat16_decode;
+ This->fat_encode = fat16_encode;
+ }
+}
+
+static char dword_endian_test[] = { 0x78, 0x56, 0x34, 0x12 };
+
+void set_fat32(Fs_t *This)
+{
+ This->fat_bits = 32;
+ This->end_fat = 0xfffffff;
+ This->last_fat = 0xffffff6;
+
+ if(sizeof(unsigned int) == 4 &&
+ * (unsigned int *) dword_endian_test == 0x12345678) {
+ This->fat_decode = fast_fat32_decode;
+ This->fat_encode = fast_fat32_encode;
+ } else {
+ This->fat_decode = fat32_decode;
+ This->fat_encode = fat32_encode;
+ }
+}
+
+
+static int check_fat(Fs_t *This)
+{
+ /*
+ * This is only a sanity check. For disks with really big FATs,
+ * there is no point in checking the whole FAT.
+ */
+
+ unsigned int i, f;
+ unsigned int tocheck;
+ if(mtools_skip_check)
+ return 0;
+
+ /* too few sectors in the FAT */
+ if(This->fat_len < NEEDED_FAT_SIZE(This))
+ return -1;
+ /* we do not warn about too much sectors in FAT, which may
+ * happen when a partition has been shrunk using FIPS, or on
+ * other occurrences */
+
+ tocheck = This->num_clus;
+ if (tocheck + 1 >= This->last_fat) {
+ fprintf(stderr, "Too many clusters in FAT\n");
+ return -1;
+ }
+
+ if(tocheck > 4096)
+ tocheck = 4096;
+
+ for ( i= 3 ; i < tocheck; i++){
+ f = This->fat_decode(This,i);
+ if (f == 1 || (f < This->last_fat && f > This->num_clus)){
+ fprintf(stderr,
+ "Cluster # at %d too big(%#x)\n", i,f);
+ fprintf(stderr,"Probably non MS-DOS disk\n");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Read the first sector of FAT table into memory. Crude error detection on
+ * wrong FAT encoding scheme.
+ */
+static int check_media_type(Fs_t *This, union bootsector *boot,
+ unsigned int tot_sectors)
+{
+ unsigned char *address;
+
+ This->num_clus = (tot_sectors - This->clus_start) / This->cluster_size;
+
+ This->FatMap = GetFatMap(This);
+ if (This->FatMap == NULL) {
+ perror("alloc fat map");
+ return -1;
+ }
+
+ address = getAddress(This, 0, FAT_ACCESS_READ);
+ if(!address) {
+ fprintf(stderr,
+ "Could not read first FAT sector\n");
+ return -1;
+ }
+
+ if(mtools_skip_check)
+ return 0;
+
+ if(!address[0] && !address[1] && !address[2])
+ /* Some Atari disks have zeroes where Dos has media descriptor
+ * and 0xff. Do not consider this as an error */
+ return 0;
+
+ if((address[0] != boot->boot.descr && boot->boot.descr >= 0xf0 &&
+ ((address[0] != 0xf9 && address[0] != 0xf7)
+ || boot->boot.descr != 0xf0)) || address[0] < 0xf0) {
+ fprintf(stderr,
+ "Bad media types %02x/%02x, probably non-MSDOS disk\n",
+ address[0],
+ boot->boot.descr);
+ return -1;
+ }
+
+ if(address[1] != 0xff || address[2] != 0xff){
+ fprintf(stderr,"Initial byte of fat is not 0xff\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fat_32_read(Fs_t *This, union bootsector *boot,
+ unsigned int tot_sectors)
+{
+ 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,
+ size_t tot_sectors, int nodups)
+{
+ This->writeAllFats = 1;
+ This->primaryFat = 0;
+ This->dir_start = This->fat_start + This->num_fat * This->fat_len;
+ This->clus_start = This->dir_start + This->dir_len;
+ This->infoSectorLoc = MAX32;
+
+ if(nodups)
+ This->num_fat = 1;
+
+ if(check_media_type(This,boot, tot_sectors))
+ return -1;
+
+ if(This->num_clus >= FAT12) {
+ set_fat16(This);
+ /* third FAT byte must be 0xff */
+ if(!mtools_skip_check && readByte(This, 3) != 0xff)
+ return -1;
+ } else
+ set_fat12(This);
+
+ return check_fat(This);
+}
+
+/*
+ * Read the first sector of the FAT table into memory and initialize
+ * structures.
+ */
+int fat_read(Fs_t *This, union bootsector *boot,
+ size_t tot_sectors, int nodups)
+{
+ This->fat_error = 0;
+ This->fat_dirty = 0;
+ This->last = MAX32;
+ This->freeSpace = MAX32;
+ This->lastFatSectorNr = 0;
+ This->lastFatSectorData = 0;
+
+ if(This->fat_len)
+ return old_fat_read(This, boot, tot_sectors, nodups);
+ else
+ return fat_32_read(This, boot, tot_sectors);
+}
+
+
+unsigned int fatDecode(Fs_t *This, unsigned int pos)
+{
+ unsigned int ret;
+
+ ret = This->fat_decode(This, pos);
+ if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) {
+ fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos);
+ This->fat_error++;
+ }
+ return ret;
+}
+
+/* append a new cluster */
+void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos)
+{
+ This->fat_encode(This, pos, newpos);
+ This->fat_encode(This, newpos, This->end_fat);
+ if(This->freeSpace != MAX32)
+ This->freeSpace--;
+}
+
+/* de-allocates the given cluster */
+void fatDeallocate(Fs_t *This, unsigned int pos)
+{
+ This->fat_encode(This, pos, 0);
+ if(This->freeSpace != MAX32)
+ This->freeSpace++;
+}
+
+/* allocate a new cluster */
+void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value)
+{
+ This->fat_encode(This, pos, value);
+ if(This->freeSpace != MAX32)
+ This->freeSpace--;
+}
+
+void fatEncode(Fs_t *This, unsigned int pos, unsigned int value)
+{
+ unsigned int oldvalue = This->fat_decode(This, pos);
+ This->fat_encode(This, pos, value);
+ if(This->freeSpace != MAX32) {
+ if(oldvalue)
+ This->freeSpace++;
+ if(value)
+ This->freeSpace--;
+ }
+}
+
+unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
+{
+ unsigned int i;
+
+ if(This->last != MAX32)
+ last = This->last;
+
+ if (last < 2 ||
+ last >= This->num_clus+1)
+ last = 1;
+
+ for (i=last+1; i< This->num_clus+2; i++) {
+ unsigned int r = fatDecode(This, i);
+ if(r == 1)
+ goto exit_0;
+ if (!r) {
+ This->last = i;
+ return i;
+ }
+ }
+
+ for(i=2; i < last+1; i++) {
+ unsigned int r = fatDecode(This, i);
+ if(r == 1)
+ goto exit_0;
+ if (!r) {
+ This->last = i;
+ return i;
+ }
+ }
+
+
+ fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters,
+ This->last);
+ return 1;
+ exit_0:
+ fprintf(stderr, "FAT error\n");
+ return 1;
+}
+
+int fat_error(Stream_t *Dir)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+
+ if(This->fat_error)
+ fprintf(stderr,"Fat error detected\n");
+
+ return This->fat_error;
+}
+
+int fat32RootCluster(Stream_t *Dir)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+
+ if(This->fat_bits == 32)
+ return This->rootCluster;
+ else
+ return 0;
+}
+
+
+/*
+ * Get the amount of free space on the diskette
+ */
+
+mt_size_t getfree(Stream_t *Dir)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+
+ if(This->freeSpace == MAX32 || This->freeSpace == 0) {
+ register unsigned int i;
+ size_t total;
+
+ total = 0L;
+ for (i = 2; i < This->num_clus + 2; i++) {
+ unsigned int r = fatDecode(This,i);
+ if(r == 1) {
+ return -1;
+ }
+ if (!r)
+ total++;
+ }
+ This->freeSpace = total;
+ }
+ return sectorsToBytes((Stream_t*)This,
+ This->freeSpace * This->cluster_size);
+}
+
+
+/*
+ * Ensure that there is a minimum of total sectors free
+ */
+int getfreeMinClusters(Stream_t *Dir, size_t size)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+ register unsigned int i, last;
+ size_t total;
+
+ if(batchmode && This->freeSpace == MAX32)
+ getfree(Stream);
+
+ if(This->freeSpace != MAX32) {
+ if(This->freeSpace >= size)
+ return 1;
+ else {
+ fprintf(stderr, "Disk full\n");
+ got_signal = 1;
+ return 0;
+ }
+ }
+
+ total = 0L;
+
+ /* we start at the same place where we'll start later to actually
+ * allocate the sectors. That way, the same sectors of the FAT, which
+ * are already loaded during getfreeMin will be able to be reused
+ * during get_next_free_cluster */
+ last = This->last;
+
+ if ( last < 2 || last >= This->num_clus + 2)
+ last = 1;
+ for (i=last+1; i< This->num_clus+2; i++){
+ unsigned int r = fatDecode(This, i);
+ if(r == 1) {
+ goto exit_0;
+ }
+ if (!r)
+ total++;
+ if(total >= size)
+ return 1;
+ }
+ for(i=2; i < last+1; i++){
+ unsigned int r = fatDecode(This, i);
+ if(r == 1) {
+ goto exit_0;
+ }
+ if (!r)
+ total++;
+ if(total >= size)
+ return 1;
+ }
+ fprintf(stderr, "Disk full\n");
+ got_signal = 1;
+ return 0;
+ exit_0:
+ fprintf(stderr, "FAT error\n");
+ return 0;
+}
+
+
+int getfreeMinBytes(Stream_t *Dir, mt_size_t size)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+ size_t size2;
+
+ size2 = size / (This->sector_size * This->cluster_size);
+ if(size % (This->sector_size * This->cluster_size))
+ size2++;
+ return getfreeMinClusters(Dir, size2);
+}
+
+
+unsigned int getStart(Stream_t *Dir, struct directory *dir)
+{
+ Stream_t *Stream = GetFs(Dir);
+ unsigned int first;
+
+ first = START(dir);
+ if(fat32RootCluster(Stream))
+ first |= STARTHI(dir) << 16;
+ return first;
+}
+
+int fs_free(Stream_t *Stream)
+{
+ DeclareThis(Fs_t);
+
+ if(This->FatMap) {
+ int i, nr_entries;
+ nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) /
+ SECT_PER_ENTRY;
+ for(i=0; i< nr_entries; i++)
+ if(This->FatMap[i].data)
+ free(This->FatMap[i].data);
+ free(This->FatMap);
+ }
+ if(This->cp)
+ cp_close(This->cp);
+ return 0;
+}
diff --git a/fat_free.c b/fat_free.c
new file mode 100644
index 0000000..6d49018
--- /dev/null
+++ b/fat_free.c
@@ -0,0 +1,72 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996-1998,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "fsP.h"
+#include "mtoolsDirentry.h"
+
+/*
+ * Remove a string of FAT entries (delete the file). The argument is
+ * the beginning of the string. Does not consider the file length, so
+ * if FAT is corrupted, watch out!
+ */
+
+int fat_free(Stream_t *Dir, unsigned int fat)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+ unsigned int next_no_step;
+ /* a zero length file? */
+ if (fat == 0)
+ return(0);
+ /* CONSTCOND */
+ while (!This->fat_error) {
+ /* get next cluster number */
+ next_no_step = fatDecode(This,fat);
+ /* mark current cluster as empty */
+ fatDeallocate(This,fat);
+ if (next_no_step >= This->last_fat)
+ break;
+ fat = next_no_step;
+ }
+ return(0);
+}
+
+int fatFreeWithDir(Stream_t *Dir, struct directory *dir)
+{
+ unsigned int first;
+
+ if((!strncmp(dir->name,". ",8) ||
+ !strncmp(dir->name,".. ",8)) &&
+ !strncmp(dir->ext," ",3)) {
+ fprintf(stderr,"Trying to remove . or .. entry\n");
+ return -1;
+ }
+
+ first = START(dir);
+ if(fat32RootCluster(Dir))
+ first |= STARTHI(dir) << 16;
+ return fat_free(Dir, first);
+}
+
+int fatFreeWithDirentry(direntry_t *entry)
+{
+ return fatFreeWithDir(entry->Dir, &entry->dir);
+}
+
diff --git a/fat_size_calculation.tex b/fat_size_calculation.tex
new file mode 100644
index 0000000..6737cca
--- /dev/null
+++ b/fat_size_calculation.tex
@@ -0,0 +1,228 @@
+% Copyright 2003,2005,2007 Alain Knaff.
+
+% This documentation is for Mtools which is a collection of tools to
+% allow Unix systems to manipulate MS-DOS files.
+
+% Permission is granted to copy, distribute and/or modify this document
+% under the terms of the GNU Free Documentation License, Version 1.3 or
+% any later version published by the Free Software Foundation; with no
+% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+%Texts. A copy of the license is included in the section entitled
+% ``GNU Free Documentation License''.
+
+\documentclass[a4paper,12pt]{article}
+
+\usepackage[T1]{fontenc}
+\usepackage[latin1]{inputenc}
+\usepackage{pslatex}
+\usepackage[pdfpagemode=None,colorlinks]{hyperref}
+
+\author{Alain Knaff}
+\title{How mformat-3.9.10 and above calculates needed FAT size}
+
+\begin{document}
+
+\maketitle
+
+This small document explains the formula used by {\tt mformat.c} to
+figure out fat size and number of clusters. Due to the way that
+filesystem parameters are stored in the boot sector, we can afford to
+have a FAT that is larger than need to be to accomodate the clusters
+present on disk, but under no circumstances can we have one that is
+too small.
+
+In this discussion, we use the following variable names:
+
+\begin{tabular}{|r|p{12cm}|}
+
+\hline
+
+$fatNybls$&
+Number of nubbles (4 bit unit per FAT). This is 3 for FAT12, 4 for
+FAT16, and 8 for FAT16\\
+
+\hline
+
+$numClus$&
+Number of clusters on the disk\\
+
+\hline
+
+$clusSiz$&
+Size of a cluster, expressed in sectors\\
+
+\hline
+
+$secSiz$&
+Size of a sector, in bytes. Size of a sector in nybbles is $secSiz$ * 2\\
+
+\hline
+
+$nfats$&
+Number of FAT copies, usually two\\
+
+\hline
+
+$remSects$&
+``Remaining sectors'', after number of boot sectors and root directory
+have been accounted for\\
+
+\hline
+
+$fatLen$&
+Length of the FAT, in sectors\\
+
+\hline
+
+
+\end{tabular}
+
+\ \\
+
+Taking into account both data and fat, each cluster takes up the
+following number of nybbles (units of 4 bytes):
+
+
+$$clusSiz * (2*secSiz) + nfats * fatNybls$$
+
+This accounts for the data of the cluster ($clusSiz * secSiz$),
+as well as for the space taken up by its descriptor.
+
+The space taken up by all clusters together, plus the space taken by
+descriptors for clusters 0 and 1 ($2*nfats*fatNybls$) should be less
+than what is available.
+
+Additional sectors may be lost due to slack (you have to use a full
+FAT sector, you also have to use a full cluster in the data
+area). Thus, an {\em upper bound} for the number of clusters is as
+follows:
+
+$$
+numClus \le {2*remSect*secSiz - 2*nfats*fatNybls \over
+2*clusSiz*secSiz + nfats*fatNybls}
+$$
+
+
+$$
+numClus \le {(remSect+2*clusSiz)*2*secSiz \over
+2*clusSiz*secSiz + nfats*fatNybls} - 2
+$$
+
+
+These will take up at most the following space in one copy of the FAT
+(we have to round up, because even a half-full fat sector must be
+taken in its entirety)
+
+$$
+fatLen \le \left\lceil { (numClus+2)*fatNybls \over secSiz * 2 } \right\rceil
+$$
+
+
+$$
+fatLen \le \left\lceil {
+\left( { 2*(remSect+2*clusSiz)*secSiz \over
+2*clusSiz*secSiz + nfats*fatNybls} \right) * fatNybls \over
+2*secSiz
+} \right\rceil
+$$
+
+
+$$
+fatLen \le \left\lceil {
+(remSect+2*clusSiz)* fatNybls \over
+2*clusSiz*secSiz + nfats*fatNybls
+} \right\rceil
+$$
+
+The space left after FAT sector has been deduced is now {\em less than
+or equal} to what would be needed for the data area of the clusters
+(including fractional clusters), which is good, as we may have under
+no circumstances {\em more} clusters in the data area than in the FAT.
+An important point in this calculation is that we based the needed FAT
+size on a {\em fractional} number of clusters, rather than a rounded
+down amount of clusters. Indeed, using a rounded down number could
+have exposed us to a situation where we had an {\em almost enough}
+space for one more cluster (i.e. not enough space for data + FAT, but
+enough for data alone). This situation, combined with a situation
+where the last FAT sector was flush full could have lead to a
+situation where $numClus$ would become too large for the FAT to
+accomodate. I think this is clearer with an example:
+\begin{itemize}
+\item $remSect=4127$, $clusSiz=1$, $nfats=1$
+\item (Non rounded down) $numClus={(4127+2)*(1024) \over 1032} -
+2 =4094.992$
+\item Rounded down: 4094 clusters
+\item These fit into 16 FAT sectors, exactly
+\item ... leaving us 4095 clusters, which is one to many (because
+these 4095 clusters would now need 17 FAT clusters)
+\end{itemize}
+
+Keeping the fractional part (0.992) allows us to round {\em up} the
+needed number of FAT sectors to 17, nicely solving this problem.
+
+The downside of counting the fractional part however is that we quite
+often waste a sector in the really common situation where both $nfats$
+and $clusSiz$ are even, while $remSect$ is odd. An easy way to address
+this is to substract one from $remSect$ before application of the
+formula, if this case is detected. Such operation carries no risk, as
+the odd final sector cannot be used to make a full cluster.
+
+There is still a case however, where fatLen must be grown manually
+after application of the formula: If numClus exceeds the maximum
+number of clusters allowable for FAT12 or FAT16), we need to shrink
+$numClus$ after application of the formula, and manually make the FAT
+larger in order to take up any excess space.
+
+Also note that as we used upper bounds, we may waste a certain number
+of sectors, which an exact calculation may not have wasted. However,
+normally, we should not lose more than one sector per FAT copy.
+
+N.B. In its document at \url{http://www.microsoft.com/hwdev/download/hardware/fatgen103.pdf},
+Microsoft proposes a much simpler formula. However, this formula is
+both wrong (i.e. occasionally it produces a smaller FAT than is
+needed for the clusters on disk), less generic (only works for sector
+sizes equal to 512), and less efficient (in case of FAT32, it may
+waste up to 8 sectors!)
+
+The formula is the following (for FAT16):
+$$
+fatLen \le \left\lceil { remSect \over 256 * clusSiz + nfats} \right\rceil
+$$
+
+Note that it doesn't account for the dummy clusters 0 and 1. Thus, if
+we have 258 sectors remaining, with a cluster size of 1, and two FAT
+copies, the Microsoft formula mistakenly assumes fatLen = 1. This
+leaves 258 - 2 = 256 sectors for clusters, which yields 256 clusters.
+However, those clusters do not fit into the FAT, as two clusters are
+lost (0 and 1). However, to Micro\$ofts' credit, this is not actually
+the formula they're using (tested with $remsect=160056$ and
+$clusSize=4$), so this seems to be a documentation issue rather than a
+genuine bug.
+
+In case of FAT32, Microsoft just halves the denominator. This is
+wasteful, as only the $256*clusSiz$ part would need to be halved.
+
+If we assume 16777000, and a cluster size of 8, our formula would give
+us:
+$$fatLen = \left\lceil (16777000 + 16) * 8 \over 2 * 8 * 512 + 16
+\right\rceil = 16352$$
+This would leave $16777000-2*16352=16744296$ sectors for the clusters,
+i.e. 2093037 clusters. The FAT descriptors for those 2093037 clusters
+do indeed fit into our 16352 fat sectors.
+
+Microsoft, on the other hand, would get: $$fatLen = \left\lceil{
+16777000 \over (256 * 8 + 2)/2} \right\rceil = 16368$$ This would only
+leave $16777000-2*16368=16744264$, i.e. 2093033 clusters, thus wasting
+4 clusters. The FAT would be 28 sectors too big, i.e. more than the
+mere 8 sectors announced by Microsoft! Unfortunately, I currently
+don't have access to any sufficiently recent Windows to check out
+whether this really happens in the code, or whether it is only a
+documentation issue as well.
+
+Oh, and before somebody points it out: the formula in this document
+occassionnally wastes sectors too, although not as much (Example: With
+$remsect=685$, $clusSiz=1$ and $nfats=2$ our formula gives $fatLen=3$,
+which leaves 679 clusters. However, we could use $fatLen=2$, leaving
+681 clusters.
+
+\end{document}
diff --git a/file.c b/file.c
new file mode 100644
index 0000000..22ba233
--- /dev/null
+++ b/file.c
@@ -0,0 +1,723 @@
+/* Copyright 1996-1999,2001-2003,2007-2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "stream.h"
+#include "mtools.h"
+#include "fsP.h"
+#include "file.h"
+#include "htable.h"
+#include "dirCache.h"
+
+typedef struct File_t {
+ Class_t *Class;
+ int refs;
+ struct Fs_t *Fs; /* Filesystem that this fat file belongs to */
+ Stream_t *Buffer;
+
+ int (*map)(struct File_t *this, off_t where, size_t *len, int mode,
+ mt_off_t *res);
+ size_t FileSize;
+
+ size_t preallocatedSize;
+ int preallocatedClusters;
+
+ /* Absolute position of first cluster of file */
+ unsigned int FirstAbsCluNr;
+
+ /* Absolute position of previous cluster */
+ unsigned int PreviousAbsCluNr;
+
+ /* Relative position of previous cluster */
+ unsigned int PreviousRelCluNr;
+ direntry_t direntry;
+ 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(">");
+ }
+}
+
+void printFatWithOffset(Stream_t *Stream, off_t offset) {
+ File_t *This = getUnbufferedFile(Stream);
+ unsigned long n;
+ int rel;
+ off_t clusSize;
+
+ n = This->FirstAbsCluNr;
+ if(!n) {
+ printf("Root directory or empty file\n");
+ return;
+ }
+
+ clusSize = This->Fs->cluster_size * This->Fs->sector_size;
+
+ rel = 0;
+ while(offset >= clusSize) {
+ n = fatDecode(This->Fs, n);
+ rel++;
+ if(loopDetect(This, rel, n) < 0)
+ return;
+ if(n > This->Fs->last_fat)
+ return;
+ offset -= clusSize;
+ }
+
+ printf("%lu", n);
+}
+
+static int normal_map(File_t *This, off_t where, size_t *len, int mode,
+ mt_off_t *res)
+{
+ 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 UNUSEDP,
+ mt_off_t *res)
+{
+ Fs_t *Fs = This->Fs;
+
+ if(Fs->dir_len * Fs->sector_size < (size_t) where) {
+ *len = 0;
+ errno = ENOSPC;
+ return -2;
+ }
+
+ 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);
+ if(tmbuf) {
+ dst = (tmbuf->tm_isdst) ? (-60L * 60L) : 0L;
+ accum += dst;
+ }
+ return accum;
+}
+
+
+static int get_file_data(Stream_t *Stream, time_t *date, mt_size_t *size,
+ int *type, int *address)
+{
+ DeclareThis(File_t);
+
+ if(date)
+ *date = conv_stamp(& This->direntry.dir);
+ if(size)
+ *size = (mt_size_t) This->FileSize;
+ if(type)
+ *type = This->direntry.dir.attr & ATTR_DIR;
+ if(address)
+ *address = This->FirstAbsCluNr;
+ return 0;
+}
+
+
+static int free_file(Stream_t *Stream)
+{
+ DeclareThis(File_t);
+ Fs_t *Fs = This->Fs;
+ fsPreallocateClusters(Fs, -This->preallocatedClusters);
+ FREE(&This->direntry.Dir);
+ freeDirCache(Stream);
+ return hash_remove(filehash, (void *) Stream, This->hint);
+}
+
+
+static int flush_file(Stream_t *Stream)
+{
+ DeclareThis(File_t);
+ direntry_t *entry = &This->direntry;
+
+ if(isRootDir(Stream)) {
+ return 0;
+ }
+
+ if(This->FirstAbsCluNr != getStart(entry->Dir, &entry->dir)) {
+ set_word(entry->dir.start, This->FirstAbsCluNr & 0xffff);
+ set_word(entry->dir.startHi, This->FirstAbsCluNr >> 16);
+ dir_write(entry);
+ }
+ return 0;
+}
+
+
+static int pre_allocate_file(Stream_t *Stream, mt_size_t isize)
+{
+ DeclareThis(File_t);
+
+ size_t size = truncBytes32(isize);
+
+ if(size > This->FileSize &&
+ size > This->preallocatedSize) {
+ This->preallocatedSize = size;
+ return recalcPreallocSize(This);
+ } else
+ return 0;
+}
+
+static Class_t FileClass = {
+ read_file,
+ write_file,
+ flush_file, /* flush */
+ free_file, /* free */
+ 0, /* get_geom */
+ get_file_data,
+ pre_allocate_file,
+ get_dosConvert_pass_through
+};
+
+static unsigned int getAbsCluNr(File_t *This)
+{
+ if(This->FirstAbsCluNr)
+ return This->FirstAbsCluNr;
+ if(isRootDir((Stream_t *) This))
+ return 0;
+ return 1;
+}
+
+static unsigned int func1(void *Stream)
+{
+ DeclareThis(File_t);
+
+ return getAbsCluNr(This) ^ (long) This->Fs;
+}
+
+static unsigned int func2(void *Stream)
+{
+ DeclareThis(File_t);
+
+ return getAbsCluNr(This);
+}
+
+static int comp(void *Stream, void *Stream2)
+{
+ DeclareThis(File_t);
+
+ File_t *This2 = (File_t *) Stream2;
+
+ return This->Fs != This2->Fs ||
+ getAbsCluNr(This) != getAbsCluNr(This2);
+}
+
+static void init_hash(void)
+{
+ static int is_initialised=0;
+
+ if(!is_initialised){
+ make_ht(func1, func2, comp, 20, &filehash);
+ is_initialised = 1;
+ }
+}
+
+
+static Stream_t *_internalFileOpen(Stream_t *Dir, unsigned int first,
+ size_t size, direntry_t *entry)
+{
+ Stream_t *Stream = GetFs(Dir);
+ DeclareThis(Fs_t);
+ File_t Pattern;
+ File_t *File;
+
+ init_hash();
+ This->refs++;
+
+ if(first != 1){
+ /* we use the illegal cluster 1 to mark newly created files.
+ * do not manage those by hashtable */
+ Pattern.Fs = This;
+ Pattern.Class = &FileClass;
+ if(first || (entry && !IS_DIR(entry)))
+ Pattern.map = normal_map;
+ else
+ Pattern.map = root_map;
+ Pattern.FirstAbsCluNr = first;
+ Pattern.loopDetectRel = 0;
+ Pattern.loopDetectAbs = first;
+ if(!hash_lookup(filehash, (T_HashTableEl) &Pattern,
+ (T_HashTableEl **)&File, 0)){
+ File->refs++;
+ This->refs--;
+ return (Stream_t *) File;
+ }
+ }
+
+ File = New(File_t);
+ if (!File)
+ return NULL;
+ File->dcp = 0;
+ File->preallocatedClusters = 0;
+ File->preallocatedSize = 0;
+ /* memorize dir for date and attrib */
+ File->direntry = *entry;
+ if(entry->entry == -3)
+ File->direntry.Dir = (Stream_t *) File; /* root directory */
+ else
+ COPY(File->direntry.Dir);
+
+ File->Class = &FileClass;
+ File->Fs = This;
+ if(first || (entry && !IS_DIR(entry)))
+ File->map = normal_map;
+ else
+ File->map = root_map; /* FAT 12/16 root directory */
+ if(first == 1)
+ File->FirstAbsCluNr = 0;
+ else
+ File->FirstAbsCluNr = first;
+
+ File->loopDetectRel = 0;
+ File->loopDetectAbs = 0;
+
+ File->PreviousRelCluNr = 0xffff;
+ File->FileSize = size;
+ File->refs = 1;
+ File->Buffer = 0;
+ hash_add(filehash, (void *) File, &File->hint);
+ return (Stream_t *) File;
+}
+
+Stream_t *OpenRoot(Stream_t *Dir)
+{
+ unsigned int num;
+ direntry_t entry;
+ size_t size;
+ Stream_t *file;
+
+ memset(&entry, 0, sizeof(direntry_t));
+
+ num = fat32RootCluster(Dir);
+
+ /* make the directory entry */
+ entry.entry = -3;
+ entry.name[0] = '\0';
+ mk_entry_from_base("/", ATTR_DIR, num, 0, 0, &entry.dir);
+
+ if(num)
+ size = countBytes(Dir, num);
+ else {
+ Fs_t *Fs = (Fs_t *) GetFs(Dir);
+ size = Fs->dir_len * Fs->sector_size;
+ }
+ file = _internalFileOpen(Dir, num, size, &entry);
+ bufferize(&file);
+ return file;
+}
+
+
+Stream_t *OpenFileByDirentry(direntry_t *entry)
+{
+ Stream_t *file;
+ unsigned int first;
+ size_t size;
+
+ first = getStart(entry->Dir, &entry->dir);
+
+ if(!first && IS_DIR(entry))
+ return OpenRoot(entry->Dir);
+ if (IS_DIR(entry))
+ size = countBytes(entry->Dir, first);
+ else
+ size = FILE_SIZE(&entry->dir);
+ file = _internalFileOpen(entry->Dir, first, size, entry);
+ if(IS_DIR(entry)) {
+ bufferize(&file);
+ if(first == 1)
+ dir_grow(file, 0);
+ }
+
+ return file;
+}
+
+
+int isRootDir(Stream_t *Stream)
+{
+ File_t *This = getUnbufferedFile(Stream);
+
+ return This->map == root_map;
+}
diff --git a/file.h b/file.h
new file mode 100644
index 0000000..f7669c5
--- /dev/null
+++ b/file.h
@@ -0,0 +1,28 @@
+#ifndef MTOOLS_FILE_H
+#define MTOOLS_FILE_H
+/* Copyright 1996,1997,2001,2002,2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+#include "mtoolsDirentry.h"
+
+Stream_t *OpenFileByDirentry(direntry_t *entry);
+Stream_t *OpenRoot(Stream_t *Dir);
+void printFat(Stream_t *Stream);
+void printFatWithOffset(Stream_t *Stream, off_t offset);
+direntry_t *getDirentry(Stream_t *Stream);
+#endif
diff --git a/file_name.c b/file_name.c
new file mode 100644
index 0000000..963a137
--- /dev/null
+++ b/file_name.c
@@ -0,0 +1,220 @@
+/* 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++) {
+ /* 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;
+ 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 UNUSEDP,
+ 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;
+ }
+}
+
+
+/*
+ * 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
index 0000000..0d9ac90
--- /dev/null
+++ b/file_name.h
@@ -0,0 +1,44 @@
+#ifndef FILE_NAME_H
+#define FILE_NAME_H
+
+/* Copyright 2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..60e336f
--- /dev/null
+++ b/file_read.c
@@ -0,0 +1,55 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996,1997,1999,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "file.h"
+
+/*
+ * Read the clusters given the beginning FAT entry. Returns 0 on success.
+ */
+
+int file_read(FILE *fp, Stream_t *Source, int textmode, int stripmode)
+{
+ char buffer[16384];
+ int pos;
+ int ret;
+
+ if (!Source){
+ fprintf(stderr,"Couldn't open source file\n");
+ return -1;
+ }
+
+ pos = 0;
+ while(1){
+ ret = Source->Class->read(Source, buffer, pos, 16384);
+ if (ret < 0 ){
+ perror("file read");
+ return -1;
+ }
+ if ( ret == 0)
+ break;
+ if(!fwrite(buffer, 1, ret, fp)){
+ perror("write");
+ return -1;
+ }
+ pos += ret;
+ }
+ return 0;
+}
diff --git a/filter.c b/filter.c
new file mode 100644
index 0000000..11d8158
--- /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 UNUSEDP)
+{
+ Filter_t *This;
+
+ This = New(Filter_t);
+ if (!This)
+ return NULL;
+ This->Class = &FilterClass;
+ This->dospos = This->unixpos = This->rw = 0;
+ This->Next = Next;
+ This->refs = 1;
+ This->Buffer = 0;
+ /*
+ This->convertCharset = convertCharset;
+ */
+
+ return (Stream_t *) This;
+}
diff --git a/floppyd.1 b/floppyd.1
new file mode 100644
index 0000000..5c5edfb
--- /dev/null
+++ b/floppyd.1
@@ -0,0 +1,255 @@
+'\" t
+.TH floppyd 1 "09Jan13" mtools-4.0.18
+.SH Name
+floppyd - floppy daemon for remote access to floppy drive
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+\&\fR\&\f(CWFloppyd\fR is used as a server to grant access to the floppy drive
+to clients running on a remote machine, just as an X server grants
+access to the display to remote clients. It has the following syntax:
+.PP
+\&\fR\&\f(CWfloppyd\fR [\fR\&\f(CW-d\fR] [\fR\&\f(CW-l\fR] [\fR\&\f(CW-s\fR \fIport\fR] [\fR\&\f(CW-r\fR
+\&\fIuser\fR] [\fR\&\f(CW-b\fR \fIipaddr\fR] [\fR\&\f(CW-x\fR \fIdisplay\fR] \fIdevicenames\fR
+.PP
+\&\fR\&\f(CWfloppyd\fR is always associated with an X server. It runs on the
+same machine as its X server, and listens on port 5703 and above.
+.PP
+.SH Authentication
+.PP
+\&\fR\&\f(CWfloppyd\fR authenticates remote clients using the \fR\&\f(CWXauthority\fR
+protocol. Xhost authentication is not supported. Each floppyd is
+associated with an X server. When a remote client attempts to connect
+to floppyd, it sends floppyd the X authority record corresponding to
+floppyd's X server. Floppyd in turn then tries to open up a connection
+to the X server in order to verify the authenticity of the xauth record.
+If the connection to the X server succeeds, the client is granted
+access.
+\&\fR\&\f(CWDISPLAY\fR.
+.PP
+\&\fBCaution\fR: In order to make authentication work correctly, the
+local host should \fBnot\fR be listed in the \fR\&\f(CWxhost\fR list of
+allowed hosts.
+ Indeed, hosts listed in \fR\&\f(CWxhost\fR do not need a correct
+\&\fR\&\f(CWXauthority\fR cookie to connect to the X server. As \fR\&\f(CWfloppyd\fR
+runs on the same host as the X server, all its probe connection would
+succeed even for clients who supplied a bad cookie. This means that
+your floppy drive would be open to the world, i.e. a huge security hole.
+ If your X server does not allow you to remove \fR\&\f(CWlocalhost:0\fR and
+\&\fR\&\f(CW:0\fR from the \fR\&\f(CWxhost\fR list, you can prevent floppyd from
+probing those display names with the \fR\&\f(CW-l\fR option.
+.PP
+.SH Command\ line\ options
+.TP
+\&\fR\&\f(CWd\fR\
+Daemon mode. Floppyd runs its own server loop. Do not supply this if
+you start floppyd from \fR\&\f(CWinetd.conf\fR
+.TP
+\&\fR\&\f(CWs\ \ \fIport\fR\&\f(CW\fR\
+Port number for daemon mode. Default is 5703 + \fIdisplaynumber\fR.
+This flag implies daemon mode. For example, for display
+\&\fR\&\f(CWhitchhiker:5\fR, the port would be 5708.
+.TP
+\&\fR\&\f(CWb\ \ \fIipaddr\fR\&\f(CW\fR\
+Bind address (for multi homed hosts). This flag implies daemon mode
+.TP
+\&\fR\&\f(CWr\ \fIuser\fR\&\f(CW\fR\
+Run the server under as the given user
+.TP
+\&\fR\&\f(CWx\ \fIdisplay\fR\&\f(CW\fR\
+X display to use for authentication. By default, this is taken from the
+\&\fR\&\f(CWDISPLAY\fR variable. If neither the \fR\&\f(CWx\fR attribute is present
+nor \fR\&\f(CWDISPLAY\fR is set, floppyd uses \fR\&\f(CW:0.0\fR.
+.PP
+\&\fIdevicenames\fR is a list of device nodes to be opened. Default
+is \fR\&\f(CW/dev/fd0\fR. Multiple devices are only supported on mtools
+versions newer than 3.9.11.
+.PP
+.SH Connecting\ to\ floppyd
+.PP
+ In order to use floppyd, add the flag \fR\&\f(CWremote\fR to the device
+description in your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR file. If the flag \fR\&\f(CWremote\fR
+is given, the \fR\&\f(CWfile\fR parameter of the device description is taken
+to be a remote address. It's format is the following:
+\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR[\fIbaseport\fR][\fR\&\f(CW/\fR\fIdrive\fR]]. When
+using this entry, mtools connects to port
+\&\fIbaseport\fR+\fIdisplaynumber\fR at \fIhostname\fR. By default
+\&\fIbaseport\fR is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+.PP
+.SH Examples:
+.PP
+ The following starts a floppy daemon giving access to \fR\&\f(CW\(if/dev/fd0\(is\fR,
+listening on the default port 5703, tied to the default X servers:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+floppyd -d /dev/fd0
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ Each of the following starts a floppy daemon giving access to
+\&\fR\&\f(CW\(if/dev/fd1\(is\fR, tied to the :1 local X servers, and listening on port
+5704. We assume that the local host is named \fR\&\f(CWhitchhiker\fR.
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+floppyd -d /dev/fd0
+floppyd -d -x :1 -p 5704 /dev/fd0
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ If you want to start floppyd by \fR\&\f(CWinetd\fR instead of running it as a
+daemon, insert the following lines into \fR\&\f(CW\(if/etc/services\(is\fR:
+
+.nf
+.ft 3
+.in +0.3i
+# floppy daemon
+floppyd-0 5703/tcp # floppy daemon for X server :0
+floppyd-1 5704/tcp # floppy daemon for X server :1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ And insert the following into \fR\&\f(CW\(if/etc/inetd.conf\(is\fR (assuming that you
+have defined a user named floppy in your \fR\&\f(CW\(if/etc/passwd\(is\fR):
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+# floppy daemon
+floppyd-0 stream tcp wait floppy /usr/sbin/floppyd floppyd /dev/fd0
+floppyd-1 stream tcp wait floppy /usr/sbin/floppyd floppyd -x :1 /dev/fd0
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ Note that you need to supply the X display names for the second
+floppyd. This is because the port is opened by inetd.conf, and hence
+floppyd cannot know its number to interfere the display number.
+.PP
+On the client side, insert the following into your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR
+to define a drive letter accessing floppy drive in your X terminal:
+
+.nf
+.ft 3
+.in +0.3i
+drive x: file="$DISPLAY" remote
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+If your X terminal has more than one drive, you may access the
+additional drives as follows:
+
+.nf
+.ft 3
+.in +0.3i
+drive y: file="$DISPLAY//1" remote
+drive z: file="$DISPLAY//2" remote
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/floppyd.c b/floppyd.c
new file mode 100644
index 0000000..92ca38c
--- /dev/null
+++ b/floppyd.c
@@ -0,0 +1,1297 @@
+/* Copyright 1999 Peter Schlaile.
+ * Copyright 1999-2005,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * the floppyd daemon running on the local X-Server
+ *
+ * written by:
+ *
+ * Peter Schlaile
+ *
+ * udbz@rz.uni-karlsruhe.de
+ *
+ * Large parts of the network code shamelessly stolen from
+ * transproxy by John Saunders <john@nlc.net.au>
+ *
+ * Rewritten in C by Alain Knaff. Apparently C++ is still not as
+ * portable as C. */
+
+#define DEBUG 0
+
+#include "sysincludes.h"
+#include "llong.h"
+
+#ifdef USE_FLOPPYD
+
+#define USE_FLOPPYD_BUFFERED_IO 1
+#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;
+typedef mt_off_t Qword;
+
+#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 void put_qword(Packet packet, int my_index, Qword val) {
+ qword2byte(val, packet->data+my_index);
+}
+
+static Dword get_dword(Packet packet, int my_index) {
+ return byte2dword(packet->data+my_index);
+}
+
+static Qword get_qword(Packet packet, int my_index) {
+ return byte2qword(packet->data+my_index);
+}
+
+static Dword get_length(Packet packet) {
+ return packet->len;
+}
+
+static int eat(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 {
+ Dword cap = FLOPPYD_CAP_EXPLICIT_OPEN;
+ if(sizeof(mt_off_t) >= 8) {
+ cap |= FLOPPYD_CAP_LARGE_SEEK;
+ }
+ make_new(reply, 12);
+ put_dword(reply, 0, AUTH_SUCCESS);
+ put_dword(reply, 4, FLOPPYD_PROTOCOL_VERSION);
+ put_dword(reply, 8, cap);
+ }
+ send_packet(reply, sock);
+ destroyPacket(proto_version);
+
+ make_new(reply, 4);
+ mit_cookie = newPacket();
+ if (!recv_packet(mit_cookie, sock, MAX_XAUTHORITY_LENGTH)) {
+ put_dword(reply, 0, AUTH_PACKETOVERSIZE);
+ send_packet(reply, sock);
+ destroyPacket(reply);
+ destroyPacket(mit_cookie);
+ return 0;
+ }
+
+ umask(077);
+ fd = mkstemp(authFile);
+ if(fd == -1) {
+ /* Different error than file exists */
+ put_dword(reply, 0, AUTH_DEVLOCKED);
+ send_packet(reply, sock);
+ close(fd);
+ destroyPacket(reply);
+ destroyPacket(mit_cookie);
+ return 0;
+ }
+#ifdef HAVE_SETENV
+ setenv(XAUTHORITY, authFile, 1);
+#else
+ {
+ char *buffer=malloc(strlen(XAUTHORITY)+strlen(authFile)+2);
+ strcpy(buffer, XAUTHORITY);
+ strcat(buffer, "=");
+ strcat(buffer, authFile);
+ putenv(buffer);
+ }
+#endif
+
+ ptr = template;
+ ptr[4095] = 0;
+ *ptr++ = 1;
+ *ptr++ = 0;
+ *ptr++ = 0;
+ gethostname(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;
+
+ 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;
+ bind_port = getportnum(optarg);
+ break;
+
+ case 'r':
+ free(username); username = strdup(optarg);
+ run_uid = getuserid(optarg);
+ run_gid = getgroupid(run_uid);
+ break;
+
+ case 'b':
+ run_as_server = 1;
+ bind_ip = getipaddress(optarg);
+ break;
+ case 'x':
+ dispName = strdup(optarg);
+ break;
+
+ case 'h':
+ usage(argv[0], NULL, 0);
+ 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)) {
+ bind_port = ntohs(addr.sin_port);
+ }
+ }
+
+ umask(0077);
+
+ /*
+ * Test to make sure required args were provided and are valid.
+ */
+ if (run_as_server && (bind_ip == INADDR_NONE)) {
+ usage(argv[0], "The server ipaddr is invalid.", 1);
+ }
+ if (run_as_server && (bind_port == 0)) {
+ usage(argv[0], "No server port was specified (or it was invalid).", 1);
+ }
+
+
+ /*
+ * See if we should run as a server.
+ */
+ if (run_as_server) {
+ /*
+ * Start by binding to the port, the child inherits this socket.
+ */
+ sock = bind_to_port(bind_ip, bind_port);
+
+ /*
+ * Start a server process. When DEBUG is defined, just run
+ * in the foreground.
+ */
+#if DEBUG
+ switch (0)
+#else
+ switch (fork())
+#endif
+ {
+ case -1:
+ perror("fork()");
+ exit(1);
+
+ case 0:
+ /*
+ * Ignore some signals.
+ */
+ signal(SIGHUP, SIG_IGN);
+#if DEBUG
+ signal(SIGINT, SIG_IGN);
+#endif
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGCONT, SIG_IGN);
+ signal(SIGPIPE, alarm_signal);
+ /*signal(SIGALRM, alarm_signal);*/
+
+ /*
+ * Drop back to an untrusted user.
+ */
+ setgid(run_gid);
+ initgroups(username, -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 send_reply64(int rval, io_buffer sock, mt_off_t len) {
+ Packet reply = newPacket();
+
+ make_new(reply, 12);
+ put_qword(reply, 0, len);
+ if (rval == -1) {
+ put_dword(reply, 8, 0);
+ } else {
+ put_dword(reply, 8, 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|O_LARGEFILE);
+
+ if (devFd < 0) {
+ readOnly = 1;
+ devFd = open(device_name[0],
+ O_RDONLY|O_LARGEFILE);
+ }
+ 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 | O_LARGEFILE);
+#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_SEEK64:
+ if(sizeof(mt_off_t) < 8) {
+#if DEBUG
+ fprintf(stderr, "64 bit requested where not available!\n");
+#endif
+ errno = EINVAL;
+ send_reply(devFd, sock, -1);
+ break;
+ }
+#if DEBUG
+ fprintf(stderr, "SEEK64:\n");
+#endif
+ mt_lseek(devFd,
+ get_qword(parm,0), get_dword(parm,8));
+ send_reply64(devFd,
+ sock,
+ mt_lseek(devFd, 0, SEEK_CUR));
+ break;
+ case OP_FLUSH:
+#if DEBUG
+ fprintf(stderr, "FLUSH:\n");
+#endif
+ fsync(devFd);
+ send_reply(devFd, sock, 0);
+ break;
+ case OP_CLOSE:
+#if DEBUG
+ fprintf(stderr, "CLOSE:\n");
+#endif
+
+ close(devFd);
+ needSendReply = 1;
+ rval = devFd;
+ devFd = -1;
+ stopLoop = 1;
+ break;
+ case OP_IOCTL:
+ /* Unimplemented for now... */
+ break;
+ default:
+#if DEBUG
+ fprintf(stderr, "Invalid Opcode!\n");
+#endif
+ errno = EINVAL;
+ send_reply(devFd, sock, -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
index 0000000..80dac2c
--- /dev/null
+++ b/floppyd_installtest.1
@@ -0,0 +1,94 @@
+'\" t
+.TH floppyd_installtest 1 "09Jan13" mtools-4.0.18
+.SH Name
+floppyd_installtest - tests whether floppyd is installed and running
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+\&\fR\&\f(CWFloppyd_installtest\fR is used to check for the presence of a running
+floppyd daemon. This is useful, if you have a small front-end script to
+mtools, which decides whether to use floppyd or not.
+.PP
+\&\fR\&\f(CWfloppyd_installtest\fR [\fR\&\f(CW-f\fR] Connect-String
+.PP
+If the \fR\&\f(CW-f\fR option is specified, \fR\&\f(CWfloppyd_installtest\fR does a
+full X-Cookie authentication and complains if this does not work.
+.PP
+The connect-String has the format described in the floppyd-section:
+\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR\fIbaseport\fR]
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/floppyd_installtest.c b/floppyd_installtest.c
new file mode 100644
index 0000000..92ed54f
--- /dev/null
+++ b/floppyd_installtest.c
@@ -0,0 +1,330 @@
+/* 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;
+typedef mt_off_t Qword;
+
+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;
+ int cap=0;
+
+ if (fullauth) {
+ command[4] = display;
+
+ filelen=strlen(display);
+ filelen += 100;
+
+ xcookie = (char *) safe_malloc(filelen+4);
+ filelen = safePopenOut(command, xcookie+4, filelen);
+ if(filelen < 1)
+ return AUTH_AUTHFAILED;
+ }
+ dword2byte(4,buf);
+ dword2byte(protoversion,buf+4);
+ if(write(sock, buf, 8) < 8)
+ return AUTH_IO_ERROR;
+
+ bytesRead = read_dword(sock);
+
+ if (bytesRead != 4 && bytesRead != 12) {
+ return AUTH_WRONGVERSION;
+ }
+
+
+ errcode = read_dword(sock);
+
+ if (errcode != AUTH_SUCCESS) {
+ return errcode;
+ }
+
+ protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;
+ if(bytesRead >= 12) {
+ protoversion = read_dword(sock);
+ cap = read_dword(sock);
+ }
+
+ fprintf(stderr, "Protocol Version=%d\n", protoversion);
+ if(protoversion >= FLOPPYD_PROTOCOL_VERSION) {
+ fprintf(stderr, "Capabilities:%s%s\n",
+ (cap & FLOPPYD_CAP_EXPLICIT_OPEN) ? " ExplicitOpen" : "",
+ (cap & FLOPPYD_CAP_LARGE_SEEK) ? " LargeFiles" : "");
+ }
+
+ if (fullauth) {
+ dword2byte(filelen, (Byte *) xcookie);
+ if(write(sock, xcookie, filelen+4) < filelen+4)
+ return AUTH_IO_ERROR;
+
+ if (read_dword(sock) != 4) {
+ return AUTH_PACKETOVERSIZE;
+ }
+
+ errcode = read_dword(sock);
+ }
+
+ return errcode;
+
+}
+
+
+/* ######################################################################## */
+
+static int get_host_and_port(const char* name, char** hostname, char **display,
+ short* port)
+{
+ char* newname = strdup(name);
+ char* p;
+ char* p2;
+
+ p = newname;
+ while (*p != '/' && *p) p++;
+ p2 = p;
+ if (*p) p++;
+ *p2 = 0;
+
+ *port = atoi(p);
+ if (*port == 0) {
+ *port = FLOPPYD_DEFAULT_PORT;
+ }
+
+ *display = strdup(newname);
+
+ p = newname;
+ while (*p != ':' && *p) p++;
+ p2 = p;
+ if (*p) p++;
+ *p2 = 0;
+
+ *port += atoi(p); /* add display number to the port */
+
+ if (!*newname || strcmp(newname, "unix") == 0) {
+ free(newname);
+ newname = strdup("localhost");
+ }
+
+ *hostname = newname;
+ return 1;
+}
+
+/*
+ * * Return the IP address of the specified host.
+ * */
+static IPaddr_t getipaddress(char *ipaddr)
+{
+
+ struct hostent *host;
+ IPaddr_t ip;
+
+ if (((ip = inet_addr(ipaddr)) == INADDR_NONE) &&
+ (strcmp(ipaddr, "255.255.255.255") != 0)) {
+
+ if ((host = gethostbyname(ipaddr)) != NULL) {
+ memcpy(&ip, host->h_addr, sizeof(ip));
+ }
+
+ endhostent();
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "IP lookup %s -> 0x%08lx\n", ipaddr, ip);
+#endif
+
+ return (ip);
+}
+
+/*
+ * * Connect to the floppyd server.
+ * */
+static int connect_to_server(IPaddr_t ip, short port)
+{
+
+ struct sockaddr_in addr;
+ int sock;
+
+ /*
+ * Allocate a socket.
+ */
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ return (-1);
+ }
+
+ /*
+ * Set the address to connect to.
+ */
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = ip;
+
+ /*
+ * Connect our socket to the above address.
+ */
+ if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ return (-1);
+ }
+
+ /*
+ * Set the keepalive socket option to on.
+ */
+ {
+ int on = 1;
+ setsockopt(STDIN_FILENO, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on));
+
+ }
+
+ return (sock);
+}
+
+int main (int argc, char** argv)
+{
+ char* hostname;
+ char* display;
+ char* name;
+ short port;
+ int sock;
+ int reply;
+ int rval;
+ int protoversion;
+ char fullauth = 0;
+ Byte opcode = OP_CLOSE;
+
+ if (argc < 2) {
+ puts("Usage: floppyd_installtest [-f] Connect-String\n"
+ "-f\tDo full X-Cookie-Authentication");
+ return -1;
+ }
+
+ name = argv[1];
+ if (strcmp(name, "-f") == 0) {
+ fullauth = 1;
+ name = argv[2];
+ }
+
+ rval = get_host_and_port(name, &hostname, &display, &port);
+
+ if (!rval) return -1;
+
+ sock = connect_to_server(getipaddress(hostname), port);
+
+ if (sock == -1) {
+ fprintf(stderr,
+ "Can't connect to floppyd server on %s, port %i!\n",
+ hostname, port);
+ return -1;
+ }
+
+ protoversion = FLOPPYD_PROTOCOL_VERSION;
+ while(1) {
+ reply = authenticate_to_floppyd(fullauth, sock, display,
+ protoversion);
+ if(protoversion == FLOPPYD_PROTOCOL_VERSION_OLD)
+ break;
+ if(reply == AUTH_WRONGVERSION) {
+ /* fall back on old version */
+ protoversion = FLOPPYD_PROTOCOL_VERSION_OLD;
+ continue;
+ }
+ break;
+ }
+
+ if (reply != 0) {
+ fprintf(stderr,
+ "Connection to floppyd failed:\n"
+ "%s\n", AuthErrors[reply]);
+ return -1;
+ }
+
+ free(hostname);
+ free(display);
+
+ if(write_dword(sock, 1) < 0) {
+ fprintf(stderr,
+ "Short write to floppyd:\n"
+ "%s\n", strerror(errno));
+ }
+
+ if(write(sock, &opcode, 1) < 0) {
+ fprintf(stderr,
+ "Short write to floppyd:\n"
+ "%s\n", strerror(errno));
+ }
+
+ close(sock);
+
+ return 0;
+}
+#endif
diff --git a/floppyd_io.c b/floppyd_io.c
new file mode 100644
index 0000000..d8e0fdb
--- /dev/null
+++ b/floppyd_io.c
@@ -0,0 +1,679 @@
+/* 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;
+typedef mt_off_t Qword;
+
+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 mt_off_t floppyd_lseek64(int fd, mt_off_t offset, int whence)
+{
+ Dword errcode;
+ Qword gotlen;
+ Byte buf[32];
+
+ dword2byte(1, buf);
+ buf[4] = OP_SEEK64;
+
+ dword2byte(12, buf+5);
+ qword2byte(offset, buf+9);
+ dword2byte(whence, buf+17);
+
+ if(write(fd, buf, 21) < 21)
+ return AUTH_IO_ERROR;
+
+ if (read_dword(fd) != 12) {
+ errno = EIO;
+ return -1;
+ }
+
+ gotlen = read_qword(fd);
+ errcode = read_dword(fd);
+
+ errno = errcode;
+
+ return gotlen;
+}
+
+static int floppyd_open(RemoteFile_t *This, int mode)
+{
+ Dword errcode;
+ Dword gotlen;
+ Byte buf[16];
+
+ if(! (This->capabilities & FLOPPYD_CAP_EXPLICIT_OPEN) ) {
+ /* floppyd has no "explicit seek" capabilities */
+ return 0;
+ }
+
+ dword2byte(1, buf);
+ if((mode & O_ACCMODE) == O_RDONLY)
+ buf[4] = OP_OPRO;
+ else
+ buf[4] = OP_OPRW;
+ dword2byte(4, buf+5);
+ dword2byte(This->drive, buf+9);
+
+ if(write(This->fd, buf, 13) < 13)
+ return AUTH_IO_ERROR;
+
+ if (read_dword(This->fd) != 8) {
+ errno = EIO;
+ return -1;
+ }
+
+ gotlen = read_dword(This->fd);
+ errcode = read_dword(This->fd);
+
+ errno = errcode;
+
+ return gotlen;
+}
+
+
+/* ######################################################################## */
+
+typedef int (*iofn) (int, char *, 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(This->capabilities & FLOPPYD_CAP_LARGE_SEEK) {
+ if(floppyd_lseek64( This->fd, where, SEEK_SET) < 0 ){
+ perror("floppyd_lseek64");
+ This->lastwhere = (mt_off_t) -1;
+ return -1;
+ }
+ } else {
+ if(floppyd_lseek( This->fd, where, SEEK_SET) < 0 ){
+ perror("floppyd_lseek");
+ This->lastwhere = (mt_off_t) -1;
+ return -1;
+ }
+ }
+ }
+ ret = io(This->fd, buf, len);
+ if ( ret == -1 ){
+ perror("floppyd_io");
+ This->lastwhere = (mt_off_t) -1;
+ return -1;
+ }
+ This->lastwhere = where + ret;
+ return ret;
+}
+
+static int floppyd_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len)
+{
+ return floppyd_io(Stream, buf, where, len, (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 UNUSEDP,
+ 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,
+ char *name, int mode, char *errmsg,
+ mt_size_t *maxSize)
+{
+ RemoteFile_t *This;
+
+ if (!dev || !(dev->misc_flags & FLOPPYD_FLAG))
+ return NULL;
+
+ This = New(RemoteFile_t);
+ if (!This){
+ printOom();
+ return NULL;
+ }
+ This->Class = &FloppydFileClass;
+ This->Next = 0;
+ This->offset = 0;
+ This->lastwhere = 0;
+ This->refs = 1;
+ This->Buffer = 0;
+
+ This->fd = ConnectToFloppyd(This, name, errmsg);
+ if (This->fd == -1) {
+ Free(This);
+ return NULL;
+ }
+
+ if(floppyd_open(This, mode) < 0) {
+ sprintf(errmsg,
+ "Can't open remote drive: %s", strerror(errno));
+ close(This->fd);
+ Free(This);
+ return NULL;
+ }
+
+ if(maxSize) {
+ *maxSize =
+ (This->capabilities & FLOPPYD_CAP_LARGE_SEEK) ?
+ max_off_t_seek : max_off_t_31;
+ }
+ return (Stream_t *) This;
+}
+
+static int ConnectToFloppyd(RemoteFile_t *floppyd, const char* name,
+ char *errmsg)
+{
+ char* hostname;
+ char* display;
+ short port;
+ int rval = get_host_and_port_and_drive(name, &hostname, &display,
+ &port, &floppyd->drive);
+ int sock;
+ int reply;
+
+ if (!rval) return -1;
+
+ floppyd->version = FLOPPYD_PROTOCOL_VERSION;
+ floppyd->capabilities = 0;
+ while(1) {
+ sock = connect_to_server(getipaddress(hostname), port);
+
+ if (sock == -1) {
+#ifdef HAVE_SNPRINTF
+ snprintf(errmsg, 200,
+ "Can't connect to floppyd server on %s, port %i (%s)!",
+ hostname, port, strerror(errno));
+#else
+ sprintf(errmsg,
+ "Can't connect to floppyd server on %s, port %i!",
+ hostname, port);
+#endif
+ return -1;
+ }
+
+ reply = authenticate_to_floppyd(floppyd, sock, display);
+ if(floppyd->version == FLOPPYD_PROTOCOL_VERSION_OLD)
+ break;
+ if(reply == AUTH_WRONGVERSION) {
+ /* fall back on old version */
+ floppyd->version = FLOPPYD_PROTOCOL_VERSION_OLD;
+ continue;
+ }
+ break;
+ }
+
+ if (reply != 0) {
+ fprintf(stderr,
+ "Permission denied, authentication failed!\n"
+ "%s\n", AuthErrors[reply]);
+ return -1;
+ }
+
+ free(hostname);
+ free(display);
+
+ return sock;
+}
+#endif
diff --git a/floppyd_io.h b/floppyd_io.h
new file mode 100644
index 0000000..d767ea8
--- /dev/null
+++ b/floppyd_io.h
@@ -0,0 +1,65 @@
+#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,
+ char *name, int mode, char *errmsg,
+ mt_size_t *maxSize);
+
+#define FLOPPYD_DEFAULT_PORT 5703
+
+#define FLOPPYD_PROTOCOL_VERSION_OLD 10
+#define FLOPPYD_PROTOCOL_VERSION 11
+
+#define FLOPPYD_CAP_EXPLICIT_OPEN 1 /* explicit open. Useful for
+ * clean signalling of readonly disks */
+#define FLOPPYD_CAP_LARGE_SEEK 2 /* large seeks */
+
+enum FloppydOpcodes {
+ OP_READ,
+ OP_WRITE,
+ OP_SEEK,
+ OP_FLUSH,
+ OP_CLOSE,
+ OP_IOCTL,
+ OP_OPRO,
+ OP_OPRW,
+ OP_SEEK64
+};
+
+enum AuthErrorsEnum {
+ AUTH_SUCCESS,
+ AUTH_PACKETOVERSIZE,
+ AUTH_AUTHFAILED,
+ AUTH_WRONGVERSION,
+ AUTH_DEVLOCKED,
+ AUTH_BADPACKET,
+ AUTH_IO_ERROR
+};
+
+typedef unsigned long IPaddr_t;
+
+#endif
+#endif
diff --git a/force_io.c b/force_io.c
new file mode 100644
index 0000000..006d315
--- /dev/null
+++ b/force_io.c
@@ -0,0 +1,63 @@
+/* Copyright 1996,1997,1999,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Force I/O to be done to complete transfer length
+ *
+ * written by:
+ *
+ * Alain L. Knaff
+ * alain@knaff.lu
+ *
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "stream.h"
+
+static int force_io(Stream_t *Stream,
+ char *buf, mt_off_t start, size_t len,
+ int (*io)(Stream_t *, char *, mt_off_t, size_t))
+{
+ int ret;
+ int done=0;
+
+ while(len){
+ ret = io(Stream, buf, start, len);
+ if ( ret <= 0 ){
+ if (done)
+ return done;
+ else
+ return ret;
+ }
+ start += ret;
+ done += ret;
+ len -= ret;
+ buf += ret;
+ }
+ return done;
+}
+
+int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+ return force_io(Stream, buf, start, len,
+ Stream->Class->write);
+}
+
+int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+ return force_io(Stream, buf, start, len,
+ Stream->Class->read);
+}
diff --git a/fs.h b/fs.h
new file mode 100644
index 0000000..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
index 0000000..3fb88e4
--- /dev/null
+++ b/fsP.h
@@ -0,0 +1,103 @@
+#ifndef MTOOLS_FSP_H
+#define MTOOLS_FSP_H
+
+/* Copyright 1996-1999,2001-2003,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "stream.h"
+#include "msdos.h"
+#include "fs.h"
+
+typedef enum fatAccessMode_t {
+ FAT_ACCESS_READ,
+ FAT_ACCESS_WRITE
+} fatAccessMode_t;
+
+typedef struct Fs_t {
+ Class_t *Class;
+ int refs;
+ Stream_t *Next;
+ Stream_t *Buffer;
+
+ int serialized;
+ unsigned long serial_number;
+ unsigned int cluster_size;
+ unsigned int sector_size;
+ int fat_error;
+
+ unsigned int (*fat_decode)(struct Fs_t *This, unsigned int num);
+ void (*fat_encode)(struct Fs_t *This, unsigned int num,
+ unsigned int code);
+
+ Stream_t *Direct;
+ int fat_dirty;
+ unsigned int fat_start;
+ unsigned int fat_len;
+
+ unsigned int num_fat;
+ unsigned int end_fat;
+ unsigned int last_fat;
+ int fat_bits; /* must be signed, because we use negative values
+ * for special purposes */
+ struct FatMap_t *FatMap;
+
+ unsigned int dir_start;
+ unsigned int dir_len;
+ unsigned int clus_start;
+
+ unsigned int num_clus;
+ char drive; /* for error messages */
+
+ /* fat 32 */
+ unsigned int primaryFat;
+ unsigned int writeAllFats;
+ unsigned int rootCluster;
+ unsigned int infoSectorLoc;
+ unsigned int last; /* last sector allocated, or MAX32 if unknown */
+ unsigned int freeSpace; /* free space, or MAX32 if unknown */
+ int preallocatedClusters;
+
+ int lastFatSectorNr;
+ unsigned char *lastFatSectorData;
+ fatAccessMode_t lastFatAccessMode;
+ int sectorMask;
+ int sectorShift;
+
+ doscp_t *cp;
+} Fs_t;
+
+int fs_free(Stream_t *Stream);
+
+void set_fat12(Fs_t *Fs);
+void set_fat16(Fs_t *Fs);
+void set_fat32(Fs_t *Fs);
+unsigned int get_next_free_cluster(Fs_t *Fs, unsigned int last);
+unsigned int fatDecode(Fs_t *This, unsigned int pos);
+void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos);
+void fatDeallocate(Fs_t *This, unsigned int pos);
+void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value);
+void fatEncode(Fs_t *This, unsigned int pos, unsigned int value);
+
+int fat_read(Fs_t *This, union bootsector *boot,
+ size_t tot_sectors, int nodups);
+void fat_write(Fs_t *This);
+int zero_fat(Fs_t *Fs, int media_descriptor);
+extern Class_t FsClass;
+int fsPreallocateClusters(Fs_t *Fs, long);
+Fs_t *getFs(Stream_t *Stream);
+
+
+#endif
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..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
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
index 0000000..c9152e0
--- /dev/null
+++ b/init.c
@@ -0,0 +1,426 @@
+/* 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)
+{
+ short boot_sector_size; /* sector size, as stored in boot sector */
+
+ /* read the first sector, or part of it */
+ if(!size)
+ size = BOOTSIZE;
+ if(size > MAX_BOOT)
+ size = MAX_BOOT;
+
+ if (force_read(Stream, boot->characters, 0, size) != size)
+ return -1;
+
+ boot_sector_size = WORD(secsiz);
+ if(boot_sector_size >= 0 &&
+ boot_sector_size < sizeof(boot->bytes)) {
+ /* zero rest of in-memory boot sector */
+ memset(boot->bytes+boot_sector_size, 0,
+ sizeof(boot->bytes) - boot_sector_size);
+ }
+
+ return 0;
+}
+
+static int fs_flush(Stream_t *Stream)
+{
+ DeclareThis(Fs_t);
+
+ fat_write(This);
+ return 0;
+}
+
+static doscp_t *get_dosConvert(Stream_t *Stream)
+{
+ DeclareThis(Fs_t);
+ return This->cp;
+}
+
+Class_t FsClass = {
+ read_pass_through, /* read */
+ write_pass_through, /* write */
+ fs_flush,
+ fs_free, /* free */
+ 0, /* set geometry */
+ get_data_pass_through,
+ 0, /* pre allocate */
+ get_dosConvert, /* dosconvert */
+};
+
+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, name, mode,
+ errmsg, maxSize);
+#endif
+ } else {
+
+#ifdef USE_XDF
+ Stream = XdfOpen(out_dev, name, mode, errmsg, 0);
+ if(Stream) {
+ out_dev->use_2m = 0x7f;
+ if(maxSize)
+ *maxSize = max_off_t_31;
+ }
+#endif
+
+
+ if (!Stream)
+ Stream = SimpleFileOpen(out_dev, dev, name,
+ isRop ? mode | O_RDWR: mode,
+ errmsg, 0, 1, maxSize);
+
+ if(Stream) {
+ isRo=0;
+ } else if(isRop &&
+ (errno == EPERM || errno == EACCES || errno == EROFS)) {
+ Stream = SimpleFileOpen(out_dev, dev, name,
+ mode | O_RDONLY,
+ errmsg, 0, 1, maxSize);
+ if(Stream) {
+ isRo=1;
+ }
+ }
+ }
+
+ if( !Stream)
+ continue;
+
+ /* read the boot sector */
+ if ((r=read_boot(Stream, boot, out_dev->blocksize)) < 0){
+ sprintf(errmsg,
+ "init %c: could not read boot sector",
+ drive);
+ continue;
+ }
+
+ if((*media= get_media_type(Stream, boot)) <= 0xf0 ){
+ if (boot->boot.jump[2]=='L')
+ sprintf(errmsg,
+ "diskette %c: is Linux LILO, not DOS",
+ drive);
+ else
+ sprintf(errmsg,"init %c: non DOS media", drive);
+ continue;
+ }
+
+ /* set new parameters, if needed */
+ errno = 0;
+ if(SET_GEOM(Stream, out_dev, dev, *media, boot)){
+ if(errno)
+#ifdef HAVE_SNPRINTF
+ snprintf(errmsg, 199,
+ "Can't set disk parameters for %c: %s",
+ drive, strerror(errno));
+#else
+ sprintf(errmsg,
+ "Can't set disk parameters for %c: %s",
+ drive, strerror(errno));
+#endif
+ else
+ sprintf(errmsg,
+ "Can't set disk parameters for %c",
+ drive);
+ continue;
+ }
+ break;
+ }
+
+ /* print error msg if needed */
+ if ( dev->drive == 0 ){
+ FREE(&Stream);
+ fprintf(stderr,"%s\n",errmsg);
+ return NULL;
+ }
+ if(isRop)
+ *isRop = isRo;
+ return Stream;
+}
+
+
+Stream_t *fs_init(char drive, int mode, int *isRop)
+{
+ int blocksize;
+ int media,i;
+ 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;
+ } 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);
+
+ 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, tot_sectors, dev.use_2m&0x7f)){
+ This->num_fat = 1;
+ FREE(&This->Next);
+ Free(This->Next);
+ return NULL;
+ }
+
+ /* Set the codepage */
+ This->cp = cp_open(dev.codepage);
+ if(This->cp == NULL) {
+ fs_free((Stream_t *)This);
+ FREE(&This->Next);
+ Free(This->Next);
+ return NULL;
+ }
+
+ return (Stream_t *) This;
+}
+
+char getDrive(Stream_t *Stream)
+{
+ DeclareThis(Fs_t);
+
+ if(This->Class != &FsClass)
+ return getDrive(GetFs(Stream));
+ else
+ return This->drive;
+}
+
+int fsPreallocateClusters(Fs_t *Fs, long size)
+{
+ if(size > 0 && getfreeMinClusters((Stream_t *)Fs, size) != 1)
+ return -1;
+
+ Fs->preallocatedClusters += size;
+ return 0;
+}
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..89fc9b0
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,238 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/llong.c b/llong.c
new file mode 100644
index 0000000..a1eaeec
--- /dev/null
+++ b/llong.c
@@ -0,0 +1,96 @@
+/* Copyright 1999-2003,2006,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..8c01918
--- /dev/null
+++ b/llong.h
@@ -0,0 +1,110 @@
+#ifndef MTOOLS_LLONG_H
+#define MTOOLS_LLONG_H
+
+/* Copyright 1999,2001-2004,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if 1
+
+
+#ifdef HAVE_OFF_T_64
+/* if off_t is already 64 bits, be happy, and don't worry about the
+ * loff_t and llseek stuff */
+# define MT_OFF_T off_t
+# if SIZEOF_SIZE_T == 4
+/* Some systems (NetBSD) apparently have 64 bit off_t, but 32 bit size_t ... */
+# define MT_SIZE_T off_t
+# else
+# define MT_SIZE_T size_t
+# endif
+#endif
+
+#ifndef MT_OFF_T
+# if defined(HAVE_LLSEEK) || defined(HAVE_LSEEK64)
+/* we have llseek. Now, what's its type called? loff_t or offset_t ? */
+# ifdef HAVE_LOFF_T
+# define MT_OFF_T loff_t
+/* use the same type for size. Better to get signedness wrong than width */
+# define MT_SIZE_T loff_t
+# else
+# ifdef HAVE_OFFSET_T
+# define MT_OFF_T offset_t
+/* use the same type for size. Better to get signedness wrong than width */
+# define MT_SIZE_T offset_t
+# endif
+# endif
+# endif
+#endif
+
+#ifndef MT_OFF_T
+/* we still don't have a suitable mt_off_t type...*/
+# ifdef HAVE_LONG_LONG
+/* ... first try long long ... */
+# define MT_OFF_T long long
+# define MT_SIZE_T unsigned long long
+# else
+# ifdef HAVE_OFF64_T
+# define MT_OFF_T off64_t
+# define MT_SIZE_T off64_t
+# else
+/* ... and if that fails, fall back on good ole' off_t */
+# define MT_OFF_T off_t
+# define MT_SIZE_T size_t
+# endif
+# endif
+#endif
+
+typedef MT_OFF_T mt_off_t;
+typedef MT_SIZE_T mt_size_t;
+
+#else
+/* testing: meant to flag dubious assignments between 32 bit length types
+ * and 64 bit ones */
+typedef struct {
+ unsigned int lo;
+ int high;
+} *mt_off_t;
+
+typedef struct {
+ unsigned int lo;
+ unsigned int high;
+} *mt_size_t;
+
+#endif
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define MAX_OFF_T_B(bits) \
+ ((((mt_off_t) 1 << min(bits-1, sizeof(mt_off_t)*8 - 2)) -1) << 1 | 1)
+
+#if defined(HAVE_LLSEEK) || defined(HAVE_LSEEK64)
+# define SEEK_BITS 63
+#else
+# define SEEK_BITS (sizeof(off_t) * 8 - 1)
+#endif
+
+extern const mt_off_t max_off_t_31;
+extern const mt_off_t max_off_t_41;
+extern const mt_off_t max_off_t_seek;
+
+extern off_t truncBytes32(mt_off_t off);
+extern int fileTooBig(mt_off_t off);
+
+int mt_lseek(int fd, mt_off_t where, int whence);
+
+unsigned int log_2(int);
+
+#endif
diff --git a/lockdev.h b/lockdev.h
new file mode 100644
index 0000000..4467bc2
--- /dev/null
+++ b/lockdev.h
@@ -0,0 +1,77 @@
+#ifndef LOCK_DEV
+#define LOCK_DEV
+
+/* Copyright 2005,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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/lz.1 b/lz.1
new file mode 100644
index 0000000..af90462
--- /dev/null
+++ b/lz.1
@@ -0,0 +1,42 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for lz
+.\"
+.\" Copyright (C), 2000, Robert A.R. King
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Fri Dec 1 01:50:54 EST 2000 Robert A.R. King (Robert.King@mailbox.gu.edu.au)
+.\"
+.TH LZ 1 "Wed Feb 23 00:00:00 EET 2000" "" "Mtools Users Manual"
+.SH NAME
+lz \- gunzips and shows a listing of a gzip'd tar'd archive
+.SH SYNOPSIS
+.\" The command line
+.B lz
+.I file
+.SH DESCRIPTION
+.B lz
+provides a listing of a gzip'd tar'd archive, that is a \fBtar\fR(1) archive
+compressed with the \fBgzip\fR(1) utility.
+It is not strictly necessary on Debian GNU/Linux, because the GNU
+\fBtar\fR(1) program provides the same capability with the command
+
+.B tar -tzf
+.I file
+
+but this utility is provided in the mtools package for other platforms and
+is retained here for completeness.
+
+.SH AUTHOR
+Robert King (Robert.King@mailbox.gu.edu.au) wrote this page for the
+.I Debian/GNU
+mtools package.
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR gzip (1),
+.BR tar (1),
+.BR uz (1).
diff --git a/mainloop.c b/mainloop.c
new file mode 100644
index 0000000..f5f8349
--- /dev/null
+++ b/mainloop.c
@@ -0,0 +1,671 @@
+/* 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(UNUSED(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 UNUSEDP)
+{
+ return unix_dir_loop(Dir, mp);
+}
+
+int unix_loop(UNUSED(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(arg);
+ }
+ }
+
+ if(isdir)
+ ret = mp->dirCallback(0, mp);
+ else
+ ret = mp->unixcallback(mp);
+ FREE(&mp->File);
+ return ret;
+}
+
+
+int isSpecial(const char *name)
+{
+ if(name[0] == '\0')
+ return 1;
+ if(!strcmp(name,"."))
+ return 1;
+ if(!strcmp(name,".."))
+ return 1;
+ return 0;
+}
+
+#ifdef HAVE_WCHAR_H
+int isSpecialW(const wchar_t *name)
+{
+ if(name[0] == '\0')
+ return 1;
+ if(!wcscmp(name,L"."))
+ return 1;
+ if(!wcscmp(name,L".."))
+ return 1;
+ return 0;
+}
+#endif
+
+static int checkForDot(int lookupflags, const wchar_t *name)
+{
+ return (lookupflags & NO_DOTS) && isSpecialW(name);
+}
+
+
+typedef struct lookupState_t {
+ Stream_t *container;
+ int nbContainers;
+ Stream_t *Dir;
+ int nbDirs;
+ const char *filename;
+} lookupState_t;
+
+static int isUniqueTarget(const char *name)
+{
+ return name && strcmp(name, "-");
+}
+
+static int handle_leaf(direntry_t *direntry, MainParam_t *mp,
+ lookupState_t *lookupState)
+{
+ Stream_t *MyFile=0;
+ int ret;
+
+ if(got_signal)
+ return ERROR_ONE;
+ if(lookupState) {
+ /* we are looking for a "target" file */
+ switch(lookupState->nbDirs) {
+ case 0: /* no directory yet, open it */
+ lookupState->Dir = OpenFileByDirentry(direntry);
+ lookupState->nbDirs++;
+ /* dump the container, we have
+ * better now */
+ FREE(&lookupState->container);
+ return 0;
+ case 1: /* we have already a directory */
+ FREE(&lookupState->Dir);
+ fprintf(stderr,"Ambigous\n");
+ return STOP_NOW | ERROR_ONE;
+ default:
+ return STOP_NOW | ERROR_ONE;
+ }
+ }
+
+ mp->direntry = direntry;
+ if(IS_DIR(direntry)) {
+ if(mp->lookupflags & (DO_OPEN | DO_OPEN_DIRS))
+ MyFile = mp->File = OpenFileByDirentry(direntry);
+ ret = mp->dirCallback(direntry, mp);
+ } else {
+ if(mp->lookupflags & DO_OPEN)
+ MyFile = mp->File = OpenFileByDirentry(direntry);
+ ret = mp->callback(direntry, mp);
+ }
+ FREE(&MyFile);
+ if(isUniqueTarget(mp->targetName))
+ ret |= STOP_NOW;
+ return ret;
+}
+
+static int _dos_loop(Stream_t *Dir, MainParam_t *mp, const char *filename)
+{
+ Stream_t *MyFile=0;
+ direntry_t entry;
+ int ret;
+ int r;
+
+ ret = 0;
+ r=0;
+ initializeDirentry(&entry, Dir);
+ while(!got_signal &&
+ (r=vfat_lookup(&entry, filename, -1,
+ mp->lookupflags, mp->shortname,
+ mp->longname)) == 0 ){
+ mp->File = NULL;
+ if(!checkForDot(mp->lookupflags,entry.name)) {
+ MyFile = 0;
+ if((mp->lookupflags & DO_OPEN) ||
+ (IS_DIR(&entry) &&
+ (mp->lookupflags & DO_OPEN_DIRS))) {
+ MyFile = mp->File = OpenFileByDirentry(&entry);
+ }
+ if(got_signal)
+ break;
+ mp->direntry = &entry;
+ if(IS_DIR(&entry))
+ ret |= mp->dirCallback(&entry,mp);
+ else
+ ret |= mp->callback(&entry, mp);
+ FREE(&MyFile);
+ }
+ if (fat_error(Dir))
+ ret |= ERROR_ONE;
+ if(mp->fast_quit && (ret & ERROR_ONE))
+ break;
+ }
+ if (r == -2)
+ return ERROR_ONE;
+ if(got_signal)
+ ret |= ERROR_ONE;
+ return ret;
+}
+
+static int recurs_dos_loop(MainParam_t *mp, const char *filename0,
+ const char *filename1,
+ lookupState_t *lookupState)
+{
+ /* Dir is de-allocated by the same entity which allocated it */
+ const char *ptr;
+ direntry_t entry;
+ int length;
+ int lookupflags;
+ int ret;
+ int have_one;
+ int doing_mcwd;
+ int r;
+
+ while(1) {
+ /* strip dots and / */
+ if(!strncmp(filename0,"./", 2)) {
+ filename0 += 2;
+ continue;
+ }
+ if(!strcmp(filename0,".") && filename1) {
+ filename0 ++;
+ continue;
+ }
+ if(filename0[0] == '/') {
+ filename0++;
+ continue;
+ }
+ if(!filename0[0]) {
+ if(!filename1)
+ break;
+ filename0 = filename1;
+ filename1 = 0;
+ continue;
+ }
+ break;
+ }
+
+ if(!strncmp(filename0,"../", 3) ||
+ (!strcmp(filename0, "..") && filename1)) {
+ /* up one level */
+ mp->File = getDirentry(mp->File)->Dir;
+ return recurs_dos_loop(mp, filename0+2, filename1, lookupState);
+ }
+
+ doing_mcwd = !!filename1;
+
+ ptr = strchr(filename0, '/');
+ if(!ptr) {
+ length = strlen(filename0);
+ ptr = filename1;
+ filename1 = 0;
+ } else {
+ length = ptr - filename0;
+ ptr++;
+ }
+ if(!ptr) {
+ if(mp->lookupflags & OPEN_PARENT) {
+ mp->targetName = filename0;
+ ret = handle_leaf(getDirentry(mp->File), mp,
+ lookupState);
+ mp->targetName = 0;
+ return ret;
+ }
+
+ if(!strcmp(filename0, ".") || !filename0[0]) {
+ return handle_leaf(getDirentry(mp->File),
+ mp, lookupState);
+ }
+
+ if(!strcmp(filename0, "..")) {
+ return handle_leaf(getParent(getDirentry(mp->File)), mp,
+ lookupState);
+ }
+
+ lookupflags = mp->lookupflags;
+
+ if(lookupState) {
+ lookupState->filename = filename0;
+ if(lookupState->nbContainers + lookupState->nbDirs > 0){
+ /* we have already one target, don't bother
+ * with this one. */
+ FREE(&lookupState->container);
+ } else {
+ /* no match yet. Remember this container for
+ * later use */
+ lookupState->container = COPY(mp->File);
+ }
+ lookupState->nbContainers++;
+ }
+ } else
+ lookupflags = ACCEPT_DIR | DO_OPEN | NO_DOTS;
+
+ ret = 0;
+ r = 0;
+ have_one = 0;
+ initializeDirentry(&entry, mp->File);
+ while(!(ret & STOP_NOW) &&
+ !got_signal &&
+ (r=vfat_lookup(&entry, filename0, length,
+ lookupflags | NO_MSG,
+ mp->shortname, mp->longname)) == 0 ){
+ if(checkForDot(lookupflags, entry.name))
+ /* while following the path, ignore the
+ * special entries if they were not
+ * explicitly given */
+ continue;
+ have_one = 1;
+ if(ptr) {
+ Stream_t *SubDir;
+ SubDir = mp->File = OpenFileByDirentry(&entry);
+ ret |= recurs_dos_loop(mp, ptr, filename1, lookupState);
+ FREE(&SubDir);
+ } else {
+ ret |= handle_leaf(&entry, mp, lookupState);
+ if(isUniqueTarget(mp->targetName))
+ return ret | STOP_NOW;
+ }
+ if(doing_mcwd)
+ break;
+ }
+ if (r == -2)
+ return ERROR_ONE;
+ if(got_signal)
+ return ret | ERROR_ONE;
+ if(doing_mcwd && !have_one)
+ return NO_CWD;
+ return ret;
+}
+
+static int common_dos_loop(MainParam_t *mp, const char *pathname,
+ lookupState_t *lookupState, int open_mode)
+
+{
+ Stream_t *RootDir;
+ const char *cwd;
+ char drive;
+
+ int ret;
+ mp->loop = _dos_loop;
+
+ drive='\0';
+ cwd = "";
+ if(*pathname && pathname[1] == ':') {
+ drive = toupper(*pathname);
+ pathname += 2;
+ if(mp->mcwd[0] == drive)
+ cwd = mp->mcwd+2;
+ } else if(mp->mcwd[0]) {
+ drive = mp->mcwd[0];
+ cwd = mp->mcwd+2;
+ } else {
+ drive = get_default_drive();
+ }
+
+ if(*pathname=='/') /* absolute path name */
+ cwd = "";
+
+ RootDir = mp->File = open_root_dir(drive, open_mode, NULL);
+ if(!mp->File)
+ return ERROR_ONE;
+
+ ret = recurs_dos_loop(mp, cwd, pathname, lookupState);
+ if(ret & NO_CWD) {
+ /* no CWD */
+ *mp->mcwd = '\0';
+ unlink_mcwd();
+ ret = recurs_dos_loop(mp, "", pathname, lookupState);
+ }
+ FREE(&RootDir);
+ return ret;
+}
+
+static int dos_loop(MainParam_t *mp, const char *arg)
+{
+ return common_dos_loop(mp, arg, 0, mp->openflags);
+}
+
+
+static int dos_target_lookup(MainParam_t *mp, const char *arg)
+{
+ lookupState_t lookupState;
+ int ret;
+ int lookupflags;
+
+ lookupState.nbDirs = 0;
+ lookupState.Dir = 0;
+ lookupState.nbContainers = 0;
+ lookupState.container = 0;
+
+ lookupflags = mp->lookupflags;
+ mp->lookupflags = DO_OPEN | ACCEPT_DIR;
+ ret = common_dos_loop(mp, arg, &lookupState, O_RDWR);
+ mp->lookupflags = lookupflags;
+ if(ret & ERROR_ONE)
+ return ret;
+
+ if(lookupState.nbDirs) {
+ mp->targetName = 0;
+ mp->targetDir = lookupState.Dir;
+ FREE(&lookupState.container); /* container no longer needed */
+ return ret;
+ }
+
+ switch(lookupState.nbContainers) {
+ case 0:
+ /* no match */
+ fprintf(stderr,"%s: no match for target\n", arg);
+ return MISSED_ONE;
+ case 1:
+ mp->targetName = strdup(lookupState.filename);
+ mp->targetDir = lookupState.container;
+ return ret;
+ default:
+ /* too much */
+ fprintf(stderr, "Ambigous %s\n", arg);
+ return ERROR_ONE;
+ }
+}
+
+static int unix_target_lookup(MainParam_t *mp, const char *arg)
+{
+ char *ptr;
+ mp->unixTarget = strdup(arg);
+ /* try complete filename */
+ if(access(mp->unixTarget, F_OK) == 0)
+ return GOT_ONE;
+ ptr = strrchr(mp->unixTarget, '/');
+ if(!ptr) {
+ mp->targetName = mp->unixTarget;
+ mp->unixTarget = strdup(".");
+ return GOT_ONE;
+ } else {
+ *ptr = '\0';
+ mp->targetName = ptr+1;
+ return GOT_ONE;
+ }
+}
+
+int target_lookup(MainParam_t *mp, const char *arg)
+{
+ if((mp->lookupflags & NO_UNIX) || (arg[0] && arg[1] == ':' ))
+ return dos_target_lookup(mp, arg);
+ else
+ return unix_target_lookup(mp, arg);
+}
+
+int main_loop(MainParam_t *mp, char **argv, int argc)
+{
+ int i;
+ int ret, Bret;
+
+ Bret = 0;
+
+ if(argc != 1 && mp->targetName) {
+ fprintf(stderr,
+ "Several file names given, but last argument (%s) not a directory\n", mp->targetName);
+ }
+
+ for (i = 0; i < argc; i++) {
+ if ( got_signal )
+ break;
+ mp->originalArg = argv[i];
+ mp->basenameHasWildcard = strpbrk(_basename(mp->originalArg),
+ "*[?") != 0;
+ if (mp->unixcallback && (!argv[i][0]
+#ifdef OS_mingw32msvc
+/* On Windows, support only the command-line image drive. */
+ || argv[i][0] != ':'
+#endif
+ || argv[i][1] != ':' ))
+ ret = unix_loop(0, mp, argv[i], 1);
+ else
+ ret = dos_loop(mp, argv[i]);
+
+ if (! (ret & (GOT_ONE | ERROR_ONE)) ) {
+ /* one argument was unmatched */
+ fprintf(stderr, "%s: File \"%s\" not found\n",
+ progname, argv[i]);
+ ret |= ERROR_ONE;
+ }
+ Bret |= ret;
+ if(mp->fast_quit && (Bret & (MISSED_ONE | ERROR_ONE)))
+ break;
+ }
+ FREE(&mp->targetDir);
+ if(Bret & ERROR_ONE)
+ return 1;
+ if ((Bret & GOT_ONE) && ( Bret & MISSED_ONE))
+ return 2;
+ if (Bret & MISSED_ONE)
+ return 1;
+ return 0;
+}
+
+static int dispatchToFile(direntry_t *entry, MainParam_t *mp)
+{
+ if(entry)
+ return mp->callback(entry, mp);
+ else
+ return mp->unixcallback(mp);
+}
+
+
+void init_mp(MainParam_t *mp)
+{
+ fix_mcwd(mp->mcwd);
+ mp->openflags = O_RDONLY;
+ mp->targetName = 0;
+ mp->targetDir = 0;
+ mp->unixTarget = 0;
+ mp->dirCallback = dispatchToFile;
+ mp->unixcallback = NULL;
+ mp->shortname = mp->longname = 0;
+ mp->File = 0;
+ mp->fast_quit = 0;
+}
+
+const char *mpGetBasename(MainParam_t *mp)
+{
+ if(mp->direntry) {
+ wchar_to_native(mp->direntry->name, mp->targetBuffer,
+ MAX_VNAMELEN+1);
+ return mp->targetBuffer;
+ } else
+ return _basename(mp->unixSourceName);
+}
+
+void mpPrintFilename(FILE *fp, MainParam_t *mp)
+{
+ if(mp->direntry)
+ fprintPwd(fp, mp->direntry, 0);
+ else
+ fprintf(fp,"%s",mp->originalArg);
+}
+
+const char *mpPickTargetName(MainParam_t *mp)
+{
+ /* picks the target name: either the one explicitly given by the
+ * user, or the same as the source */
+ if(mp->targetName)
+ return mp->targetName;
+ else
+ return mpGetBasename(mp);
+}
+
+char *mpBuildUnixFilename(MainParam_t *mp)
+{
+ const char *target;
+ char *ret;
+ char *tmp;
+
+ target = mpPickTargetName(mp);
+ ret = malloc(strlen(mp->unixTarget) + 2 + strlen(target));
+ if(!ret)
+ return 0;
+ strcpy(ret, mp->unixTarget);
+ if(*target) {
+#if 1 /* fix for 'mcopy -n x:file existingfile' -- H. Lermen 980816 */
+ if(!mp->targetName && !mp->targetDir) {
+ struct MT_STAT buf;
+ if (!MT_STAT(ret, &buf) && !S_ISDIR(buf.st_mode))
+ return ret;
+ }
+#endif
+ strcat(ret, "/");
+ if(!strcmp(target, ".")) {
+ target="DOT";
+ } else if(!strcmp(target, "..")) {
+ target="DOTDOT";
+ }
+ while( (tmp=strchr(target, '/')) ) {
+ strncat(ret, target, tmp-target);
+ strcat(ret, "\\");
+ target=tmp+1;
+ }
+ strcat(ret, target);
+ }
+ return ret;
+}
diff --git a/mainloop.h b/mainloop.h
new file mode 100644
index 0000000..940c853
--- /dev/null
+++ b/mainloop.h
@@ -0,0 +1,101 @@
+#ifndef MTOOLS_MAINLOOP_H
+#define MTOOLS_MAINLOOP_H
+
+/* Copyright 1997,2001,2002,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..12bb530
--- /dev/null
+++ b/man-warning-end.texi
@@ -0,0 +1,46 @@
+@c Copyright 1998,2001,2002 Alain Knaff.
+@c This file is part of mtools
+@c Released under the terms of the GNU Free Documentation License,
+@c Version 1.3 or any later version published by the Free Software
+@c Foundation
+
+@c for man page version only
+@unnumbered See Also
+Mtools' texinfo doc
+@unnumbered Viewing the texi doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+
+@itemize @bullet
+@item
+To generate a printable copy from the texinfo doc, run the following
+commands:
+@example
+ ./configure; make dvi; dvips mtools.dvi
+@end example
+
+@item
+To generate a html copy, run:
+@example
+ ./configure; make html
+@end example
+A premade html can be found at
+@file{http://www.gnu.org/software/mtools/manual/mtools.html}
+
+@item
+To generate an info copy (browsable using emacs' info mode), run:
+@example
+ ./configure; make info
+@end example
+@end itemize
+
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+
diff --git a/man-warning.texi b/man-warning.texi
new file mode 100644
index 0000000..4e3ab61
--- /dev/null
+++ b/man-warning.texi
@@ -0,0 +1,12 @@
+@c Copyright 1997,1998,2001,2002 Alain Knaff.
+@c This file is part of mtools
+@c Released under the terms of the GNU Free Documentation License,
+@c Version 1.3 or any later version published by the Free Software
+@c Foundation
+@c for man page version only
+@unnumbered Note of warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+
+@c skipskipskip
diff --git a/man/floppyd.1 b/man/floppyd.1
new file mode 100644
index 0000000..070f3c5
--- /dev/null
+++ b/man/floppyd.1
@@ -0,0 +1,257 @@
+.TH floppyd 1 "21Feb10" mtools-4.0.12
+.SH Name
+floppyd - floppy daemon for remote access to floppy drive
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.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 daemon mode. Default is 5703 + \fIdisplaynumber\fR.
+This flag implies daemon mode. For example, for display
+\&\fR\&\f(CWhitchhiker:5\fR, the port would be 5708.
+.TP
+\&\fR\&\f(CWb\ \ \fIipaddr\fR\&\f(CW\fR\
+Bind address (for multi homed hosts). This flag implies daemon mode
+.TP
+\&\fR\&\f(CWr\ \fIuser\fR\&\f(CW\fR\
+Run the server under as the given user
+.TP
+\&\fR\&\f(CWx\ \fIdisplay\fR\&\f(CW\fR\
+X display to use for authentication. By default, this is taken from the
+\&\fR\&\f(CWDISPLAY\fR variable. If neither the \fR\&\f(CWx\fR attribute is present
+nor \fR\&\f(CWDISPLAY\fR is set, floppyd uses \fR\&\f(CW:0.0\fR.
+.PP
+\&\fIdevicenames\fR is a list of device nodes to be opened. Default
+is \fR\&\f(CW/dev/fd0\fR. Multiple devices are only supported on mtools
+versions newer than 3.9.11.
+.PP
+.SH Connecting\ to\ floppyd
+.PP
+ In order to use floppyd, add the flag \fR\&\f(CWremote\fR to the device
+description in your \fR\&\f(CW\(if~/.mtoolsrc\(is\fR file. If the flag \fR\&\f(CWremote\fR
+is given, the \fR\&\f(CWfile\fR parameter of the device description is taken
+to be a remote address. It's format is the following:
+\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR[\fIbaseport\fR][\fR\&\f(CW/\fR\fIdrive\fR]]. When
+using this entry, mtools connects to port
+\&\fIbaseport\fR+\fIdisplaynumber\fR at \fIhostname\fR. By default
+\&\fIbaseport\fR is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+.PP
+.SH Examples:
+.PP
+ The following starts a floppy daemon giving access to \fR\&\f(CW\(if/dev/fd0\(is\fR,
+listening on the default port 5703, tied to the default X servers:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+floppyd -d /dev/fd0
+.fi
+.in -0.3i
+.ft R
+.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/man/floppyd_installtest.1 b/man/floppyd_installtest.1
new file mode 100644
index 0000000..8f6751c
--- /dev/null
+++ b/man/floppyd_installtest.1
@@ -0,0 +1,96 @@
+.TH floppyd_installtest 1 "21Feb10" 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 useful, if you have a small front-end script to
+mtools, which decides whether to use floppyd or not.
+.PP
+\&\fR\&\f(CWfloppyd_installtest\fR [\fR\&\f(CW-f\fR] Connect-String
+.PP
+If the \fR\&\f(CW-f\fR option is specified, \fR\&\f(CWfloppyd_installtest\fR does a
+full X-Cookie authentication and complains if this does not work.
+.PP
+The connect-String has the format described in the floppyd-section:
+\&\fIhostname\fR\fR\&\f(CW:\fR\fIdisplaynumber\fR[\fR\&\f(CW/\fR\fIbaseport\fR]
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mattrib.1 b/man/mattrib.1
new file mode 100644
index 0000000..3d54b29
--- /dev/null
+++ b/man/mattrib.1
@@ -0,0 +1,133 @@
+.TH mattrib 1 "21Feb10" 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 without any whitespace padding. If
+neither the "/" option is given, nor the \fImsdosfile\fR contains a
+wildcard, and there is only one MS-DOS file parameter on the command
+line, only the attribute is printed, and not the filename. This option
+is convenient for scripts
+.TP
+\&\fR\&\f(CWp\fR\
+Replay mode. Outputs a series of mformat commands that will reproduce
+the current situation, starting from a situation as left by untarring
+the MS-DOS file system. Commands are only output for attribute settings
+that differ from the default (archive bit set for files, unset for
+directories). This option is intended to be used in addition to
+tar. The \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/man/mbadblocks.1 b/man/mbadblocks.1
new file mode 100644
index 0000000..ad94ca6
--- /dev/null
+++ b/man/mbadblocks.1
@@ -0,0 +1,98 @@
+.TH mbadblocks 1 "21Feb10" 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/man/mcat.1 b/man/mcat.1
new file mode 100644
index 0000000..903acf7
--- /dev/null
+++ b/man/mcat.1
@@ -0,0 +1,103 @@
+.TH mcat 1 "21Feb10" 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 low-level nature of this
+command, it will happily destroy any data written before on the
+disk without warning!
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mcd.1 b/man/mcd.1
new file mode 100644
index 0000000..f455c7e
--- /dev/null
+++ b/man/mcd.1
@@ -0,0 +1,116 @@
+.TH mcd 1 "21Feb10" 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 file system.
+.PP
+The environmental variable \fR\&\f(CWMCWD\fR may be used to locate the file
+where the device and current working directory information is stored.
+The default is \fR\&\f(CW\(if$HOME/.mcwd\(is\fR. Information in this file is ignored
+if the file is more than 6 hours old.
+.PP
+\&\fR\&\f(CWMcd\fR returns 0 on success or 1 on failure.
+.PP
+Unlike MS-DOS versions of \fR\&\f(CWCD\fR, \fR\&\f(CWmcd\fR can be used to change to
+another device. It may be wise to remove old \fR\&\f(CW\(if.mcwd\(is\fR files at logout.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mclasserase.1 b/man/mclasserase.1
new file mode 100644
index 0000000..8151b96
--- /dev/null
+++ b/man/mclasserase.1
@@ -0,0 +1,115 @@
+.TH mclasserase 1 "21Feb10" 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
+MS-DOS drive is optional, if none is specified, use \fR\&\f(CWA:\fR. If more than
+one drive are specified, all but the last are ignored.
+.PP
+\&\fR\&\f(CWMclasserase\fR accepts the following command line options:
+.TP
+\&\fR\&\f(CWd\fR\
+Stop after each erase cycle, for testing purposes
+.TP
+\&\fR\&\f(CWp\fR\
+Not yet implemented
+.PP
+\&\fR\&\f(CWMclasserase\fR returns 0 on success or -1 on failure.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mcopy.1 b/man/mcopy.1
new file mode 100644
index 0000000..5fc9323
--- /dev/null
+++ b/man/mcopy.1
@@ -0,0 +1,183 @@
+.TH mcopy 1 "21Feb10" 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 MS-DOS to Unix, and vice-versa when
+copying from Unix to MS-DOS.
+.TP
+\&\fR\&\f(CWb\fR\
+Batch mode. Optimized for huge recursive copies, but less secure if a
+crash happens during the copy.
+.TP
+\&\fR\&\f(CWs\fR\
+Recursive copy. Also copies directories and their contents
+.TP
+\&\fR\&\f(CWp\fR\
+Preserves the attributes of the copied files
+.TP
+\&\fR\&\f(CWQ\fR\
+When mcopying multiple files, quits as soon as one copy fails (for
+example due to lacking storage space on the target disk)
+.TP
+\&\fR\&\f(CWa\fR\
+Text (ASCII) file transfer. \fR\&\f(CWASCII\fR translates incoming carriage
+return/line feeds to line feeds.
+.TP
+\&\fR\&\f(CWT\fR\
+Text (ASCII) file transfer with character set conversion. Differs from
+\&\fR\&\f(CW-a\fR in the \fR\&\f(CWASCII\fR also translates incoming PC-8 characters
+to ISO-8859-1 equivalents as far as possible. When reading DOS files,
+untranslatable characters are replaced by '\fR\&\f(CW#\fR'; when writing DOS files,
+untranslatable characters are replaced by '\fR\&\f(CW.\fR'.
+.TP
+\&\fR\&\f(CWn\fR\
+No confirmation when overwriting Unix files. \fR\&\f(CWASCII\fR doesn't warn
+the user when overwriting an existing Unix file. If the target file already exists,
+and the \fR\&\f(CW-n\fR option is not in effect, \fR\&\f(CWmcopy\fR asks whether to
+overwrite the file or to rename the new file (\(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/man/mdel.1 b/man/mdel.1
new file mode 100644
index 0000000..96e945f
--- /dev/null
+++ b/man/mdel.1
@@ -0,0 +1,99 @@
+.TH mdel 1 "21Feb10" mtools-4.0.12
+.SH Name
+mdel - delete an MSDOS file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.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 file system.
+.PP
+\&\fR\&\f(CWMdel\fR asks for verification prior to removing a read-only file.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mdeltree.1 b/man/mdeltree.1
new file mode 100644
index 0000000..017b3be
--- /dev/null
+++ b/man/mdeltree.1
@@ -0,0 +1,100 @@
+.TH mdeltree 1 "21Feb10" 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 file system. An error occurs if the directory
+to be removed does not exist.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mdir.1 b/man/mdir.1
new file mode 100644
index 0000000..e752d57
--- /dev/null
+++ b/man/mdir.1
@@ -0,0 +1,121 @@
+.TH mdir 1 "21Feb10" 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 MS-DOS' \fR\&\f(CW-s\fR option
+.TP
+\&\fR\&\f(CWw\fR\
+Wide output. With this option, \fR\&\f(CWmdir\fR prints the filenames across
+the page without displaying the file size or creation date.
+.TP
+\&\fR\&\f(CWa\fR\
+Also list hidden files.
+.TP
+\&\fR\&\f(CWf\fR\
+Fast. Do not try to find out free space. On larger disks, finding out
+the amount of free space takes up some non trivial amount of time, as
+the whole FAT must be read in and scanned. The \fR\&\f(CW-f\fR flag bypasses
+this step. This flag is not needed on FAT32 file systems, which store
+the size explicitly.
+.TP
+\&\fR\&\f(CWb\fR\
+Concise listing. Lists each directory name or filename, one per line
+(including the filename extension). This switch displays no heading
+information and no summary. Only a newline separated list of pathnames
+is displayed.
+.PP
+An error occurs if a component of the path is not a directory.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mdu.1 b/man/mdu.1
new file mode 100644
index 0000000..c5ebc9a
--- /dev/null
+++ b/man/mdu.1
@@ -0,0 +1,99 @@
+.TH mdu 1 "21Feb10" 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/man/mformat.1 b/man/mformat.1
new file mode 100644
index 0000000..b20375f
--- /dev/null
+++ b/man/mformat.1
@@ -0,0 +1,282 @@
+.TH mformat 1 "21Feb10" 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 File system creation"
+.PP
+The \fR\&\f(CWmformat\fR command is used to add an MS-DOS file system to a
+low-level formatted diskette. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmformat\fR [\fR\&\f(CW-t\fR \fIcylinders\fR] [\fR\&\f(CW-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 file system (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+.PP
+The following options are supported: (The S, 2, 1 and M options may not
+exist if this copy of mtools has been compiled without the USE_2M
+option)
+.PP
+The following options are the same as for MS-DOS's format command:
+.PP
+.SH Options
+.TP
+\&\fR\&\f(CWv\fR\
+Specifies the volume label. A volume label identifies the disk and can
+be a maximum of 11 characters. If you omit the -v switch, mlabel will
+assign no label to the disk.
+.TP
+\&\fR\&\f(CWf\fR\
+Specifies the size of the DOS file system to format. Only a certain
+number of predefined sizes are supported by this flag; for others use
+the -h/-t/-s flags. The following sizes are supported:
+.RS
+.TP
+160\
+160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+180\
+160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+320\
+320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+360\
+360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+720\
+720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD)
+.TP
+1200\
+1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD)
+.TP
+1440\
+1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD)
+.TP
+2880\
+2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED)
+.RE
+.TP
+\&\fR\&\f(CWt\fR\
+Specifies the number of tracks on the disk.
+.TP
+\&\fR\&\f(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
+MS-DOS format's \fR\&\f(CWq\fR, \fR\&\f(CWu\fR and \fR\&\f(CWb\fR options are not
+supported, and \fR\&\f(CWs\fR has a different meaning.
+.PP
+The following options are specific to mtools:
+.IP
+.TP
+\&\fR\&\f(CWF\fR\
+Format the partition as FAT32.
+.TP
+\&\fR\&\f(CWS\fR\
+The size code. The size of the sector is 2 ^ (sizecode + 7).
+.TP
+\&\fR\&\f(CWX\fR\
+formats the disk as an XDF disk. See section XDF, for more details. The disk
+has first to be low-level formatted using the xdfcopy utility included
+in the fdutils package. XDF disks are used for instance for OS/2 install
+disks.
+.TP
+\&\fR\&\f(CW2\fR\
+2m format. The parameter to this option describes the number of
+sectors on track 0, head 0. This option is recommended for sectors
+bigger than normal.
+.TP
+\&\fR\&\f(CW3\fR\
+don't use a 2m format, even if the current geometry of the disk is a 2m
+geometry.
+.TP
+\&\fR\&\f(CW0\fR\
+Data transfer rate on track 0
+.TP
+\&\fR\&\f(CWA\fR\
+Data transfer rate on tracks other than 0
+.TP
+\&\fR\&\f(CWM\fR\
+software sector size. This parameter describes the sector size in bytes used
+by the MS-DOS file system. By default it is the physical sector size.
+.TP
+\&\fR\&\f(CWN\fR\
+Uses the requested serial number, instead of generating one
+automatically
+.TP
+\&\fR\&\f(CWa\fR\
+If this option is given, an Atari style serial number is generated.
+Ataris store their serial number in the OEM label.
+.TP
+\&\fR\&\f(CWC\fR\
+creates the disk image file to install the MS-DOS file system on
+it. Obviously, this is useless on physical devices such as floppies
+and hard disk partitions, but is interesting for image files.
+.TP
+\&\fR\&\f(CWH\fR\
+number of hidden sectors. This parameter is useful for formatting hard
+disk partition, which are not aligned on track boundaries (i.e. first
+head of first track doesn't belong to the partition, but contains a
+partition table). In that case the number of hidden sectors is in
+general the number of sectors per cylinder. This is untested.
+.TP
+\&\fR\&\f(CWI\fR\
+Sets the fsVersion id when formatting a FAT32 drive. In order to find
+this out, run minfo on an existing FAT32 drive, and mail me about it, so
+I can include the correct value in future versions of mtools.
+.TP
+\&\fR\&\f(CWc\fR\
+Sets the size of a cluster (in sectors). If this cluster size would
+generate a FAT that too big for its number of bits, mtools automatically
+increases the cluster size, until the FAT is small enough.
+.TP
+\&\fR\&\f(CWd\fR\
+Sets the number of FAT copies. Default is 2. This setting can also be
+specified using the \fR\&\f(CWMTOOLS_NFATS\fR environment variable.
+.TP
+\&\fR\&\f(CWr\fR\
+Sets the size of the root directory (in sectors). Only applicable to 12
+and 16 bit FATs. This setting can also be specified using the
+\&\fR\&\f(CWMTOOLS_DIR_LEN\fR environment variable.
+.TP
+\&\fR\&\f(CWL\fR\
+Sets the length of the FAT.
+.TP
+\&\fR\&\f(CWB\fR\
+Use the boot sector stored in the given file or device, instead of using
+its own. Only the geometry fields are updated to match the target disks
+parameters.
+.TP
+\&\fR\&\f(CWk\fR\
+Keep the existing boot sector as much as possible. Only the geometry
+fields and other similar file system data are updated to match the target
+disks parameters.
+.TP
+\&\fR\&\f(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/man/minfo.1 b/man/minfo.1
new file mode 100644
index 0000000..fb7686b
--- /dev/null
+++ b/man/minfo.1
@@ -0,0 +1,101 @@
+.TH minfo 1 "21Feb10" 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 MS-DOS file system"
+.PP
+The \fR\&\f(CWminfo\fR command prints the parameters of a MS-DOS file system, such
+as number of sectors, heads and cylinders. It also prints an mformat
+command line which can be used to create a similar MS-DOS file system on
+another media. However, this doesn't work with 2m or XDF media, and
+with MS-DOS 1.0 file systems
+.ft I
+.nf
+\&\fR\&\f(CWminfo\fR \fIdrive\fR:
+.fi
+.ft R
+
+.PP
+Mlabel supports the following option:
+.TP
+\&\fR\&\f(CWv\fR\
+Prints a hexdump of the boot sector, in addition to the other information
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mkmanifest.1 b/man/mkmanifest.1
new file mode 100644
index 0000000..a2df254
--- /dev/null
+++ b/man/mkmanifest.1
@@ -0,0 +1,181 @@
+.TH mkmanifest 1 "21Feb10" 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(CWASCII\fR
+converts the names to:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ very_lon
+ 2xmany.dot
+ illegalx
+ good.c
+ xprn.dev
+ capital
+.fi
+.in -0.3i
+.ft R
+.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/man/mlabel.1 b/man/mlabel.1
new file mode 100644
index 0000000..6e2ec17
--- /dev/null
+++ b/man/mlabel.1
@@ -0,0 +1,117 @@
+.TH mlabel 1 "21Feb10" 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/man/mmd.1 b/man/mmd.1
new file mode 100644
index 0000000..a5c2f06
--- /dev/null
+++ b/man/mmd.1
@@ -0,0 +1,95 @@
+.TH mmd 1 "21Feb10" 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 file system. An error occurs
+if the directory already exists.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mmount.1 b/man/mmount.1
new file mode 100644
index 0000000..e0afa64
--- /dev/null
+++ b/man/mmount.1
@@ -0,0 +1,99 @@
+.TH mmount 1 "21Feb10" 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/man/mmove.1 b/man/mmove.1
new file mode 100644
index 0000000..775ead0
--- /dev/null
+++ b/man/mmove.1
@@ -0,0 +1,101 @@
+.TH mmove 1 "21Feb10" 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 file system. Data cannot be moved from MS-DOS to Unix or
+vice-versa. If you omit the drive letter from the target file or
+directory, the same letter as for the source is assumed. If you omit
+the drive letter from all parameters, drive a: is assumed by default.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mpartition.1 b/man/mpartition.1
new file mode 100644
index 0000000..faacd67
--- /dev/null
+++ b/man/mpartition.1
@@ -0,0 +1,187 @@
+.TH mpartition 1 "21Feb10" 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 file systems as
+partitions. This is intended to be used on non-Linux systems,
+i.e. systems where fdisk and easy access to SCSI devices are not
+available. This command only works on drives whose partition variable
+is set.
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-p\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-r\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-I\fR [\fR\&\f(CW-B\fR \fIbootSector\fR] \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-a\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-d\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-c\fR [\fR\&\f(CW-s\fR \fIsectors\fR] [\fR\&\f(CW-h\fR \fIheads\fR]
+[\fR\&\f(CW-t\fR \fIcylinders\fR] [\fR\&\f(CW-v\fR [\fR\&\f(CW-T\fR \fItype\fR] [\fR\&\f(CW-b\fR
+\&\fIbegin\fR] [\fR\&\f(CW-l\fR length] [\fR\&\f(CW-f\fR]
+\&\&
+.fi
+.ft R
+
+.PP
+Mpartition supports the following operations:
+.TP
+\&\fR\&\f(CWp\fR\
+Prints a command line to recreate the partition for the drive. Nothing
+is printed if the partition for the drive is not defined, or an
+inconsistency has been detected. If verbose (\fR\&\f(CW-v\fR) is also set,
+prints the current partition table.
+.TP
+\&\fR\&\f(CWr\fR\
+Removes the partition described by \fIdrive\fR.
+.TP
+\&\fR\&\f(CWI\fR\
+Initializes the partition table, and removes all partitions.
+.TP
+\&\fR\&\f(CWc\fR\
+Creates the partition described by \fIdrive\fR.
+.TP
+\&\fR\&\f(CWa\fR\
+"Activates" the partition, i.e. makes it bootable. Only one partition
+can be bootable at a time.
+.TP
+\&\fR\&\f(CWd\fR\
+"Deactivates" the partition, i.e. makes it unbootable.
+.PP
+If no operation is given, the current settings are printed.
+.PP
+For partition creations, the following options are available:
+.TP
+\&\fR\&\f(CWs\ \fIsectors\fR\&\f(CW\fR\
+The number of sectors per track of the partition (which is also the
+number of sectors per track for the whole drive).
+.TP
+\&\fR\&\f(CWh\ \fIheads\fR\&\f(CW\fR\
+The number of heads of the partition (which is also the number of heads
+for the whole drive). By default, the geometry information (number of
+sectors and heads) is figured out from neighboring partition table
+entries, or guessed from the size.
+.TP
+\&\fR\&\f(CWt\ \fIcylinders\fR\&\f(CW\fR\
+The number of cylinders of the partition (not the number of cylinders of
+the whole drive.
+.TP
+\&\fR\&\f(CWb\ \fIbegin\fR\&\f(CW\fR\
+The starting offset of the partition, expressed in sectors. If begin is
+not given, 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 consistency 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/man/mrd.1 b/man/mrd.1
new file mode 100644
index 0000000..98fe178
--- /dev/null
+++ b/man/mrd.1
@@ -0,0 +1,100 @@
+.TH mrd 1 "21Feb10" 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 file system. An error occurs
+if the directory does not exist or is not empty.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mren.1 b/man/mren.1
new file mode 100644
index 0000000..5c7e73c
--- /dev/null
+++ b/man/mren.1
@@ -0,0 +1,107 @@
+.TH mren 1 "21Feb10" 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 file system.
+.PP
+In verbose mode, \fR\&\f(CWMren\fR displays the new filename if the name
+supplied is invalid.
+.PP
+If the first syntax is used (only one source file), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+\&\fR\&\f(CWmcd\fR directory as would be the case with \fR\&\f(CWmmove\fR. Unlike the
+MS-DOS version of \fR\&\f(CWREN\fR, \fR\&\f(CWmren\fR can be used to rename
+directories.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.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/man/mshowfat.1 b/man/mshowfat.1
new file mode 100644
index 0000000..9a989b8
--- /dev/null
+++ b/man/mshowfat.1
@@ -0,0 +1,94 @@
+.TH mshowfat 1 "21Feb10" 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/man/mtools.1 b/man/mtools.1
new file mode 100644
index 0000000..c735082
--- /dev/null
+++ b/man/mtools.1
@@ -0,0 +1,555 @@
+'\" t
+.TH mtools 1 "21Feb10" 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
+file system (typically a floppy disk). Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However,
+unnecessary restrictions and oddities of DOS are not emulated. For
+instance, it is possible to move subdirectories from one subdirectory
+to another.
+.PP
+Mtools is sufficient to give access to MS-DOS file systems. For
+instance, commands such as \fR\&\f(CWmdir a:\fR work on the \fR\&\f(CWa:\fR floppy
+without any preliminary mounting or initialization (assuming the default
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR works on your machine). With mtools, one can
+change floppies too without unmounting and mounting.
+.PP
+.SH Where\ to\ get\ mtools
+.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 file system),
+otherwise the default is assumed to be \fR\&\f(CWA:/\fR. However, unlike
+MS-DOS, there is only one working directory for all drives, and not one
+per drive.
+.PP
+.SS VFAT-style\ long\ file\ names
+.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\ file\ system
+.iX "c Case sensitivity"
+.PP
+The VFAT file system is able to remember the case of the
+filenames. However, filenames which differ only in case are not allowed
+to coexist in the same directory. For example if you store a file called
+LongFileName on a VFAT file system, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+.PP
+The VFAT file system allows 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 operating systems. Mtools recognizes
+these formats transparently where supported.
+.PP
+In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+\&\fR\&\f(CWfdutils\fR package at the following locations~:
+
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(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 manual pages included in that package for further detail: Use
+\&\fR\&\f(CWsuperformat\fR to format all formats except XDF, and use
+\&\fR\&\f(CWxdfcopy\fR to format XDF.
+.PP
+.SS \ \ More\ sectors
+.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 hubris, Bill Gate$
+believed that he invented this, and called it \fR\&\f(CW\(ifDMF disks\(is\fR, or
+\&\fR\&\f(CW\(ifWindows formatted disks\(is\fR. But in reality, it has already existed
+years before! Mtools supports these formats on Linux, on SunOS and on
+the DELL Unix PC.
+.PP
+.SS \ \ Bigger\ sectors
+.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 easier to
+handle by DOS. Indeed this method allows to have a standard sized
+boot sector, which contains a description of how the rest of the disk
+should be read.
+.PP
+However, the drawback of this is that the first cylinder can hold less
+data than the others. Unfortunately, DOS can only handle disks where
+each track contains the same amount of data. Thus 2m hides the fact that
+the first track contains less data by using a \fIshadow
+FAT\fR. (Usually, DOS stores the FAT in two identical copies, for
+additional safety. XDF stores only one copy, 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 file system\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 \(ifmiscellaneous variables\(is,
+for details on how to do this. Fast XDF access is only available for
+Linux kernels which are more recent than 1.1.34.
+.PP
+Mtools supports this format only on Linux.
+.PP
+\&\fBCaution / Attention distributors\fR: If mtools is compiled on a
+Linux kernel more recent than 1.3.34, it won't run on an older
+kernel. However, if it has been compiled on an older kernel, it still
+runs on a newer kernel, except that XDF access is slower. It is
+recommended that distribution authors only include mtools binaries
+compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will
+be out, mtools binaries compiled on newer kernels may (and should) be
+distributed. Mtools binaries compiled on kernels older than 1.3.34 won't
+run on any 2.1 kernel or later.
+.PP
+.SS Exit\ codes
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure. All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or MINIX disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(see section global variables)
+.SS Bugs
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver. These can be safely ignored.
+.PP
+The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7
+mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the
+corresponding configuration file variable, \(ifglobal variables\(is) to
+bypass the fat checking.
+.PP
+.SH See also
+floppyd_installtest
+mattrib
+mbadblocks
+mcd
+mcopy
+mdel
+mdeltree
+mdir
+mdu
+mformat
+minfo
+mkmanifest
+mlabel
+mmd
+mmount
+mmove
+mrd
+mren
+mtoolstest
+mtype
diff --git a/man/mtools.5 b/man/mtools.5
new file mode 100644
index 0000000..211c707
--- /dev/null
+++ b/man/mtools.5
@@ -0,0 +1,633 @@
+'\" t
+.TH mtools 5 "21Feb10" 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 manual page 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 long names, such as
+FreeDOS.
+.TP
+\&\fR\&\f(CWMTOOLS_DOTTED_DIR\fR\
+In a wide directory, prints the short name with a dot instead of spaces
+separating the basename and the extension.
+.TP
+\&\fR\&\f(CWMTOOLS_NAME_NUMERIC_TAIL\fR\
+If this is set to one (default), generate numeric tails for all long
+names (~1). If set to zero, only generate numeric tails if otherwise a
+clash would have happened.
+.TP
+\&\fR\&\f(CWMTOOLS_TWENTY_FOUR_HOUR_CLOCK\fR\
+If 1, uses the European notation for times (twenty four hour clock),
+else uses the UK/US notation (am/pm)
+.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 (image 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 Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks and
+magneto-optical disks as \fR\&\f(CW\(ifgiant floppy disks\(is\fR which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partitioned devices. The \fR\&\f(CWpartition\fR flag is also useful DOSEMU
+hdimages. It is not recommended for hard disks for which direct access
+to partitions is available through mounting.
+.TP
+\&\fR\&\f(CWoffset\fR\
+.iX "c Ram disk"
+.iX "c Atari Ram disk"
+Describes where in the file the MS-DOS file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system starts right at the
+beginning of the device or file.
+.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 Unixes there are device nodes which only support one physical
+geometry. For instance, you might need a different node to access a disk
+as high density or as low density. The geometry is compared to the
+actual geometry stored on the boot sector to make sure that this device
+node is able to correctly read the disk. If the geometry doesn't match,
+this drive entry fails, and the next drive entry bearing the same drive
+letter is tried. See section multiple descriptions, for more details on
+supplying several descriptions for one drive letter.
+.IP
+If no geometry information is supplied in the configuration file, all
+disks are accepted. On Linux (and on SPARC) there exist device nodes
+with configurable geometry (\fR\&\f(CW\(if/dev/fd0\(is\fR, \fR\&\f(CW\(if/dev/fd1\(is\fR etc),
+and thus filtering is not needed (and ignored) for disk drives. (Mtools
+still does do filtering on plain files (disk images) in Linux: this is
+mainly intended for test purposes, as I don't have access to a Unix
+which would actually need filtering).
+.IP
+If you do not need filtering, but want still a default geometry for
+mformatting, you may switch off filtering using the \fR\&\f(CWmformat_only\fR
+flag.
+.IP
+If you want filtering, you should supply the \fR\&\f(CWfilter\fR flag. If you
+supply a geometry, you must supply one of both flags.
+.TP
+initial\ geometry\
+On devices that support it (usually floppy devices), the geometry
+information is also used to set the initial geometry. This initial
+geometry is applied while reading the boot sector, which contains the
+real geometry. If no geometry information is supplied in the
+configuration file, or if the \fR\&\f(CWmformat_only\fR flag is supplied, no
+initial configuration is done.
+.IP
+On Linux, initial geometry is not really needed, as the configurable
+devices are able to auto-detect the disk type accurately enough (for
+most common formats) to read the boot sector.
+.PP
+Wrong geometry information may lead to very bizarre errors. That's why I
+strongly recommend that you add the \fR\&\f(CWmformat_only\fR flag to your
+drive description, unless you really need filtering or initial geometry.
+.PP
+The following geometry related variables are available:
+.TP
+\&\fR\&\f(CWcylinders\fR\
+.TQ
+\&\fR\&\f(CWtracks\fR
+.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 auto-detected number of fat bits wrong, or if you want
+to mformat a disk with a weird number of fat bits.
+.TP
+\&\fR\&\f(CWcodepage\fR\
+Describes the DOS code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+for all drives by using the global \fR\&\f(CWdefault_codepage\fR parameter
+(outside of any drive description). This parameters exists starting at
+version 4.0.0
+.TP
+\&\fR\&\f(CWprecmd\fR\
+.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,
+independently of the sector size registered in the file system's boot
+sector. This is useful for character devices whose sector size is not
+512, such as for example CD-ROM drives on Solaris.
+.PP
+Only the \fR\&\f(CWfile\fR variable is mandatory. The other parameters may
+be left out. In that case a default value or an auto-detected value is
+used.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Flags
+.PP
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+omitted, it is enabled. For example, \fR\&\f(CWscsi\fR is equivalent to
+\&\fR\&\f(CWscsi=1\fR
+.TP
+\&\fR\&\f(CWnolock\fR\
+.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 Syquest disks (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 system calls, because the OS expects
+them to contain a Sun specific "disk label".
+.IP
+As raw SCSI access always uses the whole device, you need to specify the
+"partition" flag in addition
+.IP
+On some architectures, such as Solaris, mtools needs root privileges to
+be able to use the \fR\&\f(CWscsi\fR option. Thus mtools should be installed
+setuid root on Solaris if you want to access Zip/Jaz drives. Thus, if
+the \fR\&\f(CWscsi\fR flag is given, \fR\&\f(CWprivileged\fR is automatically
+implied, unless explicitly disabled by \fR\&\f(CWprivileged=0\fR
+.IP
+Mtools uses its root privileges to open the device, and to issue the
+actual SCSI I/O calls. Moreover, root privileges are only used for
+drives described in a system-wide configuration file such as
+\&\fR\&\f(CW\(if/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 setuid and setgid
+privileges for opening the given drive. This option is only valid for
+drives described in the system-wide configuration files (such as
+\&\fR\&\f(CW\(if/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 explicitly to 0, in order to tell mtools not
+to use its privileges for a given drive even if \fR\&\f(CWscsi=1\fR is set.
+.IP
+Mtools only needs to be installed setuid if you use the
+\&\fR\&\f(CWprivileged\fR or \fR\&\f(CWscsi\fR drive variables. If you do not use
+these options, mtools works perfectly well even when not installed
+setuid root.
+.TP
+\&\fR\&\f(CWvold\fR\
+.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/man/mtoolstest.1 b/man/mtoolstest.1
new file mode 100644
index 0000000..329ab3b
--- /dev/null
+++ b/man/mtoolstest.1
@@ -0,0 +1,93 @@
+.TH mtoolstest 1 "21Feb10" 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/man/mtype.1 b/man/mtype.1
new file mode 100644
index 0000000..9aad7eb
--- /dev/null
+++ b/man/mtype.1
@@ -0,0 +1,113 @@
+.TH mtype 1 "21Feb10" 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/man/mzip.1 b/man/mzip.1
new file mode 100644
index 0000000..ff28795
--- /dev/null
+++ b/man/mzip.1
@@ -0,0 +1,155 @@
+.TH mzip 1 "21Feb10" 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 HP-UX. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmzip\fR [\fR\&\f(CW-epqrwx\fR]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMzip\fR allows the following
+command line options:
+.TP
+\&\fR\&\f(CWe\fR\
+Ejects the disk.
+.TP
+\&\fR\&\f(CWf\fR\
+Force eject even if the disk is mounted (must be given in addition to
+\&\fR\&\f(CW-e\fR).
+.TP
+\&\fR\&\f(CWr\fR\
+Write protect the disk.
+.TP
+\&\fR\&\f(CWw\fR\
+Remove write protection.
+.TP
+\&\fR\&\f(CWp\fR\
+Password write protect.
+.TP
+\&\fR\&\f(CWx\fR\
+Password protect
+.TP
+\&\fR\&\f(CWu\fR\
+Temporarily unprotect the disk until it is ejected. The disk becomes
+writable, and reverts back to its old state when ejected.
+.TP
+\&\fR\&\f(CWq\fR\
+Queries the status
+.PP
+To remove the password, set it to one of the password-less modes
+\&\fR\&\f(CW-r\fR or \fR\&\f(CW-w\fR: mzip will then ask you for the password, and
+unlock the disk. If you have forgotten the password, you can get rid of
+it by low-level formatting the disk (using your SCSI adapter's BIOS
+setup).
+.PP
+The ZipTools disk shipped with the drive is also password protected. On
+MS-DOS or on a Mac, this password is automatically removed once the
+ZipTools have been installed. From various articles posted to Usenet, I
+learned that the password for the tools disk is
+\&\fR\&\f(CWAPlaceForYourStuff\fR\fR. Mzip knows about this
+password, and tries it first, before prompting you for a password. Thus
+\&\fR\&\f(CWmzip -w z:\fR unlocks the tools disk. The tools disk is
+formatted in a special way so as to be usable both in a PC and in a Mac.
+On a PC, the Mac file system appears as a hidden file named
+\&\fR\&\f(CW\(ifpartishn.mac\(is\fR. You may erase it to reclaim the 50 Megs of space
+taken up by the Mac file system.
+.PP
+.SH Bugs
+.PP
+This command is a big kludge. A proper implementation would take a
+rework of significant parts of mtools, but unfortunately I don't have
+the time for this right now. The main downside of this implementation is
+that it is inefficient on some architectures (several successive calls
+to mtools, which defeats mtools' caching).
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/match.c b/match.c
new file mode 100644
index 0000000..da3a497
--- /dev/null
+++ b/match.c
@@ -0,0 +1,158 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996-1998,2001,2002,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..85acb64
--- /dev/null
+++ b/mattrib.1
@@ -0,0 +1,128 @@
+'\" t
+.TH mattrib 1 "09Jan13" mtools-4.0.18
+.SH Name
+mattrib - change MSDOS file attribute flags
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+\&\fR\&\f(CWMattrib\fR is used to change MS-DOS file attribute flags. It has the
+following syntax:
+.PP
+\&\fR\&\f(CWmattrib\fR [\fR\&\f(CW-a|+a\fR] [\fR\&\f(CW-h|+h\fR] [\fR\&\f(CW-r|+r\fR]
+[\fR\&\f(CW-s|+s\fR] [\fR\&\f(CW-/\fR] [\fR\&\f(CW-p\fR] [\fR\&\f(CW-X\fR] \fImsdosfile\fR [ \fImsdosfiles\fR \&... ]
+.PP
+\&\fR\&\f(CWMattrib\fR adds attribute flags to an MS-DOS file (with the
+`\fR\&\f(CW+\fR' operator) or remove attribute flags (with the `\fR\&\f(CW-\fR'
+operator).
+.PP
+\&\fR\&\f(CWMattrib\fR supports the following attribute bits:
+.TP
+\&\fR\&\f(CWa\fR\
+Archive bit. Used by some backup programs to indicate a new file.
+.TP
+\&\fR\&\f(CWr\fR\
+Read-only bit. Used to indicate a read-only file. Files with this bit
+set cannot be erased by \fR\&\f(CWDEL\fR nor modified.
+.TP
+\&\fR\&\f(CWs\fR\
+System bit. Used by MS-DOS to indicate a operating system file.
+.TP
+\&\fR\&\f(CWh\fR\
+Hidden bit. Used to make files hidden from \fR\&\f(CWDIR\fR.
+.PP
+\&\fR\&\f(CWMattrib\fR supports the following command line flags:
+.TP
+\&\fR\&\f(CW/\fR\
+Recursive. Recursively list the attributes of the files in the subdirectories.
+.TP
+\&\fR\&\f(CWX\fR\
+Concise. Prints the attributes without any whitespace padding. If
+neither the "/" option is given, nor the \fImsdosfile\fR contains a
+wildcard, and there is only one MS-DOS file parameter on the command
+line, only the attribute is printed, and not the filename. This option
+is convenient for scripts
+.TP
+\&\fR\&\f(CWp\fR\
+Replay mode. Outputs a series of mformat commands that will reproduce
+the current situation, starting from a situation as left by untarring
+the MS-DOS file system. Commands are only output for attribute settings
+that differ from the default (archive bit set for files, unset for
+directories). This option is intended to be used in addition to
+tar. The \fR\&\f(CWreadonly\fR attribute is not taken into account, as tar can
+set that one itself.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mattrib.c b/mattrib.c
new file mode 100644
index 0000000..89bdc94
--- /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 UNUSEDP)
+{
+ if ( (IS_ARCHIVE(entry) && IS_DIR(entry)) ||
+ (!IS_ARCHIVE(entry) && !IS_DIR(entry)) ||
+ IS_SYSTEM(entry) || IS_HIDDEN(entry)) {
+
+ printf("mattrib ");
+
+ if (IS_ARCHIVE(entry) && IS_DIR(entry)) {
+ printf("+a ");
+ }
+
+ if (!IS_ARCHIVE(entry) && !IS_DIR(entry)) {
+ printf("-a ");
+ }
+
+ if (IS_SYSTEM(entry)) {
+ printf("+s ");
+ }
+
+ if (IS_HIDDEN(entry)) {
+ printf("+h ");
+ }
+
+ fprintPwd(stdout, entry, 1);
+ printf("\n");
+ }
+ return GOT_ONE;
+}
+
+
+
+static int view_attrib(direntry_t *entry, MainParam_t *mp UNUSEDP)
+{
+ printf(" ");
+ if(IS_ARCHIVE(entry))
+ putchar('A');
+ else
+ putchar(' ');
+ fputs(" ",stdout);
+ if(IS_SYSTEM(entry))
+ putchar('S');
+ else
+ putchar(' ');
+ if(IS_HIDDEN(entry))
+ putchar('H');
+ else
+ putchar(' ');
+ if(IS_READONLY(entry))
+ putchar('R');
+ else
+ putchar(' ');
+ printf(" ");
+ fprintPwd(stdout, entry, 0);
+ printf("\n");
+ return GOT_ONE;
+}
+
+
+static int concise_view_attrib(direntry_t *entry, MainParam_t *mp)
+{
+ Arg_t *arg=(Arg_t *) mp->arg;
+
+ if(IS_ARCHIVE(entry))
+ putchar('A');
+ if(IS_DIR(entry))
+ putchar('D');
+ if(IS_SYSTEM(entry))
+ putchar('S');
+ if(IS_HIDDEN(entry))
+ putchar('H');
+ if(IS_READONLY(entry))
+ putchar('R');
+ if(arg->doPrintName) {
+ putchar(' ');
+ fprintPwd(stdout, entry, 0);
+ }
+ putchar('\n');
+ return GOT_ONE;
+}
+
+static int recursive_attrib(direntry_t *entry, MainParam_t *mp)
+{
+ mp->callback(entry, mp);
+ return mp->loop(mp->File, mp, "*");
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+ fprintf(stderr, "Mtools version %s, dated %s\n",
+ mversion, mdate);
+ fprintf(stderr,
+ "Usage: %s [-p] [-a|+a] [-h|+h] [-r|+r] [-s|+s] msdosfile [msdosfiles...]\n",
+ progname);
+ exit(ret);
+}
+
+static int letterToCode(int letter)
+{
+ switch (toupper(letter)) {
+ case 'A':
+ return ATTR_ARCHIVE;
+ case 'H':
+ return ATTR_HIDDEN;
+ case 'R':
+ return ATTR_READONLY;
+ case 'S':
+ return ATTR_SYSTEM;
+ default:
+ usage(1);
+ }
+}
+
+
+void mattrib(int argc, char **argv, int type UNUSEDP)
+{
+ Arg_t arg;
+ int view;
+ int c;
+ int concise;
+ int replay;
+ char *ptr;
+ int wantUsage;
+
+ arg.add = 0;
+ arg.remove = 0xff;
+ arg.recursive = 0;
+ arg.doPrintName = 1;
+ view = 0;
+ concise = 0;
+ replay = 0;
+ wantUsage = 0;
+
+ if(helpFlag(argc, argv))
+ usage(0);
+ while ((c = getopt(argc, argv, "i:/ahrsAHRSXp")) != EOF) {
+ switch (c) {
+ case 'h':
+ wantUsage = 1;
+ /* FALL THROUGH */
+ default:
+ arg.remove &= ~letterToCode(c);
+ break;
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 'p':
+ replay = 1;
+ break;
+ case '/':
+ arg.recursive = 1;
+ break;
+ case 'X':
+ concise = 1;
+ break;
+ case '?':
+ usage(1);
+ }
+ }
+
+ if(optind == argc && wantUsage) {
+ usage(0);
+ }
+
+ for(;optind < argc;optind++) {
+ switch(argv[optind][0]) {
+ case '+':
+ for(ptr = argv[optind] + 1; *ptr; ptr++)
+ arg.add |= letterToCode(*ptr);
+ continue;
+ case '-':
+ for(ptr = argv[optind] + 1; *ptr; ptr++)
+ arg.remove &= ~letterToCode(*ptr);
+ continue;
+ }
+ break;
+ }
+
+ if(arg.remove == 0xff && !arg.add)
+ view = 1;
+
+ if (optind >= argc)
+ usage(1);
+
+ init_mp(&arg.mp);
+ if(view){
+ if(concise) {
+ arg.mp.callback = concise_view_attrib;
+ arg.doPrintName = (argc - optind > 1 ||
+ arg.recursive ||
+ strpbrk(argv[optind], "*[?") != 0);
+ } else if (replay) {
+ arg.mp.callback = replay_attrib;
+ } else
+ arg.mp.callback = view_attrib;
+ arg.mp.openflags = O_RDONLY;
+ } else {
+ arg.mp.callback = attrib_file;
+ arg.mp.openflags = O_RDWR;
+ }
+
+ if(arg.recursive)
+ arg.mp.dirCallback = recursive_attrib;
+
+ arg.mp.arg = (void *) &arg;
+ arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR;
+ if(arg.recursive)
+ arg.mp.lookupflags |= DO_OPEN_DIRS | NO_DOTS;
+ exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mbadblocks.1 b/mbadblocks.1
new file mode 100644
index 0000000..3e66662
--- /dev/null
+++ b/mbadblocks.1
@@ -0,0 +1,115 @@
+'\" t
+.TH mbadblocks 1 "09Jan13" mtools-4.0.18
+.SH Name
+mbadblocks - tests a floppy disk, and marks the bad blocks in the FAT
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmbadblocks\fR command is used to mark some clusters on an
+MS-DOS filesystem bad. It has the following syntax:
+.PP
+\&\fR\&\f(CWmbadblocks\fR [\fR\&\f(CW-s\fR \fIsectorlist\fR|\fR\&\f(CW-c\fR \fIclusterlist\fR|-w] \fIdrive\fR\fR\&\f(CW:\fR
+.PP
+If no command line flags are supplied, \fR\&\f(CWMbadblocks\fR scans an
+MS-DOS filesystem for bad blocks by simply trying to read them and
+flag them if read fails. All blocks that are unused are scanned, and
+if detected bad are marked as such in the FAT.
+.PP
+This command is intended to be used right after \fR\&\f(CWmformat\fR. It is
+not intended to salvage data from bad disks.
+.PP
+.SH Command\ line\ options
+.TP
+\&\fR\&\f(CWc\ \fIfile\fR\&\f(CW\fR\
+Use a list of bad clusters, rather than scanning for bad clusters
+itself.
+.TP
+\&\fR\&\f(CWs\ \fIfile\fR\&\f(CW\fR\
+Use a list of bad sectors (counted from beginning of filesystem),
+rather than trying for bad clusters itself.
+.TP
+\&\fR\&\f(CWw\fR\
+Write a random pattern to each cluster, then read it back and flag
+cluster as bad if mismatch. Only free clusters are tested in such a
+way, so any file data is preserved.
+.PP
+.SH Bugs
+\&\fR\&\f(CWMbadblocks\fR should (but doesn't yet :-( ) also try to salvage bad
+blocks which are in use by reading them repeatedly, and then mark them
+bad.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mbadblocks.c b/mbadblocks.c
new file mode 100644
index 0000000..df5605f
--- /dev/null
+++ b/mbadblocks.c
@@ -0,0 +1,282 @@
+/* Copyright 1995-1999,2001-2003,2007,2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mbadblocks.c
+ * Mark bad blocks on disk
+ *
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "mainloop.h"
+#include "fsP.h"
+
+#define N_PATTERN 311
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+ fprintf(stderr, "Mtools version %s, dated %s\n",
+ mversion, mdate);
+ fprintf(stderr, "Usage: %s: [-c clusterList] [-s sectorList] [-c] [-V] device\n",
+ progname);
+ exit(ret);
+}
+
+static void checkListTwice(char *filename) {
+ if(filename != NULL) {
+ fprintf(stderr, "Only one of the -c or -s options may be given\n");
+ exit(1);
+ }
+}
+
+/**
+ * Marks given cluster as bad, but prints error instead if cluster already used
+ */
+static void mark(Fs_t *Fs, long offset, unsigned int badClus) {
+ unsigned int old = Fs->fat_decode((Fs_t*)Fs, offset);
+ if(old == 0) {
+ fatEncode((Fs_t*)Fs, offset, badClus);
+ return;
+ }
+ if(old == badClus) {
+ fprintf(stderr, "Cluster %ld already marked\n", offset);
+ } else {
+ fprintf(stderr, "Cluster %ld is busy\n", offset);
+ }
+}
+
+static char *in_buf;
+static char *pat_buf;
+static int in_len;
+
+
+static void progress(unsigned int i, unsigned int total) {
+ if(i % 10 == 0)
+ fprintf(stderr, " \r%d/%d\r", i, total);
+}
+
+static int scan(Fs_t *Fs, Stream_t *dev,
+ long cluster, unsigned int badClus,
+ char *buffer, int doWrite) {
+ off_t start;
+ off_t ret;
+ off_t pos;
+ int bad=0;
+
+ if(Fs->fat_decode((Fs_t*)Fs, cluster))
+ /* cluster busy, or already marked */
+ return 0;
+ start = (cluster - 2) * Fs->cluster_size + Fs->clus_start;
+ pos = sectorsToBytes((Stream_t*)Fs, start);
+ if(doWrite) {
+ ret = force_write(dev, buffer, pos, in_len);
+ if(ret < in_len )
+ bad = 1;
+ } else {
+ ret = force_read(dev, in_buf, pos, in_len);
+ if(ret < in_len )
+ bad = 1;
+ else if(buffer) {
+ int i;
+ for(i=0; i<in_len; i++)
+ if(in_buf[i] != buffer[i]) {
+ bad = 1;
+ break;
+ }
+ }
+ }
+
+ if(bad) {
+ printf("Bad cluster %ld found\n", cluster);
+ fatEncode((Fs_t*)Fs, cluster, badClus);
+ return 1;
+ }
+ return 0;
+}
+
+void mbadblocks(int argc, char **argv, int type UNUSEDP)
+{
+ unsigned int i;
+ unsigned int startSector=2;
+ unsigned int endSector=0;
+ struct MainParam_t mp;
+ Fs_t *Fs;
+ Stream_t *Dir;
+ int ret;
+ char *filename = NULL;
+ char c;
+ unsigned int badClus;
+ int sectorMode=0;
+ int writeMode=0;
+
+ while ((c = getopt(argc, argv, "i:s:cwS:E:")) != EOF) {
+ switch(c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 'c':
+ checkListTwice(filename);
+ filename = strdup(optarg);
+ break;
+ case 's':
+ checkListTwice(filename);
+ filename = strdup(optarg);
+ sectorMode = 1;
+ break;
+ case 'S':
+ startSector = atol(optarg);
+ break;
+ case 'E':
+ endSector = atol(optarg);
+ break;
+ case 'w':
+ writeMode = 1;
+ break;
+ case 'h':
+ usage(0);
+ default:
+ usage(1);
+ }
+ }
+
+ if (argc != optind+1 ||
+ !argv[optind][0] || argv[optind][1] != ':' || argv[optind][2]) {
+ usage(1);
+ }
+
+ init_mp(&mp);
+
+ Dir = open_root_dir(argv[optind][0], O_RDWR, NULL);
+ if (!Dir) {
+ fprintf(stderr,"%s: Cannot initialize drive\n", argv[0]);
+ exit(1);
+ }
+
+ Fs = (Fs_t *)GetFs(Dir);
+ in_len = Fs->cluster_size * Fs->sector_size;
+ in_buf = malloc(in_len);
+ if(!in_buf) {
+ printOom();
+ ret = 1;
+ goto exit_0;
+ }
+ if(writeMode) {
+ pat_buf=malloc(in_len * N_PATTERN);
+ if(!pat_buf) {
+ printOom();
+ ret = 1;
+ goto exit_0;
+ }
+ srandom(time(NULL));
+ for(i=0; i < in_len * N_PATTERN; i++) {
+ pat_buf[i] = random();
+ }
+ }
+ for(i=0; i < Fs->clus_start; i++ ){
+ ret = READS(Fs->Next, in_buf,
+ sectorsToBytes((Stream_t*)Fs, i), Fs->sector_size);
+ if( ret < 0 ){
+ perror("early error");
+ goto exit_0;
+ }
+ if(ret < (signed int) Fs->sector_size){
+ fprintf(stderr,"end of file in file_read\n");
+ ret = 1;
+ goto exit_0;
+ }
+ }
+ ret = 0;
+
+ badClus = Fs->last_fat + 1;
+
+ if(startSector < 2)
+ startSector = 2;
+ if(endSector > Fs->num_clus + 2 || endSector <= 0)
+ endSector = Fs->num_clus + 2;
+
+ if(filename) {
+ char line[80];
+
+ FILE *f = fopen(filename, "r");
+ if(f == NULL) {
+ fprintf(stderr, "Could not open %s (%s)\n",
+ filename, strerror(errno));
+ ret = 1;
+ goto exit_0;
+ }
+ while(fgets(line, sizeof(line), f)) {
+ char *ptr = line + strspn(line, " \t");
+ long offset = strtoul(ptr, 0, 0);
+ if(sectorMode)
+ offset = (offset-Fs->clus_start)/Fs->cluster_size + 2;
+ if(offset < 2) {
+ fprintf(stderr, "Sector before start\n");
+ } else if(offset >= Fs->num_clus) {
+ fprintf(stderr, "Sector beyond end\n");
+ } else {
+ mark(Fs, offset, badClus);
+ ret = 1;
+ }
+ }
+ } else {
+ Stream_t *dev;
+ dev = Fs->Next;
+ if(dev->Next)
+ dev = dev->Next;
+
+ in_len = Fs->cluster_size * Fs->sector_size;
+ if(writeMode) {
+ /* Write pattern */
+ for(i=startSector; i< endSector; i++){
+ if(got_signal)
+ break;
+ progress(i, Fs->num_clus);
+ ret |= scan(Fs, dev, i, badClus,
+ pat_buf + in_len * (i % N_PATTERN),
+ 1);
+ }
+
+ /* Flush cache, so that we are sure we read the data
+ back from disk, rather than from the cache */
+ if(!got_signal)
+ DISCARD(dev);
+
+ /* Read data back, and compare to pattern */
+ for(i=startSector; i< endSector; i++){
+ if(got_signal)
+ break;
+ progress(i, Fs->num_clus);
+ ret |= scan(Fs, dev, i, badClus,
+ pat_buf + in_len * (i % N_PATTERN),
+ 0);
+ }
+
+ } else {
+
+ for(i=startSector; i< endSector; i++){
+ if(got_signal)
+ break;
+ progress(i, Fs->num_clus);
+ ret |= scan(Fs, dev, i, badClus, NULL, 0);
+ }
+ }
+ }
+ exit_0:
+ FREE(&Dir);
+ exit(ret);
+}
diff --git a/mcat.1 b/mcat.1
new file mode 100644
index 0000000..74a9f02
--- /dev/null
+++ b/mcat.1
@@ -0,0 +1,100 @@
+'\" t
+.TH mcat 1 "09Jan13" mtools-4.0.18
+.SH Name
+mcat - dump raw disk image
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmcat\fR command is used to copy an entire disk image from or
+to the floppy device. It uses the following syntax:
+.PP
+\&\fR\&\f(CWmcat\fR [\fR\&\f(CW-w\fR] \fIdrive\fR\fR\&\f(CW:\fR
+.PP
+\&\fR\&\f(CWMcat\fR performs the same task as the Unix \fR\&\f(CWcat\fR command. It
+is included into the mtools package, since \fR\&\f(CWcat\fR cannot access
+remote floppy devices offered by the mtools floppy daemon.
+Now it is possible to create boot floppies remotely.
+.PP
+The default operation is reading. The output is written to stdout.
+.PP
+If the \fR\&\f(CW-w\fR option is specified, mcat reads a disk-image from
+stdin and writes it to the given device.
+\&\fBUse this carefully!\fR Because of the low-level nature of this
+command, it will happily destroy any data written before on the
+disk without warning!
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mcat.c b/mcat.c
new file mode 100644
index 0000000..8899529
--- /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 UNUSEDP)
+{
+ struct device *dev;
+ struct device out_dev;
+ char drive, name[EXPAND_BUF];
+ char errmsg[200];
+ Stream_t *Stream;
+ char buf[BUF_SIZE];
+
+ mt_off_t address = 0;
+
+ char mode = O_RDONLY;
+ int optindex = 1;
+ size_t len;
+
+ noPrivileges = 1;
+
+ if (argc < 2) {
+ usage();
+ }
+
+ if (argv[1][0] == '-') {
+ if (argv[1][1] != 'w') {
+ usage();
+ }
+ mode = O_WRONLY;
+ optindex++;
+ }
+
+ if (argc - optindex < 1)
+ usage();
+
+
+ if (!argv[optindex][0] || argv[optindex][1] != ':'
+ || argv[optindex][2]) {
+ usage();
+ }
+
+ drive = toupper(argv[optindex][0]);
+
+ /* check out a drive whose letter and parameters match */
+ sprintf(errmsg, "Drive '%c:' not supported", drive);
+ Stream = NULL;
+ for (dev=devices; dev->name; dev++) {
+ FREE(&Stream);
+ if (dev->drive != drive)
+ continue;
+ out_dev = *dev;
+ expand(dev->name,name);
+#ifdef USING_NEW_VOLD
+ strcpy(name, getVoldName(dev, name));
+#endif
+
+ Stream = 0;
+#ifdef USE_XDF
+ Stream = XdfOpen(&out_dev, name, mode, errmsg, 0);
+ if(Stream)
+ out_dev.use_2m = 0x7f;
+
+#endif
+
+#ifdef USE_FLOPPYD
+ if(!Stream)
+ Stream = FloppydOpen(&out_dev, name,
+ mode, errmsg, NULL);
+#endif
+
+
+ if (!Stream)
+ Stream = SimpleFileOpen(&out_dev, dev, name, mode,
+ errmsg, 0, 1, 0);
+
+ if( !Stream)
+ continue;
+ break;
+ }
+
+ /* print error msg if needed */
+ if ( dev->drive == 0 ){
+ FREE(&Stream);
+ fprintf(stderr,"%s\n",errmsg);
+ exit(1);
+ }
+
+
+ if (mode == O_WRONLY) {
+ mt_size_t size=0;
+ size = out_dev.sectors * out_dev.heads * out_dev.tracks;
+ size *= 512;
+ while ((len = fread(buf, 1,
+ bufLen(BUF_SIZE, size, address),
+ stdin)) > 0) {
+ int r = WRITES(Stream, buf, address, len);
+ fprintf(stderr, "Wrote to %d\n", (int) address);
+ if(r < 0)
+ break;
+ address += len;
+ }
+ } else {
+ while ((len = READS(Stream, buf, address, BUF_SIZE)) > 0) {
+ fwrite(buf, 1, len, stdout);
+ address += len;
+ }
+ }
+
+ FREE(&Stream);
+ exit(0);
+}
diff --git a/mcd.1 b/mcd.1
new file mode 100644
index 0000000..6f7b935
--- /dev/null
+++ b/mcd.1
@@ -0,0 +1,111 @@
+'\" t
+.TH mcd 1 "09Jan13" mtools-4.0.18
+.SH Name
+mcd - change MSDOS directory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmcd\fR command is used to change the mtools working directory
+on the MS-DOS disk. It uses the following syntax:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWmcd [\fImsdosdirectory\fR\&\f(CW]
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+Without arguments, \fR\&\f(CWmcd\fR reports the current device and working
+directory. Otherwise, \fR\&\f(CWmcd\fR changes the current device and current
+working directory relative to an MS-DOS file system.
+.PP
+The environmental variable \fR\&\f(CWMCWD\fR may be used to locate the file
+where the device and current working directory information is stored.
+The default is \fR\&\f(CW\(if$HOME/.mcwd\(is\fR. Information in this file is ignored
+if the file is more than 6 hours old.
+.PP
+\&\fR\&\f(CWMcd\fR returns 0 on success or 1 on failure.
+.PP
+Unlike MS-DOS versions of \fR\&\f(CWCD\fR, \fR\&\f(CWmcd\fR can be used to change to
+another device. It may be wise to remove old \fR\&\f(CW\(if.mcwd\(is\fR files at logout.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mcd.c b/mcd.c
new file mode 100644
index 0000000..689fcef
--- /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 UNUSEDP)
+{
+ FILE *fp;
+
+ if (!(fp = open_mcwd("w"))){
+ fprintf(stderr,"mcd: Can't open mcwd .file for writing\n");
+ return ERROR_ONE;
+ }
+
+ fprintPwd(fp, entry,0);
+ fprintf(fp, "\n");
+ fclose(fp);
+ return GOT_ONE | STOP_NOW;
+}
+
+
+void mcd(int argc, char **argv, int type UNUSEDP)
+{
+ struct MainParam_t mp;
+
+ if (argc > 2) {
+ fprintf(stderr, "Mtools version %s, dated %s\n",
+ mversion, mdate);
+ fprintf(stderr, "Usage: %s: [-V] msdosdirectory\n", argv[0]);
+ exit(1);
+ }
+
+ init_mp(&mp);
+ mp.lookupflags = ACCEPT_DIR | NO_DOTS;
+ mp.dirCallback = mcd_callback;
+ if (argc == 1) {
+ printf("%s\n", mp.mcwd);
+ exit(0);
+ } else
+ exit(main_loop(&mp, argv + 1, 1));
+}
diff --git a/mclasserase.1 b/mclasserase.1
new file mode 100644
index 0000000..19dc9af
--- /dev/null
+++ b/mclasserase.1
@@ -0,0 +1,112 @@
+'\" t
+.TH mclasserase 1 "09Jan13" mtools-4.0.18
+.SH Name
+mclasserase - erase memory cards
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmclasserase\fR command is used to wipe memory cards by
+overwriting it three times: first with \fR\&\f(CW0xff\fR, then with
+\&\fR\&\f(CW0x00\fR, then with \fR\&\f(CW0xff\fR again. The command uses the following
+syntax:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWmclasserase [\fR\&\f(CW-d] \fImsdosdrive\fR\&\f(CW
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+MS-DOS drive is optional, if none is specified, use \fR\&\f(CWA:\fR. If more than
+one drive are specified, all but the last are ignored.
+.PP
+\&\fR\&\f(CWMclasserase\fR accepts the following command line options:
+.TP
+\&\fR\&\f(CWd\fR\
+Stop after each erase cycle, for testing purposes
+.TP
+\&\fR\&\f(CWp\fR\
+Not yet implemented
+.PP
+\&\fR\&\f(CWMclasserase\fR returns 0 on success or -1 on failure.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mclasserase.c b/mclasserase.c
new file mode 100644
index 0000000..fb610eb
--- /dev/null
+++ b/mclasserase.c
@@ -0,0 +1,351 @@
+/* Copyright 2003 Stefan Feuz, Lukas Meyer, Thomas Locher
+ * Copyright 2004,2006,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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[3]; /* 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 UNUSEDP)
+{
+ /* 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/mcomp.1 b/mcomp.1
new file mode 100644
index 0000000..1bf8417
--- /dev/null
+++ b/mcomp.1
@@ -0,0 +1,44 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for mcomp
+.\"
+.\" Copyright (C), 2003, Luis Bustamante
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Mon Mar 3 11:58:15 COT 2003 Luis Bustamante <luferbu@fluidsignal.com>
+.\"
+.TH MCOMP 1 "Mon Mar 3 11:58:15 COT 2003" "" "Mtools Users Manual"
+.SH NAME
+mcomp \- Compares two files using mtools
+.SH SYNOPSIS
+.\" The command line
+.B mcomp
+.I file-on-floppy
+.I local-file
+.SH DESCRIPTION
+.B mcomp
+compares two files, the first one must be on a floppy disk so it can
+be accesed via \fBmtools\fR.
+It is not strictly necessary on Debian GNU/Linux, because the diffutils
+\fBcmp\fR(1) program provides the same capability after copying the
+file locally with
+
+.B mcopy
+.I file
+.I destination
+
+but this utility is provided in the mtools package for other platforms and
+is retained here for completeness.
+
+.SH AUTHOR
+Luis Bustamante <luferbu@fluidsignal.com> wrote this page for the
+.I Debian/GNU
+mtools package.
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR cmp (1),
+.BR mcopy (1)
diff --git a/mcopy.1 b/mcopy.1
new file mode 100644
index 0000000..57347bc
--- /dev/null
+++ b/mcopy.1
@@ -0,0 +1,177 @@
+'\" t
+.TH mcopy 1 "09Jan13" mtools-4.0.18
+.SH Name
+mcopy - copy MSDOS files to/from Unix
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmcopy\fR command is used to copy MS-DOS files to and from
+Unix. It uses the following syntax:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(CWmcopy [\fR\&\f(CW-bspanvmQT] [\fR\&\f(CW-D \fIclash_option\fR\&\f(CW] \fIsourcefile\fR\&\f(CW \fItargetfile\fR\&\f(CW
+\&\fR\&\f(CWmcopy [\fR\&\f(CW-bspanvmQT] [\fR\&\f(CW-D \fIclash_option\fR\&\f(CW] \fIsourcefile\fR\&\f(CW [ \fIsourcefiles\fR\&\f(CW\&... ] \fItargetdirectory\fR\&\f(CW
+\&\fR\&\f(CWmcopy [\fR\&\f(CW-tnvm] \fIMSDOSsourcefile\fR\&\f(CW
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+\&\fR\&\f(CWMcopy\fR copies the specified file to the named file, or copies
+multiple files to the named directory. The source and target can be
+either MS-DOS or Unix files.
+.PP
+The use of a drive letter designation on the MS-DOS files, 'a:' for
+example, determines the direction of the transfer. A missing drive
+designation implies a Unix file whose path starts in the current
+directory. If a source drive letter is specified with no attached file
+name (e.g. \fR\&\f(CWmcopy a: .\fR), all files are copied from that drive.
+.PP
+If only a single, MS-DOS source parameter is provided (e.g. "mcopy
+a:foo.exe"), an implied destination of the current directory
+(`\fR\&\f(CW.\fR') is assumed.
+.PP
+A filename of `\fR\&\f(CW-\fR' means standard input or standard output, depending
+on its position on the command line.
+.PP
+\&\fR\&\f(CWMcopy\fR accepts the following command line options:
+.TP
+\&\fR\&\f(CWt\fR\
+Text file transfer. Mcopy translates incoming carriage return/line
+feeds to line feeds when copying from MS-DOS to Unix, and vice-versa when
+copying from Unix to MS-DOS.
+.TP
+\&\fR\&\f(CWb\fR\
+Batch mode. Optimized for huge recursive copies, but less secure if a
+crash happens during the copy.
+.TP
+\&\fR\&\f(CWs\fR\
+Recursive copy. Also copies directories and their contents
+.TP
+\&\fR\&\f(CWp\fR\
+Preserves the attributes of the copied files
+.TP
+\&\fR\&\f(CWQ\fR\
+When mcopying multiple files, quits as soon as one copy fails (for
+example due to lacking storage space on the target disk)
+.TP
+\&\fR\&\f(CWa\fR\
+Text (ASCII) file transfer. \fR\&\f(CWASCII\fR translates incoming carriage
+return/line feeds to line feeds.
+.TP
+\&\fR\&\f(CWT\fR\
+Text (ASCII) file transfer with character set conversion. Differs from
+\&\fR\&\f(CW-a\fR in the \fR\&\f(CWASCII\fR also translates incoming PC-8 characters
+to ISO-8859-1 equivalents as far as possible. When reading DOS files,
+untranslatable characters are replaced by '\fR\&\f(CW#\fR'; when writing DOS files,
+untranslatable characters are replaced by '\fR\&\f(CW.\fR'.
+.TP
+\&\fR\&\f(CWn\fR\
+No confirmation when overwriting Unix files. \fR\&\f(CWASCII\fR doesn't warn
+the user when overwriting an existing Unix file. If the target file already exists,
+and the \fR\&\f(CW-n\fR option is not in effect, \fR\&\f(CWmcopy\fR asks whether to
+overwrite the file or to rename the new file (\(ifname clashes\(is) for
+details). In order to switch off confirmation for DOS files, use \fR\&\f(CW-o\fR.
+.TP
+\&\fR\&\f(CWm\fR\
+Preserve the file modification time.
+.TP
+\&\fR\&\f(CWv\fR\
+Verbose. Displays the name of each file as it is copied.
+.PP
+.SH Bugs
+Unlike MS-DOS, the '+' operator (append) from MS-DOS is not
+supported. However, you may use \fR\&\f(CWmtype\fR to produce the same effect:
+
+.nf
+.ft 3
+.in +0.3i
+mtype a:file1 a:file2 a:file3 >unixfile
+mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mcopy.c b/mcopy.c
new file mode 100644
index 0000000..3b4d4cf
--- /dev/null
+++ b/mcopy.c
@@ -0,0 +1,631 @@
+/* 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(MainParam_t *mp, int needfilter, const char *unixFile);
+
+/* Write the Unix file */
+static int unix_write(MainParam_t *mp, int needfilter)
+{
+ Arg_t *arg=(Arg_t *) mp->arg;
+
+ if(arg->type)
+ return _unix_write(mp, needfilter, "-");
+ else {
+ char *unixFile = mpBuildUnixFilename(mp);
+ int ret;
+ if(!unixFile) {
+ printOom();
+ return ERROR_ONE;
+ }
+ ret = _unix_write(mp, needfilter, unixFile);
+ free(unixFile);
+ return ret;
+ }
+}
+
+
+/* Write the Unix file */
+static int _unix_write(MainParam_t *mp, int needfilter, const char *unixFile)
+{
+ Arg_t *arg=(Arg_t *) mp->arg;
+ time_t mtime;
+ Stream_t *File=mp->File;
+ Stream_t *Target, *Source;
+ struct MT_STAT stbuf;
+ int ret;
+ char errmsg[80];
+
+ File->Class->get_data(File, &mtime, 0, 0, 0);
+
+ if (!arg->preserveTime)
+ mtime = 0L;
+
+ /* if we are creating a file, check whether it already exists */
+ if(!arg->type) {
+ if (!arg->nowarn && &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 UNUSEDP, MainParam_t *mp)
+{
+ return unix_write(mp, 1);
+}
+
+
+static int unix_to_unix(MainParam_t *mp)
+{
+ return unix_write(mp, 0);
+}
+
+
+static int directory_dos_to_unix(direntry_t *entry, MainParam_t *mp)
+{
+ return unix_copydir(entry, mp);
+}
+
+/*
+ * Open the named file for read, create the cluster chain, return the
+ * directory structure or NULL on error.
+ */
+static int writeit(struct dos_name_t *dosname,
+ char *longname,
+ void *arg0,
+ direntry_t *entry)
+{
+ Stream_t *Target;
+ time_t now;
+ int type, fat, ret;
+ time_t date;
+ mt_size_t filesize, newsize;
+ Arg_t *arg = (Arg_t *) arg0;
+
+
+
+ if (arg->mp.File->Class->get_data(arg->mp.File,
+ & date, &filesize, &type, 0) < 0 ){
+ fprintf(stderr, "Can't stat source file\n");
+ return -1;
+ }
+
+ if(fileTooBig(filesize)) {
+ fprintf(stderr, "File \"%s\" too big\n", longname);
+ return 1;
+ }
+
+ if (type){
+ if (arg->verbose)
+ fprintf(stderr, "\"%s\" is a directory\n", longname);
+ return -1;
+ }
+
+ /*if (!arg->single || arg->recursive)*/
+ if(arg->verbose)
+ fprintf(stderr,"Copying %s\n", longname);
+ if(got_signal)
+ return -1;
+
+ /* will it fit? */
+ if (!getfreeMinBytes(arg->mp.targetDir, filesize))
+ return -1;
+
+ /* preserve mod time? */
+ if (arg->preserveTime)
+ now = date;
+ else
+ getTimeNow(&now);
+
+ mk_entry(dosname, arg->attr, 1, 0, now, &entry->dir);
+
+ Target = OpenFileByDirentry(entry);
+ if(!Target){
+ fprintf(stderr,"Could not open Target\n");
+ exit(1);
+ }
+ if (arg->needfilter & arg->textmode)
+ Target = open_filter(Target,arg->convertCharset);
+
+
+
+ ret = copyfile(arg->mp.File, Target);
+ GET_DATA(Target, 0, &newsize, 0, &fat);
+ FREE(&Target);
+ if (arg->needfilter & arg->textmode)
+ newsize++; /* ugly hack: we gathered the size before the Ctrl-Z
+ * was written. Increment it manually */
+ if(ret < 0 ){
+ fat_free(arg->mp.targetDir, fat);
+ return -1;
+ } else {
+ mk_entry(dosname, arg->attr, fat, truncBytes32(newsize),
+ now, &entry->dir);
+ return 0;
+ }
+}
+
+
+
+static int dos_write(direntry_t *entry, MainParam_t *mp, int needfilter)
+/* write a messy dos file to another messy dos file */
+{
+ int result;
+ Arg_t * arg = (Arg_t *) (mp->arg);
+ const char *targetName = mpPickTargetName(mp);
+
+ if(entry && arg->preserveAttributes)
+ arg->attr = entry->dir.attr;
+ else
+ arg->attr = ATTR_ARCHIVE;
+
+ arg->needfilter = needfilter;
+ if (entry && mp->targetDir == entry->Dir){
+ arg->ch.ignore_entry = -1;
+ arg->ch.source = entry->entry;
+ } else {
+ arg->ch.ignore_entry = -1;
+ arg->ch.source = -2;
+ }
+ result = mwrite_one(mp->targetDir, targetName, 0,
+ writeit, (void *)arg, &arg->ch);
+ if(result == 1)
+ return GOT_ONE;
+ else
+ return ERROR_ONE;
+}
+
+static Stream_t *subDir(Stream_t *parent, const char *filename)
+{
+ direntry_t entry;
+ initializeDirentry(&entry, parent);
+
+ switch(vfat_lookup(&entry, filename, -1, ACCEPT_DIR, 0, 0)) {
+ 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, fastquit;
+
+
+ /* get command line options */
+
+ init_clash_handling(& arg.ch);
+
+ /* get command line options */
+ arg.recursive = 0;
+ arg.preserveTime = 0;
+ arg.preserveAttributes = 0;
+ arg.nowarn = 0;
+ arg.textmode = 0;
+ arg.verbose = 0;
+ arg.convertCharset = 0;
+ arg.type = mtype;
+ fastquit = 0;
+ if(helpFlag(argc, argv))
+ usage(0);
+ while ((c = getopt(argc, argv, "i:abB/sptTnmvQD:oh")) != EOF) {
+ switch (c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 's':
+ case '/':
+ arg.recursive = 1;
+ break;
+ case 'p':
+ arg.preserveAttributes = 1;
+ break;
+ case 'T':
+ arg.convertCharset = 1;
+ case 'a':
+ case 't':
+ arg.textmode = 1;
+ break;
+ case 'n':
+ arg.nowarn = 1;
+ break;
+ case 'm':
+ arg.preserveTime = 1;
+ break;
+ case 'v':
+ arg.verbose = 1;
+ break;
+ case 'Q':
+ fastquit = 1;
+ break;
+ case 'B':
+ case 'b':
+ batchmode = 1;
+ break;
+ case 'o':
+ handle_clash_options(&arg.ch, c);
+ break;
+ case 'D':
+ if(handle_clash_options(&arg.ch, *optarg))
+ usage(1);
+ break;
+ case 'h':
+ usage(0);
+ case '?':
+ usage(1);
+ default:
+ break;
+ }
+ }
+
+ if (argc - optind < 1)
+ usage(1);
+
+ init_mp(&arg.mp);
+ arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN | NO_DOTS;
+ arg.mp.fast_quit = fastquit;
+ arg.mp.arg = (void *) &arg;
+ arg.mp.openflags = O_RDONLY;
+ arg.noClobber = 0;
+
+ /* last parameter is "-", use mtype mode */
+ if(!mtype && !strcmp(argv[argc-1], "-")) {
+ arg.type = mtype = 1;
+ argc--;
+ }
+
+ if(mtype){
+ /* Mtype = copying to stdout */
+ arg.mp.targetName = strdup("-");
+ arg.mp.unixTarget = strdup("");
+ arg.mp.callback = dos_to_unix;
+ arg.mp.dirCallback = unix_copydir;
+ arg.mp.unixcallback = unix_to_unix;
+ } else {
+ const char *target;
+ if (argc - optind == 1) {
+ /* copying to the current directory */
+ target = ".";
+ arg.noClobber = 1;
+ } else {
+ /* target is the last item mentioned */
+ argc--;
+ target = argv[argc];
+ }
+
+ target_lookup(&arg.mp, target);
+ if(!arg.mp.targetDir && !arg.mp.unixTarget) {
+ fprintf(stderr,"Bad target %s\n", target);
+ exit(1);
+ }
+
+ /* callback functions */
+ if(arg.mp.unixTarget) {
+ arg.mp.callback = dos_to_unix;
+ arg.mp.dirCallback = directory_dos_to_unix;
+ arg.mp.unixcallback = unix_to_unix;
+ } else {
+ arg.mp.dirCallback = dos_copydir;
+ arg.mp.callback = dos_to_dos;
+ arg.mp.unixcallback = unix_to_dos;
+ }
+ }
+
+ exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mdel.1 b/mdel.1
new file mode 100644
index 0000000..10fec95
--- /dev/null
+++ b/mdel.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mdel 1 "09Jan13" mtools-4.0.18
+.SH Name
+mdel - delete an MSDOS file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmdel\fR command is used to delete an MS-DOS file. Its syntax
+is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmdel\fR [\fR\&\f(CW-v\fR] \fImsdosfile\fR [ \fImsdosfiles\fR \&... ]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMdel\fR deletes files on an MS-DOS file system.
+.PP
+\&\fR\&\f(CWMdel\fR asks for verification prior to removing a read-only file.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdel.c b/mdel.c
new file mode 100644
index 0000000..0b8a4bb
--- /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);
+ 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
index 0000000..a436484
--- /dev/null
+++ b/mdeltree.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mdeltree 1 "09Jan13" mtools-4.0.18
+.SH Name
+mdeltree - recursively delete an MSDOS directory and its contents
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmdeltree\fR command is used to delete an MS-DOS file. Its syntax
+is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmdeltree\fR [\fR\&\f(CW-v\fR] \fImsdosdirectory\fR [\fImsdosdirectories\fR\&...]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMdeltree\fR removes a directory and all the files and subdirectories
+it contains from an MS-DOS file system. An error occurs if the directory
+to be removed does not exist.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdir.1 b/mdir.1
new file mode 100644
index 0000000..acdd9dd
--- /dev/null
+++ b/mdir.1
@@ -0,0 +1,118 @@
+'\" t
+.TH mdir 1 "09Jan13" mtools-4.0.18
+.SH Name
+mdir - display an MSDOS directory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmdir\fR command is used to display an MS-DOS directory. Its
+syntax is:
+.PP
+\&\fR\&\f(CWmdir\fR [\fR\&\f(CW-/\fR] [\fR\&\f(CW-f\fR] [\fR\&\f(CW-w\fR] [\fR\&\f(CW-a\fR] [\fR\&\f(CW-b\fR] \fImsdosfile\fR [ \fImsdosfiles\fR\&...]
+.PP
+\&\fR\&\f(CWMdir\fR
+displays the contents of MS-DOS directories, or the entries for some
+MS-DOS files.
+.PP
+\&\fR\&\f(CWMdir\fR supports the following command line options:
+.TP
+\&\fR\&\f(CW/\fR\
+Recursive output, just like MS-DOS' \fR\&\f(CW-s\fR option
+.TP
+\&\fR\&\f(CWw\fR\
+Wide output. With this option, \fR\&\f(CWmdir\fR prints the filenames across
+the page without displaying the file size or creation date.
+.TP
+\&\fR\&\f(CWa\fR\
+Also list hidden files.
+.TP
+\&\fR\&\f(CWf\fR\
+Fast. Do not try to find out free space. On larger disks, finding out
+the amount of free space takes up some non trivial amount of time, as
+the whole FAT must be read in and scanned. The \fR\&\f(CW-f\fR flag bypasses
+this step. This flag is not needed on FAT32 file systems, which store
+the size explicitly.
+.TP
+\&\fR\&\f(CWb\fR\
+Concise listing. Lists each directory name or filename, one per line
+(including the filename extension). This switch displays no heading
+information and no summary. Only a newline separated list of pathnames
+is displayed.
+.PP
+An error occurs if a component of the path is not a directory.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdir.c b/mdir.c
new file mode 100644
index 0000000..549e0e9
--- /dev/null
+++ b/mdir.c
@@ -0,0 +1,617 @@
+/* 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 UNUSEDP)
+{
+ unsigned long size;
+ int i;
+ int Case;
+ int r;
+
+ wchar_t ext[4];
+ wchar_t name[9];
+ doscp_t *cp;
+
+ if(!all && (entry->dir.attr & 0x6))
+ return 0;
+
+ if(concise && isSpecialW(entry->name))
+ return 0;
+
+ r=enterDirectory(entry->Dir);
+ if (r)
+ return ERROR_ONE;
+ if (wide) {
+ if(filesInDir % 5)
+ putchar(' ');
+ else
+ putchar('\n');
+ }
+
+ if(IS_DIR(entry)){
+ size = 0;
+ } else
+ size = FILE_SIZE(&entry->dir);
+
+ Case = entry->dir.Case;
+ if(!(Case & (BASECASE | EXTCASE)) &&
+ mtools_ignore_short_case)
+ Case |= BASECASE | EXTCASE;
+
+ cp = GET_DOSCONVERT(entry->Dir);
+ dos_to_wchar(cp, entry->dir.ext, ext, 3);
+ if(Case & EXTCASE){
+ for(i=0; i<3;i++)
+ ext[i] = 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("%-12s ", 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 UNUSEDP,
+ MainParam_t *mp UNUSEDP)
+{
+ MainParam_t subMp;
+ int ret;
+
+ /* first list the files */
+ subMp = *mp;
+ subMp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN;
+ subMp.dirCallback = list_file;
+ subMp.callback = list_file;
+
+ ret = mp->loop(mp->File, &subMp, "*");
+
+ /* then list subdirectories */
+ subMp = *mp;
+ subMp.lookupflags = ACCEPT_DIR | NO_DOTS | NO_MSG | DO_OPEN;
+ return ret | mp->loop(mp->File, &subMp, "*");
+}
+
+#if 0
+static int test_directory(direntry_t *entry, MainParam_t *mp)
+{
+ Stream_t *File=mp->File;
+ Stream_t *Target;
+ char errmsg[80];
+
+ if ((Target = SimpleFileOpen(0, 0, "-",
+ O_WRONLY,
+ errmsg, 0, 0, 0))) {
+ copyfile(File, Target);
+ FREE(&Target);
+ }
+ return GOT_ONE;
+}
+#endif
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+ fprintf(stderr, "Mtools version %s, dated %s\n",
+ mversion, mdate);
+ fprintf(stderr, "Usage: %s: [-V] [-w] [-a] [-b] [-s] [-f] msdosdirectory\n",
+ progname);
+ fprintf(stderr,
+ " %s: [-V] [-w] [-a] [-b] [-s] [-f] msdosfile [msdosfiles...]\n",
+ progname);
+ exit(ret);
+}
+
+
+void mdir(int argc, char **argv, int type UNUSEDP)
+{
+ int ret;
+ MainParam_t mp;
+ int c;
+ const char *fakedArgv[] = { "." };
+
+ concise = 0;
+ recursive = 0;
+ wide = all = 0;
+ /* first argument */
+ if(helpFlag(argc, argv))
+ usage(0);
+ while ((c = getopt(argc, argv, "i:waXbfds/h")) != EOF) {
+ switch(c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 'w':
+ wide = 1;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ case 'b':
+ case 'X':
+ concise = 1;
+ /*recursive = 1;*/
+ break;
+ case 's':
+ case '/':
+ recursive = 1;
+ break;
+ case 'f':
+ fast = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+#if 0
+ case 't': /* test mode */
+ testmode = 1;
+ break;
+#endif
+ case 'h':
+ usage(0);
+ default:
+ usage(1);
+ }
+ }
+
+ /* fake an argument */
+ if (optind == argc) {
+ argv = (char **)fakedArgv;
+ argc = 1;
+ optind = 0;
+ }
+
+ init_mp(&mp);
+ currentDrive = '\0';
+ currentDir = 0;
+ RootDir = 0;
+ dirPath = 0;
+#if 0
+ if (testmode) {
+ mp.lookupflags = ACCEPT_DIR | NO_DOTS;
+ mp.dirCallback = test_directory;
+ } else
+#endif
+ if(recursive) {
+ mp.lookupflags = ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
+ mp.dirCallback = list_recurs_directory;
+ } else {
+ mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN | DO_OPEN_DIRS;
+ mp.dirCallback = list_non_recurs_directory;
+ mp.callback = list_file;
+ }
+ mp.longname = global_longname;
+ mp.shortname = global_shortname;
+ ret=main_loop(&mp, argv + optind, argc - optind);
+ leaveDirectory(ret);
+ leaveDrive(ret);
+ exit(ret);
+}
diff --git a/mdoctorfat.c b/mdoctorfat.c
new file mode 100644
index 0000000..668fc19
--- /dev/null
+++ b/mdoctorfat.c
@@ -0,0 +1,183 @@
+/* Copyright 1999,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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 UNUSEDP)
+{
+ fprintf(stderr,"File does not reside on a Dos fs\n");
+ return ERROR_ONE;
+}
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+ fprintf(stderr,
+ "Mtools version %s, dated %s\n", mversion, mdate);
+ fprintf(stderr,
+ "Usage: [-b] %s file fat\n", progname);
+ exit(ret);
+}
+
+void mdoctorfat(int argc, char **argv, int mtype UNUSEDP)
+{
+ 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);
+ break;
+ case 'b':
+ arg.markbad = 1;
+ break;
+ case 'o':
+ offset = strtoul(optarg,0,0);
+ break;
+ case 's':
+ arg.setsize=1;
+ arg.size = strtoul(optarg,0,0);
+ break;
+ case 'h':
+ usage(0);
+ case '?':
+ usage(1);
+ break;
+ }
+ }
+
+ if (argc - optind < 2)
+ usage(1);
+
+
+ /* only 1 file to copy... */
+ init_mp(&arg.mp);
+ arg.mp.arg = (void *) &arg;
+
+ arg.mp.callback = dos_doctorfat;
+ arg.mp.unixcallback = unix_doctorfat;
+
+ arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
+ arg.mp.openflags = O_RDWR;
+ arg.fat = strtoul(argv[optind+1], 0, 0) + offset;
+ ret=main_loop(&arg.mp, argv + optind, 1);
+ if(ret)
+ exit(ret);
+ address = 0;
+ for(i=optind+1; i < argc; i++) {
+ number = argv[i];
+ if (*number == '<') {
+ number++;
+ }
+ begin = strtoul(number, &eptr, 0);
+ if (eptr && *eptr == '-') {
+ number = eptr+1;
+ end = strtoul(number, &eptr, 0);
+ } else {
+ end = begin;
+ }
+ if (eptr == number) {
+ fprintf(stderr, "Not a number: %s\n", number);
+ exit(-1);
+ }
+
+ if (eptr && *eptr == '>') {
+ eptr++;
+ }
+ if (eptr && *eptr) {
+ fprintf(stderr, "Not a number: %s\n", eptr);
+ exit(-1);
+ }
+
+ for (j=begin; j <= end; j++) {
+ if(arg.markbad) {
+ arg.Fs->fat_encode(arg.Fs, j+offset, arg.Fs->last_fat ^ 6 ^ 8);
+ } else {
+ if(address) {
+ arg.Fs->fat_encode(arg.Fs, address, j+offset);
+ }
+ address = j+offset;
+ }
+ }
+ }
+
+ if (address && !arg.markbad) {
+ arg.Fs->fat_encode(arg.Fs, address, arg.Fs->end_fat);
+ }
+
+ exit(ret);
+}
diff --git a/mdu.1 b/mdu.1
new file mode 100644
index 0000000..7ead711
--- /dev/null
+++ b/mdu.1
@@ -0,0 +1,95 @@
+'\" t
+.TH mdu 1 "09Jan13" mtools-4.0.18
+.SH Name
+mdu - display the amount of space occupied by an MSDOS directory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+\&\fR\&\f(CWMdu\fR is used to list the space occupied by a directory, its
+subdirectories and its files. It is similar to the \fR\&\f(CWdu\fR command on
+Unix. The unit used are clusters. Use the minfo command to find out
+the cluster size.
+.PP
+\&\fR\&\f(CWmdu\fR [\fR\&\f(CW-a\fR] [ \fImsdosfiles\fR \&... ]
+.TP
+\&\fR\&\f(CWa\fR\
+All files. List also the space occupied for individual files.
+.TP
+\&\fR\&\f(CWs\fR\
+Only list the total space, don't give details for each subdirectory.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mdu.c b/mdu.c
new file mode 100644
index 0000000..1073271
--- /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 UNUSEDP)
+{
+ Arg_t arg;
+ int c;
+
+ arg.all = 0;
+ arg.inDir = 0;
+ arg.summary = 0;
+ if(helpFlag(argc, argv))
+ usage(0);
+ while ((c = getopt(argc, argv, "i:ash")) != EOF) {
+ switch (c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 'a':
+ arg.all = 1;
+ break;
+ case 's':
+ arg.summary = 1;
+ break;
+ case 'h':
+ usage(0);
+ case '?':
+ usage(1);
+ }
+ }
+
+ if (optind >= argc)
+ usage(1);
+
+ if(arg.summary && arg.all) {
+ fprintf(stderr,"-a and -s options are mutually exclusive\n");
+ usage(1);
+ }
+
+ init_mp(&arg.mp);
+ arg.mp.callback = file_mdu;
+ arg.mp.openflags = O_RDONLY;
+ arg.mp.dirCallback = dir_mdu;
+
+ arg.mp.arg = (void *) &arg;
+ arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
+ exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mformat.1 b/mformat.1
new file mode 100644
index 0000000..fcd47a5
--- /dev/null
+++ b/mformat.1
@@ -0,0 +1,290 @@
+'\" t
+.TH mformat 1 "09Jan13" mtools-4.0.18
+.SH Name
+mformat - add an MSDOS filesystem to a low-level formatted floppy disk
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmformat\fR command is used to add an MS-DOS file system to a
+low-level formatted diskette. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmformat\fR [\fR\&\f(CW-t\fR \fIcylinders\fR|\fR\&\f(CW-T\fR \fItot_sectors\fR] [\fR\&\f(CW-h\fR \fIheads\fR] [\fR\&\f(CW-s\fR \fIsectors\fR]
+ [\fR\&\f(CW-f\fR \fIsize\fR] [\fR\&\f(CW-1\fR] [\fR\&\f(CW-4\fR] [\fR\&\f(CW-8\fR]
+ [\fR\&\f(CW-v\fR \fIvolume_label\fR]
+ [\fR\&\f(CW-F\fR] [\fR\&\f(CW-S\fR \fIsizecode\fR]
+ [\fR\&\f(CW-M\fR \fIsoftware_sector_size\fR]
+ [\fR\&\f(CW-N\fR \fIserial_number\fR] [\fR\&\f(CW-a\fR]
+ [\fR\&\f(CW-C\fR] [\fR\&\f(CW-H\fR \fIhidden_sectors\fR] [\fR\&\f(CW-I\fR \fIfsVersion\fR]
+ [\fR\&\f(CW-r\fR \fIroot_sectors\fR] [\fR\&\f(CW-L\fR \fIfat_len\fR]
+ [\fR\&\f(CW-B\fR \fIboot_sector\fR] [\fR\&\f(CW-k\fR]
+ [\fR\&\f(CW-m\fR \fImedia_descriptor\fR]
+ [\fR\&\f(CW-K\fR \fIbackup_boot\fR]
+ [\fR\&\f(CW-c\fR \fIclusters_per_sector\fR]
+ [\fR\&\f(CW-d\fR \fIfat_copies\fR]
+ [\fR\&\f(CW-X\fR] [\fR\&\f(CW-2\fR \fIsectors_on_track_0\fR] [\fR\&\f(CW-3\fR]
+ [\fR\&\f(CW-0\fR \fIrate_on_track_0\fR] [\fR\&\f(CW-A\fR \fIrate_on_other_tracks\fR]
+ \fIdrive:\fR
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMformat\fR adds a minimal MS-DOS file system (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+.PP
+The following options are supported: (The S, 2, 1 and M options may not
+exist if this copy of mtools has been compiled without the USE_2M
+option)
+.PP
+The following options are the same as for MS-DOS's format command:
+.PP
+.SH Options
+.TP
+\&\fR\&\f(CWv\fR\
+Specifies the volume label. A volume label identifies the disk and can
+be a maximum of 11 characters. If you omit the -v switch, mformat will
+assign no label to the disk.
+.TP
+\&\fR\&\f(CWf\fR\
+Specifies the size of the DOS file system to format. Only a certain
+number of predefined sizes are supported by this flag; for others use
+the -h/-t/-s flags. The following sizes are supported:
+.RS
+.TP
+160\
+160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+180\
+160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+320\
+320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+360\
+360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+.TP
+720\
+720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD)
+.TP
+1200\
+1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD)
+.TP
+1440\
+1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD)
+.TP
+2880\
+2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED)
+.RE
+.TP
+\&\fR\&\f(CWt\fR\
+Specifies the number of tracks on the disk.
+.TP
+\&\fR\&\f(CWT\fR\
+Specifies the number of total sectors on the disk. Only one of these 2
+options may be specified (tracks or total sectors)
+.TP
+\&\fR\&\f(CWh\fR\
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWs\fR\
+Specifies the number of sectors per track. If the 2m option is given,
+number of 512-byte sector equivalents on generic tracks (i.e. not head 0
+track 0). If the 2m option is not given, number of physical sectors per
+track (which may be bigger than 512 bytes).
+.TP
+\&\fR\&\f(CW1\fR\
+Formats a single side (equivalent to -h 1)
+.TP
+\&\fR\&\f(CW4\fR\
+Formats a 360K double-sided disk (equivalent to -f 360). When used
+together with -the 1 switch, this switch formats a 180K disk
+.TP
+\&\fR\&\f(CW8\fR\
+Formats a disk with 8 sectors per track.
+.PP
+MS-DOS format's \fR\&\f(CWq\fR, \fR\&\f(CWu\fR and \fR\&\f(CWb\fR options are not
+supported, and \fR\&\f(CWs\fR has a different meaning.
+.PP
+The following options are specific to mtools:
+.IP
+.TP
+\&\fR\&\f(CWF\fR\
+Format the partition as FAT32.
+.TP
+\&\fR\&\f(CWS\fR\
+The size code. The size of the sector is 2 ^ (sizecode + 7).
+.TP
+\&\fR\&\f(CWX\fR\
+formats the disk as an XDF disk. See section XDF, for more details. The disk
+has first to be low-level formatted using the xdfcopy utility included
+in the fdutils package. XDF disks are used for instance for OS/2 install
+disks.
+.TP
+\&\fR\&\f(CW2\fR\
+2m format. The parameter to this option describes the number of
+sectors on track 0, head 0. This option is recommended for sectors
+bigger than normal.
+.TP
+\&\fR\&\f(CW3\fR\
+don't use a 2m format, even if the current geometry of the disk is a 2m
+geometry.
+.TP
+\&\fR\&\f(CW0\fR\
+Data transfer rate on track 0
+.TP
+\&\fR\&\f(CWA\fR\
+Data transfer rate on tracks other than 0
+.TP
+\&\fR\&\f(CWM\fR\
+software sector size. This parameter describes the sector size in bytes used
+by the MS-DOS file system. By default it is the physical sector size.
+.TP
+\&\fR\&\f(CWN\fR\
+Uses the requested serial number, instead of generating one
+automatically
+.TP
+\&\fR\&\f(CWa\fR\
+If this option is given, an Atari style serial number is generated.
+Ataris store their serial number in the OEM label.
+.TP
+\&\fR\&\f(CWC\fR\
+creates the disk image file to install the MS-DOS file system on
+it. Obviously, this is useless on physical devices such as floppies
+and hard disk partitions, but is interesting for image files.
+.TP
+\&\fR\&\f(CWH\fR\
+number of hidden sectors. This parameter is useful for formatting hard
+disk partition, which are not aligned on track boundaries (i.e. first
+head of first track doesn't belong to the partition, but contains a
+partition table). In that case the number of hidden sectors is in
+general the number of sectors per cylinder. This is untested.
+.TP
+\&\fR\&\f(CWI\fR\
+Sets the fsVersion id when formatting a FAT32 drive. In order to find
+this out, run minfo on an existing FAT32 drive, and mail me about it, so
+I can include the correct value in future versions of mtools.
+.TP
+\&\fR\&\f(CWc\fR\
+Sets the size of a cluster (in sectors). If this cluster size would
+generate a FAT that too big for its number of bits, mtools automatically
+increases the cluster size, until the FAT is small enough.
+.TP
+\&\fR\&\f(CWd\fR\
+Sets the number of FAT copies. Default is 2. This setting can also be
+specified using the \fR\&\f(CWMTOOLS_NFATS\fR environment variable.
+.TP
+\&\fR\&\f(CWr\fR\
+Sets the size of the root directory (in sectors). Only applicable to 12
+and 16 bit FATs. This setting can also be specified using the
+\&\fR\&\f(CWMTOOLS_DIR_LEN\fR environment variable.
+.TP
+\&\fR\&\f(CWL\fR\
+Sets the length of the FAT.
+.TP
+\&\fR\&\f(CWB\fR\
+Use the boot sector stored in the given file or device, instead of using
+its own. Only the geometry fields are updated to match the target disks
+parameters.
+.TP
+\&\fR\&\f(CWk\fR\
+Keep the existing boot sector as much as possible. Only the geometry
+fields and other similar file system data are updated to match the target
+disks parameters.
+.TP
+\&\fR\&\f(CWK\fR\
+Sets the sector number where the backup of the boot sector should be
+stored (only relevant on FAT32).
+.TP
+\&\fR\&\f(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
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mformat.c b/mformat.c
new file mode 100644
index 0000000..89b27a3
--- /dev/null
+++ b/mformat.c
@@ -0,0 +1,1382 @@
+/* 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);
+
+#ifdef HAVE_ASSERT_H
+ assert(*tot_sectors != 0);
+#endif
+
+ 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(Fs->cluster_size == 0 &&
+ tot_sectors >= 2* min_fat16_size)
+ return 16; /* heuristics */
+ }
+
+ return estimate;
+}
+
+
+/*
+ * According to Microsoft "Hardware White Paper", "Microsoft
+ * Extensible Formware Initiative", "FAT32 File System Specification",
+ * Version 1.03, December 6, 2000:
+ * If (CountofClusters < 4085) {
+ * // 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_uc;
+ ch.ignore_entry = -2;
+
+ buf = safe_malloc(Fs->sector_size);
+ RootDir = OpenRoot((Stream_t *)Fs);
+ if(!RootDir){
+ fprintf(stderr,"Could not open root directory\n");
+ exit(1);
+ }
+
+ memset(buf, '\0', Fs->sector_size);
+
+ if(Fs->fat_bits == 32) {
+ /* on a FAT32 system, we only write one sector,
+ * as the directory can be extended at will...*/
+ dirlen = Fs->cluster_size;
+ fatAllocate(Fs, Fs->rootCluster, Fs->end_fat);
+ } else
+ dirlen = Fs->dir_len;
+ for (i = 0; i < dirlen; i++)
+ WRITES(RootDir, buf, sectorsToBytes((Stream_t*)Fs, i),
+ Fs->sector_size);
+
+ ch.ignore_entry = 1;
+ if(label[0])
+ mwrite_one(RootDir,label, 0, labelit, NULL,&ch);
+
+ FREE(&RootDir);
+ if(Fs->fat_bits == 32)
+ set_word(boot->boot.dirents, 0);
+ else
+ set_word(boot->boot.dirents, Fs->dir_len * (Fs->sector_size / 32));
+ free(buf);
+}
+
+
+#ifdef USE_XDF
+static void xdf_calc_fat_size(Fs_t *Fs, unsigned long tot_sectors,
+ int fat_bits)
+{
+ unsigned int rem_sect;
+
+ rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start - 2 * Fs->fat_len;
+
+ if(Fs->fat_len) {
+ /* an XDF disk, we know the fat_size and have to find
+ * out the rest. We start with a cluster size of 1 and
+ * keep doubling until everything fits into the
+ * FAT. This will occur eventually, as our FAT has a
+ * minimal size of 1 */
+ for(Fs->cluster_size = 1; 1 ; Fs->cluster_size <<= 1) {
+ Fs->num_clus = rem_sect / Fs->cluster_size;
+ if(abs(fat_bits) == 16 || Fs->num_clus >= FAT12)
+ set_fat16(Fs);
+ else
+ set_fat12(Fs);
+ if (Fs->fat_len >= NEEDED_FAT_SIZE(Fs))
+ return;
+ }
+ }
+ fprintf(stderr,"Internal error while calculating Xdf fat size\n");
+ exit(1);
+}
+#endif
+
+static void calc_fat_size(Fs_t *Fs, unsigned long tot_sectors)
+{
+ unsigned long rem_sect;
+ unsigned long real_rem_sect;
+ unsigned long numerator;
+ unsigned long denominator;
+ 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);
+ }
+
+ if(tot_sectors <= Fs->fat_start + Fs->num_fat + Fs->dir_len) {
+ /* we need at least enough sectors to fit boot, fat and root
+ * dir */
+ fprintf(stderr, "Not enough sectors\n");
+ exit(1);
+ }
+
+ rem_sect = tot_sectors - Fs->dir_len - Fs->fat_start;
+
+ /* double the cluster size until we can fill up the disk with
+ * the maximal number of sectors of this size */
+ while(Fs->cluster_size * max_clusters + max_fat_size < rem_sect) {
+ if(Fs->cluster_size > 64) {
+ /* bigger than 64. Should fit */
+ fprintf(stderr,
+ "Internal error while calculating cluster size\n");
+ exit(1);
+ }
+ Fs->cluster_size <<= 1;
+ }
+}
+
+
+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) || tot_sectors % (dev->sectors * dev->heads))
+ boot->boot.descr = 0xf8;
+ else
+ boot->boot.descr = 0xf0;
+
+
+ if(!Fs->cluster_size) {
+ if (dev->heads == 1)
+ Fs->cluster_size = 1;
+ else {
+ Fs->cluster_size = (tot_sectors > 2000 ) ? 1:2;
+ if (dev->use_2m & 0x7f)
+ Fs->cluster_size = 1;
+ }
+ }
+
+ if(!Fs->dir_len) {
+ if (dev->heads == 1)
+ Fs->dir_len = 4;
+ else
+ Fs->dir_len = (tot_sectors > 2000) ? 32 : 7;
+ }
+
+ calc_cluster_size(Fs, tot_sectors, dev->fat_bits);
+#ifdef USE_XDF
+ if(Fs->fat_len)
+ xdf_calc_fat_size(Fs, tot_sectors, dev->fat_bits);
+ else
+#endif
+ {
+ calc_fat_bits2(Fs, tot_sectors, dev->fat_bits,
+ may_change_cluster_size,
+ may_change_root_size);
+ calc_fat_size(Fs, tot_sectors);
+ }
+ }
+
+ set_word(boot->boot.fatlen, Fs->fat_len);
+}
+
+
+
+static void calc_fs_parameters_32(unsigned long tot_sectors,
+ struct Fs_t *Fs, union bootsector *boot)
+{
+ 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 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) / sect_per_track;
+ 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=0;
+ 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 ? */
+
+ int backupBoot = 6;
+
+ char *endptr;
+
+ hs = hs_set = 0;
+ argtracks = 0;
+ argheads = 0;
+ argsectors = 0;
+ arguse_2m = 0;
+ argssize = 0x2;
+ label[0] = '\0';
+ serial_set = 0;
+ serial = 0;
+ fsVersion = 0;
+
+ Fs.cluster_size = 0;
+ Fs.refs = 1;
+ Fs.dir_len = 0;
+ if(getenv("MTOOLS_DIR_LEN")) {
+ Fs.dir_len = 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"
+ "kK:B:r:L:I:FCc:Xh:s:T:l:N:H:M:S:2:30:Aad:m:"))!= EOF) {
+ endptr = NULL;
+ switch (c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+
+ /* standard DOS flags */
+ case '1':
+ argheads = 1;
+ break;
+ case '4':
+ argsectors = 9;
+ argtracks = 40;
+ break;
+ case '8':
+ argsectors = 8;
+ argtracks = 40;
+ break;
+ case 'f':
+ r=old_dos_size_to_geom(atoi(optarg),
+ &argtracks, &argheads,
+ &argsectors);
+ if(r) {
+ fprintf(stderr,
+ "Bad size %s\n", optarg);
+ exit(1);
+ }
+ break;
+ case 't':
+ argtracks = atoi(optarg);
+ break;
+
+ case 'T':
+ tot_sectors = 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 < 0x80)
+ usage(1);
+ if(argssize >= 0x87) {
+ fprintf(stderr, "argssize must be less than 6\n");
+ usage(1);
+ }
+ break;
+
+#ifdef USE_XDF
+ case 'X':
+ format_xdf = 1;
+ break;
+#endif
+
+ case '2':
+ arguse_2m = 0xff;
+ sectors0 = 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,&endptr,16);
+ serial_set = 1;
+ break;
+ case 'a': /* Atari style serial number */
+ Atari = 1;
+ break;
+
+ case 'C':
+ create = O_CREAT | O_TRUNC;
+ break;
+
+ case 'H':
+ hs = atoi(optarg);
+ hs_set = 1;
+ break;
+
+ case 'I':
+ fsVersion = strtoul(optarg,&endptr,0);
+ break;
+
+ case 'c':
+ Fs.cluster_size = atoi(optarg);
+ break;
+
+ case 'r':
+ Fs.dir_len = strtoul(optarg,&endptr,0);
+ break;
+ case 'L':
+ Fs.fat_len = strtoul(optarg,&endptr,0);
+ break;
+
+
+ case 'B':
+ bootSector = optarg;
+ break;
+ case 'k':
+ keepBoot = 1;
+ break;
+ case 'K':
+ backupBoot = atoi(optarg);
+ if(backupBoot < 2 || backupBoot >= 32) {
+ fprintf(stderr, "Backupboot must be comprised between 2 and 32\n");
+ exit(1);
+ }
+ break;
+ case 'h':
+ argheads = atoi(optarg);
+ break;
+ case 'd':
+ Fs.num_fat = atoi(optarg);
+ break;
+ case 'm':
+ mediaDesc = strtoul(optarg,&endptr,0);
+ if(*endptr)
+ mediaDesc = strtoul(optarg,&endptr,16);
+ break;
+ default:
+ usage(1);
+ }
+ if(endptr && *endptr) {
+ fprintf(stderr, "Bad number %s\n", optarg);
+ exit(1);
+ }
+ }
+
+ if (argc - optind > 1)
+ usage(1);
+ if(argc - optind == 1) {
+ if(!argv[optind][0] || argv[optind][1] != ':')
+ usage(1);
+ drive = toupper(argv[argc -1][0]);
+ } else {
+ drive = get_default_drive();
+ if(drive != ':') {
+ /* Use default drive only if it is ":" (image file), as else
+ it would be too dangerous... */
+ fprintf(stderr, "Drive letter missing\n");
+ exit(1);
+ }
+ }
+
+ if(argtracks && tot_sectors) {
+ fprintf(stderr, "Only one of -t or -T may be specified\n");
+ usage(1);
+ }
+
+#ifdef USE_XDF
+ if(create && format_xdf) {
+ fprintf(stderr,"Create and XDF can't be used together\n");
+ exit(1);
+ }
+#endif
+
+ /* check out a drive whose letter and parameters match */
+ sprintf(errmsg, "Drive '%c:' not supported", drive);
+ Fs.Direct = NULL;
+ blocksize = 0;
+ for(dev=devices;dev->drive;dev++) {
+ FREE(&(Fs.Direct));
+ /* drive letter */
+ if (dev->drive != drive)
+ continue;
+ used_dev = *dev;
+
+ SET_INT(used_dev.tracks, argtracks);
+ SET_INT(used_dev.heads, argheads);
+ SET_INT(used_dev.sectors, argsectors);
+ SET_INT(used_dev.use_2m, arguse_2m);
+ SET_INT(used_dev.ssize, argssize);
+ if(hs_set)
+ used_dev.hidden = hs;
+
+ expand(dev->name, name);
+#ifdef USING_NEW_VOLD
+ strcpy(name, getVoldName(dev, name));
+#endif
+
+#ifdef USE_XDF
+ if(!format_xdf) {
+#endif
+ Fs.Direct = 0;
+#ifdef USE_FLOPPYD
+ Fs.Direct = FloppydOpen(&used_dev, name,
+ O_RDWR | create,
+ errmsg, &maxSize);
+#endif
+ if(!Fs.Direct) {
+ Fs.Direct = SimpleFileOpen(&used_dev, dev, name,
+ O_RDWR | create,
+ errmsg, 0, 1,
+ &maxSize);
+ }
+#ifdef USE_XDF
+ } else {
+ used_dev.misc_flags |= USE_XDF_FLAG;
+ Fs.Direct = XdfOpen(&used_dev, name, O_RDWR,
+ errmsg, &info);
+ if(Fs.Direct && !Fs.fat_len)
+ Fs.fat_len = info.FatSize;
+ if(Fs.Direct && !Fs.dir_len)
+ Fs.dir_len = info.RootDirSize;
+ }
+#endif
+
+ if (!Fs.Direct)
+ continue;
+
+#ifdef OS_linux
+ if ((!used_dev.tracks || !used_dev.heads || !used_dev.sectors) &&
+ (!IS_SCSI(dev))) {
+ int fd= get_fd(Fs.Direct);
+ struct MT_STAT stbuf;
+
+ if (MT_FSTAT(fd, &stbuf) < 0) {
+ sprintf(errmsg, "Could not stat file (%s)", strerror(errno));
+ continue;
+ }
+
+ if (S_ISBLK(stbuf.st_mode) &&
+ get_block_geom(fd, &used_dev, errmsg) < 0)
+ continue;
+ }
+#endif
+
+ /* no way to find out geometry */
+ if ((!used_dev.tracks && !tot_sectors) ||
+ !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 */
+ if(tot_sectors == 0) {
+ unsigned long sect_per_track = used_dev.heads*used_dev.sectors;
+ tot_sectors = used_dev.tracks*sect_per_track - used_dev.hidden%sect_per_track;
+ }
+
+ /* create the image file if needed */
+ if (create) {
+ WRITES(Fs.Direct, &boot.characters,
+ sectorsToBytes((Stream_t*)&Fs, tot_sectors-1),
+ Fs.sector_size);
+ }
+
+ /* the boot sector */
+ if(bootSector) {
+ int fd;
+
+ fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
+ if(fd < 0) {
+ perror("open boot sector");
+ exit(1);
+ }
+ if(read(fd, &boot.bytes, blocksize) < blocksize) {
+ perror("short read on boot sector");
+ exit(1);
+ }
+ keepBoot = 1;
+ close(fd);
+ }
+ if(!keepBoot && !(used_dev.use_2m & 0x7f)) {
+ memset(boot.characters, '\0', Fs.sector_size);
+ 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, backupBoot);
+
+ 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_pc(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(used_dev.fat_bits == 32) {
+ WRITES((Stream_t *)&Fs, boot.characters,
+ (mt_off_t) backupBoot * Fs.sector_size, Fs.sector_size);
+ }
+
+ if(Fs.fat_bits == 32 && WORD_S(ext.fat32.backupBoot) != MAX16) {
+ WRITES((Stream_t *)&Fs, boot.characters,
+ sectorsToBytes((Stream_t*)&Fs,
+ WORD_S(ext.fat32.backupBoot)),
+ Fs.sector_size);
+ }
+ FLUSH((Stream_t *)&Fs); /* flushes Fs.
+ * This triggers the writing of the FAT */
+ FREE(&Fs.Next);
+ Fs.Class->freeFunc((Stream_t *)&Fs);
+#ifdef USE_XDF
+ if(format_xdf && isatty(0) && !getenv("MTOOLS_USE_XDF"))
+ fprintf(stderr,
+ "Note:\n"
+ "Remember to set the \"MTOOLS_USE_XDF\" environmental\n"
+ "variable before accessing this disk\n\n"
+ "Bourne shell syntax (sh, ash, bash, ksh, zsh etc):\n"
+ " export MTOOLS_USE_XDF=1\n\n"
+ "C shell syntax (csh and tcsh):\n"
+ " setenv MTOOLS_USE_XDF 1\n" );
+#endif
+ exit(0);
+}
diff --git a/minfo.1 b/minfo.1
new file mode 100644
index 0000000..b8838b7
--- /dev/null
+++ b/minfo.1
@@ -0,0 +1,99 @@
+'\" t
+.TH minfo 1 "09Jan13" mtools-4.0.18
+.SH Name
+minfo - print the parameters of a MSDOS filesystem
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWminfo\fR command prints the parameters of a MS-DOS file system, such
+as number of sectors, heads and cylinders. It also prints an mformat
+command line which can be used to create a similar MS-DOS file system on
+another media. However, this doesn't work with 2m or XDF media, and
+with MS-DOS 1.0 file systems
+.ft I
+.nf
+\&\fR\&\f(CWminfo\fR \fIdrive\fR:
+.fi
+.ft R
+
+.PP
+Minfo supports the following option:
+.TP
+\&\fR\&\f(CWv\fR\
+Prints a hexdump of the boot sector, in addition to the other information
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/minfo.c b/minfo.c
new file mode 100644
index 0000000..51cc65a
--- /dev/null
+++ b/minfo.c
@@ -0,0 +1,233 @@
+/* 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;
+ unsigned long 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;
+ int have_drive = 0;
+
+ unsigned long sect_per_track;
+ int tracks_match=0;
+ int hidden;
+
+ char *imgFile=NULL;
+
+ if(helpFlag(argc, argv))
+ usage(0);
+ while ((c = getopt(argc, argv, "i:vh")) != EOF) {
+ switch (c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ imgFile=optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'h':
+ usage(0);
+ default:
+ usage(1);
+ }
+ }
+
+ for(;optind <= argc; optind++) {
+ if(optind == argc) {
+ if(have_drive)
+ break;
+ drive = get_default_drive();
+ } else {
+ if(!argv[optind][0] || argv[optind][1] != ':')
+ usage(1);
+ drive = toupper(argv[optind][0]);
+ }
+ have_drive = 1;
+
+ 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);
+
+ sect_per_track = dev.sectors * dev.heads;
+ if(sect_per_track != 0) {
+ printf("mformat command line: mformat ");
+ hidden = DWORD_S(nhs);
+ if(tot_sectors ==
+ dev.tracks * sect_per_track - hidden % sect_per_track) {
+ tracks_match=1;
+ printf("-t %d ", dev.tracks);
+ } else {
+ printf("-T %ld ", tot_sectors);
+ }
+ if(imgFile != NULL)
+ printf("-i %s ", imgFile);
+ printf (" -h %d -s %d ", dev.heads, dev.sectors);
+ if(hidden || !tracks_match)
+ printf("-H %d ", hidden);
+ if(size_code != 2)
+ printf("-S %d ",size_code);
+ printf("%c:\n", tolower(drive));
+ printf("\n");
+ }
+ printf("bootsector information\n");
+ printf("======================\n");
+ printf("banner:\"%.8s\"\n", boot.boot.banner);
+ printf("sector size: %d bytes\n", WORD_S(secsiz));
+ printf("cluster size: %d sectors\n", boot.boot.clsiz);
+ printf("reserved (boot) sectors: %d\n", WORD_S(nrsvsect));
+ printf("fats: %d\n", boot.boot.nfat);
+ printf("max available root directory slots: %d\n",
+ WORD_S(dirents));
+ printf("small size: %d sectors\n", WORD_S(psect));
+ printf("media descriptor byte: 0x%x\n", boot.boot.descr);
+ printf("sectors per fat: %d\n", WORD_S(fatlen));
+ printf("sectors per track: %d\n", WORD_S(nsect));
+ printf("heads: %d\n", WORD_S(nheads));
+ printf("hidden sectors: %d\n", DWORD_S(nhs));
+ printf("big size: %d sectors\n", DWORD_S(bigsect));
+
+ if(WORD_S(fatlen)) {
+ labelBlock = &boot.boot.ext.old.labelBlock;
+ } else {
+ labelBlock = &boot.boot.ext.fat32.labelBlock;
+ }
+
+ printf("physical drive id: 0x%x\n",
+ labelBlock->physdrive);
+ printf("reserved=0x%x\n",
+ labelBlock->reserved);
+ printf("dos4=0x%x\n",
+ labelBlock->dos4);
+ printf("serial number: %08X\n",
+ _DWORD(labelBlock->serial));
+ printf("disk label=\"%11.11s\"\n",
+ labelBlock->label);
+ printf("disk type=\"%8.8s\"\n",
+ labelBlock->fat_type);
+
+ if(!WORD_S(fatlen)){
+ printf("Big fatlen=%u\n",
+ DWORD_S(ext.fat32.bigFat));
+ printf("Extended flags=0x%04x\n",
+ WORD_S(ext.fat32.extFlags));
+ printf("FS version=0x%04x\n",
+ WORD_S(ext.fat32.fsVersion));
+ printf("rootCluster=%u\n",
+ DWORD_S(ext.fat32.rootCluster));
+ if(WORD_S(ext.fat32.infoSector) != MAX16)
+ printf("infoSector location=%d\n",
+ WORD_S(ext.fat32.infoSector));
+ if(WORD_S(ext.fat32.backupBoot) != MAX16)
+ printf("backup boot sector=%d\n",
+ WORD_S(ext.fat32.backupBoot));
+ displayInfosector(Stream,&boot);
+ }
+
+ if(verbose) {
+ int size;
+ unsigned char *buf;
+
+ printf("\n");
+ size = WORD_S(secsiz);
+
+ buf = (unsigned char *) malloc(size);
+ if(!buf) {
+ fprintf(stderr, "Out of memory error\n");
+ exit(1);
+ }
+
+ size = READS(Stream, buf, (mt_off_t) 0, size);
+ if(size < 0) {
+ perror("read boot sector");
+ exit(1);
+ }
+
+ print_sector("Boot sector hexdump", buf, size);
+ }
+ }
+ FREE(&Stream);
+ exit(0);
+}
diff --git a/misc.c b/misc.c
new file mode 100644
index 0000000..6adf33b
--- /dev/null
+++ b/misc.c
@@ -0,0 +1,262 @@
+/* Copyright 1996-2002,2005,2007,2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Miscellaneous routines.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "stream.h"
+#include "vfat.h"
+#include "mtools.h"
+
+
+void printOom(void)
+{
+ fprintf(stderr, "Out of memory error");
+}
+
+char *get_homedir(void)
+{
+#ifndef OS_mingw32msvc
+ struct passwd *pw;
+ uid_t uid;
+ char *homedir;
+ char *username;
+
+ homedir = getenv ("HOME");
+ /*
+ * first we call getlogin.
+ * There might be several accounts sharing one uid
+ */
+ if ( homedir )
+ return homedir;
+
+ pw = 0;
+
+ username = getenv("LOGNAME");
+ if ( !username )
+ username = getlogin();
+ if ( username )
+ pw = getpwnam( username);
+
+ if ( pw == 0 ){
+ /* if we can't getlogin, look up the pwent by uid */
+ uid = geteuid();
+ pw = getpwuid(uid);
+ }
+
+ /* we might still get no entry */
+ if ( pw )
+ return pw->pw_dir;
+ return 0;
+#else
+ return getenv("HOME");
+#endif
+}
+
+
+static void get_mcwd_file_name(char *file)
+{
+ char *mcwd_path;
+ const char *homedir;
+
+ mcwd_path = getenv("MCWD");
+ if (mcwd_path == NULL || *mcwd_path == '\0'){
+ homedir= get_homedir();
+ if(!homedir)
+ homedir="/tmp";
+ strncpy(file, homedir, MAXPATHLEN-6);
+ file[MAXPATHLEN-6]='\0';
+ strcat( file, "/.mcwd");
+ } else {
+ strncpy(file, mcwd_path, MAXPATHLEN);
+ file[MAXPATHLEN]='\0';
+ }
+}
+
+void unlink_mcwd(void)
+{
+ char file[MAXPATHLEN+1];
+ get_mcwd_file_name(file);
+ unlink(file);
+}
+
+FILE *open_mcwd(const char *mode)
+{
+ struct MT_STAT sbuf;
+ char file[MAXPATHLEN+1];
+ time_t now;
+
+ get_mcwd_file_name(file);
+ if (*mode == 'r'){
+ if (MT_STAT(file, &sbuf) < 0)
+ return NULL;
+ /*
+ * Ignore the info, if the file is more than 6 hours old
+ */
+ getTimeNow(&now);
+ if (now - sbuf.st_mtime > 6 * 60 * 60) {
+ fprintf(stderr,
+ "Warning: \"%s\" is out of date, removing it\n",
+ file);
+ unlink(file);
+ return NULL;
+ }
+ }
+
+ return fopen(file, mode);
+}
+
+
+
+void *safe_malloc(size_t size)
+{
+ void *p;
+
+ p = malloc(size);
+ if(!p){
+ printOom();
+ exit(1);
+ }
+ return p;
+}
+
+void print_sector(const char *message, unsigned char *data, int size)
+{
+ int col;
+ int row;
+
+ printf("%s:\n", message);
+
+ for(row = 0; row * 16 < size; row++){
+ printf("%03x ", row * 16);
+ for(col = 0; col < 16; col++)
+ printf("%02x ", data [row*16+col]);
+ for(col = 0; col < 16; col++) {
+ if(isprint(data [row*16+col]))
+ printf("%c", data [row*16+col]);
+ else
+ printf(".");
+ }
+ printf("\n");
+ }
+}
+
+
+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;
+}
+
+/* Convert a string to an offset. The string should be a number,
+ optionally followed by S (sectors), K (K-Bytes), M (Megabytes), G
+ (Gigabytes) */
+off_t str_to_offset(char *str) {
+ char s, *endp = NULL;
+ off_t ofs;
+
+ ofs = strtol(str, &endp, 0);
+ if (ofs <= 0)
+ return 0; /* invalid or missing offset */
+ s = *endp++;
+ if (s) { /* trailing char, see if it is a size specifier */
+ if (s == 's' || s == 'S') /* sector */
+ ofs <<= 9;
+ else if (s == 'k' || s == 'K') /* kb */
+ ofs <<= 10;
+ else if (s == 'm' || s == 'M') /* Mb */
+ ofs <<= 20;
+ else if (s == 'g' || s == 'G') /* Gb */
+ ofs <<= 30;
+ else
+ return 0; /* invalid character */
+ if (*endp)
+ return 0; /* extra char, invalid */
+ }
+ return ofs;
+}
+
+#if 0
+
+#undef free
+#undef malloc
+
+static int total=0;
+
+void myfree(void *ptr)
+{
+ int *size = ((int *) ptr)-1;
+ total -= *size;
+ fprintf(stderr, "freeing %d bytes at %p total alloced=%d\n",
+ *size, ptr, total);
+ free(size);
+}
+
+void *mymalloc(size_t size)
+{
+ int *ptr;
+ ptr = (int *)malloc(size+sizeof(int));
+ if(!ptr)
+ return 0;
+ *ptr = size;
+ ptr++;
+ total += size;
+ fprintf(stderr, "allocating %d bytes at %p total allocated=%d\n",
+ size, ptr, total);
+ return (void *) ptr;
+}
+
+void *mycalloc(size_t nmemb, size_t size)
+{
+ void *ptr = mymalloc(nmemb * size);
+ if(!ptr)
+ return 0;
+ memset(ptr, 0, size);
+ return ptr;
+}
+
+void *myrealloc(void *ptr, size_t size)
+{
+ int oldsize = ((int *)ptr) [-1];
+ void *new = mymalloc(size);
+ if(!new)
+ return 0;
+ memcpy(new, ptr, oldsize);
+ myfree(ptr);
+ return new;
+}
+
+char *mystrdup(char *src)
+{
+ char *dest;
+ dest = mymalloc(strlen(src)+1);
+ if(!dest)
+ return 0;
+ strcpy(dest, src);
+ return dest;
+}
+
+#endif
diff --git a/missFuncs.c b/missFuncs.c
new file mode 100644
index 0000000..e16d9e3
--- /dev/null
+++ b/missFuncs.c
@@ -0,0 +1,477 @@
+/* Copyright 1991 Free Software Foundation, Inc.
+ * Copyright 1997,1999-2002,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..cba1846
--- /dev/null
+++ b/mk_direntry.c
@@ -0,0 +1,709 @@
+/* Copyright 1995-1998,2000-2003,2005,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mk_direntry.c
+ * Make new directory entries, and handles name clashes
+ *
+ */
+
+/*
+ * This file is used by those commands that need to create new directory entries
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "nameclash.h"
+#include "fs.h"
+#include "stream.h"
+#include "mainloop.h"
+#include "file_name.h"
+
+/**
+ * Converts input to shortname
+ * @param un unix name (in Unix charset)
+ *
+ * @return 1 if name had to be mangled
+ */
+static __inline__ int convert_to_shortname(doscp_t *cp, ClashHandling_t *ch,
+ const char *un, dos_name_t *dn)
+{
+ int mangled;
+
+ /* Then do conversion to dn */
+ ch->name_converter(cp, un, 0, &mangled, dn);
+ dn->sentinel = '\0';
+ 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
index 0000000..7af3f23
--- /dev/null
+++ b/mkdosboot
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Copyright 2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+# Example of a script making a Doc boot disk. Image will be t.img, a
+# FreeDos boot sector is expected in bootsect.dos, and diag contains
+# the system files
+
+IMAGE=t.img
+if [ $# = 1 ] ; then
+ IMAGE=$1
+fi
+
+./mformat -i $IMAGE -C -t 80 -s 18 -h 2 -B bootsect.dos ::
+./mcopy -i $IMAGE diag/io.sys ::IO.SYS
+./mcopy -i $IMAGE diag/msdos.sys ::MSDOS.SYS
+./mcopy -i $IMAGE diag/command.com ::COMMAND.COM
+./mcopy -i $IMAGE diag/drvspace.bin ::DRVSPACE.BIN
+
+./mattrib -i $IMAGE +s +h +r ::io.sys ::msdos.sys ::drvspace.bin
diff --git a/mkinstalldirs b/mkinstalldirs
new file mode 100755
index 0000000..6a5fd0b
--- /dev/null
+++ b/mkinstalldirs
@@ -0,0 +1,50 @@
+#! /bin/sh
+
+# Copyright 1993 Noah Friedman <friedman@prep.ai.mit.edu>
+# Copyright 1996,1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d in ${1+"$@"} ; do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "$pathcomp" || errstatus=$?
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
diff --git a/mkmanifest.1 b/mkmanifest.1
new file mode 100644
index 0000000..7154116
--- /dev/null
+++ b/mkmanifest.1
@@ -0,0 +1,180 @@
+'\" t
+.TH mkmanifest 1 "09Jan13" mtools-4.0.18
+.SH Name
+mkmanifest - makes list of file names and their DOS 8+3 equivalent
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmkmanifest\fR command is used to create a shell script (packing
+list) to restore Unix filenames. Its syntax is:
+.PP
+\&\fR\&\f(CWmkmanifest\fR [ \fIfiles\fR ]
+.PP
+\&\fR\&\f(CWMkmanifest\fR creates a shell script that aids in the restoration of
+Unix filenames that got clobbered by the MS-DOS filename restrictions.
+MS-DOS filenames are restricted to 8 character names, 3 character
+extensions, upper case only, no device names, and no illegal characters.
+.PP
+The mkmanifest program is compatible with the methods used in
+\&\fR\&\f(CWpcomm, arc,\fR and \fR\&\f(CWmtools\fR to change perfectly good Unix
+filenames to fit the MS-DOS restrictions. This command is only useful if
+the target system which will read the diskette cannot handle VFAT long
+names.
+.PP
+.SH Example
+You want to copy the following Unix files to a MS-DOS diskette (using the
+\&\fR\&\f(CWmcopy\fR command).
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ very_long_name
+ 2.many.dots
+ illegal:
+ good.c
+ prn.dev
+ Capital
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+\&\fR\&\f(CWASCII\fR
+converts the names to:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ very_lon
+ 2xmany.dot
+ illegalx
+ good.c
+ xprn.dev
+ capital
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The command:
+
+.nf
+.ft 3
+.in +0.3i
+mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRwould produce the following:
+
+.nf
+.ft 3
+.in +0.3i
+ mv very_lon very_long_name
+ mv 2xmany.dot 2.many.dots
+ mv illegalx illegal:
+ mv xprn.dev prn.dev
+ mv capital Capital
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+Notice that "good.c" did not require any conversion, so it did not
+appear in the output.
+.PP
+Suppose I've copied these files from the diskette to another Unix
+system, and I now want the files back to their original names. If the
+file "manifest" (the output captured above) was sent along with those
+files, it could be used to convert the filenames.
+.PP
+.SH Bugs
+.PP
+The short names generated by \fR\&\f(CWmkmanifest\fR follow the old convention
+(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mkmanifest.c b/mkmanifest.c
new file mode 100644
index 0000000..1b56b3d
--- /dev/null
+++ b/mkmanifest.c
@@ -0,0 +1,112 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996-1998,2001,2002,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..cc10eb1
--- /dev/null
+++ b/mkmanpages
@@ -0,0 +1,147 @@
+#!/bin/bash
+
+# Copyright 1997,1999,2001,2002,2004,2009,2010 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+# TODO
+VERSION=`cat version.texi | awk '$2 == "VERSION" {print $3}'`
+UPDATED=`cat version.texi | awk '$2 == "UPDATED" {print $3 " " $4}'`
+
+# extracts the manpage for a given command out of a texinfo doc
+unset LANG
+
+date=`date +%d%b%y`
+package="mtools-"`grep mversion patchlevel.c | sed 's/^.*"\(.*\)";/\1/'`
+
+infile=/tmp/infile.$$
+
+extract()
+{
+ command=$1
+ echo extracting $command
+ outfile=`echo $command | tr '[A-Z]' '[a-z]'`.1
+ exec 4>&1
+ exec >$outfile
+
+ echo \'\\\" t
+# '
+ echo .TH\ $command\ 1\ \"$date\" $package
+ echo .SH Name
+ egrep -i "^$command " cmdname | fgrep -v '#'
+ #echo ".SH Description"
+
+ cat man-warning.texi mtools.texi man-warning-end.texi |
+ egrep -v '@end copying|@copying|@insertcopying' |
+ sed \
+ -e "/^@c\(omment\)\? skipskipskip/,/^@node $command/d" \
+ -e "/^@node [^,]*, [^,]*, $command, Commands$/,/^@bye/d" \
+ -e "/^@node [^,]*, [^,]*, Commands/,/^@bye/d" \
+ -e 's/^@section/@chapter/' \
+ -e 's/^@subs/@s/' \
+ -e 's/^@chapter.*$/@chapter Description/' \
+ -e 's/^@section/@chapter/' \
+ -e 's/^@subs/@s/' \
+ -e 's/^@c\(omment\)\? xMANoptions/@chapter Options/' \
+ -e "s/^@c\(omment\)\? MAN/@MAN/" |
+ texi2roff -ma |
+ sed -f strip-pp.sed |
+ sed -e '/^\.iX/d'
+ exec 1>&4
+# echo ".SH See Also"
+# echo "Mtools' texinfo doc"
+}
+
+
+for name in `fgrep -v '#' cmdname | cut -f1 -d\ ` ; do
+ extract $name
+done
+
+rm -f mtools.tmpl.1
+exec >mtools.tmpl.1
+echo \'\\\" t
+# '
+echo .TH mtools 1 \"$date\" $package
+echo .SH Name
+echo "mtools - utilities to access DOS disks in Unix."
+cat mtools.texi |
+ egrep -v '@end copying|@copying|@insertcopying' |
+ sed \
+ -e "1,/^@c\(omment\)\? MANstart 1/d" \
+ -e '/^@c\(omment\)\? MANskip 1/,/^@c\(omment\)\? MANend-skip 1/d' \
+ -e '/^@c\(omment\)\? MANend-skip 5/d' \
+ -e '/^@c\(omment\)\? MANend 5/d' \
+ -e "s/^@c\(omment\)\? MAN/@MAN/" \
+ -e "s/@value{VERSION}/$VERSION/g" \
+ -e "s%@value{SYSCONFDIR}%SYSCONFDIR%g" |
+ texi2roff -ma |
+ sed -f strip-pp.sed |
+ sed -e '/^\.iX/d'
+
+echo .SH See also
+echo floppyd_installtest
+echo mattrib
+echo mbadblocks
+echo mcd
+echo mclasserase
+echo mcopy
+echo mdel
+echo mdeltree
+echo mdir
+echo mdu
+echo mformat
+echo minfo
+echo mkmanifest
+echo mlabel
+echo mmd
+echo mmount
+echo mmove
+echo mrd
+echo mren
+echo mshortname
+echo mshowfat
+echo mtoolstest
+echo mtype
+
+rm -f mtools.tmpl.5
+exec >mtools.tmpl.5
+echo \'\\\" t
+# '
+echo .TH mtools 5 \"$date\" "MTOOLS" "MTOOLS"
+echo .SH Name
+echo "mtools.conf - mtools configuration files"
+cat mtools.texi |
+ egrep -v '@end copying|@copying|@insertcopying' |
+ sed \
+ -e '1d' \
+ -e '/^@c\(omment\)\? MANskip 5/,/^@c\(omment\)\? MANend-skip 5/d' \
+ -e '/^@c\(omment\)\? MANend-skip 1/d' \
+ -e '/^@c\(omment\)\? MANskip 1/d' \
+ -e "s/^@c\(omment\)\? MAN/@MAN/" \
+ -e "/@include/ d" \
+ -e "s/@value{VERSION}/$VERSION/g" \
+ -e "s/@value{UPDATED}/$UPDATED/g" \
+ -e "s%@value{SYSCONFDIR}%SYSCONFDIR%g" \
+ -e "/@top/d" \
+ -e "/@format/d" \
+ -e "/@end format/d" \
+ -e "/@ifnottex/d" \
+ -e "/@end ifnottex/d" |
+ texi2roff -ma |
+ sed -f strip-pp.sed |
+ sed -e '/^\.iX/d' -e 's/\.SS Description/.SH Description/'
+
+echo .SH See also
+echo mtools
diff --git a/mlabel.1 b/mlabel.1
new file mode 100644
index 0000000..2f8db30
--- /dev/null
+++ b/mlabel.1
@@ -0,0 +1,118 @@
+'\" t
+.TH mlabel 1 "09Jan13" mtools-4.0.18
+.SH Name
+mlabel - make an MSDOS volume label
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmlabel\fR command adds a volume label to a disk. Its syntax is:
+.ft I
+.nf
+\&\fR\&\f(CWmlabel\fR [\fR\&\f(CW-vcsn\fR] [\fR\&\f(CW-N\fR \fIserial\fR] \fIdrive\fR:[\fInew_label\fR]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMlabel\fR displays the current volume label, if present. If
+\&\fInew_label\fR is not given, and if neither the \fR\&\f(CWc\fR nor the
+\&\fR\&\f(CWs\fR options are set, it prompts the user for a new volume label.
+To delete an existing volume label, press return at the prompt.
+.PP
+The label is limited to 11 single-byte characters,
+e.g. \fR\&\f(CWName1234567\fR.
+.PP
+Reasonable care is taken to create a valid MS-DOS volume label. If an
+invalid label is specified, \fR\&\f(CWmlabel\fR changes the label (and
+displays the new label if the verbose mode is set). \fR\&\f(CWMlabel\fR
+returns 0 on success or 1 on failure.
+.PP
+Mlabel supports the following options:
+.TP
+\&\fR\&\f(CWc\fR\
+Clears an existing label, without prompting the user
+.TP
+\&\fR\&\f(CWs\fR\
+Shows the existing label, without prompting the user.
+.TP
+\&\fR\&\f(CWn\ \fR\
+Assigns a new (random) serial number to the disk
+.TP
+\&\fR\&\f(CWN\ \fIserial\fR\&\f(CW\fR\
+Sets the supplied serial number. The serial number should be supplied as
+an 8 digit hexadecimal number, without spaces
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mlabel.c b/mlabel.c
new file mode 100644
index 0000000..4385d42
--- /dev/null
+++ b/mlabel.c
@@ -0,0 +1,331 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996-1998,2000-2002,2005,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mlabel.c
+ * Make an MSDOS volume label
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mainloop.h"
+#include "vfat.h"
+#include "mtools.h"
+#include "nameclash.h"
+#include "file_name.h"
+
+static void _label_name(doscp_t *cp, const char *filename, int verbose,
+ int *mangled, dos_name_t *ans, int preserve_case)
+{
+ int len;
+ int i;
+ int have_lower, have_upper;
+ wchar_t wbuffer[12];
+
+ memset(ans, ' ', sizeof(*ans)-1);
+ ans->sentinel = '\0';
+ len = native_to_wchar(filename, wbuffer, 11, 0, 0);
+ if(len > 11){
+ *mangled = 1;
+ len = 11;
+ } else
+ *mangled = 0;
+
+ have_lower = have_upper = 0;
+ for(i=0; i<len; i++){
+ if(islower(wbuffer[i]))
+ have_lower = 1;
+ if(isupper(wbuffer[i]))
+ have_upper = 1;
+ if(!preserve_case)
+ wbuffer[i] = towupper(wbuffer[i]);
+ if(
+#ifdef HAVE_WCHAR_H
+ wcschr(L"^+=/[]:,?*\\<>|\".", wbuffer[i])
+#else
+ strchr("^+=/[]:,?*\\<>|\".", wbuffer[i])
+#endif
+ ){
+ *mangled = 1;
+ wbuffer[i] = '~';
+ }
+ }
+ if (have_lower && have_upper)
+ *mangled = 1;
+ wchar_to_dos(cp, wbuffer, ans->base, len, mangled);
+}
+
+void label_name_uc(doscp_t *cp, const char *filename, int verbose,
+ int *mangled, dos_name_t *ans)
+{
+ _label_name(cp, filename, verbose, mangled, ans, 0);
+}
+
+void label_name_pc(doscp_t *cp, const char *filename, int verbose,
+ int *mangled, dos_name_t *ans)
+{
+ _label_name(cp, filename, verbose, mangled, ans, 1);
+}
+
+int labelit(struct dos_name_t *dosname,
+ char *longname,
+ 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)
+{
+
+ const char *newLabel="";
+ int verbose, clear, interactive, show;
+ direntry_t entry;
+ int result=0;
+ char longname[VBUFSIZE];
+ char shortname[45];
+ ClashHandling_t ch;
+ struct MainParam_t mp;
+ Stream_t *RootDir;
+ int c;
+ int mangled;
+ enum { SER_NONE, SER_RANDOM, SER_SET } set_serial = SER_NONE;
+ 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;
+ char drive;
+
+ init_clash_handling(&ch);
+ ch.name_converter = label_name_uc;
+ 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);
+ 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 = strtoul(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)
+ usage(1);
+ if(argc - optind == 1) {
+ if(!argv[optind][0] || argv[optind][1] != ':')
+ usage(1);
+ drive = toupper(argv[argc -1][0]);
+ newLabel = argv[optind]+2;
+ } else {
+ drive = get_default_drive();
+ }
+
+ init_mp(&mp);
+ if(strlen(newLabel) > VBUFSIZE) {
+ fprintf(stderr, "Label too long\n");
+ FREE(&RootDir);
+ exit(1);
+ }
+
+ interactive = !show && !clear &&!newLabel[0] &&
+ (set_serial == SER_NONE);
+ if(!clear && !newLabel[0]) {
+ isRop = &isRo;
+ }
+ if(clear && newLabel[0]) {
+ /* Clear and new label specified both */
+ fprintf(stderr, "Both clear and new label specified\n");
+ FREE(&RootDir);
+ exit(1);
+ }
+ RootDir = open_root_dir(drive, isRop ? 0 : O_RDWR, isRop);
+ if(isRo) {
+ show = 1;
+ interactive = 0;
+ }
+ if(!RootDir) {
+ fprintf(stderr, "%s: Cannot initialize drive\n", argv[0]);
+ exit(1);
+ }
+
+ initializeDirentry(&entry, RootDir);
+ r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
+ shortname, longname);
+ if (r == -2) {
+ FREE(&RootDir);
+ exit(1);
+ }
+
+ if(show || interactive){
+ if(isNotFound(&entry))
+ printf(" Volume has no label\n");
+ else if (*longname)
+ printf(" Volume label is %s (abbr=%s)\n",
+ longname, shortname);
+ else
+ printf(" Volume label is %s\n", shortname);
+
+ }
+
+ /* ask for new label */
+ if(interactive){
+ saved_sig_state ss;
+ newLabel = longname;
+ allow_interrupts(&ss);
+ fprintf(stderr,"Enter the new volume label : ");
+ if(fgets(longname, VBUFSIZE, stdin) == NULL) {
+ fprintf(stderr, "\n");
+ if(errno == EINTR) {
+ FREE(&RootDir);
+ exit(1);
+ }
+ longname[0] = '\0';
+ }
+ if(longname[0])
+ longname[strlen(newLabel)-1] = '\0';
+ }
+
+ if(strlen(newLabel) > 11) {
+ fprintf(stderr,"New label too long\n");
+ FREE(&RootDir);
+ exit(1);
+ }
+
+ if((!show || newLabel[0]) && !isNotFound(&entry)){
+ /* if we have a label, wipe it out before putting new one */
+ if(interactive && newLabel[0] == '\0')
+ if(ask_confirmation("Delete volume label (y/n): ")){
+ FREE(&RootDir);
+ exit(0);
+ }
+ entry.dir.attr = 0; /* for old mlabel */
+ wipeEntry(&entry);
+ }
+
+ if (newLabel[0] != '\0') {
+ ch.ignore_entry = 1;
+ result = mwrite_one(RootDir,newLabel,0,labelit,NULL,&ch) ?
+ 0 : 1;
+ }
+
+ have_boot = 0;
+ if( (!show || newLabel[0]) || set_serial != SER_NONE) {
+ Fs = GetFs(RootDir);
+ have_boot = (force_read(Fs,boot.characters,0,sizeof(boot)) ==
+ sizeof(boot));
+ }
+
+ if(WORD_S(fatlen)) {
+ labelBlock = &boot.boot.ext.old.labelBlock;
+ } else {
+ labelBlock = &boot.boot.ext.fat32.labelBlock;
+ }
+
+ if(!show || newLabel[0]){
+ dos_name_t dosname;
+ const char *shrtLabel;
+ doscp_t *cp;
+ if(!newLabel[0])
+ shrtLabel = "NO NAME ";
+ else
+ shrtLabel = newLabel;
+ cp = GET_DOSCONVERT(Fs);
+ label_name_pc(cp, shrtLabel, verbose, &mangled, &dosname);
+
+ if(have_boot && boot.boot.descr >= 0xf0 &&
+ 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));
+ /* If this is fat 32, write backup boot sector too */
+ if(!WORD_S(fatlen)) {
+ int backupBoot = WORD_S(ext.fat32.backupBoot);
+ force_write(Fs, (char *)&boot,
+ backupBoot * WORD_S(secsiz),
+ sizeof(boot));
+ }
+ }
+
+ FREE(&RootDir);
+ exit(result);
+}
diff --git a/mmd.1 b/mmd.1
new file mode 100644
index 0000000..8b65fd9
--- /dev/null
+++ b/mmd.1
@@ -0,0 +1,91 @@
+'\" t
+.TH mmd 1 "09Jan13" mtools-4.0.18
+.SH Name
+mmd - make an MSDOS subdirectory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmmd\fR command is used to make an MS-DOS subdirectory. Its
+syntax is:
+.PP
+\&\fR\&\f(CWmmd\fR [\fR\&\f(CW-D\fR \fIclash_option\fR] \fImsdosdirectory\fR [
+\&\fImsdosdirectories\fR\&... ]
+.PP
+\&\fR\&\f(CWMmd\fR makes a new directory on an MS-DOS file system. An error occurs
+if the directory already exists.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mmd.c b/mmd.c
new file mode 100644
index 0000000..bb9c1d7
--- /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);
+ break;
+ case '?':
+ usage(1);
+ case 'o':
+ handle_clash_options(&arg.ch, c);
+ break;
+ case 'D':
+ if(handle_clash_options(&arg.ch, *optarg))
+ usage(1);
+ break;
+ case 'h':
+ usage(0);
+ default:
+ usage(1);
+ break;
+ }
+ }
+
+ if (argc - optind < 1)
+ usage(1);
+
+ init_mp(&arg.mp);
+ arg.mp.arg = (void *) &arg;
+ arg.mp.openflags = O_RDWR;
+ arg.mp.callback = createDirCallback;
+ arg.mp.lookupflags = OPEN_PARENT | DO_OPEN_DIRS;
+ exit(main_loop(&arg.mp, argv + optind, argc - optind));
+}
diff --git a/mmount.1 b/mmount.1
new file mode 100644
index 0000000..d232cb4
--- /dev/null
+++ b/mmount.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mmount 1 "09Jan13" mtools-4.0.18
+.SH Name
+mmount - mount an MSDOS disk
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmmount\fR command is used to mount an MS-DOS disk. It is only
+available on Linux, as it is only useful if the OS kernel allows 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
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mmount.c b/mmount.c
new file mode 100644
index 0000000..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
index 0000000..65a49af
--- /dev/null
+++ b/mmove.1
@@ -0,0 +1,99 @@
+'\" t
+.TH mmove 1 "09Jan13" mtools-4.0.18
+.SH Name
+mmove - move or rename an MSDOS file or subdirectory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmmove\fR command is used to 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 file system. Data cannot be moved from MS-DOS to Unix or
+vice-versa. If you omit the drive letter from the target file or
+directory, the same letter as for the source is assumed. If you omit
+the drive letter from all parameters, drive a: is assumed by default.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mmove.c b/mmove.c
new file mode 100644
index 0000000..7f5e5ef
--- /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);
+ 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
index 0000000..1796fc8
--- /dev/null
+++ b/mpartition.1
@@ -0,0 +1,184 @@
+'\" t
+.TH mpartition 1 "09Jan13" mtools-4.0.18
+.SH Name
+mpartition - partition an MSDOS hard disk
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmpartition\fR command is used to create MS-DOS file systems as
+partitions. This is intended to be used on non-Linux systems,
+i.e. systems where fdisk and easy access to SCSI devices are not
+available. This command only works on drives whose partition variable
+is set.
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-p\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-r\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-I\fR [\fR\&\f(CW-B\fR \fIbootSector\fR] \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-a\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-d\fR \fIdrive\fR
+\&\fR\&\f(CWmpartition\fR \fR\&\f(CW-c\fR [\fR\&\f(CW-s\fR \fIsectors\fR] [\fR\&\f(CW-h\fR \fIheads\fR]
+[\fR\&\f(CW-t\fR \fIcylinders\fR] [\fR\&\f(CW-v\fR [\fR\&\f(CW-T\fR \fItype\fR] [\fR\&\f(CW-b\fR
+\&\fIbegin\fR] [\fR\&\f(CW-l\fR length] [\fR\&\f(CW-f\fR]
+\&\&
+.fi
+.ft R
+
+.PP
+Mpartition supports the following operations:
+.TP
+\&\fR\&\f(CWp\fR\
+Prints a command line to recreate the partition for the drive. Nothing
+is printed if the partition for the drive is not defined, or an
+inconsistency has been detected. If verbose (\fR\&\f(CW-v\fR) is also set,
+prints the current partition table.
+.TP
+\&\fR\&\f(CWr\fR\
+Removes the partition described by \fIdrive\fR.
+.TP
+\&\fR\&\f(CWI\fR\
+Initializes the partition table, and removes all partitions.
+.TP
+\&\fR\&\f(CWc\fR\
+Creates the partition described by \fIdrive\fR.
+.TP
+\&\fR\&\f(CWa\fR\
+"Activates" the partition, i.e. makes it bootable. Only one partition
+can be bootable at a time.
+.TP
+\&\fR\&\f(CWd\fR\
+"Deactivates" the partition, i.e. makes it unbootable.
+.PP
+If no operation is given, the current settings are printed.
+.PP
+For partition creations, the following options are available:
+.TP
+\&\fR\&\f(CWs\ \fIsectors\fR\&\f(CW\fR\
+The number of sectors per track of the partition (which is also the
+number of sectors per track for the whole drive).
+.TP
+\&\fR\&\f(CWh\ \fIheads\fR\&\f(CW\fR\
+The number of heads of the partition (which is also the number of heads
+for the whole drive). By default, the geometry information (number of
+sectors and heads) is figured out from neighboring partition table
+entries, or guessed from the size.
+.TP
+\&\fR\&\f(CWt\ \fIcylinders\fR\&\f(CW\fR\
+The number of cylinders of the partition (not the number of cylinders of
+the whole drive.
+.TP
+\&\fR\&\f(CWb\ \fIbegin\fR\&\f(CW\fR\
+The starting offset of the partition, expressed in sectors. If begin is
+not given, 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 consistency 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
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mpartition.c b/mpartition.c
new file mode 100644
index 0000000..24ac840
--- /dev/null
+++ b/mpartition.c
@@ -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);
+ 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
index 0000000..9b4afc3
--- /dev/null
+++ b/mrd.1
@@ -0,0 +1,95 @@
+'\" t
+.TH mrd 1 "09Jan13" mtools-4.0.18
+.SH Name
+mrd - remove an MSDOS subdirectory
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmrd\fR command is used to remove an MS-DOS subdirectory. Its
+syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmrd\fR [\fR\&\f(CW-v\fR] \fImsdosdirectory\fR [ \fImsdosdirectories\fR\&... ]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMrd\fR removes a directory from an MS-DOS file system. An error occurs
+if the directory does not exist or is not empty.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mren.1 b/mren.1
new file mode 100644
index 0000000..721f2ee
--- /dev/null
+++ b/mren.1
@@ -0,0 +1,105 @@
+'\" t
+.TH mren 1 "09Jan13" mtools-4.0.18
+.SH Name
+mren - rename an existing MSDOS file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmren\fR command is used to rename or move an existing MS-DOS
+file or subdirectory. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmren\fR [\fR\&\f(CW-voOsSrRA\fR] \fIsourcefile\fR \fItargetfile\fR
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMren\fR
+renames an existing file on an MS-DOS file system.
+.PP
+In verbose mode, \fR\&\f(CWMren\fR displays the new filename if the name
+supplied is invalid.
+.PP
+If the first syntax is used (only one source file), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+\&\fR\&\f(CWmcd\fR directory as would be the case with \fR\&\f(CWmmove\fR. Unlike the
+MS-DOS version of \fR\&\f(CWREN\fR, \fR\&\f(CWmren\fR can be used to rename
+directories.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/msdos.h b/msdos.h
new file mode 100644
index 0000000..c060455
--- /dev/null
+++ b/msdos.h
@@ -0,0 +1,279 @@
+#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)
+#define ENDMARK ((char) 0x00)
+
+struct directory {
+ char name[8]; /* 0 file name */
+ char ext[3]; /* 8 file extension */
+ unsigned char attr; /* 11 attribute byte */
+ unsigned char Case; /* 12 case of short filename */
+ unsigned char ctime_ms; /* 13 creation time, milliseconds (?) */
+ unsigned char ctime[2]; /* 14 creation time */
+ unsigned char cdate[2]; /* 16 creation date */
+ unsigned char adate[2]; /* 18 last access date */
+ unsigned char startHi[2]; /* 20 start cluster, Hi */
+ unsigned char time[2]; /* 22 time stamp */
+ unsigned char date[2]; /* 24 date stamp */
+ unsigned char start[2]; /* 26 starting cluster number */
+ unsigned char size[4]; /* 28 size of the file */
+};
+
+#define EXTCASE 0x10
+#define BASECASE 0x8
+
+#define MAX16 0xffff
+#define MAX32 0xffffffff
+#define MAX_SIZE 0x7fffffff
+
+#define FILE_SIZE(dir) (_DWORD((dir)->size))
+#define START(dir) (_WORD((dir)->start))
+#define STARTHI(dir) (_WORD((dir)->startHi))
+
+/* ASSUMPTION: long is at least 32 bits */
+UNUSED(static __inline__ void set_dword(unsigned char *data, 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/mshortname.1 b/mshortname.1
new file mode 100644
index 0000000..b85043f
--- /dev/null
+++ b/mshortname.1
@@ -0,0 +1,95 @@
+'\" t
+.TH mshortname 1 "09Jan13" mtools-4.0.18
+.SH Name
+mshortname - shows short name of a file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmshortname\fR command is used to display the short name of a
+file. Syntax:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmshortname\fR \fIfiles\fR
+.fi
+.ft R
+
+.PP
+The shortname is displayed as it is stored in raw format on disk,
+without any character set conversion.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mshortname.c b/mshortname.c
new file mode 100644
index 0000000..5cdfa3f
--- /dev/null
+++ b/mshortname.c
@@ -0,0 +1,76 @@
+/* Copyright 2010 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mshortname.c
+ * Change MSDOS file attribute flags
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "mainloop.h"
+
+static int print_short_name(direntry_t *entry, MainParam_t *mp)
+{
+ fprintShortPwd(stdout, entry);
+ putchar('\n');
+ return GOT_ONE;
+}
+
+
+static void usage(int ret) NORETURN;
+static void usage(int ret)
+{
+ fprintf(stderr, "Mtools version %s, dated %s\n",
+ mversion, mdate);
+ fprintf(stderr,
+ "Usage: %s msdosfile [msdosfiles...]\n",
+ progname);
+ exit(ret);
+}
+
+void mshortname(int argc, char **argv, int type)
+{
+ struct MainParam_t mp;
+ int c;
+
+ if(helpFlag(argc, argv))
+ usage(0);
+ while ((c = getopt(argc, argv, "i:h")) != EOF) {
+ switch (c) {
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 'h':
+ usage(0);
+ case '?':
+ usage(1);
+ }
+ }
+
+ if(optind == argc) {
+ usage(0);
+ }
+
+ if (optind >= argc)
+ usage(1);
+
+ init_mp(&mp);
+ mp.callback = print_short_name;
+ mp.arg = NULL;
+ mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR;
+ exit(main_loop(&mp, argv + optind, argc - optind));
+}
diff --git a/mshowfat.1 b/mshowfat.1
new file mode 100644
index 0000000..75ac8c0
--- /dev/null
+++ b/mshowfat.1
@@ -0,0 +1,96 @@
+'\" t
+.TH mshowfat 1 "09Jan13" mtools-4.0.18
+.SH Name
+mshowfat - shows FAT clusters allocated to file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmshowfat\fR command is used to display the FAT entries for a
+file. Syntax:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmshowfat\fR [\fR\&\f(CW-o\fR \fIoffset\fR] \fIfiles\fR
+.fi
+.ft R
+
+.PP
+If no offset is given, a list of all clusters occupied by the file is
+printed. If an offset is given, only the number of the cluster
+containing that offset is printed.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mshowfat.c b/mshowfat.c
new file mode 100644
index 0000000..6c1ebe9
--- /dev/null
+++ b/mshowfat.c
@@ -0,0 +1,110 @@
+/* Copyright 1997,2000-2002,2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * mcopy.c
+ * Copy an MSDOS files to and from Unix
+ *
+ */
+
+
+#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 {
+ MainParam_t mp;
+ off_t offset;
+} Arg_t;
+
+static int dos_showfat(direntry_t *entry, MainParam_t *mp)
+{
+ Stream_t *File=mp->File;
+ Arg_t *arg = (Arg_t *) mp->arg;
+ fprintPwd(stdout, entry,0);
+ putchar(' ');
+ if(arg->offset == -1) {
+ printFat(File);
+ } else {
+ printFatWithOffset(File, arg->offset);
+ }
+ printf("\n");
+ return GOT_ONE;
+}
+
+static int unix_showfat(MainParam_t *mp)
+{
+ 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 */
+ if(helpFlag(argc, argv))
+ usage(0);
+ arg.offset = -1;
+ while ((c = getopt(argc, argv, "i:ho:")) != EOF) {
+ switch (c) {
+ case 'o':
+ arg.offset = str_to_offset(optarg);
+ break;
+ case 'i':
+ set_cmd_line_image(optarg);
+ break;
+ case 'h':
+ usage(0);
+ case '?':
+ usage(1);
+ break;
+ }
+ }
+
+ if (argc - optind < 1)
+ usage(1);
+
+ /* only 1 file to handle... */
+ init_mp(&arg.mp);
+ arg.mp.arg = (void *) &arg;
+
+ arg.mp.callback = dos_showfat;
+ arg.mp.unixcallback = unix_showfat;
+
+ arg.mp.lookupflags = ACCEPT_PLAIN | ACCEPT_DIR | DO_OPEN;
+ ret=main_loop(&arg.mp, argv + optind, argc - optind);
+ exit(ret);
+}
diff --git a/mtools.1 b/mtools.1
new file mode 100644
index 0000000..7d416d4
--- /dev/null
+++ b/mtools.1
@@ -0,0 +1,521 @@
+'\" t
+.TH mtools 1 "09Jan13" mtools-4.0.18
+.SH Name
+mtools - utilities to access DOS disks in Unix.
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.PP
+.SH Introduction
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS
+file system (typically a floppy disk). Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However,
+unnecessary restrictions and oddities of DOS are not emulated. For
+instance, it is possible to move subdirectories from one subdirectory
+to another.
+.PP
+Mtools is sufficient to give access to MS-DOS file systems. For
+instance, commands such as \fR\&\f(CWmdir a:\fR work on the \fR\&\f(CWa:\fR floppy
+without any preliminary mounting or initialization (assuming the default
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR works on your machine). With mtools, one can
+change floppies too without unmounting and mounting.
+.PP
+.SH Where\ to\ get\ mtools
+.PP
+Mtools can be found at the following places (and their mirrors):
+
+.nf
+.ft 3
+.in +0.3i
+http://ftp.gnu.org/gnu/mtools/mtools-4.0.18.tar.gz
+http://mtools.linux.lu/mtools-4.0.18.tar.gz
+ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.18.tar.gz
+ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.18.tar.gz
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\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
+.PP
+
+\&\fR
+.PP
+These patches are named
+\&\fR\&\f(CWmtools-\fR\fIversion\fR\fR\&\f(CW-\fR\fIddmm\fR\fR\&\f(CW.taz\fR, where version
+stands for the base version, \fIdd\fR for the day and \fImm\fR for the
+month. Due to a lack of space, I usually leave only the most recent
+patch.
+.PP
+There is an mtools mailing list at 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
+MS-DOS filenames are composed of a drive letter followed by a colon, a
+subdirectory, and a filename. Only the filename part is mandatory, the
+drive letter and the subdirectory are optional. Filenames without a
+drive letter refer to Unix files. Subdirectory names can use either the
+\&'\fR\&\f(CW/\fR' or '\fR\&\f(CW\e\fR' separator. The use of the '\fR\&\f(CW\e\fR' separator
+or wildcards requires the names to be enclosed in quotes to protect them
+from the shell. However, wildcards in Unix filenames should not be
+enclosed in quotes, because here we \fBwant\fR the shell to expand
+them.
+.PP
+The regular expression "pattern matching" routines follow the Unix-style
+rules. For example, `\fR\&\f(CW*\fR' matches all MS-DOS files in lieu of
+`\fR\&\f(CW*.*\fR'. The archive, hidden, read-only and system attribute bits
+are ignored during pattern matching.
+.PP
+All options use the \fR\&\f(CW-\fR (minus) as their first character, not
+\&\fR\&\f(CW/\fR as you'd expect in MS-DOS.
+.PP
+Most mtools commands allow multiple filename parameters, which
+doesn't follow MS-DOS conventions, but which is more user-friendly.
+.PP
+Most mtools commands allow options that instruct them how to handle file
+name clashes. See section name clashes, for more details on these. All
+commands accept the \fR\&\f(CW-V\fR flags which prints the version, and most
+accept the \fR\&\f(CW-v\fR flag, which switches on verbose mode. In verbose
+mode, these commands print out the name of the MS-DOS files upon which
+they act, unless stated otherwise. See section Commands, for a description of
+the options which are specific to each command.
+.PP
+.SS Drive\ letters
+.PP
+The meaning of the drive letters depends on the target architectures.
+However, on most target architectures, drive A is the first floppy
+drive, drive B is the second floppy drive (if available), drive J is a
+Jaz drive (if available), and drive Z is a Zip drive (if available). On
+those systems where the device name is derived from the SCSI id, the Jaz
+drive is assumed to be at SCSI target 4, and the Zip at SCSI target 5
+(factory default settings). On Linux, both drives are assumed to be the
+second drive on the SCSI bus (/dev/sdb). The default settings can be
+changes using a configuration file (see section Configuration).
+.PP
+The drive letter : (colon) has a special meaning. It is used to access
+image files which are directly specified on the command line using the
+\&\fR\&\f(CW-i\fR options.
+.PP
+Example:
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy -i my-image-file.bin ::file1 ::file2 .
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+This copies \fR\&\f(CWfile1\fR and \fR\&\f(CWfile2\fR from the image file
+(\fR\&\f(CWmy-image-file.bin\fR) to the \fR\&\f(CW/tmp\fR directory.
+.PP
+You can also supply an offset within the image file by including
+\&\fR\&\f(CW@@\fR\fIoffset\fR into the file name.
+.PP
+Example:
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy -i my-image-file.bin@@1M ::file1 ::file2 .
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+This looks for the image at the offset of 1M in the file, rather than
+at its beginning.
+.PP
+.SS Current\ working\ directory
+.PP
+The \fR\&\f(CWmcd\fR command (\(ifmcd\(is) is used to establish the device and
+the current working directory (relative to the MS-DOS file system),
+otherwise the default is assumed to be \fR\&\f(CWA:/\fR. However, unlike
+MS-DOS, there is only one working directory for all drives, and not one
+per drive.
+.PP
+.SS VFAT-style\ long\ file\ names
+.PP
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a
+VFAT long name, and a companion short name is generated. This short
+name is what you see when you examine the disk with a pre-7.0 version
+of DOS.
+ The following table shows some examples of short names:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+Long name MS-DOS name Reason for the change
+--------- ---------- ---------------------
+thisisatest THISIS~1 filename too long
+alain.knaff ALAIN~1.KNA extension too long
+prn.txt PRN~1.TXT PRN is a device name
+\&\&.abc ABC~1 null filename
+hot+cold HOT_CO~1 illegal character
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ As you see, the following transformations happen to derive a short
+name:
+.TP
+* \ \
+Illegal characters are replaced by underscores. The illegal characters
+are \fR\&\f(CW;+=[]',\e"*\e\e<>/?:|\fR.
+.TP
+* \ \
+Extra dots, which cannot be interpreted as a main name/extension
+separator are removed
+.TP
+* \ \
+A \fR\&\f(CW~\fR\fIn\fR number is generated,
+.TP
+* \ \
+The name is shortened so as to fit in the 8+3 limitation
+.PP
+ The initial Unix-style file name (whether long or short) is also called
+the \fIprimary\fR name, and the derived short name is also called the
+\&\fIsecondary\fR name.
+.PP
+ Example:
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy /etc/motd a:Reallylongname
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy /etc/motd a:motd
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+.PP
+ In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+.PP
+ Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (\fR\&\f(CW\e"*\e\e<>/?:|\fR), and device names are still
+reserved.
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+Unix name Long name Reason for the change
+--------- ---------- ---------------------
+prn prn-1 PRN is a device name
+ab:c ab_c-1 illegal character
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ As you see, the following transformations happen if a long name is
+illegal:
+.TP
+* \ \
+Illegal characters are replaces by underscores,
+.TP
+* \ \
+A \fR\&\f(CW-\fR\fIn\fR number is generated,
+.PP
+.SS Name\ clashes
+.PP
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as \fR\&\f(CWmcopy\fR,
+\&\fR\&\f(CWmmd\fR, \fR\&\f(CWmren\fR, \fR\&\f(CWmmove\fR. When a name clash happens, mtools
+asks you what it should do. It offers several choices:
+.TP
+\&\fR\&\f(CWoverwrite\fR\
+Overwrites the existing file. It is not possible to overwrite a
+directory with a file.
+.TP
+\&\fR\&\f(CWrename\fR\
+Renames the newly created file. Mtools prompts for the new filename
+.TP
+\&\fR\&\f(CWautorename\fR\
+Renames the newly created file. Mtools chooses a name by itself, without
+prompting
+.TP
+\&\fR\&\f(CWskip\fR\
+Gives up on this file, and moves on to the next (if any)
+.PP
+To chose one of these actions, type its first letter at the prompt. If
+you use a lower case letter, the action only applies for this file only,
+if you use an upper case letter, the action applies to all files, and
+you won't be prompted again.
+.PP
+You may also chose actions (for all files) on the command line, when
+invoking mtools:
+.TP
+\&\fR\&\f(CW-D\ o\fR\
+Overwrites primary names by default.
+.TP
+\&\fR\&\f(CW-D\ O\fR\
+Overwrites secondary names by default.
+.TP
+\&\fR\&\f(CW-D\ r\fR\
+Renames primary name by default.
+.TP
+\&\fR\&\f(CW-D\ R\fR\
+Renames secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ a\fR\
+Autorenames primary name by default.
+.TP
+\&\fR\&\f(CW-D\ A\fR\
+Autorenames secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ s\fR\
+Skip primary name by default.
+.TP
+\&\fR\&\f(CW-D\ S\fR\
+Skip secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ m\fR\
+Ask user what to do with primary name.
+.TP
+\&\fR\&\f(CW-D\ M\fR\
+Ask user what to do with secondary name.
+.PP
+Note that for command line switches lower/upper differentiates between
+primary/secondary name whereas for interactive choices, lower/upper
+differentiates between just-this-time/always.
+.PP
+The primary name is the name as displayed in Windows 95 or Windows NT:
+i.e. the long name if it exists, and the short name otherwise. The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+.PP
+By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+.PP
+If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+.PP
+.SS Case\ sensitivity\ of\ the\ VFAT\ file\ system
+.PP
+The VFAT file system is able to remember the case of the
+filenames. However, filenames which differ only in case are not allowed
+to coexist in the same directory. For example if you store a file called
+LongFileName on a VFAT file system, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+.PP
+The VFAT file system allows to store the case of a filename in the
+attribute byte, if all letters of the filename are the same case, and if
+all letters of the extension are the same case too. Mtools uses this
+information when displaying the files, and also to generate the Unix
+filename when mcopying to a Unix directory. This may have unexpected
+results when applied to files written using an pre-7.0 version of DOS:
+Indeed, the old style filenames map to all upper case. This is different
+from the behavior of the old version of mtools which used to generate
+lower case Unix filenames.
+.PP
+.SS high\ capacity\ formats
+.PP
+Mtools supports a number of formats which allow to store more data on
+disk as usual. Due to different operating system abilities, these
+formats are not supported on all operating systems. Mtools recognizes
+these formats transparently where supported.
+.PP
+In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+\&\fR\&\f(CWfdutils\fR package at the following locations~:
+
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(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
+.PP
+
+\&\fR
+.PP
+See the manual pages included in that package for further detail: Use
+\&\fR\&\f(CWsuperformat\fR to format all formats except XDF, and use
+\&\fR\&\f(CWxdfcopy\fR to format XDF.
+.PP
+.SS \ \ More\ sectors
+.PP
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+.PP
+These formats are supported by numerous DOS shareware utilities such as
+\&\fR\&\f(CWfdformat\fR and \fR\&\f(CWvgacopy\fR. In his infinite hubris, Bill Gate$
+believed that he invented this, and called it \fR\&\f(CW\(ifDMF disks\(is\fR, or
+\&\fR\&\f(CW\(ifWindows formatted disks\(is\fR. But in reality, it has already existed
+years before! Mtools supports these formats on Linux, on SunOS and on
+the DELL Unix PC.
+.PP
+.SS \ \ Bigger\ sectors
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+\&\fIfewer\fR, but bigger sectors. For example, 1 sector of 4K only takes
+up header space once, whereas 8 sectors of 512 bytes have also 8
+headers, for the same amount of useful data.
+.PP
+This method allows to store up to 1992K on a 3 1/2 HD disk.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ 2m
+.PP
+The 2m format was originally invented by Ciriaco Garcia de Celis. It
+also uses bigger sectors than usual in order to fit more data on the
+disk. However, it uses the standard format (18 sectors of 512 bytes
+each) on the first cylinder, in order to make these disks easier to
+handle by DOS. Indeed this method allows to have a standard sized
+boot sector, which contains a description of how the rest of the disk
+should be read.
+.PP
+However, the drawback of this is that the first cylinder can hold less
+data than the others. Unfortunately, DOS can only handle disks where
+each track contains the same amount of data. Thus 2m hides the fact that
+the first track contains less data by using a \fIshadow
+FAT\fR. (Usually, DOS stores the FAT in two identical copies, for
+additional safety. XDF stores only one copy, but tells DOS that it
+stores two. Thus the space that would be taken up by the second FAT copy
+is saved.) This also means that you should \fBnever use a 2m disk
+to store anything else than a DOS file system\fR.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ XDF
+.PP
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the \fR\&\f(CWuse_xdf\fR variable for the drive in the
+configuration file. See section Compiling mtools, and \(ifmiscellaneous variables\(is,
+for details on how to do this. Fast XDF access is only available for
+Linux kernels which are more recent than 1.1.34.
+.PP
+Mtools supports this format only on Linux.
+.PP
+\&\fBCaution / Attention distributors\fR: If mtools is compiled on a
+Linux kernel more recent than 1.3.34, it won't run on an older
+kernel. However, if it has been compiled on an older kernel, it still
+runs on a newer kernel, except that XDF access is slower. It is
+recommended that distribution authors only include mtools binaries
+compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will
+be out, mtools binaries compiled on newer kernels may (and should) be
+distributed. Mtools binaries compiled on kernels older than 1.3.34 won't
+run on any 2.1 kernel or later.
+.PP
+.SS Exit\ codes
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure. All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or MINIX disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(see section global variables)
+.SS Bugs
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver. These can be safely ignored.
+.PP
+The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7
+mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the
+corresponding configuration file variable, \(ifglobal variables\(is) to
+bypass the fat checking.
+.PP
+.SH See also
+floppyd_installtest
+mattrib
+mbadblocks
+mcd
+mclasserase
+mcopy
+mdel
+mdeltree
+mdir
+mdu
+mformat
+minfo
+mkmanifest
+mlabel
+mmd
+mmount
+mmove
+mrd
+mren
+mshortname
+mshowfat
+mtoolstest
+mtype
diff --git a/mtools.5 b/mtools.5
new file mode 100644
index 0000000..06f54b8
--- /dev/null
+++ b/mtools.5
@@ -0,0 +1,539 @@
+'\" t
+.TH mtools 5 "09Jan13" 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.18
+.oh '\\*(St''%'
+.eh '%''\\*(St'
+.PP
+.SH Description
+.PP
+This manual page describes the configuration files for mtools. They
+are called \fR\&\f(CW\(if/etc/mtools.conf\(is\fR and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR. If
+the environmental variable \fR\&\f(CWMTOOLSRC\fR is set, its contents is used
+as the filename for a third configuration file. These configuration
+files describe the following items:
+.TP
+* \ Global\ configuration\ flags\ and\ variables\
+.TP
+* \ Per\ drive\ flags\ and\ variables\
+.PP
+.SS Location\ of\ the\ configuration\ files
+.PP
+.PP
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR is the system-wide configuration file,
+and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR is the user's private configuration file.
+.PP
+On some systems, the system-wide configuration file is called
+\&\fR\&\f(CW\(if/etc/default/mtools.conf\(is\fR instead.
+.PP
+.SS \ \ General\ configuration\ file\ syntax
+.PP
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon.
+Then follow variable assignments and flags. Variable assignments take
+the following form:
+.ft I
+.nf
+name=value
+.fi
+.ft R
+
+Flags are lone keywords without an equal sign and value following
+them. A section either ends at the end of the file or where the next
+section begins.
+.PP
+Lines starting with a hash (\fR\&\f(CW#\fR) are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+.PP
+.SS Default\ values
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives. Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+DOSEMU image files.
+.PP
+.SS Global\ variables
+.PP
+Global flags may be set to 1 or to 0.
+.PP
+The following global flags are recognized:
+.TP
+\&\fR\&\f(CWMTOOLS_SKIP_CHECK\fR\
+If this is set to 1, mtools skips most of its sanity checks. This is
+needed to read some Atari disks which have been made with the earlier
+ROMs, and which would not be recognized otherwise.
+.TP
+\&\fR\&\f(CWMTOOLS_FAT_COMPATIBILITY\fR\
+If this is set to 1, mtools skips the fat size checks. Some disks have
+a bigger FAT than they really need to. These are rejected if this
+option is not set.
+.TP
+\&\fR\&\f(CWMTOOLS_LOWER_CASE\fR\
+If this is set to 1, mtools displays all-upper-case short filenames as
+lowercase. This has been done to allow a behavior which is consistent
+with older versions of mtools which didn't know about the case bits.
+.TP
+\&\fR\&\f(CWMTOOLS_NO_VFAT\fR\
+If this is set to 1, mtools won't generate VFAT entries for filenames
+which are mixed-case, but otherwise legal dos filenames. This is useful
+when working with DOS versions which can't grok VFAT long names, such as
+FreeDOS.
+.TP
+\&\fR\&\f(CWMTOOLS_DOTTED_DIR\fR\
+In a wide directory, prints the short name with a dot instead of spaces
+separating the basename and the extension.
+.TP
+\&\fR\&\f(CWMTOOLS_NAME_NUMERIC_TAIL\fR\
+If this is set to one (default), generate numeric tails for all long
+names (~1). If set to zero, only generate numeric tails if otherwise a
+clash would have happened.
+.TP
+\&\fR\&\f(CWMTOOLS_TWENTY_FOUR_HOUR_CLOCK\fR\
+If 1, uses the European notation for times (twenty four hour clock),
+else uses the UK/US notation (am/pm)
+.PP
+Example:
+Inserting the following line into your configuration file instructs
+mtools to skip the sanity checks:
+
+.nf
+.ft 3
+.in +0.3i
+ MTOOLS_SKIP_CHECK=1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+Global variables may also be set via the environment:
+
+.nf
+.ft 3
+.in +0.3i
+ export MTOOLS_SKIP_CHECK=1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+Global string variables may be set to any value:
+.TP
+\&\fR\&\f(CWMTOOLS_DATE_STRING\fR\
+The format used for printing dates of files. By default, is dd-mm-yyyy.
+.PP
+.SS Per\ drive\ flags\ and\ variables
+.PP
+.SS \ \ General\ information
+.PP
+Per drive flags and values may be described in a drive section. A
+drive section starts with
+\&\fR\&\f(CWdrive\fR "\fIdriveletter\fR" :
+.PP
+Then follow variable-value pairs and flags.
+.PP
+This is a sample drive description:
+
+.nf
+.ft 3
+.in +0.3i
+ drive a:
+ file="/dev/fd0" use_xdf=1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+.SS \ \ Location\ information
+.PP
+For each drive, you need to describe where its data is physically
+stored (image file, physical device, partition, offset).
+.TP
+\&\fR\&\f(CWfile\fR\
+The name of the file or device holding the disk image. This is
+mandatory. The file name should be enclosed in quotes.
+.TP
+\&\fR\&\f(CWpartition\fR\
+Tells mtools to treat the drive as a partitioned device, and to use the
+given partition. Only primary partitions are accessible using this
+method, and they are numbered from 1 to 4. For logical partitions, use
+the more general \fR\&\f(CWoffset\fR variable. The \fR\&\f(CWpartition\fR variable
+is intended for removable media such as Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks and
+magneto-optical disks as \fR\&\f(CW\(ifgiant floppy disks\(is\fR which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partitioned devices. The \fR\&\f(CWpartition\fR flag is also useful DOSEMU
+hdimages. It is not recommended for hard disks for which direct access
+to partitions is available through mounting.
+.TP
+\&\fR\&\f(CWoffset\fR\
+Describes where in the file the MS-DOS file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system starts right at the
+beginning of the device or file.
+.PP
+.SS \ \ Disk\ Geometry\ Configuration
+.PP
+Geometry information describes the physical characteristics about the
+disk. Its has three purposes:
+.TP
+formatting\
+The geometry information is written into the boot sector of the newly
+made disk. However, you may also describe the geometry information on
+the command line. See section mformat, for details.
+.TP
+filtering\
+On some Unixes there are device nodes which only support one physical
+geometry. For instance, you might need a different node to access a disk
+as high density or as low density. The geometry is compared to the
+actual geometry stored on the boot sector to make sure that this device
+node is able to correctly read the disk. If the geometry doesn't match,
+this drive entry fails, and the next drive entry bearing the same drive
+letter is tried. See section multiple descriptions, for more details on
+supplying several descriptions for one drive letter.
+.IP
+If no geometry information is supplied in the configuration file, all
+disks are accepted. On Linux (and on SPARC) there exist device nodes
+with configurable geometry (\fR\&\f(CW\(if/dev/fd0\(is\fR, \fR\&\f(CW\(if/dev/fd1\(is\fR etc),
+and thus filtering is not needed (and ignored) for disk drives. (Mtools
+still does do filtering on plain files (disk images) in Linux: this is
+mainly intended for test purposes, as I don't have access to a Unix
+which would actually need filtering).
+.IP
+If you do not need filtering, but want still a default geometry for
+mformatting, you may switch off filtering using the \fR\&\f(CWmformat_only\fR
+flag.
+.IP
+If you want filtering, you should supply the \fR\&\f(CWfilter\fR flag. If you
+supply a geometry, you must supply one of both flags.
+.TP
+initial\ geometry\
+On devices that support it (usually floppy devices), the geometry
+information is also used to set the initial geometry. This initial
+geometry is applied while reading the boot sector, which contains the
+real geometry. If no geometry information is supplied in the
+configuration file, or if the \fR\&\f(CWmformat_only\fR flag is supplied, no
+initial configuration is done.
+.IP
+On Linux, initial geometry is not really needed, as the configurable
+devices are able to auto-detect the disk type accurately enough (for
+most common formats) to read the boot sector.
+.PP
+Wrong geometry information may lead to very bizarre errors. That's why I
+strongly recommend that you add the \fR\&\f(CWmformat_only\fR flag to your
+drive description, unless you really need filtering or initial geometry.
+.PP
+The following geometry related variables are available:
+.TP
+\&\fR\&\f(CWcylinders\fR\
+.TQ
+\&\fR\&\f(CWtracks\fR
+The number of cylinders. (\fR\&\f(CWcylinders\fR is the preferred form,
+\&\fR\&\f(CWtracks\fR is considered obsolete)
+.TP
+\&\fR\&\f(CWheads\fR\
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWsectors\fR\
+The number of sectors per track.
+.PP
+Example: the following drive section describes a 1.44M drive:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ drive a:
+ file="/dev/fd0H1440"
+ fat_bits=12
+ cylinders=80 heads=2 sectors=18
+ mformat_only
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The following shorthand geometry descriptions are available:
+.TP
+\&\fR\&\f(CW1.44m\fR\
+high density 3 1/2 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=18\fR
+.TP
+\&\fR\&\f(CW1.2m\fR\
+high density 5 1/4 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=15\fR
+.TP
+\&\fR\&\f(CW720k\fR\
+double density 3 1/2 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=9\fR
+.TP
+\&\fR\&\f(CW360k\fR\
+double density 5 1/4 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=9\fR
+.PP
+The shorthand format descriptions may be amended. For example,
+\&\fR\&\f(CW360k sectors=8\fR
+describes a 320k disk and is equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=8\fR
+.PP
+.SS \ \ Open\ Flags
+.PP
+Moreover, the following flags are available:
+.TP
+\&\fR\&\f(CWsync\fR\
+All i/o operations are done synchronously
+.TP
+\&\fR\&\f(CWnodelay\fR\
+The device or file is opened with the O_NDELAY flag. This is needed on
+some non-Linux architectures.
+.TP
+\&\fR\&\f(CWexclusive\fR\
+The device or file is opened with the O_EXCL flag. On Linux, this
+ensures exclusive access to the floppy drive. On most other
+architectures, and for plain files it has no effect at all.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Variables
+.PP
+The following general purpose drive variables are available. Depending
+to their type, these variables can be set to a string (precmd) or
+an integer (all others)
+.TP
+\&\fR\&\f(CWfat_bits\fR\
+The number of FAT bits. This may be 12 or 16. This is very rarely
+needed, as it can almost always be deduced from information in the
+boot sector. On the contrary, describing the number of fat bits may
+actually be harmful if you get it wrong. You should only use it if
+mtools gets the auto-detected number of fat bits wrong, or if you want
+to mformat a disk with a weird number of fat bits.
+.TP
+\&\fR\&\f(CWcodepage\fR\
+Describes the DOS code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+for all drives by using the global \fR\&\f(CWdefault_codepage\fR parameter
+(outside of any drive description). This parameters exists starting at
+version 4.0.0
+.TP
+\&\fR\&\f(CWprecmd\fR\
+On some variants of Solaris, it is necessary to call 'volcheck -v'
+before opening a floppy device, in order for the system to notice that
+there is indeed a disk in the drive. \fR\&\f(CWprecmd="volcheck -v"\fR in the
+drive clause establishes the desired behavior.
+.TP
+\&\fR\&\f(CWblocksize\fR\
+This parameter represents a default block size to be always used on this
+device. All I/O is done with multiples of this block size,
+independently of the sector size registered in the file system's boot
+sector. This is useful for character devices whose sector size is not
+512, such as for example CD-ROM drives on Solaris.
+.PP
+Only the \fR\&\f(CWfile\fR variable is mandatory. The other parameters may
+be left out. In that case a default value or an auto-detected value is
+used.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Flags
+.PP
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+omitted, it is enabled. For example, \fR\&\f(CWscsi\fR is equivalent to
+\&\fR\&\f(CWscsi=1\fR
+.TP
+\&\fR\&\f(CWnolock\fR\
+Instruct mtools to not use locking on this drive. This is needed on
+systems with buggy locking semantics. However, enabling this makes
+operation less safe in cases where several users may access the same
+drive at the same time.
+.TP
+\&\fR\&\f(CWscsi\fR\
+When set to 1, this option tells mtools to use raw SCSI I/O instead of
+the standard read/write calls to access the device. Currently, this is
+supported on HP-UX, Solaris and SunOS. This is needed because on some
+architectures, such as SunOS or Solaris, PC media can't be accessed
+using the \fR\&\f(CWread\fR and \fR\&\f(CWwrite\fR system calls, because the OS expects
+them to contain a Sun specific "disk label".
+.IP
+As raw SCSI access always uses the whole device, you need to specify the
+"partition" flag in addition
+.IP
+On some architectures, such as Solaris, mtools needs root privileges to
+be able to use the \fR\&\f(CWscsi\fR option. Thus mtools should be installed
+setuid root on Solaris if you want to access Zip/Jaz drives. Thus, if
+the \fR\&\f(CWscsi\fR flag is given, \fR\&\f(CWprivileged\fR is automatically
+implied, unless explicitly disabled by \fR\&\f(CWprivileged=0\fR
+.IP
+Mtools uses its root privileges to open the device, and to issue the
+actual SCSI I/O calls. Moreover, root privileges are only used for
+drives described in a system-wide configuration file such as
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR, and not for those described in
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR or \fR\&\f(CW\(if$MTOOLSRC\(is\fR.
+.TP
+\&\fR\&\f(CWprivileged\fR\
+When set to 1, this instructs mtools to use its setuid and setgid
+privileges for opening the given drive. This option is only valid for
+drives described in the system-wide configuration files (such as
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR, not \fR\&\f(CW\(if~/.mtoolsrc\(is\fR or
+\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR). Obviously, this option is also a no op if mtools is
+not installed setuid or setgid. This option is implied by 'scsi=1', but
+again only for drives defined in system-wide configuration files.
+Privileged may also be set explicitly to 0, in order to tell mtools not
+to use its privileges for a given drive even if \fR\&\f(CWscsi=1\fR is set.
+.IP
+Mtools only needs to be installed setuid if you use the
+\&\fR\&\f(CWprivileged\fR or \fR\&\f(CWscsi\fR drive variables. If you do not use
+these options, mtools works perfectly well even when not installed
+setuid root.
+.TP
+\&\fR\&\f(CWvold\fR\
+.IP
+Instructs mtools to interpret the device name as a vold identifier
+rather than as a filename. The vold identifier is translated into a
+real filename using the \fR\&\f(CWmedia_findname()\fR and
+\&\fR\&\f(CWmedia_oldaliases()\fR functions of the \fR\&\f(CWvolmgt\fR library. This
+flag is only available if you configured mtools with the
+\&\fR\&\f(CW--enable-new-vold\fR option before compilation.
+.TP
+\&\fR\&\f(CWswap\fR\
+.IP
+Consider the media as a word-swapped Atari disk.
+.TP
+\&\fR\&\f(CWuse_xdf\fR\
+If this is set to a non-zero value, mtools also tries to access this
+disk as an XDF disk. XDF is a high capacity format used by OS/2. This
+is off by default. See section XDF, for more details.
+.TP
+\&\fR\&\f(CWmformat_only\fR\
+Tells mtools to use the geometry for this drive only for mformatting and
+not for filtering.
+.TP
+\&\fR\&\f(CWfilter\fR\
+Tells mtools to use the geometry for this drive both for mformatting and
+filtering.
+.TP
+\&\fR\&\f(CWremote\fR\
+Tells mtools to connect to floppyd (see section floppyd).
+.PP
+.SS \ \ Supplying\ multiple\ descriptions\ for\ a\ drive
+.PP
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that
+fits. Descriptions may fail for several reasons:
+.TP
+1.\
+because the geometry is not appropriate,
+.TP
+2.\
+because there is no disk in the drive,
+.TP
+3.\
+or because of other problems.
+.PP
+Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry.
+Example:
+
+.nf
+.ft 3
+.in +0.3i
+ drive a: file="/dev/fd0H1440" 1.44m
+ drive a: file="/dev/fd0H720" 720k
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+.PP
+You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ drive z: file="/dev/fd0"
+ drive z: file="/dev/fd1"
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+With this description, \fR\&\f(CWmdir z:\fR accesses your first physical
+drive if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+.PP
+When using multiple configuration files, drive descriptions in the files
+parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the \fR\&\f(CWdrive+\fR or \fR\&\f(CW+drive\fR
+keywords instead of \fR\&\f(CWdrive\fR. The first adds a description to the
+end of the list (i.e. it will be tried last), and the first adds it to
+the start of the list.
+.PP
+.SS Location\ of\ configuration\ files\ and\ parsing\ order
+.PP
+The configuration files are parsed in the following order:
+.TP
+1.\
+compiled-in defaults
+.TP
+2.\
+\&\fR\&\f(CW\(if/etc/mtools.conf\(is\fR
+.TP
+3.\
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR.
+.TP
+4.\
+\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR (file pointed by the \fR\&\f(CWMTOOLSRC\fR environmental
+variable)
+.PP
+Options described in the later files override those described in the
+earlier files. Drives defined in earlier files persist if they are not
+overridden in the later files. For instance, drives A and B may be
+defined in \fR\&\f(CW\(if/etc/mtools.conf\(is\fR and drives C and D may be
+defined in \fR\&\f(CW\(if~/.mtoolsrc\(is\fR However, if \fR\&\f(CW\(if~/.mtoolsrc\(is\fR also
+defines drive A, this new description would override the description of
+drive A in \fR\&\f(CW\(if/etc/mtools.conf\(is\fR instead of adding to it. If
+you want to add a new description to a drive already described in an
+earlier file, you need to use either the \fR\&\f(CW+drive\fR or \fR\&\f(CWdrive+\fR
+keyword.
+.PP
+.SS Backwards\ compatibility\ with\ old\ configuration\ file\ syntax
+.PP
+The syntax described herein is new for version \fR\&\f(CWmtools-3.0\fR. The
+old line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+.PP
+.SH See also
+mtools
diff --git a/mtools.c b/mtools.c
new file mode 100644
index 0000000..ffac8bb
--- /dev/null
+++ b/mtools.c
@@ -0,0 +1,201 @@
+/* Copyright 1996-2004,2007-2010 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "partition.h"
+#include "vfat.h"
+
+const char *progname;
+
+static const struct dispatch {
+ const char *cmd;
+ void (*fn)(int, char **, int);
+ int type;
+} dispatch[] = {
+ {"mattrib",mattrib, 0},
+ {"mbadblocks",mbadblocks, 0},
+ {"mcat",mcat, 0},
+ {"mcd",mcd, 0},
+ {"mclasserase",mclasserase, 0},
+ {"mcopy",mcopy, 0},
+ {"mdel",mdel, 0},
+ {"mdeltree",mdel, 2},
+ {"mdir",mdir, 0},
+ {"mdoctorfat",mdoctorfat, 0},
+ {"mdu",mdu, 0},
+ {"mformat",mformat, 0},
+ {"minfo", minfo, 0},
+ {"mlabel",mlabel, 0},
+ {"mmd",mmd, 0},
+ {"mmount",mmount, 0},
+ {"mpartition",mpartition, 0},
+ {"mrd",mdel, 1},
+ {"mread",mcopy, 0},
+ {"mmove",mmove, 0},
+ {"mren",mmove, 1},
+ {"mshowfat", mshowfat, 0},
+ {"mshortname", mshortname, 0},
+ {"mtoolstest", mtoolstest, 0},
+ {"mtype",mcopy, 1},
+ {"mwrite",mcopy, 0},
+ {"mzip", mzip, 0}
+};
+#define NDISPATCH (sizeof dispatch / sizeof dispatch[0])
+
+int main(int argc,char **argv)
+{
+ unsigned int i;
+ const char *name;
+
+#ifdef HAVE_SETLOCALE
+ char *locale;
+ locale=setlocale(LC_ALL, "");
+ if(locale == NULL || !strcmp(locale, "C"))
+ setlocale(LC_ALL, "en_US");
+#endif
+
+ init_privs();
+#ifdef __EMX__
+ _wildcard(&argc,&argv);
+#endif
+
+/*#define PRIV_TEST*/
+
+#ifdef PRIV_TEST
+ {
+ int euid;
+ char command[100];
+
+ printf("INIT: %d %d\n", getuid(), geteuid());
+ drop_privs();
+ printf("DROP: %d %d\n", getuid(), geteuid());
+ reclaim_privs();
+ printf("RECLAIM: %d %d\n", getuid(), geteuid());
+ euid = geteuid();
+ if(argc & 1) {
+ drop_privs();
+ printf("DROP: %d %d\n", getuid(), geteuid());
+ }
+ if(!((argc-1) & 2)) {
+ destroy_privs();
+ printf("DESTROY: %d %d\n", getuid(), geteuid());
+ }
+ sprintf(command, "a.out %d", euid);
+ system(command);
+ return 1;
+ }
+#endif
+
+
+#ifdef __EMX__
+ _wildcard(&argc,&argv);
+#endif
+
+
+ /* check whether the compiler lays out structures in a sane way */
+ if(sizeof(struct partition) != 16 ||
+ sizeof(struct directory) != 32 ||
+ sizeof(struct vfat_subentry) !=32) {
+ fprintf(stderr,"Mtools has not been correctly compiled\n");
+ fprintf(stderr,"Recompile it using a more recent compiler\n");
+ return 137;
+ }
+
+#ifdef __EMX__
+ argv[0] = _getname(argv[0]); _remext(argv[0]); name = argv[0];
+#else
+#ifdef OS_mingw32msvc
+ _stripexe(argv[0]);
+#endif
+ name = _basename(argv[0]);
+#endif
+ progname = argv[0];
+
+ /* this allows the different tools to be called as "mtools -c <command>"
+ ** where <command> is mdir, mdel, mcopy etcetera
+ ** Mainly done for the BeOS, which doesn't support links yet.
+ */
+
+ if(argc >= 3 &&
+ !strcmp(argv[1], "-c") &&
+ !strcmp(name, "mtools")) {
+ argc-=2;
+ argv+=2;
+ name = argv[0];
+ }
+
+
+
+ /* print the version */
+ if(argc >= 2 &&
+ (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") ==0)) {
+ printf("%s (GNU mtools) %s\n",
+ name, mversion);
+ printf("configured with the following options: ");
+#ifdef USE_XDF
+ printf("enable-xdf ");
+#else
+ printf("disable-xdf ");
+#endif
+#ifdef USING_VOLD
+ printf("enable-vold ");
+#else
+ printf("disable-vold ");
+#endif
+#ifdef USING_NEW_VOLD
+ printf("enable-new-vold ");
+#else
+ printf("disable-new-vold ");
+#endif
+#ifdef DEBUG
+ printf("enable-debug ");
+#else
+ printf("disable-debug ");
+#endif
+#ifdef USE_RAWTERM
+ printf("enable-raw-term ");
+#else
+ printf("disable-raw-term ");
+#endif
+ printf("\n");
+ return 0;
+ }
+
+ read_config();
+ setup_signal();
+ for (i = 0; i < NDISPATCH; i++) {
+ if (!strcmp(name,dispatch[i].cmd))
+ dispatch[i].fn(argc, argv, dispatch[i].type);
+ }
+ if (strcmp(name,"mtools"))
+ fprintf(stderr,"Unknown mtools command '%s'\n",name);
+ fprintf(stderr,"Supported commands:");
+ for (i = 0; i < NDISPATCH; i++) {
+ if (i%8 == 0) putc('\n', stderr);
+ else fprintf(stderr, ", ");
+ fprintf(stderr, "%s", dispatch[i].cmd);
+ }
+ putc('\n', stderr);
+
+ return 1;
+}
+
+int helpFlag(int argc, char **argv) {
+ return (argc > 1 && !strcmp(argv[1], "--help"));
+}
diff --git a/mtools.conf b/mtools.conf
new file mode 100644
index 0000000..dc186df
--- /dev/null
+++ b/mtools.conf
@@ -0,0 +1,80 @@
+# Copyright 1996-1998,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+# Example mtools.conf files. Uncomment the lines which correspond to
+# your architecture and comment out the "SAMPLE FILE" line below
+SAMPLE FILE
+
+# # Linux floppy drives
+# drive a: file="/dev/fd0" exclusive
+# drive b: file="/dev/fd1" exclusive
+
+# # First SCSI hard disk partition
+# drive c: file="/dev/sda1"
+
+# # First IDE hard disk partition
+# drive c: file="/dev/hda1"
+
+# # dosemu floppy image
+# drive m: file="/var/lib/dosemu/diskimage"
+
+# # dosemu hdimage
+# drive n: file="/var/lib/dosemu/diskimage" offset=3840
+
+# # Atari ramdisk image
+# drive o: file="/tmp/atari_rd" offset=136
+
+# # ZIP disk for Solaris:
+# Drive X is ZIP-100 at target 5
+# drive X: file="/dev/rdsk/c0t5d0s2" partition=4 scsi=1 nodelay
+
+# # ZIP disk for SunOS:
+# # Zip drive is at target 5, which default kernel calls tape st1 !!
+# drive Y: file="/dev/rsd5c" partition=4 scsi=1 nodelay
+
+# # autoselect zip drive/floppy on HP-UX 9/10
+# drive a: file="/dev/rdsk/c201d5" exclusive partition=4
+# drive a: file="/dev/rdsk/c201d5s0" exclusive partition=4
+# drive a: file="/dev/rfloppy/c201d0s0" exclusive
+
+# A/UX target 5 on 1st scsi bus jaz or zip
+# drive X: file="/dev/rdsk/c105d0s31" partition=4
+
+
+# Some examples for BeOS.
+# floppy drive. hardcoded in devices.c, so no real need to define it here
+#drive a: file="/dev/floppy_disk" exclusive
+# ZIP drive on SCSI ID 6
+#drive z: file="/dev/scsi_disk_060" offset=16384 fat_bits=16
+
+# SCO Unix 3.2v4
+# # Floppy disk drives
+#
+# drive a: file="/dev/install" exclusive
+# drive b: file="/dev/install1" exclusive
+#
+# # SCSI hard disk partitions
+#
+# drive c: file="/dev/dsk/0sC"
+# drive d: file="/dev/dsk/0sD"
+# drive e: file="/dev/dsk/0sE"
+# drive f: file="/dev/dsk/0sF"
+# drive g: file="/dev/dsk/0sG"
+# drive h: file="/dev/dsk/0sH"
+
+# # uncomment the following line to display all file names in lower
+# # case by default
+# mtools_lower_case=1
diff --git a/mtools.h b/mtools.h
new file mode 100644
index 0000000..ef98e94
--- /dev/null
+++ b/mtools.h
@@ -0,0 +1,287 @@
+#ifndef MTOOLS_MTOOLS_H
+#define MTOOLS_MTOOLS_H
+/* Copyright 1996-2005,2007-2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "msdos.h"
+
+typedef struct dos_name_t dos_name_t;
+
+#if defined(OS_sco3)
+#define MAXPATHLEN 1024
+#include <signal.h>
+extern int lockf(int, int, off_t); /* SCO has no proper include file for lockf */
+#endif
+
+#define SCSI_FLAG 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);
+#ifdef HAVE_SIGACTION
+typedef struct { struct sigaction sa[4]; } saved_sig_state;
+#else
+typedef int saved_sig_state;
+#endif
+
+void allow_interrupts(saved_sig_state *ss);
+void restore_interrupts(saved_sig_state *ss);
+
+#define SET_INT(target, source) \
+if(source)target=source
+
+
+UNUSED(static __inline__ int compare (long ref, long testee))
+{
+ return (ref && ref != testee);
+}
+
+Stream_t *GetFs(Stream_t *Fs);
+
+void label_name_uc(doscp_t *cp, const char *filename, int verbose,
+ int *mangled, dos_name_t *ans);
+
+void label_name_pc(doscp_t *cp, const char *filename, int verbose,
+ int *mangled, dos_name_t *ans);
+
+/* environmental variables */
+extern unsigned int mtools_skip_check;
+extern unsigned int mtools_fat_compatibility;
+extern unsigned int mtools_ignore_short_case;
+extern unsigned int mtools_no_vfat;
+extern unsigned int mtools_numeric_tail;
+extern unsigned int mtools_dotted_dir;
+extern unsigned int mtools_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);
+void read_config(void);
+off_t str_to_offset(char *str);
+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 mshortname(int argc, char **argv, int mtype);
+void mshowfat(int argc, char **argv, int mtype);
+void mtoolstest(int argc, char **argv, int type);
+void mzip(int argc, char **argv, int type);
+
+extern int noPrivileges;
+void init_privs(void);
+void reclaim_privs(void);
+void drop_privs(void);
+void destroy_privs(void);
+uid_t get_real_uid(void);
+void closeExec(int fd);
+
+extern const char *progname;
+
+void precmd(struct device *dev);
+
+void print_sector(const char *message, unsigned char *data, int size);
+time_t getTimeNow(time_t *now);
+
+#ifdef USING_NEW_VOLD
+char *getVoldName(struct device *dev, char *name);
+#endif
+
+
+Stream_t *OpenDir(const char *filename);
+/* int unix_dir_loop(Stream_t *Stream, MainParam_t *mp);
+int unix_loop(MainParam_t *mp, char *arg); */
+
+struct dirCache_t **getDirCacheP(Stream_t *Stream);
+int isRootDir(Stream_t *Stream);
+unsigned int getStart(Stream_t *Dir, struct directory *dir);
+unsigned int countBlocks(Stream_t *Dir, unsigned int block);
+char getDrive(Stream_t *Stream);
+
+
+void printOom(void);
+int ask_confirmation(const char *, ...) __attribute__ ((format (printf, 1, 2)));
+
+int helpFlag(int, char **);
+
+char *get_homedir(void);
+#define EXPAND_BUF 2048
+const char *expand(const char *, char *);
+FILE *open_mcwd(const char *mode);
+void unlink_mcwd(void);
+
+#ifndef OS_mingw32msvc
+int safePopenOut(const char **command, char *output, int len);
+#endif
+
+#define ROUND_DOWN(value, grain) ((value) - (value) % (grain))
+#define ROUND_UP(value, grain) ROUND_DOWN((value) + (grain)-1, (grain))
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#endif
diff --git a/mtools.info b/mtools.info
new file mode 100644
index 0000000..332b042
--- /dev/null
+++ b/mtools.info
@@ -0,0 +1,2801 @@
+This is mtools.info, produced by makeinfo version 4.13 from mtools.texi.
+
+This manual is for Mtools (version 4.0.18, January 2013), 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-2011,2013 Alain Knaff.
+
+ Permission is granted to copy, distribute and/or modify this
+ document under the terms of the GNU Free Documentation License,
+ Version 1.3 or any later version published by the Free Software
+ Foundation; with no Invariant Sections, with no Front-Cover Texts,
+ and with no Back-Cover Texts. A copy of the license is included
+ in the section entitled "GNU Free Documentation License".
+
+INFO-DIR-SECTION DOS
+START-INFO-DIR-ENTRY
+* Mtools: (mtools). Mtools: utilities to access DOS disks in Unix.
+END-INFO-DIR-ENTRY
+
+
+File: mtools.info, Node: Top, Next: Location, Prev: (dir), Up: (dir)
+
+Mtools doc
+**********
+
+This is mtools' documentation.
+
+Introduction
+************
+
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS file
+system (typically a floppy disk). Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However, unnecessary
+restrictions and oddities of DOS are not emulated. For instance, it is
+possible to move subdirectories from one subdirectory to another.
+
+ Mtools is sufficient to give access to MS-DOS file systems. For
+instance, commands such as `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.18, January 2013), 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-2011,2013 Alain Knaff.
+
+ Permission is granted to copy, distribute and/or modify this
+ document under the terms of the GNU Free Documentation License,
+ Version 1.3 or any later version published by the Free Software
+ Foundation; with no Invariant Sections, with no Front-Cover Texts,
+ and with no Back-Cover Texts. A copy of the license is included
+ in the section entitled "GNU Free Documentation License".
+
+* Menu:
+
+* Location:: Where to find mtools and early bug fixes
+* Common features:: Common features of all mtools commands
+* Configuration:: How to configure mtools for your environment
+* Commands:: The available mtools commands
+* Compiling mtools:: Architecture specific compilation flags
+* Porting mtools:: Porting mtools to architectures which are not
+ yet supported
+
+* Command Index:: Command Index
+* Variable Index:: Variable Index
+* Concept Index:: Concept Index
+
+
+File: mtools.info, Node: Location, Next: Common features, Prev: Top, Up: Top
+
+1 Where to get mtools
+*********************
+
+Mtools can be found at the following places (and their mirrors):
+ http://ftp.gnu.org/gnu/mtools/mtools-4.0.18.tar.gz
+ http://mtools.linux.lu/mtools-4.0.18.tar.gz
+ ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.18.tar.gz
+ ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.18.tar.gz
+
+ Before reporting a bug, make sure that it has not yet been fixed in
+the Alpha patches which can be found at:
+ http://ftp.gnu.org/gnu/mtools/
+ http://mtools.linux.lu/
+ ftp://www.tux.org/pub/knaff/mtools
+
+ These patches are named `mtools-'VERSION`-'DDMM`.taz', where version
+stands for the base version, DD for the day and MM for the month. Due
+to a lack of space, I usually leave only the most recent patch.
+
+ There is an mtools mailing list at mtools @ tux.org . Please send
+all bug reports to this list. You may subscribe to the list by sending
+a message with 'subscribe mtools @ tux.org' in its body to majordomo @
+tux.org . (N.B. Please remove the spaces around the "@" both times. I
+left them there in order to fool spambots.) Announcements of new
+mtools versions will also be sent to the list, in addition to the Linux
+announce newsgroups. The mailing list is archived at
+http://lists.gnu.org/pipermail/info-mtools/
+
+
+File: mtools.info, Node: Common features, Next: Configuration, Prev: Location, Up: Top
+
+2 Common features of all mtools commands
+****************************************
+
+* Menu:
+
+* arguments:: What the command line parameters of mtools
+ mean
+* drive letters:: Which drives are defined by default
+* directory:: Current working directory
+* long names:: VFAT-style long filenames
+* name clashes:: Name clash handling, and associated command
+ line options
+* case sensitivity:: Case sensitivity
+* high capacity formats:: How to fit more data on your floppies
+* exit codes:: Exit codes
+* bugs:: Happens to everybody
+
+
+File: mtools.info, Node: arguments, Next: drive letters, Prev: Common features, Up: Common features
+
+2.1 Options and filenames
+=========================
+
+MS-DOS filenames are composed of a drive letter followed by a colon, a
+subdirectory, and a filename. Only the filename part is mandatory, the
+drive letter and the subdirectory are optional. Filenames without a
+drive letter refer to Unix files. Subdirectory names can use either the
+'`/'' or '`\'' separator. The use of the '`\'' separator or wildcards
+requires the names to be enclosed in quotes to protect them from the
+shell. However, wildcards in Unix filenames should not be enclosed in
+quotes, because here we *want* the shell to expand them.
+
+ The regular expression "pattern matching" routines follow the
+Unix-style rules. For example, ``*'' matches all MS-DOS files in lieu
+of ``*.*''. The archive, hidden, read-only and system attribute bits
+are ignored during pattern matching.
+
+ All options use the `-' (minus) as their first character, not `/' as
+you'd expect in MS-DOS.
+
+ Most mtools commands allow multiple filename parameters, which
+doesn't follow MS-DOS conventions, but which is more user-friendly.
+
+ Most mtools commands allow options that instruct them how to handle
+file name clashes. *Note name clashes::, for more details on these. All
+commands accept the `-V' flags which prints the version, and most
+accept the `-v' flag, which switches on verbose mode. In verbose mode,
+these commands print out the name of the MS-DOS files upon which they
+act, unless stated otherwise. *Note Commands::, for a description of
+the options which are specific to each command.
+
+
+File: mtools.info, Node: drive letters, Next: directory, Prev: arguments, Up: Common features
+
+2.2 Drive letters
+=================
+
+The meaning of the drive letters depends on the target architectures.
+However, on most target architectures, drive A is the first floppy
+drive, drive B is the second floppy drive (if available), drive J is a
+Jaz drive (if available), and drive Z is a Zip drive (if available). On
+those systems where the device name is derived from the SCSI id, the Jaz
+drive is assumed to be at SCSI target 4, and the Zip at SCSI target 5
+(factory default settings). On Linux, both drives are assumed to be the
+second drive on the SCSI bus (/dev/sdb). The default settings can be
+changes using a configuration file (*note Configuration::).
+
+ The drive letter : (colon) has a special meaning. It is used to
+access image files which are directly specified on the command line
+using the `-i' options.
+
+ Example:
+ mcopy -i my-image-file.bin ::file1 ::file2 .
+
+ This copies `file1' and `file2' from the image file
+(`my-image-file.bin') to the `/tmp' directory.
+
+ You can also supply an offset within the image file by including
+`@@'OFFSET into the file name.
+
+ Example:
+ mcopy -i my-image-file.bin@@1M ::file1 ::file2 .
+
+ This looks for the image at the offset of 1M in the file, rather than
+at its beginning.
+
+
+File: mtools.info, Node: directory, Next: long names, Prev: drive letters, Up: Common features
+
+2.3 Current working directory
+=============================
+
+The `mcd' command (*note mcd::) is used to establish the device and the
+current working directory (relative to the MS-DOS file system),
+otherwise the default is assumed to be `A:/'. However, unlike MS-DOS,
+there is only one working directory for all drives, and not one per
+drive.
+
+
+File: mtools.info, Node: long names, Next: name clashes, Prev: directory, Up: Common features
+
+2.4 VFAT-style long file names
+==============================
+
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a VFAT
+long name, and a companion short name is generated. This short name is
+what you see when you examine the disk with a pre-7.0 version of DOS.
+The following table shows some examples of short names:
+
+ Long name MS-DOS name Reason for the change
+ --------- ---------- ---------------------
+ thisisatest THISIS~1 filename too long
+ alain.knaff ALAIN~1.KNA extension too long
+ prn.txt PRN~1.TXT PRN is a device name
+ .abc ABC~1 null filename
+ hot+cold HOT_CO~1 illegal character
+
+ As you see, the following transformations happen to derive a short
+name:
+ * Illegal characters are replaced by underscores. The illegal
+ characters are `;+=[]',\"*\\<>/?:|'.
+
+ * Extra dots, which cannot be interpreted as a main name/extension
+ separator are removed
+
+ * A `~'N number is generated,
+
+ * The name is shortened so as to fit in the 8+3 limitation
+
+ The initial Unix-style file name (whether long or short) is also
+called the "primary" name, and the derived short name is also called the
+"secondary" name.
+
+ Example:
+ mcopy /etc/motd a:Reallylongname
+ Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+ mcopy /etc/motd a:motd
+ Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+
+ In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+
+ Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (`\"*\\<>/?:|'), and device names are still reserved.
+
+ Unix name Long name Reason for the change
+ --------- ---------- ---------------------
+ prn prn-1 PRN is a device name
+ ab:c ab_c-1 illegal character
+
+ As you see, the following transformations happen if a long name is
+illegal:
+ * Illegal characters are replaces by underscores,
+
+ * A `-'N number is generated,
+
+
+File: mtools.info, Node: name clashes, Next: case sensitivity, Prev: long names, Up: Common features
+
+2.5 Name clashes
+================
+
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as `mcopy', `mmd',
+`mren', `mmove'. When a name clash happens, mtools asks you what it
+should do. It offers several choices:
+
+`overwrite'
+ Overwrites the existing file. It is not possible to overwrite a
+ directory with a file.
+
+`rename'
+ Renames the newly created file. Mtools prompts for the new filename
+
+`autorename'
+ Renames the newly created file. Mtools chooses a name by itself,
+ without prompting
+
+`skip'
+ Gives up on this file, and moves on to the next (if any)
+
+ To chose one of these actions, type its first letter at the prompt.
+If you use a lower case letter, the action only applies for this file
+only, if you use an upper case letter, the action applies to all files,
+and you won't be prompted again.
+
+ You may also chose actions (for all files) on the command line, when
+invoking mtools:
+
+`-D o'
+ Overwrites primary names by default.
+
+`-D O'
+ Overwrites secondary names by default.
+
+`-D r'
+ Renames primary name by default.
+
+`-D R'
+ Renames secondary name by default.
+
+`-D a'
+ Autorenames primary name by default.
+
+`-D A'
+ Autorenames secondary name by default.
+
+`-D s'
+ Skip primary name by default.
+
+`-D S'
+ Skip secondary name by default.
+
+`-D m'
+ Ask user what to do with primary name.
+
+`-D M'
+ Ask user what to do with secondary name.
+
+ Note that for command line switches lower/upper differentiates
+between primary/secondary name whereas for interactive choices,
+lower/upper differentiates between just-this-time/always.
+
+ The primary name is the name as displayed in Windows 95 or Windows
+NT: i.e. the long name if it exists, and the short name otherwise. The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+
+ By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+
+ If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+
+
+File: mtools.info, Node: case sensitivity, Next: high capacity formats, Prev: name clashes, Up: Common features
+
+2.6 Case sensitivity of the VFAT file system
+============================================
+
+The VFAT file system is able to remember the case of the filenames.
+However, filenames which differ only in case are not allowed to coexist
+in the same directory. For example if you store a file called
+LongFileName on a VFAT file system, mdir shows this file as
+LongFileName, and not as Longfilename. However, if you then try to add
+LongFilename to the same directory, it is refused, because case is
+ignored for clash checks.
+
+ The VFAT file system allows to store the case of a filename in the
+attribute byte, if all letters of the filename are the same case, and if
+all letters of the extension are the same case too. Mtools uses this
+information when displaying the files, and also to generate the Unix
+filename when mcopying to a Unix directory. This may have unexpected
+results when applied to files written using an pre-7.0 version of DOS:
+Indeed, the old style filenames map to all upper case. This is different
+from the behavior of the old version of mtools which used to generate
+lower case Unix filenames.
+
+
+File: mtools.info, Node: high capacity formats, Next: exit codes, Prev: case sensitivity, Up: Common features
+
+2.7 high capacity formats
+=========================
+
+Mtools supports a number of formats which allow to store more data on
+disk as usual. Due to different operating system abilities, these
+formats are not supported on all operating systems. Mtools recognizes
+these formats transparently where supported.
+
+ In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+`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 manual pages included in that package for further detail: Use
+`superformat' to format all formats except XDF, and use `xdfcopy' to
+format XDF.
+
+* Menu:
+
+* more sectors:: Putting more sectors per track on the disk
+* bigger sectors:: Use bigger sectors to save header space
+* 2m:: Use a standard first track
+* XDF:: OS/2's eXtended density format
+
+
+File: mtools.info, Node: more sectors, Next: bigger sectors, Prev: high capacity formats, Up: high capacity formats
+
+2.7.1 More sectors
+------------------
+
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+
+ These formats are supported by numerous DOS shareware utilities such
+as `fdformat' and `vgacopy'. In his infinite hubris, Bill Gate$
+believed that he invented this, and called it `DMF disks', or `Windows
+formatted disks'. But in reality, it has already existed years before!
+Mtools supports these formats on Linux, on SunOS and on the DELL Unix
+PC.
+
+
+File: mtools.info, Node: bigger sectors, Next: 2m, Prev: more sectors, Up: high capacity formats
+
+2.7.2 Bigger sectors
+--------------------
+
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+_fewer_, but bigger sectors. For example, 1 sector of 4K only takes up
+header space once, whereas 8 sectors of 512 bytes have also 8 headers,
+for the same amount of useful data.
+
+ This method allows to store up to 1992K on a 3 1/2 HD disk.
+
+ Mtools supports these formats only on Linux.
+
+
+File: mtools.info, Node: 2m, Next: XDF, Prev: bigger sectors, Up: high capacity formats
+
+2.7.3 2m
+--------
+
+The 2m format was originally invented by Ciriaco Garcia de Celis. It
+also uses bigger sectors than usual in order to fit more data on the
+disk. However, it uses the standard format (18 sectors of 512 bytes
+each) on the first cylinder, in order to make these disks easier to
+handle by DOS. Indeed this method allows to have a standard sized boot
+sector, which contains a description of how the rest of the disk should
+be read.
+
+ However, the drawback of this is that the first cylinder can hold
+less data than the others. Unfortunately, DOS can only handle disks
+where each track contains the same amount of data. Thus 2m hides the
+fact that the first track contains less data by using a "shadow FAT".
+(Usually, DOS stores the FAT in two identical copies, for additional
+safety. XDF stores only one copy, but tells DOS that it stores two.
+Thus the space that would be taken up by the second FAT copy is saved.)
+This also means that you should *never use a 2m disk to store anything
+else than a DOS file system*.
+
+ Mtools supports these formats only on Linux.
+
+
+File: mtools.info, Node: XDF, Prev: 2m, Up: high capacity formats
+
+2.7.4 XDF
+---------
+
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the `use_xdf' variable for the drive in the
+configuration file. *Note Compiling mtools::, and *note miscellaneous
+variables::, for details on how to do this. Fast XDF access is only
+available for Linux kernels which are more recent than 1.1.34.
+
+ Mtools supports this format only on Linux.
+
+ *Caution / Attention distributors*: If mtools is compiled on a Linux
+kernel more recent than 1.3.34, it won't run on an older kernel.
+However, if it has been compiled on an older kernel, it still runs on a
+newer kernel, except that XDF access is slower. It is recommended that
+distribution authors only include mtools binaries compiled on kernels
+older than 1.3.34 until 2.0 comes out. When 2.0 will be out, mtools
+binaries compiled on newer kernels may (and should) be distributed.
+Mtools binaries compiled on kernels older than 1.3.34 won't run on any
+2.1 kernel or later.
+
+
+File: mtools.info, Node: exit codes, Next: bugs, Prev: high capacity formats, Up: Common features
+
+2.8 Exit codes
+==============
+
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure. All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or MINIX disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(*note global variables::)
+
+
+File: mtools.info, Node: bugs, Prev: exit codes, Up: Common features
+
+2.9 Bugs
+========
+
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver. These can be safely ignored.
+
+ The fat checking code chokes on 1.72 Mb disks mformatted with
+pre-2.0.7 mtools. Set the environmental variable
+MTOOLS_FAT_COMPATIBILITY (or the corresponding configuration file
+variable, *note global variables::) to bypass the fat checking.
+
+
+File: mtools.info, Node: Configuration, Next: Commands, Prev: Common features, Up: Top
+
+3 How to configure mtools for your environment
+**********************************************
+
+3.1 Description
+===============
+
+This sections explains the syntax of the configurations files for
+mtools. The configuration files are called `/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:
+
+* configuration file location:: Where mtools looks for its configuration files
+* general syntax:: The layout of the configuration files
+* default values:: Why you don't need a configuration file in most cases
+* global variables:: Variables that are independent of the drive
+* per drive variables:: Variables that are specific to a given drive
+* parsing order:: Location of configuration files and parsing order
+* old style configuration:: Backwards compatibility
+
+
+File: mtools.info, Node: configuration file location, Next: general syntax, Prev: Configuration, Up: Configuration
+
+3.2 Location of the configuration files
+=======================================
+
+`/etc/mtools.conf' is the system-wide configuration file, and
+`~/.mtoolsrc' is the user's private configuration file.
+
+ On some systems, the system-wide configuration file is called
+`/etc/default/mtools.conf' instead.
+
+
+File: mtools.info, Node: general syntax, Next: default values, Prev: configuration file location, Up: Configuration
+
+3.2.1 General configuration file syntax
+---------------------------------------
+
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon. Then
+follow variable assignments and flags. Variable assignments take the
+following form:
+ name=value
+ Flags are lone keywords without an equal sign and value following
+them. A section either ends at the end of the file or where the next
+section begins.
+
+ Lines starting with a hash (`#') are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+
+
+File: mtools.info, Node: default values, Next: global variables, Prev: general syntax, Up: Configuration
+
+3.3 Default values
+==================
+
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives. Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+DOSEMU image files.
+
+
+File: mtools.info, Node: global variables, Next: per drive variables, Prev: default values, Up: Configuration
+
+3.4 Global variables
+====================
+
+Global flags may be set to 1 or to 0.
+
+ The following global flags are recognized:
+
+`MTOOLS_SKIP_CHECK'
+ If this is set to 1, mtools skips most of its sanity checks. This
+ is needed to read some Atari disks which have been made with the
+ earlier ROMs, and which would not be recognized otherwise.
+
+`MTOOLS_FAT_COMPATIBILITY'
+ If this is set to 1, mtools skips the fat size checks. Some disks
+ have a bigger FAT than they really need to. These are rejected if
+ this option is not set.
+
+`MTOOLS_LOWER_CASE'
+ If this is set to 1, mtools displays all-upper-case short
+ filenames as lowercase. This has been done to allow a behavior
+ which is consistent with older versions of mtools which didn't
+ know about the case bits.
+
+`MTOOLS_NO_VFAT'
+ If this is set to 1, mtools won't generate VFAT entries for
+ filenames which are mixed-case, but otherwise legal dos filenames.
+ This is useful when working with DOS versions which can't grok
+ VFAT long names, such as FreeDOS.
+
+`MTOOLS_DOTTED_DIR'
+ In a wide directory, prints the short name with a dot instead of
+ spaces separating the basename and the extension.
+
+`MTOOLS_NAME_NUMERIC_TAIL'
+ If this is set to one (default), generate numeric tails for all
+ long names (~1). If set to zero, only generate numeric tails if
+ otherwise a clash would have happened.
+
+`MTOOLS_TWENTY_FOUR_HOUR_CLOCK'
+ If 1, uses the European notation for times (twenty four hour
+ clock), else uses the UK/US notation (am/pm)
+
+ Example: Inserting the following line into your configuration file
+instructs mtools to skip the sanity checks:
+ MTOOLS_SKIP_CHECK=1
+
+ Global variables may also be set via the environment:
+ export MTOOLS_SKIP_CHECK=1
+
+ Global string variables may be set to any value:
+`MTOOLS_DATE_STRING'
+ The format used for printing dates of files. By default, is
+ dd-mm-yyyy.
+
+
+File: mtools.info, Node: per drive variables, Next: parsing order, Prev: global variables, Up: Configuration
+
+3.5 Per drive flags and variables
+=================================
+
+* Menu:
+
+* general information:: What a drive description looks like
+* location information:: Where is the drive data physically stored
+* geometry description:: Describes the physical characteristics of
+ the media
+* open flags:: Flags passed to the open system call when the
+ device is opened
+* miscellaneous variables:: Variables which don't fit in either category
+* miscellaneous flags:: Switch variables, which can be enabled or disabled
+* multiple descriptions:: How to supply several descriptions for a
+ drive, to be tried one after the other.
+
+
+File: mtools.info, Node: general information, Next: location information, Prev: per drive variables, Up: per drive variables
+
+3.5.1 General information
+-------------------------
+
+Per drive flags and values may be described in a drive section. A drive
+section starts with `drive' "DRIVELETTER" :
+
+ Then follow variable-value pairs and flags.
+
+ This is a sample drive description:
+ drive a:
+ file="/dev/fd0" use_xdf=1
+
+
+File: mtools.info, Node: location information, Next: geometry description, Prev: general information, Up: per drive variables
+
+3.5.2 Location information
+--------------------------
+
+For each drive, you need to describe where its data is physically
+stored (image 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
+ Syquest disks, ZIP drives, and magneto-optical disks. Although
+ traditional DOS sees Syquest disks and magneto-optical disks as
+ `giant floppy disks' which are unpartitioned, OS/2 and Windows NT
+ treat them like hard disks, i.e. partitioned 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 file system starts. This is
+ useful for logical partitions in DOSEMU hdimages, and for ATARI
+ ram disks. By default, this is zero, meaning that the file system
+ starts right at the beginning of the device or file.
+
+
+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 Unixes there are device nodes which only support one
+ physical geometry. For instance, you might need a different node
+ to access a disk as high density or as low density. The geometry
+ is compared to the actual geometry stored on the boot sector to
+ make sure that this device node is able to correctly read the
+ disk. If the geometry doesn't match, this drive entry fails, and
+ the next drive entry bearing the same drive letter is tried. *Note
+ multiple descriptions::, for more details on supplying several
+ descriptions for one drive letter.
+
+ If no geometry information is supplied in the configuration file,
+ all disks are accepted. On Linux (and on SPARC) there exist device
+ nodes with configurable geometry (`/dev/fd0', `/dev/fd1' etc), and
+ thus filtering is not needed (and ignored) for disk drives.
+ (Mtools still does do filtering on plain files (disk images) in
+ Linux: this is mainly intended for test purposes, as I don't have
+ access to a Unix which would actually need filtering).
+
+ If you do not need filtering, but want still a default geometry for
+ mformatting, you may switch off filtering using the `mformat_only'
+ flag.
+
+ If you want filtering, you should supply the `filter' flag. If you
+ supply a geometry, you must supply one of both flags.
+
+initial geometry
+ On devices that support it (usually floppy devices), the geometry
+ information is also used to set the initial geometry. This initial
+ geometry is applied while reading the boot sector, which contains
+ the real geometry. If no geometry information is supplied in the
+ configuration file, or if the `mformat_only' flag is supplied, no
+ initial configuration is done.
+
+ On Linux, initial geometry is not really needed, as the
+ configurable devices are able to auto-detect the disk type
+ accurately enough (for most common formats) to read the boot
+ sector.
+
+ Wrong geometry information may lead to very bizarre errors. That's
+why I strongly recommend that you add the `mformat_only' flag to your
+drive description, unless you really need filtering or initial geometry.
+
+ The following geometry related variables are available:
+
+`cylinders'
+`tracks'
+ The number of cylinders. (`cylinders' is the preferred form,
+ `tracks' is considered obsolete)
+
+`heads'
+ The number of heads (sides).
+
+`sectors'
+ The number of sectors per track.
+
+ Example: the following drive section describes a 1.44M drive:
+
+ drive a:
+ file="/dev/fd0H1440"
+ fat_bits=12
+ cylinders=80 heads=2 sectors=18
+ mformat_only
+
+ The following shorthand geometry descriptions are available:
+
+`1.44m'
+ high density 3 1/2 disk. Equivalent to: `fat_bits=12 cylinders=80
+ heads=2 sectors=18'
+
+`1.2m'
+ high density 5 1/4 disk. Equivalent to: `fat_bits=12 cylinders=80
+ heads=2 sectors=15'
+
+`720k'
+ double density 3 1/2 disk. Equivalent to: `fat_bits=12
+ cylinders=80 heads=2 sectors=9'
+
+`360k'
+ double density 5 1/4 disk. Equivalent to: `fat_bits=12
+ cylinders=40 heads=2 sectors=9'
+
+ The shorthand format descriptions may be amended. For example, `360k
+sectors=8' describes a 320k disk and is equivalent to: `fat_bits=12
+cylinders=40 heads=2 sectors=8'
+
+
+File: mtools.info, Node: open flags, Next: miscellaneous variables, Prev: geometry description, Up: per drive variables
+
+3.5.4 Open Flags
+----------------
+
+Moreover, the following flags are available:
+
+`sync'
+ All i/o operations are done synchronously
+
+`nodelay'
+ The device or file is opened with the O_NDELAY flag. This is
+ needed on some non-Linux architectures.
+
+`exclusive'
+ The device or file is opened with the O_EXCL flag. On Linux, this
+ ensures exclusive access to the floppy drive. On most other
+ architectures, and for plain files it has no effect at all.
+
+
+File: mtools.info, Node: miscellaneous variables, Next: miscellaneous 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 auto-detected number of fat bits wrong, or if you
+ want to mformat a disk with a weird number of fat bits.
+
+`codepage'
+ Describes the DOS code page used for short filenames. This is a
+ number between 1 and 999. By default, code page 850 is used. The
+ reason for this is because this code page contains most of the
+ characters that are also available in ISO-Latin-1. You may also
+ specify a global code page for all drives by using the global
+ `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,
+ independently of the sector size registered in the file system's
+ boot sector. This is useful for character devices whose sector
+ size is not 512, such as for example CD-ROM drives on Solaris.
+
+
+ Only the `file' variable is mandatory. The other parameters may be
+left out. In that case a default value or an auto-detected value is
+used.
+
+
+File: mtools.info, Node: miscellaneous flags, Next: multiple descriptions, Prev: miscellaneous 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
+omitted, 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' system calls,
+ because the OS expects them to contain a Sun specific "disk label".
+
+ As raw SCSI access always uses the whole device, you need to
+ specify the "partition" flag in addition
+
+ On some architectures, such as Solaris, mtools needs root
+ privileges to be able to use the `scsi' option. Thus mtools
+ should be installed setuid 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 `/etc/mtools.conf', and not for those described in
+ `~/.mtoolsrc' or `$MTOOLSRC'.
+
+`privileged'
+ When set to 1, this instructs mtools to use its setuid and setgid
+ privileges for opening the given drive. This option is only valid
+ for drives described in the system-wide configuration files (such
+ as `/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 explicitly to 0, in order to tell
+ mtools not to use its privileges for a given drive even if
+ `scsi=1' is set.
+
+ Mtools only needs to be installed setuid if you use the
+ `privileged' or `scsi' drive variables. If you do not use these
+ options, mtools works perfectly well even when not installed
+ setuid root.
+
+`vold'
+ Instructs mtools to interpret the device name as a vold identifier
+ rather than as a filename. The vold identifier is translated into
+ a real filename using the `media_findname()' and
+ `media_oldaliases()' functions of the `volmgt' library. This flag
+ is only available if you configured mtools with the
+ `--enable-new-vold' option before compilation.
+
+`swap'
+ Consider the media as a word-swapped Atari disk.
+
+`use_xdf'
+ If this is set to a non-zero value, mtools also tries to access
+ this disk as an XDF disk. XDF is a high capacity format used by
+ OS/2. This is off by default. *Note XDF::, for more details.
+
+`mformat_only'
+ Tells mtools to use the geometry for this drive only for
+ mformatting and not for filtering.
+
+`filter'
+ Tells mtools to use the geometry for this drive both for
+ mformatting and filtering.
+
+`remote'
+ Tells mtools to connect to floppyd (*note floppyd::).
+
+
+File: mtools.info, Node: multiple descriptions, Prev: miscellaneous flags, Up: per drive variables
+
+3.5.7 Supplying multiple descriptions for a drive
+-------------------------------------------------
+
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that fits.
+Descriptions may fail for several reasons:
+
+ 1. because the geometry is not appropriate,
+
+ 2. because there is no disk in the drive,
+
+ 3. or because of other problems.
+
+ Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry. Example:
+ drive a: file="/dev/fd0H1440" 1.44m
+ drive a: file="/dev/fd0H720" 720k
+
+ This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+
+ You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+
+ drive z: file="/dev/fd0"
+ drive z: file="/dev/fd1"
+
+ With this description, `mdir z:' accesses your first physical drive
+if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+
+ When using multiple configuration files, drive descriptions in the
+files parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the `drive+' or `+drive' keywords
+instead of `drive'. The first adds a description to the end of the list
+(i.e. it will be tried last), and the first adds it to the start of the
+list.
+
+
+File: mtools.info, Node: parsing order, Next: old style configuration, 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. `/etc/mtools.conf'
+
+ 3. `~/.mtoolsrc'.
+
+ 4. `$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 `/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
+`/etc/mtools.conf' instead of adding to it. If you want to add a new
+description to a drive already described in an earlier file, you need
+to use either the `+drive' or `drive+' keyword.
+
+
+File: mtools.info, Node: old style configuration, Prev: parsing order, Up: Configuration
+
+3.7 Backwards compatibility with old configuration file syntax
+==============================================================
+
+The syntax described herein is new for version `mtools-3.0'. The old
+line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+
+
+File: mtools.info, Node: Commands, Next: Compiling mtools, Prev: Configuration, Up: Top
+
+4 Command list
+**************
+
+This section describes the available mtools commands, and the command
+line parameters that each of them accepts. Options which are common to
+all mtools commands are not described here, *note arguments:: for a
+description of those.
+
+* Menu:
+
+* floppyd:: floppy daemon to run on your X server box
+* floppyd_installtest:: small utility to check for the presence of floppyd
+* mattrib:: change MS-DOS file attribute flags
+* mbadblocks:: tests a floppy disk, and marks the bad blocks in the FAT
+* mcat:: same as cat. Only useful with floppyd.
+* mcd:: change MS-DOS directory
+* mclasserase:: erase memory card
+* mcopy:: copy MS-DOS files to/from Unix
+* mdel:: delete an MS-DOS file
+* mdeltree:: recursively delete an MS-DOS directory
+* mdir:: display an MS-DOS directory
+* mdu:: list space occupied by directory and its contents
+* mformat:: add an MS-DOS file system to a low-level formatted floppy disk
+* minfo:: get information about an MS-DOS file system.
+* mlabel:: make an MS-DOS volume label
+* mkmanifest:: makes a list of short name equivalents
+* mmd:: make an MS-DOS subdirectory
+* mmount:: mount an MS-DOS disk
+* mpartition:: create an MS-DOS as a partition
+* mrd:: remove an MS-DOS subdirectory
+* mmove:: move or rename an MS-DOS file or subdirectory
+* mren:: rename an existing MS-DOS file
+* mshortname:: shows the short name of a file
+* mshowfat:: shows the FAT map of a file
+* mtoolstest:: tests and displays the configuration
+* mtype:: display contents of an MS-DOS file
+* mzip:: zip disk specific commands
+
+
+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 daemon 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 multi homed hosts). This flag implies daemon mode
+
+`r USER'
+ Run the server under as the given user
+
+`x DISPLAY'
+ X display to use for authentication. By default, this is taken
+ from the `DISPLAY' variable. If neither the `x' attribute is
+ present nor `DISPLAY' is set, floppyd uses `:0.0'.
+
+ DEVICENAMES is a list of device nodes to be opened. Default is
+`/dev/fd0'. Multiple devices are only supported on mtools versions
+newer than 3.9.11.
+
+4.1.3 Connecting to floppyd
+---------------------------
+
+In order to use floppyd, add the flag `remote' to the device
+description in your `~/.mtoolsrc' file. If the flag `remote' is given,
+the `file' parameter of the device description is taken to be a remote
+address. It's format is the following:
+HOSTNAME`:'DISPLAYNUMBER[`/'[BASEPORT][`/'DRIVE]]. When using this
+entry, mtools connects to port BASEPORT+DISPLAYNUMBER at HOSTNAME. By
+default BASEPORT is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+
+4.1.4 Examples:
+---------------
+
+The following starts a floppy daemon giving access to `/dev/fd0',
+listening on the default port 5703, tied to the default X servers:
+
+ floppyd -d /dev/fd0
+
+ Each of the following starts a floppy daemon giving access to
+`/dev/fd1', tied to the :1 local X servers, and listening on port 5704.
+We assume that the local host is named `hitchhiker'.
+
+ floppyd -d /dev/fd0
+ floppyd -d -x :1 -p 5704 /dev/fd0
+
+ If you want to start floppyd by `inetd' instead of running it as a
+daemon, insert the following lines into `/etc/services':
+ # floppy daemon
+ floppyd-0 5703/tcp # floppy daemon for X server :0
+ floppyd-1 5704/tcp # floppy daemon for X server :1
+
+ And insert the following into `/etc/inetd.conf' (assuming that you
+have defined a user named floppy in your `/etc/passwd'):
+
+ # floppy daemon
+ floppyd-0 stream tcp wait floppy /usr/sbin/floppyd floppyd /dev/fd0
+ floppyd-1 stream tcp wait floppy /usr/sbin/floppyd floppyd -x :1 /dev/fd0
+
+ Note that you need to supply the X display names for the second
+floppyd. This is because the port is opened by inetd.conf, and hence
+floppyd cannot know its number to interfere the display number.
+
+ On the client side, insert the following into your `~/.mtoolsrc' to
+define a drive letter accessing floppy drive in your X terminal:
+ drive x: file="$DISPLAY" remote
+
+ If your X terminal has more than one drive, you may access the
+additional drives as follows:
+ drive y: file="$DISPLAY//1" remote
+ drive z: file="$DISPLAY//2" remote
+
+
+File: mtools.info, Node: floppyd_installtest, Next: mattrib, Prev: floppyd, Up: Commands
+
+4.2 Floppyd_installtest
+=======================
+
+`Floppyd_installtest' is used to check for the presence of a running
+floppyd daemon. This is useful, if you have a small front-end script to
+mtools, which decides whether to use floppyd or not.
+
+ `floppyd_installtest' [`-f'] Connect-String
+
+ If the `-f' option is specified, `floppyd_installtest' does a full
+X-Cookie authentication and complains if this does not work.
+
+ The connect-String has the format described in the floppyd-section:
+HOSTNAME`:'DISPLAYNUMBER[`/'BASEPORT]
+
+
+File: mtools.info, Node: mattrib, Next: mbadblocks, Prev: floppyd_installtest, Up: Commands
+
+4.3 Mattrib
+===========
+
+`Mattrib' is used to change MS-DOS file attribute flags. It has the
+following syntax:
+
+ `mattrib' [`-a|+a'] [`-h|+h'] [`-r|+r'] [`-s|+s'] [`-/'] [`-p']
+[`-X'] MSDOSFILE [ MSDOSFILES ... ]
+
+ `Mattrib' adds attribute flags to an MS-DOS file (with the ``+''
+operator) or remove attribute flags (with the ``-'' operator).
+
+ `Mattrib' supports the following attribute bits:
+
+`a'
+ Archive bit. Used by some backup programs to indicate a new file.
+
+`r'
+ Read-only bit. Used to indicate a read-only file. Files with
+ this bit set cannot be erased by `DEL' nor modified.
+
+`s'
+ System bit. Used by MS-DOS to indicate a operating system file.
+
+`h'
+ Hidden bit. Used to make files hidden from `DIR'.
+
+ `Mattrib' supports the following command line flags:
+`/'
+ Recursive. Recursively list the attributes of the files in the
+ subdirectories.
+
+`X'
+ Concise. Prints the attributes without any whitespace padding. If
+ neither the "/" option is given, nor the MSDOSFILE contains a
+ wildcard, and there is only one MS-DOS file parameter on the
+ command line, only the attribute is printed, and not the filename.
+ This option is convenient for scripts
+
+`p'
+ Replay mode. Outputs a series of mformat commands that will
+ reproduce the current situation, starting from a situation as left
+ by untarring the MS-DOS file system. Commands are only output for
+ attribute settings that differ from the default (archive bit set
+ for files, unset for directories). This option is intended to be
+ used in addition to tar. The `readonly' attribute is not taken
+ into account, as tar can set that one itself.
+
+
+File: mtools.info, Node: mbadblocks, Next: mcat, Prev: mattrib, Up: Commands
+
+4.4 Mbadblocks
+==============
+
+The `mbadblocks' command is used to mark some clusters on an MS-DOS
+filesystem bad. It has the following syntax:
+
+ `mbadblocks' [`-s' SECTORLIST|`-c' CLUSTERLIST|-w] DRIVE`:'
+
+ If no command line flags are supplied, `Mbadblocks' scans an MS-DOS
+filesystem for bad blocks by simply trying to read them and flag them
+if read fails. All blocks that are unused are scanned, and if detected
+bad are marked as such in the FAT.
+
+ This command is intended to be used right after `mformat'. It is
+not intended to salvage data from bad disks.
+
+4.4.1 Command line options
+--------------------------
+
+`c FILE'
+ Use a list of bad clusters, rather than scanning for bad clusters
+ itself.
+
+`s FILE'
+ Use a list of bad sectors (counted from beginning of filesystem),
+ rather than trying for bad clusters itself.
+
+`w'
+ Write a random pattern to each cluster, then read it back and flag
+ cluster as bad if mismatch. Only free clusters are tested in such a
+ way, so any file data is preserved.
+
+4.4.2 Bugs
+----------
+
+`Mbadblocks' should (but doesn't yet :-( ) also try to salvage bad
+blocks which are in use by reading them repeatedly, and then mark them
+bad.
+
+
+File: mtools.info, Node: mcat, Next: mcd, Prev: mbadblocks, Up: Commands
+
+4.5 Mcat
+========
+
+The `mcat' command is used to copy an entire disk image from or to the
+floppy device. It uses the following syntax:
+
+ `mcat' [`-w'] DRIVE`:'
+
+ `Mcat' performs the same task as the Unix `cat' command. It is
+included into the mtools package, since `cat' cannot access remote
+floppy devices offered by the mtools floppy daemon. Now it is possible
+to create boot floppies remotely.
+
+ The default operation is reading. The output is written to stdout.
+
+ If the `-w' option is specified, mcat reads a disk-image from stdin
+and writes it to the given device. *Use this carefully!* Because of
+the low-level nature of this command, it will happily destroy any data
+written before on the disk without warning!
+
+
+File: mtools.info, Node: mcd, Next: mclasserase, Prev: mcat, Up: Commands
+
+4.6 Mcd
+=======
+
+The `mcd' command is used to change the mtools working directory on the
+MS-DOS disk. It uses the following syntax:
+
+ `mcd' [MSDOSDIRECTORY]
+
+ Without arguments, `mcd' reports the current device and working
+directory. Otherwise, `mcd' changes the current device and current
+working directory relative to an MS-DOS file system.
+
+ The environmental variable `MCWD' may be used to locate the file
+where the device and current working directory information is stored.
+The default is `$HOME/.mcwd'. Information in this file is ignored if
+the file is more than 6 hours old.
+
+ `Mcd' returns 0 on success or 1 on failure.
+
+ Unlike MS-DOS versions of `CD', `mcd' can be used to change to
+another device. It may be wise to remove old `.mcwd' files at logout.
+
+
+File: mtools.info, Node: mclasserase, Next: mcopy, Prev: mcd, Up: Commands
+
+4.7 Mclasserase
+===============
+
+The `mclasserase' command is used to wipe memory cards by overwriting
+it three times: first with `0xff', then with `0x00', then with `0xff'
+again. The command uses the following syntax:
+
+ `mclasserase' [`-d'] MSDOSDRIVE
+
+ MS-DOS drive is optional, if none is specified, use `A:'. If more
+than one drive are specified, all but the last are ignored.
+
+ `Mclasserase' accepts the following command line options:
+
+`d'
+ Stop after each erase cycle, for testing purposes
+
+`p'
+ Not yet implemented
+
+ `Mclasserase' returns 0 on success or -1 on failure.
+
+
+File: mtools.info, Node: mcopy, Next: mdel, Prev: mclasserase, Up: Commands
+
+4.8 Mcopy
+=========
+
+The `mcopy' command is used to copy MS-DOS files to and from Unix. It
+uses the following syntax:
+
+ `mcopy' [`-bspanvmQT'] [`-D' CLASH_OPTION] SOURCEFILE TARGETFILE
+ `mcopy' [`-bspanvmQT'] [`-D' CLASH_OPTION] SOURCEFILE [ SOURCEFILES... ] TARGETDIRECTORY
+ `mcopy' [`-tnvm'] MSDOSSOURCEFILE
+
+ `Mcopy' copies the specified file to the named file, or copies
+multiple files to the named directory. The source and target can be
+either MS-DOS or Unix files.
+
+ The use of a drive letter designation on the MS-DOS files, 'a:' for
+example, determines the direction of the transfer. A missing drive
+designation implies a Unix file whose path starts in the current
+directory. If a source drive letter is specified with no attached file
+name (e.g. `mcopy a: .'), all files are copied from that drive.
+
+ If only a single, MS-DOS source parameter is provided (e.g. "mcopy
+a:foo.exe"), an implied destination of the current directory (``.'') is
+assumed.
+
+ A filename of ``-'' means standard input or standard output,
+depending on its position on the command line.
+
+ `Mcopy' accepts the following command line options:
+
+`t'
+ Text file transfer. Mcopy translates incoming carriage return/line
+ feeds to line feeds when copying from MS-DOS to Unix, and
+ vice-versa when copying from Unix to MS-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. `ASCII' translates incoming carriage
+ return/line feeds to line feeds.
+
+`T'
+ Text (ASCII) file transfer with character set conversion. Differs
+ from `-a' in the `ASCII' also translates incoming PC-8 characters
+ to ISO-8859-1 equivalents as far as possible. When reading DOS
+ files, untranslatable characters are replaced by '`#''; when
+ writing DOS files, untranslatable characters are replaced by '`.''.
+
+`n'
+ No confirmation when overwriting Unix files. `ASCII' doesn't warn
+ the user when overwriting an existing Unix file. If the target
+ file already exists, and the `-n' option is not in effect, `mcopy'
+ asks whether to overwrite the file or to rename the new file
+ (*note name clashes::) for details). In order to switch off
+ confirmation for DOS files, use `-o'.
+
+`m'
+ Preserve the file modification time.
+
+`v'
+ Verbose. Displays the name of each file as it is copied.
+
+4.8.1 Bugs
+----------
+
+Unlike MS-DOS, the '+' operator (append) from MS-DOS is not supported.
+However, you may use `mtype' to produce the same effect:
+ mtype a:file1 a:file2 a:file3 >unixfile
+ mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile
+
+
+File: mtools.info, Node: mdel, Next: mdeltree, Prev: mcopy, Up: Commands
+
+4.9 Mdel
+========
+
+The `mdel' command is used to delete an MS-DOS file. Its syntax is:
+
+ `mdel' [`-v'] MSDOSFILE [ MSDOSFILES ... ]
+
+ `Mdel' deletes files on an MS-DOS file system.
+
+ `Mdel' asks for verification prior to removing a read-only file.
+
+
+File: mtools.info, Node: mdeltree, Next: mdir, Prev: mdel, Up: Commands
+
+4.10 Mdeltree
+=============
+
+The `mdeltree' command is used to delete an MS-DOS file. Its syntax is:
+
+ `mdeltree' [`-v'] MSDOSDIRECTORY [MSDOSDIRECTORIES...]
+
+ `Mdeltree' removes a directory and all the files and subdirectories
+it contains from an MS-DOS file system. An error occurs if the directory
+to be removed does not exist.
+
+
+File: mtools.info, Node: mdir, Next: mdu, Prev: mdeltree, Up: Commands
+
+4.11 Mdir
+=========
+
+The `mdir' command is used to display an MS-DOS directory. Its syntax
+is:
+
+ `mdir' [`-/'] [`-f'] [`-w'] [`-a'] [`-b'] MSDOSFILE [ MSDOSFILES...]
+
+ `Mdir' displays the contents of MS-DOS directories, or the entries
+for some MS-DOS files.
+
+ `Mdir' supports the following command line options:
+
+`/'
+ Recursive output, just like MS-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
+ file systems, which store the size explicitly.
+
+`b'
+ Concise listing. Lists each directory name or filename, one per
+ line (including the filename extension). This switch displays no
+ heading information and no summary. Only a newline separated list
+ of pathnames is displayed.
+
+ An error occurs if a component of the path is not a directory.
+
+
+File: mtools.info, Node: mdu, Next: mformat, Prev: mdir, Up: Commands
+
+4.12 Mdu
+========
+
+`Mdu' is used to list the space occupied by a directory, its
+subdirectories and its files. It is similar to the `du' command on
+Unix. The unit used are clusters. Use the minfo command to find out
+the cluster size.
+
+ `mdu' [`-a'] [ MSDOSFILES ... ]
+
+`a'
+ All files. List also the space occupied for individual files.
+
+`s'
+ Only list the total space, don't give details for each
+ subdirectory.
+
+
+File: mtools.info, Node: mformat, Next: mkmanifest, Prev: mdu, Up: Commands
+
+4.13 Mformat
+============
+
+The `mformat' command is used to add an MS-DOS file system to a
+low-level formatted diskette. Its syntax is:
+
+ `mformat' [`-t' CYLINDERS|`-T' TOT_SECTORS] [`-h' HEADS] [`-s' SECTORS]
+ [`-f' SIZE] [`-1'] [`-4'] [`-8']
+ [`-v' VOLUME_LABEL]
+ [`-F'] [`-S' SIZECODE]
+ [`-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]
+ [`-K' BACKUP_BOOT]
+ [`-c' CLUSTERS_PER_SECTOR]
+ [`-d' FAT_COPIES]
+ [`-X'] [`-2' SECTORS_ON_TRACK_0] [`-3']
+ [`-0' RATE_ON_TRACK_0] [`-A' RATE_ON_OTHER_TRACKS]
+ DRIVE:
+
+ `Mformat' adds a minimal MS-DOS file system (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+
+ The following options are supported: (The S, 2, 1 and M options may
+not exist if this copy of mtools has been compiled without the USE_2M
+option)
+
+ The following options are the same as for MS-DOS's format command:
+
+`v'
+ Specifies the volume label. A volume label identifies the disk and
+ can be a maximum of 11 characters. If you omit the -v switch,
+ mformat will assign no label to the disk.
+
+`f'
+ Specifies the size of the DOS file system to format. Only a certain
+ number of predefined sizes are supported by this flag; for others
+ use the -h/-t/-s flags. The following sizes are supported:
+ 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.
+
+`T'
+ Specifies the number of total sectors on the disk. Only one of
+ these 2 options may be specified (tracks or total sectors)
+
+`h'
+ The number of heads (sides).
+
+`s'
+ Specifies the number of sectors per track. If the 2m option is
+ given, number of 512-byte sector equivalents on generic tracks
+ (i.e. not head 0 track 0). If the 2m option is not given, number
+ of physical sectors per track (which may be bigger than 512 bytes).
+
+`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.
+
+
+ MS-DOS 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 size code. 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 file system. 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 file system 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 boot sector stored in the given file or device, instead of
+ using its own. Only the geometry fields are updated to match the
+ target disks parameters.
+
+`k'
+ Keep the existing boot sector as much as possible. Only the
+ geometry fields and other similar file system data are updated to
+ match the target disks parameters.
+
+`K'
+ Sets the sector number where the backup of the boot sector should
+ be stored (only relevant on FAT32).
+
+`m'
+ Use a non-standard media descriptor byte for this disk. The media
+ descriptor is stored at position 21 of the boot sector, and as
+ first byte in each FAT copy. Using this option may confuse DOS or
+ older mtools version, and may make the disk unreadable. Only use
+ if you know what you are doing.
+
+
+ To format a diskette at a density other than the default, you must
+supply (at least) those command line parameters that are different from
+the default.
+
+ `Mformat' returns 0 on success or 1 on failure.
+
+ It doesn't record bad block information to the Fat, use `mbadblocks'
+for that.
+
+
+File: mtools.info, Node: mkmanifest, Next: minfo, Prev: mformat, Up: Commands
+
+4.14 Mkmanifest
+===============
+
+The `mkmanifest' command is used to create a shell script (packing
+list) to restore Unix filenames. Its syntax is:
+
+ `mkmanifest' [ FILES ]
+
+ `Mkmanifest' creates a shell script that aids in the restoration of
+Unix filenames that got clobbered by the MS-DOS filename restrictions.
+MS-DOS filenames are restricted to 8 character names, 3 character
+extensions, upper case only, no device names, and no illegal characters.
+
+ The mkmanifest program is compatible with the methods used in
+`pcomm, arc,' and `mtools' to change perfectly good Unix filenames to
+fit the MS-DOS restrictions. This command is only useful if the target
+system which will read the diskette cannot handle VFAT long names.
+
+4.14.1 Example
+--------------
+
+You want to copy the following Unix files to a MS-DOS diskette (using
+the `mcopy' command).
+
+ very_long_name
+ 2.many.dots
+ illegal:
+ good.c
+ prn.dev
+ Capital
+
+ `ASCII' converts the names to:
+
+ very_lon
+ 2xmany.dot
+ illegalx
+ good.c
+ xprn.dev
+ capital
+
+ The command:
+ mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest
+ would produce the following:
+ mv very_lon very_long_name
+ mv 2xmany.dot 2.many.dots
+ mv illegalx illegal:
+ mv xprn.dev prn.dev
+ mv capital Capital
+
+ Notice that "good.c" did not require any conversion, so it did not
+appear in the output.
+
+ Suppose I've copied these files from the diskette to another Unix
+system, and I now want the files back to their original names. If the
+file "manifest" (the output captured above) was sent along with those
+files, it could be used to convert the filenames.
+
+4.14.2 Bugs
+-----------
+
+The short names generated by `mkmanifest' follow the old convention
+(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0.
+
+
+File: mtools.info, Node: minfo, Next: mlabel, Prev: mkmanifest, Up: Commands
+
+4.15 Minfo
+==========
+
+The `minfo' command prints the parameters of a MS-DOS file system, such
+as number of sectors, heads and cylinders. It also prints an mformat
+command line which can be used to create a similar MS-DOS file system on
+another media. However, this doesn't work with 2m or XDF media, and
+with MS-DOS 1.0 file systems
+ `minfo' DRIVE:
+
+ Minfo supports the following option:
+`v'
+ Prints a hexdump of the boot sector, in addition to the other
+ information
+
+
+File: mtools.info, Node: mlabel, Next: mmd, Prev: minfo, Up: Commands
+
+4.16 Mlabel
+===========
+
+The `mlabel' command adds a volume label to a disk. Its syntax is:
+ `mlabel' [`-vcsn'] [`-N' SERIAL] DRIVE:[NEW_LABEL]
+
+ `Mlabel' displays the current volume label, if present. If NEW_LABEL
+is not given, and if neither the `c' nor the `s' options are set, it
+prompts the user for a new volume label. To delete an existing volume
+label, press return at the prompt.
+
+ The label is limited to 11 single-byte characters, e.g.
+`Name1234567'.
+
+ Reasonable care is taken to create a valid MS-DOS volume label. If
+an invalid label is specified, `mlabel' changes the label (and displays
+the new label if the verbose mode is set). `Mlabel' returns 0 on
+success or 1 on failure.
+
+ Mlabel supports the following options:
+`c'
+ Clears an existing label, without prompting the user
+
+`s'
+ Shows the existing label, without prompting the user.
+
+`n'
+ Assigns a new (random) serial number to the disk
+
+`N SERIAL'
+ Sets the supplied serial number. The serial number should be
+ supplied as an 8 digit hexadecimal number, without spaces
+
+
+File: mtools.info, Node: mmd, Next: mmount, Prev: mlabel, Up: Commands
+
+4.17 Mmd
+========
+
+The `mmd' command is used to make an MS-DOS subdirectory. Its syntax is:
+
+ `mmd' [`-D' CLASH_OPTION] MSDOSDIRECTORY [ MSDOSDIRECTORIES... ]
+
+ `Mmd' makes a new directory on an MS-DOS file system. An error occurs
+if the directory already exists.
+
+
+File: mtools.info, Node: mmount, Next: mmove, Prev: mmd, Up: Commands
+
+4.18 Mmount
+===========
+
+The `mmount' command is used to mount an MS-DOS disk. It is only
+available on Linux, as it is only useful if the OS kernel allows to
+configure the disk geometry. Its syntax is:
+
+ `mmount' MSDOSDRIVE [MOUNTARGS]
+
+ `Mmount' reads the boot sector of an MS-DOS disk, configures the
+drive geometry, and finally mounts it passing `mountargs' to `mount. '
+If no mount arguments are specified, the name of the device is used. If
+the disk is write protected, it is automatically mounted read only.
+
+
+File: mtools.info, Node: mmove, Next: mpartition, Prev: mmount, Up: Commands
+
+4.19 Mmove
+==========
+
+The `mmove' command is used to moves or renames an existing MS-DOS file
+or subdirectory.
+ `mmove' [`-v'] [`-D' CLASH_OPTION] SOURCEFILE TARGETFILE
+ `mmove' [`-v'] [`-D' CLASH_OPTION] SOURCEFILE [ SOURCEFILES... ] TARGETDIRECTORY
+ `Mmove' moves or renames an existing MS-DOS file or subdirectory.
+Unlike the MS-DOS version of `MOVE', `mmove' is able to move
+subdirectories. Files or directories can only be moved within one file
+system. Data cannot be moved from MS-DOS to Unix or vice-versa. If you
+omit the drive letter from the target file or directory, the same
+letter as for the source is assumed. If you omit the drive letter from
+all parameters, drive a: is assumed by default.
+
+
+File: mtools.info, Node: mpartition, Next: mrd, Prev: mmove, Up: Commands
+
+4.20 Mpartition
+===============
+
+The `mpartition' command is used to create MS-DOS file systems as
+partitions. This is intended to be used on non-Linux systems, i.e.
+systems where fdisk and easy access to SCSI devices are not available.
+This command only works on drives whose partition variable is set.
+
+ `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'
+ "Deactivates" 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 neighboring
+ 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 consistency checks, such as checking
+ for overlaps and proper alignment of the partitions. If any of
+ these checks fails, the partition table is not changes. The `-f'
+ allows you to override these safeguards.
+
+ The following options are available for all operations:
+`v'
+ Together with `-p' prints the partition table as it is now (no
+ change operation), or as it is after it is modified.
+
+`vv'
+ If the verbosity flag is given twice, mpartition will print out a
+ hexdump of the partition table when reading it from and writing it
+ to the device.
+
+ The following option is available for partition table initialization:
+`B BOOTSECTOR'
+ Reads the template master boot record from file BOOTSECTOR.
+
+
+File: mtools.info, Node: mrd, Next: mren, Prev: mpartition, Up: Commands
+
+4.21 Mrd
+========
+
+The `mrd' command is used to remove an MS-DOS subdirectory. Its syntax
+is:
+
+ `mrd' [`-v'] MSDOSDIRECTORY [ MSDOSDIRECTORIES... ]
+
+ `Mrd' removes a directory from an MS-DOS file system. An error occurs
+if the directory does not exist or is not empty.
+
+
+File: mtools.info, Node: mren, Next: mshortname, 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 file system.
+
+ In verbose mode, `Mren' displays the new filename if the name
+supplied is invalid.
+
+ If the first syntax is used (only one source file), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+`mcd' directory as would be the case with `mmove'. Unlike the MS-DOS
+version of `REN', `mren' can be used to rename directories.
+
+
+File: mtools.info, Node: mshortname, Next: mshowfat, Prev: mren, Up: Commands
+
+4.23 Mshortname
+===============
+
+The `mshortname' command is used to display the short name of a file.
+Syntax:
+
+ `mshortname' FILES
+
+ The shortname is displayed as it is stored in raw format on disk,
+without any character set conversion.
+
+
+File: mtools.info, Node: mshowfat, Next: mtoolstest, Prev: mshortname, Up: Commands
+
+4.24 Mshowfat
+=============
+
+The `mshowfat' command is used to display the FAT entries for a file.
+Syntax:
+
+ `mshowfat' [`-o' OFFSET] FILES
+
+ If no offset is given, a list of all clusters occupied by the file is
+printed. If an offset is given, only the number of the cluster
+containing that offset is printed.
+
+
+File: mtools.info, Node: mtoolstest, Next: mtype, Prev: mshowfat, Up: Commands
+
+4.25 Mtoolstest
+===============
+
+The `mtoolstest' command is used to tests the mtools configuration
+files. To invoke it, just type `mtoolstest' without any arguments.
+`Mtoolstest' reads the mtools configuration files, and prints the
+cumulative configuration to `stdout'. The output can be used as a
+configuration file itself (although you might want to remove redundant
+clauses). You may use this program to convert old-style configuration
+files into new style configuration files.
+
+
+File: mtools.info, Node: mtype, Next: mzip, Prev: mtoolstest, Up: Commands
+
+4.26 Mtype
+==========
+
+The `mtype' command is used to display contents of an MS-DOS file. Its
+syntax is:
+
+ `mtype' [`-ts'] MSDOSFILE [ MSDOSFILES... ]
+
+ `Mtype' displays the specified MS-DOS file on the screen.
+
+ In addition to the standard options, `Mtype' allows the following
+command line options:
+
+`t'
+ Text file viewing. `Mtype' translates incoming carriage
+ return/line feeds to line feeds.
+
+`s'
+ `Mtype' strips the high bit from the data.
+
+ The `mcd' command may be used to establish the device and the
+current working directory (relative to MS-DOS), otherwise the default is
+`A:/'.
+
+ `Mtype' returns 0 on success, 1 on utter failure, or 2 on partial
+failure.
+
+ Unlike the MS-DOS version of `TYPE', `mtype' allows multiple
+arguments.
+
+
+File: mtools.info, Node: mzip, Prev: mtype, Up: Commands
+
+4.27 Mzip
+=========
+
+The `mzip' command is used to issue ZIP disk specific commands on
+Linux, Solaris or HP-UX. 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 password-less 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 adapter's BIOS setup).
+
+ The ZipTools disk shipped with the drive is also password protected.
+On MS-DOS or on a Mac, this password is automatically removed once the
+ZipTools have been installed. From various articles posted to Usenet, I
+learned that the password for the tools disk is
+`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 file system
+appears as a hidden file named `partishn.mac'. You may erase it to
+reclaim the 50 Megs of space taken up by the Mac file system.
+
+4.27.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
+Google Groups
+
+ (2) I didn't know about this yet when I bought my own Zip drive.
+Thus I ended up reformatting my tools disk, and hence I haven't had the
+opportunity to test the password yet. If anybody still has their tools
+disk with the original password, could you try it out? Thanks in advance
+
+
+File: mtools.info, Node: Compiling mtools, Next: Porting mtools, Prev: Commands, Up: Top
+
+5 Architecture specific compilation flags
+*****************************************
+
+To compile mtools, first invoke `./configure' before `make'. In
+addition to the standard `autoconfigure' flags, there are two
+architecture specific flags available.
+
+`./configure --enable-xdf'
+`./configure --disable-xdf'
+ Enables support for XDF disks. This is on by default. *Note XDF::,
+ for details.
+
+`./configure --enable-vold'
+`./configure --disable-vold'
+ Enables support for vold on Solaris. When used in conjunction with
+ vold, mtools should use different device nodes than for direct
+ access.
+
+`./configure --enable-new-vold'
+`./configure --disable-new-vold'
+ Enables new support for vold on Solaris. This is supposed to work
+ more smoothly than the old support.
+
+`./configure --enable-floppyd'
+`./configure --disable-floppyd'
+ Enables support for floppyd. By default, floppyd support is
+ enabled as long as the necessary X includes and libraries are
+ available.
+
+
+File: mtools.info, Node: Porting mtools, Next: Command Index, Prev: Compiling mtools, Up: Top
+
+6 Porting mtools to architectures which are not supported yet
+*************************************************************
+
+This chapter is only interesting for those who want to port mtools to
+an architecture which is not yet supported. For most common systems,
+default drives are already defined. If you want to add default drives
+for a still unsupported system, run configuration.guess, to see which
+identification autoconf uses for that system. This identification is of
+the form cpu-vendor-os (for example sparc-sun-sunos). The cpu and the
+OS parts are passed to the compiler as preprocessor flags. The OS
+part is passed to the compiler in three forms.
+ 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 (file system doesn't start at
+beginning of file system)
+ 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 file system doesn't begin at the start of the
+ device or image file. This is mostly useful for Atari Ram disks
+ (which contain their device driver at the beginning of the file)
+ or for DOS emulator images (which may represent a partitioned
+ device.
+
+ 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 `/etc/mtools.conf' and `~/.mtoolsrc'
+configuration files.
+
+ However, the devices files also allows to supply geometry setting
+routines. These are necessary if you want to access high capacity disks.
+
+ Two routines should be supplied:
+
+ 1. Reading the current parameters
+ static inline int get_parameters(int fd, struct generic_floppy_struct *floppy)
+
+ This probes the current configured geometry, and return it in the
+ structure generic_floppy_struct (which must also be declared).
+ Fd is an open file descriptor for the device, and buf is an already
+ filled in stat structure, which may be useful. This routine
+ should return 1 if the probing fails, and 0 otherwise.
+
+ 2. Setting new parameters
+ static inline int set_parameters(int fd, struct generic_floppy_struct *floppy)
+ struct stat *buf)
+ This configures the geometry contained in floppy on the file
+ descriptor fd. Buf is the result of a stat call (already filled
+ in). This should return 1 if the new geometry cannot be
+ configured, and 0 otherwise.
+
+ A certain number of preprocessor macros should also be supplied:
+
+`TRACKS(floppy)'
+ refers to the track field in the floppy structure
+
+`HEADS(floppy)'
+ refers to the heads field in the floppy structure
+
+`SECTORS(floppy)'
+ refers to the sectors per track field in the floppy structure
+
+`SECTORS_PER_DISK(floppy)'
+ refers to the sectors per disk field in the floppy structure (if
+ applicable, otherwise leave undefined)
+
+`BLOCK_MAJOR'
+ major number of the floppy device, when viewed as a block device
+
+`CHAR_MAJOR'
+ major number of the floppy device, when viewed as a character
+ device (a.k.a. "raw" device, used for fsck) (leave this undefined,
+ if your OS doesn't have raw devices)
+
+ For the truly high capacity formats (XDF, 2m, etc), there is no clean
+and documented interface yet.
+
+
+File: mtools.info, Node: Command Index, Next: Variable Index, Prev: Porting mtools, Up: Top
+
+Command Index
+*************
+
+
+* Menu:
+
+File: mtools.info, Node: Variable Index, Next: Concept Index, Prev: Command Index, Up: Top
+
+Variable index
+**************
+
+
+* Menu:
+
+* cylinders: geometry description. (line 61)
+* drive: general information. (line 6)
+* exclusive: open flags. (line 6)
+* fat_bits: miscellaneous variables.
+ (line 11)
+* file: location information. (line 10)
+* filter: miscellaneous flags. (line 77)
+* heads: geometry description. (line 65)
+* mformat_only: miscellaneous 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: miscellaneous flags. (line 68)
+
+
+File: mtools.info, Node: Concept Index, Prev: Variable Index, Up: Top
+
+Concept index
+*************
+
+
+* Menu:
+
+* 2m: 2m. (line 6)
+* ALPHA patches: Location. (line 6)
+* APlaceForYourStuff: mzip. (line 6)
+* Archive bit: mattrib. (line 6)
+* Atari: miscellaneous flags. (line 65)
+* Atari Ram disk: location information. (line 28)
+* Backwards compatibility: old style configuration.
+ (line 6)
+* Bad blocks: mbadblocks. (line 6)
+* bigger sectors: bigger sectors. (line 6)
+* blocksize: miscellaneous variables.
+ (line 34)
+* bugs: Location. (line 6)
+* Case sensitivity: case sensitivity. (line 6)
+* Changing file attributes: mattrib. (line 6)
+* character devices: miscellaneous 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: configuration 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 configuration.
+ (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: miscellaneous 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: miscellaneous variables.
+ (line 28)
+* Fat: mshowfat. (line 6)
+* fdformat: more sectors. (line 6)
+* File name of device node: location information. (line 10)
+* File system creation: mformat. (line 6)
+* Filenames: arguments. (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 MS-DOS file system: 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): miscellaneous 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: configuration file location.
+ (line 6)
+* Location of configuration files (parsing order): parsing order.
+ (line 6)
+* locking (disabling it): miscellaneous 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 6)
+* mattrib: mattrib. (line 6)
+* mbadblocks: mbadblocks. (line 6)
+* 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)
+* mshortname: mshortname. (line 6)
+* mshowfat: mshowfat. (line 6)
+* mtoolstest: mtoolstest. (line 6)
+* mzip: mzip. (line 6)
+* Name clashes: name clashes. (line 6)
+* Name of configuration files: configuration 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 configuration.
+ (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: miscellaneous 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: miscellaneous variables.
+ (line 34)
+* Read errors: mbadblocks. (line 6)
+* 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: miscellaneous flags. (line 16)
+* Secondary file name (long names): long names. (line 6)
+* Secondary file name (name clashes): name clashes. (line 6)
+* setgid installation: miscellaneous flags. (line 40)
+* setuid installation: miscellaneous flags. (line 40)
+* setuid installation (needed for raw SCSI I/O): miscellaneous flags.
+ (line 16)
+* Solaris (compile time configuration of vold): Compiling mtools.
+ (line 6)
+* Solaris (Raw access to SCSI devices such as Zip & Jaz): miscellaneous flags.
+ (line 16)
+* Solaris (volcheck): miscellaneous variables.
+ (line 28)
+* Solaris (vold): miscellaneous 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): miscellaneous flags.
+ (line 16)
+* synchronous writing: open flags. (line 6)
+* Syntax of the configuration file: general syntax. (line 6)
+* Syquest disks: location information. (line 14)
+* Syquest disks (raw SCSI access): miscellaneous 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): miscellaneous 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: miscellaneous 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): miscellaneous 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): miscellaneous flags. (line 16)
+* ZipTools disk: mzip. (line 6)
+
+
+
+Tag Table:
+Node: Top873
+Node: Location2958
+Node: Common features4344
+Node: arguments5108
+Node: drive letters6762
+Node: directory8114
+Node: long names8559
+Node: name clashes11105
+Node: case sensitivity13388
+Node: high capacity formats14617
+Node: more sectors15736
+Node: bigger sectors16785
+Node: 2m17507
+Node: XDF18686
+Node: exit codes20021
+Node: bugs20657
+Node: Configuration21189
+Node: configuration file location22324
+Node: general syntax22748
+Node: default values23575
+Node: global variables24102
+Node: per drive variables26183
+Node: general information27018
+Node: location information27459
+Node: geometry description28977
+Node: open flags32829
+Node: miscellaneous variables33428
+Node: miscellaneous flags35496
+Node: multiple descriptions39126
+Node: parsing order40796
+Node: old style configuration41827
+Node: Commands42522
+Node: floppyd44443
+Node: floppyd_installtest49228
+Node: mattrib49859
+Node: mbadblocks51655
+Node: mcat52948
+Node: mcd53759
+Node: mclasserase54620
+Node: mcopy55299
+Node: mdel58332
+Node: mdeltree58670
+Node: mdir59087
+Node: mdu60363
+Node: mformat60869
+Node: mkmanifest67805
+Node: minfo69777
+Node: mlabel70347
+Node: mmd71499
+Node: mmount71846
+Node: mmove72442
+Node: mpartition73248
+Node: mrd76769
+Node: mren77125
+Node: mshortname77872
+Node: mshowfat78202
+Node: mtoolstest78610
+Node: mtype79180
+Node: mzip80031
+Ref: mzip-Footnote-182064
+Ref: mzip-Footnote-282145
+Node: Compiling mtools82431
+Node: Porting mtools83526
+Node: Command Index89441
+Node: Variable Index89589
+Node: Concept Index91120
+
+End Tag Table
diff --git a/mtools.spec b/mtools.spec
new file mode 100644
index 0000000..1fc62b4
--- /dev/null
+++ b/mtools.spec
@@ -0,0 +1,192 @@
+%define _binary_payload w9.gzdio
+Name: mtools
+Summary: mtools, read/write/list/format DOS disks under Unix
+Version: 4.0.18
+Release: 1
+License: GPLv3+
+Group: Utilities/System
+URL: http://www.gnu.org/software/mtools/
+Source: ftp://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz
+Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
+
+
+%description
+Mtools is a collection of utilities to access MS-DOS disks from GNU
+and Unix without mounting them. It supports long file names, OS/2 Xdf
+disks, ZIP/JAZ disks and 2m disks (store up to 1992k on a high density
+3 1/2 disk).
+
+
+%prep
+%setup -q
+
+./configure \
+ --prefix=%{buildroot}%{_prefix} \
+ --sysconfdir=/etc \
+ --infodir=%{buildroot}%{_infodir} \
+ --mandir=%{buildroot}%{_mandir} \
+ --enable-floppyd \
+
+%build
+make
+
+%clean
+echo rm -rf $RPM_BUILD_ROOT
+[ X%{buildroot} != X ] && [ X%{buildroot} != X/ ] && rm -fr %{buildroot}
+
+%install
+make install
+make install-info
+strip %{buildroot}%{_bindir}/mtools %{buildroot}%{_bindir}/mkmanifest %{buildroot}%{_bindir}/floppyd
+rm %{buildroot}%{_infodir}/dir
+
+%files
+%defattr(-,root,root)
+%{_infodir}/mtools.info*
+%{_mandir}/man1/floppyd.1*
+%{_mandir}/man1/floppyd_installtest.1.gz
+%{_mandir}/man1/mattrib.1*
+%{_mandir}/man1/mbadblocks.1*
+%{_mandir}/man1/mcat.1*
+%{_mandir}/man1/mcd.1*
+%{_mandir}/man1/mclasserase.1*
+%{_mandir}/man1/mcopy.1*
+%{_mandir}/man1/mdel.1*
+%{_mandir}/man1/mdeltree.1*
+%{_mandir}/man1/mdir.1*
+%{_mandir}/man1/mdu.1*
+%{_mandir}/man1/mformat.1*
+%{_mandir}/man1/minfo.1*
+%{_mandir}/man1/mkmanifest.1*
+%{_mandir}/man1/mlabel.1*
+%{_mandir}/man1/mmd.1*
+%{_mandir}/man1/mmount.1*
+%{_mandir}/man1/mmove.1*
+%{_mandir}/man1/mpartition.1*
+%{_mandir}/man1/mrd.1*
+%{_mandir}/man1/mren.1*
+%{_mandir}/man1/mshortname.1*
+%{_mandir}/man1/mshowfat.1*
+%{_mandir}/man1/mtools.1*
+%{_mandir}/man5/mtools.5*
+%{_mandir}/man1/mtoolstest.1*
+%{_mandir}/man1/mtype.1*
+%{_mandir}/man1/mzip.1*
+%{_bindir}/amuFormat.sh
+%{_bindir}/mattrib
+%{_bindir}/mbadblocks
+%{_bindir}/mcat
+%{_bindir}/mcd
+%{_bindir}/mclasserase
+%{_bindir}/mcopy
+%{_bindir}/mdel
+%{_bindir}/mdeltree
+%{_bindir}/mdir
+%{_bindir}/mdu
+%{_bindir}/mformat
+%{_bindir}/minfo
+%{_bindir}/mkmanifest
+%{_bindir}/mlabel
+%{_bindir}/mmd
+%{_bindir}/mmount
+%{_bindir}/mmove
+%{_bindir}/mpartition
+%{_bindir}/mrd
+%{_bindir}/mren
+%{_bindir}/mshortname
+%{_bindir}/mshowfat
+%{_bindir}/mtools
+%{_bindir}/mtoolstest
+%{_bindir}/mtype
+%{_bindir}/mzip
+%{_bindir}/floppyd
+%{_bindir}/floppyd_installtest
+%{_bindir}/mcheck
+%{_bindir}/mcomp
+%{_bindir}/mxtar
+%{_bindir}/tgz
+%{_bindir}/uz
+%{_bindir}/lz
+%doc NEWS
+
+%pre
+groupadd floppy 2>/dev/null || echo -n ""
+
+%post
+if [ -f %{_bindir}/install-info ] ; then
+ if [ -f %{_infodir}/dir ] ; then
+ %{_bindir}/install-info %{_infodir}/mtools.info %{_infodir}/dir
+ fi
+ if [ -f %{_infodir}/dir.info ] ; then
+ %{_bindir}/install-info %{_infodir}/mtools.info %{_infodir}/dir.info
+ fi
+fi
+
+
+%preun
+install-info --delete %{_infodir}/mtools.info %{_infodir}/dir.info
+if [ -f %{_bindir}/install-info ] ; then
+ if [ -f %{_infodir}/dir ] ; then
+ %{_bindir}/install-info --delete %{_infodir}/mtools.info %{_infodir}/dir
+ fi
+ if [ -f %{_infodir}/dir.info ] ; then
+ %{_bindir}/install-info --delete %{_infodir}/mtools.info %{_infodir}/dir.info
+ fi
+fi
+
+%changelog
+* Wed Jan 09 2013 Alain Knaff <alain@knaff.lu>
+- Fix for names of iconv encodings on AIX
+- Fix mt_size_t on NetBSD
+- Fixed compilation on Mingw
+- Fixed doc (especially mformat)
+- Fix mformating of FAT12 filesystems with huge cluster sizes
+- Minfo prints image file name in mformat command line if an image
+- file name was given
+- Always generate gzip-compressed RPMs, in order to remain
+- compatible with older distributions
+- Fixed buffer overflow with drive letter in mclasserase
+* Wed Jun 29 2011 Alain Knaff <alain@knaff.lu>
+- mbadblocks now takes a list of bad blocks (either as sectors
+ or as clusters)
+- mbadblocks now is able to do write scanning for bad blocks
+- mshowfat can show cluster of specific offset
+- Enable mtools to deal with very small sector sizes...
+- Fixed encoding of all-lowercase names (no need to mangle
+ these)
+- Consider every directory entry after an ENDMARK (0x00) to be deleted
+- After writing a new entry at end of a directory, be sure to also add
+ an ENDMARK (0x00)
+- Deal with possibility of a NULL pointer being returned by
+ localtime during timestamp conversion
+* Sat Apr 16 2011 Alain Knaff <alain@knaff.lu>
+- configure.in fixes
+- fixed formatting of fat_size_calculation.tex document
+- compatibility with current autoconfig versions
+- Make it clear that label is limited to 11 characters
+- Fixed typo in initialization of FAT32 info sector
+* Sun Oct 17 2010 Alain Knaff <alain@knaff.lu>
+- Added missing -i option to mshortname
+* Sun Oct 17 2010 Alain Knaff <alain@knaff.lu>
+- Released v4_0_14:
+- New mshortname command
+- Fix floppyd for disks bigger than 2 Gig
+- Remove obsolete -z flag
+- Remove now unsupported AC_USE_SYSTEM_EXTENSIONS
+- Fixed output formatting of mdir if MTOOLS_DOTTED_DIR is set
+- Mformat now correctly writes backup boot sector
+- Fixed signedness of serial number in mlabel
+- Fixed buffer size problem in mlabel
+- Make mlabel write backup boot sector if FAT32
+- Catch situation where both clear and new label are given to mlabel
+- Quote filename parameters to scripts
+- Mformat: Close file descriptor for boot sector
+- Added lzip support to scripts/uz
+- Added Tot_sectors option to mformat
+- Fixed hidden sector handling in mformat
+- Minfo generates mformat command lines containing new -T option
+- Mlabel prints error if label too long
+* Sun Feb 28 2010 Alain Knaff <alain@knaff.lu>
+- Merged Debian patches
+* Tue Nov 03 2009 Alain Knaff <alain@knaff.lu>
+- Mingw compatibility fixes
diff --git a/mtools.texi b/mtools.texi
new file mode 100644
index 0000000..1085789
--- /dev/null
+++ b/mtools.texi
@@ -0,0 +1,2638 @@
+\input texinfo @c -*-texinfo-*-
+@comment %**start of header
+@setfilename mtools.info
+@include version.texi
+@settitle Mtools @value{VERSION}
+@syncodeindex pg cp
+@comment %**end of header
+
+@comment MANskip 5
+
+@copying
+This manual is for Mtools (version @value{VERSION}, @value{UPDATED}),
+which is a collection of tools to allow Unix systems to manipulate
+MS-DOS files.
+
+Copyright @copyright{} 2007, 2009 Free Software Foundation, Inc.
+Copyright @copyright{} 1996-2005,2007-2011,2013 Alain Knaff.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with no Front-Cover Texts, and with no Back-Cover
+Texts. A copy of the license is included in the section entitled
+``GNU Free Documentation License''.
+@end quotation
+@end copying
+
+@ignore
+@unnumbered Name
+mtools - utilities to access DOS disks in Unix.
+@end ignore
+
+@include sysconfdir.texi
+
+@iftex
+@finalout
+@end iftex
+
+@dircategory DOS
+@direntry
+* Mtools: (mtools). Mtools: utilities to access DOS disks in Unix.
+@end direntry
+
+
+@titlepage
+@title Mtools
+
+@c The following two commands start the copyright page.
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@c Output the table contents at the beginning
+@contents
+
+@ifnottex
+@node Top, Location, (dir), (dir)
+@top Mtools doc
+
+This is mtools' documentation.
+@end ifnottex
+
+@comment MANstart 1
+
+@unnumbered Introduction
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS
+file system (typically a floppy disk). Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However,
+unnecessary restrictions and oddities of DOS are not emulated. For
+instance, it is possible to move subdirectories from one subdirectory
+to another.
+
+Mtools is sufficient to give access to MS-DOS file systems. For
+instance, commands such as @code{mdir a:} work on the @code{a:} floppy
+without any preliminary mounting or initialization (assuming the default
+@file{@value{SYSCONFDIR}mtools.conf} works on your machine). With mtools, one can
+change floppies too without unmounting and mounting.
+
+@insertcopying
+
+@menu
+* Location:: Where to find mtools and early bug fixes
+* Common features:: Common features of all mtools commands
+* Configuration:: How to configure mtools for your environment
+* Commands:: The available mtools commands
+* Compiling mtools:: Architecture specific compilation flags
+* Porting mtools:: Porting mtools to architectures which are not
+ yet supported
+
+* Command Index:: Command Index
+* Variable Index:: Variable Index
+* Concept Index:: Concept Index
+@end menu
+
+@node Location, Common features, Top, Top
+@chapter Where to get mtools
+@cindex bugs
+@cindex ALPHA patches
+@cindex patches
+@cindex diffs
+@cindex mailing list
+
+Mtools can be found at the following places (and their mirrors):
+@example
+http://ftp.gnu.org/gnu/mtools/mtools-@value{VERSION}.tar.gz
+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 file system),
+otherwise the default is assumed to be @code{A:/}. However, unlike
+MS-DOS, there is only one working directory for all drives, and not one
+per drive.
+
+@node long names, name clashes, directory, Common features
+@section VFAT-style long file names
+@cindex Long file name
+@cindex Windows 95-style file names
+@cindex VFAT-style file names
+@cindex Primary file name (long names)
+@cindex Secondary file name (long names)
+
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a
+VFAT long name, and a companion short name is generated. This short
+name is what you see when you examine the disk with a pre-7.0 version
+of DOS.
+ The following table shows some examples of short names:
+
+@example
+Long name MS-DOS name Reason for the change
+--------- ---------- ---------------------
+thisisatest THISIS~1 filename too long
+alain.knaff ALAIN~1.KNA extension too long
+prn.txt PRN~1.TXT PRN is a device name
+.abc ABC~1 null filename
+hot+cold HOT_CO~1 illegal character
+@end example
+
+ As you see, the following transformations happen to derive a short
+name:
+@itemize @bullet
+@item
+Illegal characters are replaced by underscores. The illegal characters
+are @code{;+=[]',\"*\\<>/?:|}.
+@item
+Extra dots, which cannot be interpreted as a main name/extension
+separator are removed
+@item
+A @code{~}@var{n} number is generated,
+@item
+The name is shortened so as to fit in the 8+3 limitation
+@end itemize
+
+ The initial Unix-style file name (whether long or short) is also called
+the @dfn{primary} name, and the derived short name is also called the
+@dfn{secondary} name.
+
+ Example:
+@example
+ mcopy /etc/motd a:Reallylongname
+@end example
+ Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+@example
+ mcopy /etc/motd a:motd
+@end example
+ Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+
+ In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+
+ Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (@code{\"*\\<>/?:|}), and device names are still
+reserved.
+
+@example
+Unix name Long name Reason for the change
+--------- ---------- ---------------------
+prn prn-1 PRN is a device name
+ab:c ab_c-1 illegal character
+@end example
+
+ As you see, the following transformations happen if a long name is
+illegal:
+@itemize @bullet
+@item
+Illegal characters are replaces by underscores,
+@item
+A @code{-}@var{n} number is generated,
+@end itemize
+
+@node name clashes, case sensitivity, long names, Common features
+@section Name clashes
+@cindex Name clashes
+@cindex Duplicate file names
+@cindex Overwriting files
+@cindex Primary file name (name clashes)
+@cindex Secondary file name (name clashes)
+
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as @code{mcopy},
+@code{mmd}, @code{mren}, @code{mmove}. When a name clash happens, mtools
+asks you what it should do. It offers several choices:
+
+@table @code
+@item overwrite
+Overwrites the existing file. It is not possible to overwrite a
+directory with a file.
+@item rename
+Renames the newly created file. Mtools prompts for the new filename
+@item autorename
+Renames the newly created file. Mtools chooses a name by itself, without
+prompting
+@item skip
+Gives up on this file, and moves on to the next (if any)
+@end table
+
+To chose one of these actions, type its first letter at the prompt. If
+you use a lower case letter, the action only applies for this file only,
+if you use an upper case letter, the action applies to all files, and
+you won't be prompted again.
+
+You may also chose actions (for all files) on the command line, when
+invoking mtools:
+
+@table @code
+@item -D o
+Overwrites primary names by default.
+@item -D O
+Overwrites secondary names by default.
+@item -D r
+Renames primary name by default.
+@item -D R
+Renames secondary name by default.
+@item -D a
+Autorenames primary name by default.
+@item -D A
+Autorenames secondary name by default.
+@item -D s
+Skip primary name by default.
+@item -D S
+Skip secondary name by default.
+@item -D m
+Ask user what to do with primary name.
+@item -D M
+Ask user what to do with secondary name.
+@end table
+
+Note that for command line switches lower/upper differentiates between
+primary/secondary name whereas for interactive choices, lower/upper
+differentiates between just-this-time/always.
+
+The primary name is the name as displayed in Windows 95 or Windows NT:
+i.e. the long name if it exists, and the short name otherwise. The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+
+By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+
+If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+
+@node case sensitivity, high capacity formats, name clashes, Common features
+@section Case sensitivity of the VFAT file system
+@cindex Case sensitivity
+
+The VFAT file system is able to remember the case of the
+filenames. However, filenames which differ only in case are not allowed
+to coexist in the same directory. For example if you store a file called
+LongFileName on a VFAT file system, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+
+The VFAT file system allows 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 operating systems. Mtools recognizes
+these formats transparently where supported.
+
+In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+@code{fdutils} package at the following locations~:
+@example
+@code{ftp://www.tux.org/pub/knaff/fdutils/}.
+@code{ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/fdutils-*}
+@end example
+
+See the manual pages included in that package for further detail: Use
+@code{superformat} to format all formats except XDF, and use
+@code{xdfcopy} to format XDF.
+
+@menu
+* more sectors:: Putting more sectors per track on the disk
+* bigger sectors:: Use bigger sectors to save header space
+* 2m:: Use a standard first track
+* XDF:: OS/2's eXtended density format
+@end menu
+
+@node more sectors, bigger sectors, high capacity formats, high capacity formats
+@subsection More sectors
+@cindex fdformat
+@cindex vgacopy
+@cindex DMF disks
+@cindex Windows 95 (DMF disks)
+
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+
+These formats are supported by numerous DOS shareware utilities such as
+@code{fdformat} and @code{vgacopy}. In his infinite hubris, Bill Gate$
+believed that he invented this, and called it @samp{DMF disks}, or
+@samp{Windows formatted disks}. But in reality, it has already existed
+years before! Mtools supports these formats on Linux, on SunOS and on
+the DELL Unix PC.
+
+@node bigger sectors, 2m, more sectors, high capacity formats
+@subsection Bigger sectors
+@cindex bigger sectors
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+@emph{fewer}, but bigger sectors. For example, 1 sector of 4K only takes
+up header space once, whereas 8 sectors of 512 bytes have also 8
+headers, for the same amount of useful data.
+
+This method 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 easier to
+handle by DOS. Indeed this method allows to have a standard sized
+boot sector, which contains a description of how the rest of the disk
+should be read.
+
+However, the drawback of this is that the first cylinder can hold less
+data than the others. Unfortunately, DOS can only handle disks where
+each track contains the same amount of data. Thus 2m hides the fact that
+the first track contains less data by using a @dfn{shadow
+FAT}. (Usually, DOS stores the FAT in two identical copies, for
+additional safety. XDF stores only one copy, but tells DOS that it
+stores two. Thus the space that would be taken up by the second FAT copy
+is saved.) This also means that you should @strong{never use a 2m disk
+to store anything else than a DOS file system}.
+
+Mtools supports these formats only on Linux.
+
+@node XDF, , 2m, high capacity formats
+@subsection XDF
+@cindex XDF disks
+@cindex OS/2 (XDF disks)
+
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the @code{use_xdf} variable for the drive in the
+configuration file. @xref{Compiling mtools}, and @ref{miscellaneous variables},
+for details on how to do this. Fast XDF access is only available for
+Linux kernels which are more recent than 1.1.34.
+
+Mtools supports this format only on Linux.
+
+@strong{Caution / Attention distributors}: If mtools is compiled on a
+Linux kernel more recent than 1.3.34, it won't run on an older
+kernel. However, if it has been compiled on an older kernel, it still
+runs on a newer kernel, except that XDF access is slower. It is
+recommended that distribution authors only include mtools binaries
+compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will
+be out, mtools binaries compiled on newer kernels may (and should) be
+distributed. Mtools binaries compiled on kernels older than 1.3.34 won't
+run on any 2.1 kernel or later.
+
+@node exit codes, bugs, high capacity formats, Common features
+@section Exit codes
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure. All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or MINIX disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(@pxref{global variables})
+@node bugs, , exit codes, Common features
+@section Bugs
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver. These can be safely ignored.
+
+The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7
+mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the
+corresponding configuration file variable, @ref{global variables}) to
+bypass the fat checking.
+
+@comment MANskip 1
+
+@ignore
+@unnumbered Name
+mtools.conf - mtools configuration files
+
+@comment MANend-skip 5
+@section Description
+
+This manual page describes the configuration files for mtools. They
+@comment MANskip 5
+@end ignore
+
+
+@node Configuration, Commands, Common features, Top
+
+
+@chapter How to configure mtools for your environment
+@section Description
+@cindex Configuration files
+@vindex MTOOLSRC
+
+ This sections explains the syntax of the configurations files for
+mtools. The configuration files
+@comment MANend-skip 5
+are called @file{@value{SYSCONFDIR}mtools.conf} and @file{~/.mtoolsrc}. If
+the environmental variable @code{MTOOLSRC} is set, its contents is used
+as the filename for a third configuration file. These configuration
+files describe the following items:
+
+@itemize @bullet
+@item Global configuration flags and variables
+@item Per drive flags and variables
+@end itemize
+
+
+@menu
+* configuration file location:: Where mtools looks for its configuration files
+* general syntax:: The layout of the configuration files
+* default values:: Why you don't need a configuration file in most cases
+* global variables:: Variables that are independent of the drive
+* per drive variables:: Variables that are specific to a given drive
+* parsing order:: Location of configuration files and parsing order
+* old style configuration:: Backwards compatibility
+@end menu
+
+@node configuration file location, general syntax, Configuration, Configuration
+@section Location of the configuration files
+
+@cindex Configuration file name
+@cindex Name of configuration files
+@cindex Location of configuration files
+
+@file{@value{SYSCONFDIR}mtools.conf} is the system-wide configuration file,
+and @file{~/.mtoolsrc} is the user's private configuration file.
+
+On some systems, the system-wide configuration file is called
+@file{/etc/default/mtools.conf} instead.
+
+
+@node general syntax, default values, configuration file location, Configuration
+@subsection General configuration file syntax
+@cindex Syntax of the configuration file
+@cindex Configuration file syntax
+
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon.
+Then follow variable assignments and flags. Variable assignments take
+the following form:
+@display
+name=value
+@end display
+Flags are lone keywords without an equal sign and value following
+them. A section either ends at the end of the file or where the next
+section begins.
+
+Lines starting with a hash (@code{#}) are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+
+@node default values, global variables, general syntax, Configuration
+@section Default values
+@cindex Default values
+@cindex Default configuration
+@cindex Configuration file
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives. Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+DOSEMU image files.
+
+@node global variables, per drive variables, default values, Configuration
+@section Global variables
+@cindex Global configuration variables
+@cindex Drive independent configuration variables
+@cindex Environmental variables
+@vindex MTOOLS_SKIP_CHECK
+@vindex MTOOLS_FAT_COMPATIBILITY
+@vindex MTOOLS_LOWER_CASE
+@vindex MTOOLS_NO_VFAT
+@cindex FreeDOS
+
+Global flags may be set to 1 or to 0.
+
+The following global flags are recognized:
+
+@table @code
+@item MTOOLS_SKIP_CHECK
+If this is set to 1, mtools skips most of its sanity checks. This is
+needed to read some Atari disks which have been made with the earlier
+ROMs, and which would not be recognized otherwise.
+@item MTOOLS_FAT_COMPATIBILITY
+If this is set to 1, mtools skips the fat size checks. Some disks have
+a bigger FAT than they really need to. These are rejected if this
+option is not set.
+@item MTOOLS_LOWER_CASE
+If this is set to 1, mtools displays all-upper-case short filenames as
+lowercase. This has been done to allow a behavior which is consistent
+with older versions of mtools which didn't know about the case bits.
+@item MTOOLS_NO_VFAT
+If this is set to 1, mtools won't generate VFAT entries for filenames
+which are mixed-case, but otherwise legal dos filenames. This is useful
+when working with DOS versions which can't grok VFAT long names, such as
+FreeDOS.
+@item MTOOLS_DOTTED_DIR
+In a wide directory, prints the short name with a dot instead of spaces
+separating the basename and the extension.
+@item MTOOLS_NAME_NUMERIC_TAIL
+If this is set to one (default), generate numeric tails for all long
+names (~1). If set to zero, only generate numeric tails if otherwise a
+clash would have happened.
+@item MTOOLS_TWENTY_FOUR_HOUR_CLOCK
+If 1, uses the European notation for times (twenty four hour clock),
+else uses the UK/US notation (am/pm)
+@end table
+
+Example:
+Inserting the following line into your configuration file instructs
+mtools to skip the sanity checks:
+@example
+ MTOOLS_SKIP_CHECK=1
+@end example
+
+Global variables may also be set via the environment:
+@example
+ export MTOOLS_SKIP_CHECK=1
+@end example
+
+Global string variables may be set to any value:
+@table @code
+@item MTOOLS_DATE_STRING
+The format used for printing dates of files. By default, is dd-mm-yyyy.
+@end table
+
+@node per drive variables, parsing order, global variables, Configuration
+@section Per drive flags and variables
+@cindex Drive description
+@cindex Drive configuration
+
+@menu
+* general information:: What a drive description looks like
+* location information:: Where is the drive data physically stored
+* geometry description:: Describes the physical characteristics of
+ the media
+* open flags:: Flags passed to the open system call when the
+ device is opened
+* miscellaneous variables:: Variables which don't fit in either category
+* miscellaneous flags:: Switch variables, which can be enabled or disabled
+* multiple descriptions:: How to supply several descriptions for a
+ drive, to be tried one after the other.
+@end menu
+
+@node general information, location information, per drive variables, per drive variables
+@subsection General information
+@cindex Drive description, example
+@cindex Drive configuration, example
+@vindex drive
+
+Per drive flags and values may be described in a drive section. A
+drive section starts with
+@code{drive} "@var{driveletter}" :
+
+Then follow variable-value pairs and flags.
+
+This is a sample drive description:
+@example
+ drive a:
+ file="/dev/fd0" use_xdf=1
+@end example
+
+@node location information, geometry description, general information, per drive variables
+@subsection Location information
+@cindex Hdimage
+
+For each drive, you need to describe where its data is physically
+stored (image file, physical device, partition, offset).
+
+@table @code
+@item file
+@cindex Image file
+@cindex Name of device node
+@cindex File name of device node
+@vindex file
+The name of the file or device holding the disk image. This is
+mandatory. The file name should be enclosed in quotes.
+
+@item partition
+@cindex DOSEMU hard disk image
+@cindex Zip disks (partitions)
+@cindex Jaz disks (partitions)
+@cindex Syquest disks
+@cindex Magneto-optical disks
+@cindex OS/2 (layout of removable media)
+@cindex Windows NT (layout of removable media)
+@cindex Removable media
+@cindex Partitioned image file
+Tells mtools to treat the drive as a partitioned device, and to use the
+given partition. Only primary partitions are accessible using this
+method, and they are numbered from 1 to 4. For logical partitions, use
+the more general @code{offset} variable. The @code{partition} variable
+is intended for removable media such as Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks and
+magneto-optical disks as @samp{giant floppy disks} which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partitioned devices. The @code{partition} flag is also useful DOSEMU
+hdimages. It is not recommended for hard disks for which direct access
+to partitions is available through mounting.
+
+@item offset
+@cindex Ram disk
+@cindex Atari Ram disk
+Describes where in the file the MS-DOS file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system starts right at the
+beginning of the device or file.
+@end table
+
+@node geometry description, open flags, location information, per drive variables
+@subsection Disk Geometry Configuration
+@cindex Disk Geometry
+@cindex Configuration of disk geometry
+@cindex Description of disk geometry
+@cindex Format of disk
+@cindex High density disk
+@cindex Low density disk
+@pindex mformat (geometry used for)
+
+Geometry information describes the physical characteristics about the
+disk. Its has three purposes:
+
+@table @asis
+@item formatting
+The geometry information is written into the boot sector of the newly
+made disk. However, you may also describe the geometry information on
+the command line. @xref{mformat}, for details.
+@item filtering
+On some Unixes there are device nodes which only support one physical
+geometry. For instance, you might need a different node to access a disk
+as high density or as low density. The geometry is compared to the
+actual geometry stored on the boot sector to make sure that this device
+node is able to correctly read the disk. If the geometry doesn't match,
+this drive entry fails, and the next drive entry bearing the same drive
+letter is tried. @xref{multiple descriptions}, for more details on
+supplying several descriptions for one drive letter.
+
+If no geometry information is supplied in the configuration file, all
+disks are accepted. On Linux (and on SPARC) there exist device nodes
+with configurable geometry (@file{/dev/fd0}, @file{/dev/fd1} etc),
+and thus filtering is not needed (and ignored) for disk drives. (Mtools
+still does do filtering on plain files (disk images) in Linux: this is
+mainly intended for test purposes, as I don't have access to a Unix
+which would actually need filtering).
+
+If you do not need filtering, but want still a default geometry for
+mformatting, you may switch off filtering using the @code{mformat_only}
+flag.
+
+If you want filtering, you should supply the @code{filter} flag. If you
+supply a geometry, you must supply one of both flags.
+
+@item initial geometry
+On devices that support it (usually floppy devices), the geometry
+information is also used to set the initial geometry. This initial
+geometry is applied while reading the boot sector, which contains the
+real geometry. If no geometry information is supplied in the
+configuration file, or if the @code{mformat_only} flag is supplied, no
+initial configuration is done.
+
+On Linux, initial geometry is not really needed, as the configurable
+devices are able to auto-detect the disk type accurately enough (for
+most common formats) to read the boot sector.
+@end table
+
+Wrong geometry information may lead to very bizarre errors. That's why I
+strongly recommend that you add the @code{mformat_only} flag to your
+drive description, unless you really need filtering or initial geometry.
+
+The following geometry related variables are available:
+
+@table @code
+@item cylinders
+@itemx tracks
+@vindex cylinders
+@vindex tracks
+The number of cylinders. (@code{cylinders} is the preferred form,
+@code{tracks} is considered obsolete)
+@item heads
+@vindex heads
+The number of heads (sides).
+@item sectors
+@vindex sectors
+The number of sectors per track.
+@end table
+
+Example: the following drive section describes a 1.44M drive:
+
+@example
+ drive a:
+ file="/dev/fd0H1440"
+ fat_bits=12
+ cylinders=80 heads=2 sectors=18
+ mformat_only
+@end example
+
+The following shorthand geometry descriptions are available:
+
+@table @code
+@item 1.44m
+high density 3 1/2 disk. Equivalent to:
+@code{fat_bits=12 cylinders=80 heads=2 sectors=18}
+@item 1.2m
+high density 5 1/4 disk. Equivalent to:
+@code{fat_bits=12 cylinders=80 heads=2 sectors=15}
+@item 720k
+double density 3 1/2 disk. Equivalent to:
+@code{fat_bits=12 cylinders=80 heads=2 sectors=9}
+@item 360k
+double density 5 1/4 disk. Equivalent to:
+@code{fat_bits=12 cylinders=40 heads=2 sectors=9}
+@end table
+
+The shorthand format descriptions may be amended. For example,
+@code{360k sectors=8}
+describes a 320k disk and is equivalent to:
+@code{fat_bits=12 cylinders=40 heads=2 sectors=8}
+
+@node open flags, miscellaneous variables, geometry description, per drive variables
+@subsection Open Flags
+@vindex sync
+@vindex nodelay
+@vindex exclusive
+@cindex open flags
+@cindex synchronous writing
+@cindex exclusive access to a drive
+
+Moreover, the following flags are available:
+
+@table @code
+@item sync
+All i/o operations are done synchronously
+@item nodelay
+The device or file is opened with the O_NDELAY flag. This is needed on
+some non-Linux architectures.
+@item exclusive
+The device or file is opened with the O_EXCL flag. On Linux, this
+ensures exclusive access to the floppy drive. On most other
+architectures, and for plain files it has no effect at all.
+@end table
+
+
+@node miscellaneous variables, miscellaneous flags, open flags, per drive variables
+@subsection General Purpose Drive Variables
+
+The following general purpose drive variables are available. Depending
+to their type, these variables can be set to a string (precmd) or
+an integer (all others)
+
+@table @code
+@item fat_bits
+@vindex fat_bits
+The number of FAT bits. This may be 12 or 16. This is very rarely
+needed, as it can almost always be deduced from information in the
+boot sector. On the contrary, describing the number of fat bits may
+actually be harmful if you get it wrong. You should only use it if
+mtools gets the auto-detected number of fat bits wrong, or if you want
+to mformat a disk with a weird number of fat bits.
+@item codepage
+Describes the DOS code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+for all drives by using the global @code{default_codepage} parameter
+(outside of any drive description). This parameters exists starting at
+version 4.0.0
+@item precmd
+@cindex Solaris (volcheck)
+@cindex Executing commands before opening the device
+On some variants of Solaris, it is necessary to call 'volcheck -v'
+before opening a floppy device, in order for the system to notice that
+there is indeed a disk in the drive. @code{precmd="volcheck -v"} in the
+drive clause establishes the desired behavior.
+
+@item blocksize
+@cindex raw device
+@cindex character devices
+@cindex blocksize
+This parameter represents a default block size to be always used on this
+device. All I/O is done with multiples of this block size,
+independently of the sector size registered in the file system's boot
+sector. This is useful for character devices whose sector size is not
+512, such as for example CD-ROM drives on Solaris.
+
+@end table
+
+Only the @code{file} variable is mandatory. The other parameters may
+be left out. In that case a default value or an auto-detected value is
+used.
+
+
+
+@node miscellaneous flags, multiple descriptions, miscellaneous variables, per drive variables
+@subsection General Purpose Drive Flags
+
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+omitted, it is enabled. For example, @code{scsi} is equivalent to
+@code{scsi=1}
+
+@table @code
+@item nolock
+@cindex disable locking
+@cindex locking (disabling it)
+@cindex plain floppy: device xxx busy
+Instruct mtools to not use locking on this drive. This is needed on
+systems with buggy locking semantics. However, enabling this makes
+operation less safe in cases where several users may access the same
+drive at the same time.
+
+@item scsi
+@cindex setuid installation (needed for raw SCSI I/O)
+@cindex Solaris (Raw access to SCSI devices such as Zip & Jaz)
+@cindex SunOS (Raw access to SCSI devices such as Zip & Jaz)
+@cindex Zip disks (raw SCSI access)
+@cindex Jaz disks (raw SCSI access)
+@cindex Syquest disks (raw SCSI access)
+@cindex SCSI devices
+When set to 1, this option tells mtools to use raw SCSI I/O instead of
+the standard read/write calls to access the device. Currently, this is
+supported on HP-UX, Solaris and SunOS. This is needed because on some
+architectures, such as SunOS or Solaris, PC media can't be accessed
+using the @code{read} and @code{write} system calls, because the OS expects
+them to contain a Sun specific "disk label".
+
+As raw SCSI access always uses the whole device, you need to specify the
+"partition" flag in addition
+
+On some architectures, such as Solaris, mtools needs root privileges to
+be able to use the @code{scsi} option. Thus mtools should be installed
+setuid root on Solaris if you want to access Zip/Jaz drives. Thus, if
+the @code{scsi} flag is given, @code{privileged} is automatically
+implied, unless explicitly disabled by @code{privileged=0}
+
+Mtools uses its root privileges to open the device, and to issue the
+actual SCSI I/O calls. Moreover, root privileges are only used for
+drives described in a system-wide configuration file such as
+@file{@value{SYSCONFDIR}mtools.conf}, and not for those described in
+@file{~/.mtoolsrc} or @file{$MTOOLSRC}.
+
+@item privileged
+@cindex setuid installation
+@cindex setgid installation
+When set to 1, this instructs mtools to use its setuid and setgid
+privileges for opening the given drive. This option is only valid for
+drives described in the system-wide configuration files (such as
+@file{@value{SYSCONFDIR}mtools.conf}, not @file{~/.mtoolsrc} or
+@file{$MTOOLSRC}). Obviously, this option is also a no op if mtools is
+not installed setuid or setgid. This option is implied by 'scsi=1', but
+again only for drives defined in system-wide configuration files.
+Privileged may also be set explicitly to 0, in order to tell mtools not
+to use its privileges for a given drive even if @code{scsi=1} is set.
+
+Mtools only needs to be installed setuid if you use the
+@code{privileged} or @code{scsi} drive variables. If you do not use
+these options, mtools works perfectly well even when not installed
+setuid root.
+
+@item vold
+@cindex Solaris (vold)
+@cindex Vold (mediamgr)
+
+Instructs mtools to interpret the device name as a vold identifier
+rather than as a filename. The vold identifier is translated into a
+real filename using the @code{media_findname()} and
+@code{media_oldaliases()} functions of the @code{volmgt} library. This
+flag is only available if you configured mtools with the
+@code{--enable-new-vold} option before compilation.
+
+@item swap
+@cindex Atari
+@cindex Wordswapped
+
+Consider the media as a word-swapped Atari disk.
+
+@item use_xdf
+@cindex XDF disks (how to configure)
+@vindex use_xdf
+If this is set to a non-zero value, mtools also tries to access this
+disk as an XDF disk. XDF is a high capacity format used by OS/2. This
+is off by default. @xref{XDF}, for more details.
+@item mformat_only
+@vindex mformat_only
+Tells mtools to use the geometry for this drive only for mformatting and
+not for filtering.
+
+@item filter
+@vindex filter
+Tells mtools to use the geometry for this drive both for mformatting and
+filtering.
+
+@item remote
+Tells mtools to connect to floppyd (@pxref{floppyd}).
+@end table
+
+
+@node multiple descriptions, , miscellaneous flags, per drive variables
+@subsection Supplying multiple descriptions for a drive
+
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that
+fits. Descriptions may fail for several reasons:
+
+@enumerate
+@item
+because the geometry is not appropriate,
+@item
+because there is no disk in the drive,
+@item
+or because of other problems.
+@end enumerate
+
+Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry.
+Example:
+@example
+ drive a: file="/dev/fd0H1440" 1.44m
+ drive a: file="/dev/fd0H720" 720k
+@end example
+
+This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+
+You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+
+@example
+ drive z: file="/dev/fd0"
+ drive z: file="/dev/fd1"
+@end example
+
+With this description, @code{mdir z:} accesses your first physical
+drive if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+
+When using multiple configuration files, drive descriptions in the files
+parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the @code{drive+} or @code{+drive}
+keywords instead of @code{drive}. The first adds a description to the
+end of the list (i.e. it will be tried last), and the first adds it to
+the start of the list.
+
+@node parsing order, old style configuration, per drive variables, Configuration
+@section Location of configuration files and parsing order
+@cindex Parsing order
+@cindex Configuration file parsing order
+@cindex Configuration file name (parsing order)
+@cindex Name of configuration files (parsing order)
+@cindex Location of configuration files (parsing order)
+
+The configuration files are parsed in the following order:
+@enumerate
+@item
+compiled-in defaults
+@item
+@file{@value{SYSCONFDIR}mtools.conf}
+@item
+@file{~/.mtoolsrc}.
+@item
+@file{$MTOOLSRC} (file pointed by the @code{MTOOLSRC} environmental
+variable)
+@end enumerate
+
+Options described in the later files override those described in the
+earlier files. Drives defined in earlier files persist if they are not
+overridden in the later files. For instance, drives A and B may be
+defined in @file{@value{SYSCONFDIR}mtools.conf} and drives C and D may be
+defined in @file{~/.mtoolsrc} However, if @file{~/.mtoolsrc} also
+defines drive A, this new description would override the description of
+drive A in @file{@value{SYSCONFDIR}mtools.conf} instead of adding to it. If
+you want to add a new description to a drive already described in an
+earlier file, you need to use either the @code{+drive} or @code{drive+}
+keyword.
+
+@node old style configuration, , parsing order, Configuration
+@section Backwards compatibility with old configuration file syntax
+@cindex Backwards compatibility
+@cindex Old configuration file syntax
+@cindex Configuration file, old syntax
+
+The syntax described herein is new for version @code{mtools-3.0}. The
+old line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+
+@comment MANskip 5
+
+@node Commands, Compiling mtools, Configuration, Top
+@chapter Command list
+@cindex Command list
+@cindex List of available commands
+
+ This section describes the available mtools commands, and the command
+line parameters that each of them accepts. Options which are common to
+all mtools commands are not described here, @ref{arguments} for a
+description of those.
+
+@menu
+* floppyd:: floppy daemon to run on your X server box
+* floppyd_installtest:: small utility to check for the presence of floppyd
+* mattrib:: change MS-DOS file attribute flags
+* mbadblocks:: tests a floppy disk, and marks the bad blocks in the FAT
+* mcat:: same as cat. Only useful with floppyd.
+* mcd:: change MS-DOS directory
+* mclasserase:: erase memory card
+* mcopy:: copy MS-DOS files to/from Unix
+* mdel:: delete an MS-DOS file
+* mdeltree:: recursively delete an MS-DOS directory
+* mdir:: display an MS-DOS directory
+* mdu:: list space occupied by directory and its contents
+* mformat:: add an MS-DOS file system to a low-level formatted floppy disk
+* minfo:: get information about an MS-DOS file system.
+* mlabel:: make an MS-DOS volume label
+* mkmanifest:: makes a list of short name equivalents
+* mmd:: make an MS-DOS subdirectory
+* mmount:: mount an MS-DOS disk
+* mpartition:: create an MS-DOS as a partition
+* mrd:: remove an MS-DOS subdirectory
+* mmove:: move or rename an MS-DOS file or subdirectory
+* mren:: rename an existing MS-DOS file
+* mshortname:: shows the short name of a file
+* mshowfat:: shows the FAT map of a file
+* mtoolstest:: tests and displays the configuration
+* mtype:: display contents of an MS-DOS file
+* mzip:: zip disk specific commands
+@end menu
+
+@node floppyd, floppyd_installtest, Commands, Commands
+@section Floppyd
+@pindex floppyd
+@cindex X terminal
+@cindex remote floppy access
+
+@code{Floppyd} is used as a server to grant access to the floppy drive
+to clients running on a remote machine, just as an X server grants
+access to the display to remote clients. It has the following syntax:
+
+@code{floppyd} [@code{-d}] [@code{-l}] [@code{-s} @var{port}] [@code{-r}
+@var{user}] [@code{-b} @var{ipaddr}] [@code{-x} @var{display}] @var{devicenames}
+
+
+@code{floppyd} is always associated with an X server. It runs on the
+same machine as its X server, and listens on port 5703 and above.
+
+@subsection Authentication
+
+@code{floppyd} authenticates remote clients using the @code{Xauthority}
+protocol. Xhost authentication is not supported. Each floppyd is
+associated with an X server. When a remote client attempts to connect
+to floppyd, it sends floppyd the X authority record corresponding to
+floppyd's X server. Floppyd in turn then tries to open up a connection
+to the X server in order to verify the authenticity of the xauth record.
+If the connection to the X server succeeds, the client is granted
+access.
+@code{DISPLAY}.
+
+@strong{Caution}: In order to make authentication work correctly, the
+local host should @strong{not} be listed in the @code{xhost} list of
+allowed hosts.
+ Indeed, hosts listed in @code{xhost} do not need a correct
+@code{Xauthority} cookie to connect to the X server. As @code{floppyd}
+runs on the same host as the X server, all its probe connection would
+succeed even for clients who supplied a bad cookie. This means that
+your floppy drive would be open to the world, i.e. a huge security hole.
+ If your X server does not allow you to remove @code{localhost:0} and
+@code{:0} from the @code{xhost} list, you can prevent floppyd from
+probing those display names with the @code{-l} option.
+
+@subsection Command line options
+
+@table @code
+@item d
+Daemon mode. Floppyd runs its own server loop. Do not supply this if
+you start floppyd from @code{inetd.conf}
+@item s @var{port}
+Port number for daemon mode. Default is 5703 + @var{displaynumber}.
+This flag implies daemon mode. For example, for display
+@code{hitchhiker:5}, the port would be 5708.
+@item b @var{ipaddr}
+Bind address (for multi homed hosts). This flag implies daemon mode
+@item r @var{user}
+Run the server under as the given user
+@item x @var{display}
+X display to use for authentication. By default, this is taken from the
+@code{DISPLAY} variable. If neither the @code{x} attribute is present
+nor @code{DISPLAY} is set, floppyd uses @code{:0.0}.
+@end table
+
+@var{devicenames} is a list of device nodes to be opened. Default
+is @code{/dev/fd0}. Multiple devices are only supported on mtools
+versions newer than 3.9.11.
+
+
+@subsection Connecting to floppyd
+
+ In order to use floppyd, add the flag @code{remote} to the device
+description in your @file{~/.mtoolsrc} file. If the flag @code{remote}
+is given, the @code{file} parameter of the device description is taken
+to be a remote address. It's format is the following:
+@var{hostname}@code{:}@var{displaynumber}[@code{/}[@var{baseport}][@code{/}@var{drive}]]. When
+using this entry, mtools connects to port
+@var{baseport}+@var{displaynumber} at @var{hostname}. By default
+@var{baseport} is 5703. The drive parameter is to distinguish among
+multiple drives associated with a single display (only mtools versions
+more recent than 3.9.11)
+
+@subsection Examples:
+
+ The following starts a floppy daemon giving access to @file{/dev/fd0},
+listening on the default port 5703, tied to the default X servers:
+
+@example
+floppyd -d /dev/fd0
+@end example
+
+ Each of the following starts a floppy daemon giving access to
+@file{/dev/fd1}, tied to the :1 local X servers, and listening on port
+5704. We assume that the local host is named @code{hitchhiker}.
+
+@example
+floppyd -d /dev/fd0
+floppyd -d -x :1 -p 5704 /dev/fd0
+@end example
+
+ If you want to start floppyd by @code{inetd} instead of running it as a
+daemon, insert the following lines into @file{/etc/services}:
+@example
+# floppy daemon
+floppyd-0 5703/tcp # floppy daemon for X server :0
+floppyd-1 5704/tcp # floppy daemon for X server :1
+@end example
+
+ And insert the following into @file{/etc/inetd.conf} (assuming that you
+have defined a user named floppy in your @file{/etc/passwd}):
+
+@example
+# floppy daemon
+floppyd-0 stream tcp wait floppy /usr/sbin/floppyd floppyd /dev/fd0
+floppyd-1 stream tcp wait floppy /usr/sbin/floppyd floppyd -x :1 /dev/fd0
+@end example
+
+ Note that you need to supply the X display names for the second
+floppyd. This is because the port is opened by inetd.conf, and hence
+floppyd cannot know its number to interfere the display number.
+
+
+On the client side, insert the following into your @file{~/.mtoolsrc}
+to define a drive letter accessing floppy drive in your X terminal:
+@example
+drive x: file="$DISPLAY" remote
+@end example
+
+If your X terminal has more than one drive, you may access the
+additional drives as follows:
+@example
+drive y: file="$DISPLAY//1" remote
+drive z: file="$DISPLAY//2" remote
+@end example
+
+@node floppyd_installtest, mattrib, floppyd, Commands
+@section Floppyd_installtest
+@pindex floppyd_installtest
+@cindex X terminal
+@cindex remote floppy access
+
+@code{Floppyd_installtest} is used to check for the presence of a running
+floppyd daemon. This is useful, if you have a small front-end script to
+mtools, which decides whether to use floppyd or not.
+
+@code{floppyd_installtest} [@code{-f}] Connect-String
+
+If the @code{-f} option is specified, @code{floppyd_installtest} does a
+full X-Cookie authentication and complains if this does not work.
+
+The connect-String has the format described in the floppyd-section:
+@var{hostname}@code{:}@var{displaynumber}[@code{/}@var{baseport}]
+
+@node mattrib, mbadblocks, floppyd_installtest, Commands
+@section Mattrib
+@pindex mattrib
+@cindex Changing file attributes
+@cindex Hidden files
+@cindex Read-only files (changing the attribute)
+@cindex System files
+@cindex Archive bit
+
+@code{Mattrib} is used to change MS-DOS file attribute flags. It has the
+following syntax:
+
+@code{mattrib} [@code{-a|+a}] [@code{-h|+h}] [@code{-r|+r}]
+[@code{-s|+s}] [@code{-/}] [@code{-p}] [@code{-X}] @var{msdosfile} [ @var{msdosfiles} @dots{} ]
+
+@code{Mattrib} adds attribute flags to an MS-DOS file (with the
+`@code{+}' operator) or remove attribute flags (with the `@code{-}'
+operator).
+
+@code{Mattrib} supports the following attribute bits:
+
+@table @code
+@item a
+Archive bit. Used by some backup programs to indicate a new file.
+@item r
+Read-only bit. Used to indicate a read-only file. Files with this bit
+set cannot be erased by @code{DEL} nor modified.
+@item s
+System bit. Used by MS-DOS to indicate a operating system file.
+@item h
+Hidden bit. Used to make files hidden from @code{DIR}.
+@end table
+
+@code{Mattrib} supports the following command line flags:
+@table @code
+@item /
+Recursive. Recursively list the attributes of the files in the subdirectories.
+@item X
+Concise. Prints the attributes without any whitespace padding. If
+neither the "/" option is given, nor the @var{msdosfile} contains a
+wildcard, and there is only one MS-DOS file parameter on the command
+line, only the attribute is printed, and not the filename. This option
+is convenient for scripts
+@item p
+Replay mode. Outputs a series of mformat commands that will reproduce
+the current situation, starting from a situation as left by untarring
+the MS-DOS file system. Commands are only output for attribute settings
+that differ from the default (archive bit set for files, unset for
+directories). This option is intended to be used in addition to
+tar. The @code{readonly} attribute is not taken into account, as tar can
+set that one itself.
+@end table
+
+@node mbadblocks, mcat, mattrib, Commands
+@section Mbadblocks
+@pindex mbadblocks
+@cindex Marking blocks as bad
+@cindex Bad blocks
+@cindex Read errors
+
+The @code{mbadblocks} command is used to mark some clusters on an
+MS-DOS filesystem bad. It has the following syntax:
+
+@code{mbadblocks} [@code{-s} @var{sectorlist}|@code{-c} @var{clusterlist}|-w] @var{drive}@code{:}
+
+If no command line flags are supplied, @code{Mbadblocks} scans an
+MS-DOS filesystem for bad blocks by simply trying to read them and
+flag them if read fails. All blocks that are unused are scanned, and
+if detected bad are marked as such in the FAT.
+
+This command is intended to be used right after @code{mformat}. It is
+not intended to salvage data from bad disks.
+
+
+@subsection Command line options
+
+@table @code
+@item c @var{file}
+Use a list of bad clusters, rather than scanning for bad clusters
+itself.
+@item s @var{file}
+Use a list of bad sectors (counted from beginning of filesystem),
+rather than trying for bad clusters itself.
+@item w
+Write a random pattern to each cluster, then read it back and flag
+cluster as bad if mismatch. Only free clusters are tested in such a
+way, so any file data is preserved.
+@end table
+
+@subsection Bugs
+@code{Mbadblocks} should (but doesn't yet :-( ) also try to salvage bad
+blocks which are in use by reading them repeatedly, and then mark them
+bad.
+
+@node mcat, mcd, mbadblocks, Commands
+@section Mcat
+
+The @code{mcat} command is used to copy an entire disk image from or
+to the floppy device. It uses the following syntax:
+
+@code{mcat} [@code{-w}] @var{drive}@code{:}
+@pindex mcat
+@cindex Copying an entire disk image
+@cindex Disk image
+@cindex Floppyd cat
+
+@code{Mcat} performs the same task as the Unix @code{cat} command. It
+is included into the mtools package, since @code{cat} cannot access
+remote floppy devices offered by the mtools floppy daemon.
+Now it is possible to create boot floppies remotely.
+
+The default operation is reading. The output is written to stdout.
+
+If the @code{-w} option is specified, mcat reads a disk-image from
+stdin and writes it to the given device.
+@strong{Use this carefully!} Because of the low-level nature of this
+command, it will happily destroy any data written before on the
+disk without warning!
+
+@node mcd, mclasserase, mcat, Commands
+@section Mcd
+@pindex mcd
+@cindex Directory (changing)
+@cindex Working directory
+@cindex Current working directory (changing the)
+@cindex Default directory (changing the)
+@cindex Mcwd file
+
+The @code{mcd} command is used to change the mtools working directory
+on the MS-DOS disk. It uses the following syntax:
+
+@example
+@code{mcd} [@var{msdosdirectory}]
+@end example
+
+Without arguments, @code{mcd} reports the current device and working
+directory. Otherwise, @code{mcd} changes the current device and current
+working directory relative to an MS-DOS file system.
+
+The environmental variable @code{MCWD} may be used to locate the file
+where the device and current working directory information is stored.
+The default is @file{$HOME/.mcwd}. Information in this file is ignored
+if the file is more than 6 hours old.
+
+@code{Mcd} returns 0 on success or 1 on failure.
+
+Unlike MS-DOS versions of @code{CD}, @code{mcd} can be used to change to
+another device. It may be wise to remove old @file{.mcwd} files at logout.
+
+@node mclasserase, mcopy, mcd, Commands
+@section Mclasserase
+@pindex mclasserase
+@cindex Memory Card
+@cindex Physically erase
+
+The @code{mclasserase} command is used to wipe memory cards by
+overwriting it three times: first with @code{0xff}, then with
+@code{0x00}, then with @code{0xff} again. The command uses the following
+syntax:
+
+@example
+@code{mclasserase} [@code{-d}] @var{msdosdrive}
+@end example
+
+MS-DOS drive is optional, if none is specified, use @code{A:}. If more than
+one drive are specified, all but the last are ignored.
+
+@code{Mclasserase} accepts the following command line options:
+
+@table @code
+@item d
+Stop after each erase cycle, for testing purposes
+@item p
+Not yet implemented
+@end table
+
+
+@code{Mclasserase} returns 0 on success or -1 on failure.
+
+
+@node mcopy, mdel, mclasserase, Commands
+@section Mcopy
+@pindex mcopy
+@cindex Reading MS-DOS files
+@cindex Writing MS-DOS files
+@cindex Copying MS-DOS files
+@cindex Concatenating MS-DOS files
+@cindex Text files
+@cindex CR/LF conversions
+
+The @code{mcopy} command is used to copy MS-DOS files to and from
+Unix. It uses the following syntax:
+
+@example
+@code{mcopy} [@code{-bspanvmQT}] [@code{-D} @var{clash_option}] @var{sourcefile} @var{targetfile}
+@code{mcopy} [@code{-bspanvmQT}] [@code{-D} @var{clash_option}] @var{sourcefile} [ @var{sourcefiles}@dots{} ] @var{targetdirectory}
+@code{mcopy} [@code{-tnvm}] @var{MSDOSsourcefile}
+@end example
+
+
+
+@code{Mcopy} copies the specified file to the named file, or copies
+multiple files to the named directory. The source and target can be
+either MS-DOS or Unix files.
+
+The use of a drive letter designation on the MS-DOS files, 'a:' for
+example, determines the direction of the transfer. A missing drive
+designation implies a Unix file whose path starts in the current
+directory. If a source drive letter is specified with no attached file
+name (e.g. @code{mcopy a: .}), all files are copied from that drive.
+
+If only a single, MS-DOS source parameter is provided (e.g. "mcopy
+a:foo.exe"), an implied destination of the current directory
+(`@code{.}') is assumed.
+
+A filename of `@code{-}' means standard input or standard output, depending
+on its position on the command line.
+
+@code{Mcopy} accepts the following command line options:
+
+@table @code
+@item t
+Text file transfer. Mcopy translates incoming carriage return/line
+feeds to line feeds when copying from MS-DOS to Unix, and vice-versa when
+copying from Unix to MS-DOS.
+@item b
+Batch mode. Optimized for huge recursive copies, but less secure if a
+crash happens during the copy.
+@item s
+Recursive copy. Also copies directories and their contents
+@item p
+Preserves the attributes of the copied files
+@item Q
+When mcopying multiple files, quits as soon as one copy fails (for
+example due to lacking storage space on the target disk)
+@item a
+Text (ASCII) file transfer. @code{ASCII} translates incoming carriage
+return/line feeds to line feeds.
+@item T
+Text (ASCII) file transfer with character set conversion. Differs from
+@code{-a} in the @code{ASCII} also translates incoming PC-8 characters
+to ISO-8859-1 equivalents as far as possible. When reading DOS files,
+untranslatable characters are replaced by '@code{#}'; when writing DOS files,
+untranslatable characters are replaced by '@code{.}'.
+@item n
+No confirmation when overwriting Unix files. @code{ASCII} doesn't warn
+the user when overwriting an existing Unix file. If the target file already exists,
+and the @code{-n} option is not in effect, @code{mcopy} asks whether to
+overwrite the file or to rename the new file (@ref{name clashes}) for
+details). In order to switch off confirmation for DOS files, use @code{-o}.
+@item m
+Preserve the file modification time.
+@item v
+Verbose. Displays the name of each file as it is copied.
+@end table
+
+@subsection Bugs
+Unlike MS-DOS, the '+' operator (append) from MS-DOS is not
+supported. However, you may use @code{mtype} to produce the same effect:
+@example
+mtype a:file1 a:file2 a:file3 >unixfile
+mtype a:file1 a:file2 a:file3 | mcopy - a:msdosfile
+@end example
+
+@node mdel, mdeltree, mcopy, Commands
+@section Mdel
+@pindex mdel
+@cindex removing MS-DOS files
+@cindex erasing MS-DOS files
+@cindex deleting MS-DOS files
+
+The @code{mdel} command is used to delete an MS-DOS file. Its syntax
+is:
+
+@display
+@code{mdel} [@code{-v}] @var{msdosfile} [ @var{msdosfiles} @dots{} ]
+@end display
+
+@code{Mdel} deletes files on an MS-DOS file system.
+
+@code{Mdel} asks for verification prior to removing a read-only file.
+
+@node mdeltree, mdir, mdel, Commands
+@section Mdeltree
+@pindex mdeltree
+@cindex removing an MS-DOS directory recursively
+@cindex erasing an MS-DOS directory recursively
+@cindex deleting an MS-DOS directory recursively
+@cindex recursively removing an MS-DOS directory
+
+The @code{mdeltree} command is used to delete an MS-DOS file. Its syntax
+is:
+
+@display
+@code{mdeltree} [@code{-v}] @var{msdosdirectory} [@var{msdosdirectories}@dots{}]
+@end display
+
+@code{Mdeltree} removes a directory and all the files and subdirectories
+it contains from an MS-DOS file system. An error occurs if the directory
+to be removed does not exist.
+
+@node mdir, mdu, mdeltree, Commands
+@section Mdir
+@pindex mdir
+@cindex Read-only files (listing them)
+@cindex Listing a directory
+@cindex Directory listing
+
+The @code{mdir} command is used to display an MS-DOS directory. Its
+syntax is:
+
+@code{mdir} [@code{-/}] [@code{-f}] [@code{-w}] [@code{-a}] [@code{-b}] @var{msdosfile} [ @var{msdosfiles}@dots{}]
+
+@code{Mdir}
+displays the contents of MS-DOS directories, or the entries for some
+MS-DOS files.
+
+@code{Mdir} supports the following command line options:
+
+@table @code
+@item /
+Recursive output, just like MS-DOS' @code{-s} option
+@item w
+Wide output. With this option, @code{mdir} prints the filenames across
+the page without displaying the file size or creation date.
+@item a
+Also list hidden files.
+@item f
+Fast. Do not try to find out free space. On larger disks, finding out
+the amount of free space takes up some non trivial amount of time, as
+the whole FAT must be read in and scanned. The @code{-f} flag bypasses
+this step. This flag is not needed on FAT32 file systems, which store
+the size explicitly.
+@item b
+Concise listing. Lists each directory name or filename, one per line
+(including the filename extension). This switch displays no heading
+information and no summary. Only a newline separated list of pathnames
+is displayed.
+@end table
+
+An error occurs if a component of the path is not a directory.
+
+@node mdu, mformat, mdir, Commands
+@section Mdu
+@pindex mdu
+@cindex Space occupied by directories and files
+@cindex du
+@cindex Listing space occupied by directories and files
+@cindex Occupation of space by directories and files
+
+@code{Mdu} is used to list the space occupied by a directory, its
+subdirectories and its files. It is similar to the @code{du} command on
+Unix. The unit used are clusters. Use the minfo command to find out
+the cluster size.
+
+@code{mdu} [@code{-a}] [ @var{msdosfiles} @dots{} ]
+
+
+@table @code
+@item a
+All files. List also the space occupied for individual files.
+@item s
+Only list the total space, don't give details for each subdirectory.
+@end table
+
+
+
+@node mformat, mkmanifest, mdu, Commands
+@section Mformat
+@pindex mformat
+@cindex Initializing disks
+@cindex Formatting disks
+@cindex File system creation
+
+The @code{mformat} command is used to add an MS-DOS file system to a
+low-level formatted diskette. Its syntax is:
+
+@display
+@code{mformat} [@code{-t} @var{cylinders}|@code{-T} @var{tot_sectors}] [@code{-h} @var{heads}] [@code{-s} @var{sectors}]
+ [@code{-f} @var{size}] [@code{-1}] [@code{-4}] [@code{-8}]
+ [@code{-v} @var{volume_label}]
+ [@code{-F}] [@code{-S} @var{sizecode}]
+ [@code{-M} @var{software_sector_size}]
+ [@code{-N} @var{serial_number}] [@code{-a}]
+ [@code{-C}] [@code{-H} @var{hidden_sectors}] [@code{-I} @var{fsVersion}]
+ [@code{-r} @var{root_sectors}] [@code{-L} @var{fat_len}]
+ [@code{-B} @var{boot_sector}] [@code{-k}]
+ [@code{-m} @var{media_descriptor}]
+ [@code{-K} @var{backup_boot}]
+ [@code{-c} @var{clusters_per_sector}]
+ [@code{-d} @var{fat_copies}]
+ [@code{-X}] [@code{-2} @var{sectors_on_track_0}] [@code{-3}]
+ [@code{-0} @var{rate_on_track_0}] [@code{-A} @var{rate_on_other_tracks}]
+ @var{drive:}
+@end display
+
+@code{Mformat} adds a minimal MS-DOS file system (boot sector, FAT, and
+root directory) to a diskette that has already been formatted by a Unix
+low-level format.
+
+
+The following options are supported: (The S, 2, 1 and M options may not
+exist if this copy of mtools has been compiled without the USE_2M
+option)
+
+The following options are the same as for MS-DOS's format command:
+
+@comment xMANoptions
+
+@table @code
+@item v
+Specifies the volume label. A volume label identifies the disk and can
+be a maximum of 11 characters. If you omit the -v switch, mformat will
+assign no label to the disk.
+@item f
+Specifies the size of the DOS file system to format. Only a certain
+number of predefined sizes are supported by this flag; for others use
+the -h/-t/-s flags. The following sizes are supported:
+@table @asis
+@item 160
+160K, single-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 180
+160K, single-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 320
+320K, double-sided, 8 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 360
+360K, double-sided, 9 sectors per track, 40 cylinders (for 5 1/4 DD)
+@item 720
+720K, double-sided, 9 sectors per track, 80 cylinders (for 3 1/2 DD)
+@item 1200
+1200K, double-sided, 15 sectors per track, 80 cylinders (for 5 1/4 HD)
+@item 1440
+1440K, double-sided, 18 sectors per track, 80 cylinders (for 3 1/2 HD)
+@item 2880
+2880K, double-sided, 36 sectors per track, 80 cylinders (for 3 1/2 ED)
+@end table
+
+@item t
+Specifies the number of tracks on the disk.
+@item T
+Specifies the number of total sectors on the disk. Only one of these 2
+options may be specified (tracks or total sectors)
+@item h
+The number of heads (sides).
+@item s
+Specifies the number of sectors per track. If the 2m option is given,
+number of 512-byte sector equivalents on generic tracks (i.e. not head 0
+track 0). If the 2m option is not given, number of physical sectors per
+track (which may be bigger than 512 bytes).
+
+@item 1
+Formats a single side (equivalent to -h 1)
+
+@item 4
+Formats a 360K double-sided disk (equivalent to -f 360). When used
+together with -the 1 switch, this switch formats a 180K disk
+
+@item 8
+Formats a disk with 8 sectors per track.
+
+@end table
+
+MS-DOS format's @code{q}, @code{u} and @code{b} options are not
+supported, and @code{s} has a different meaning.
+
+The following options are specific to mtools:
+
+@table @code
+
+@item F
+Format the partition as FAT32.
+
+@item S
+The size code. The size of the sector is 2 ^ (sizecode + 7).
+@item X
+formats the disk as an XDF disk. @xref{XDF}, for more details. The disk
+has first to be low-level formatted using the xdfcopy utility included
+in the fdutils package. XDF disks are used for instance for OS/2 install
+disks.
+@item 2
+2m format. The parameter to this option describes the number of
+sectors on track 0, head 0. This option is recommended for sectors
+bigger than normal.
+@item 3
+don't use a 2m format, even if the current geometry of the disk is a 2m
+geometry.
+@item 0
+Data transfer rate on track 0
+@item A
+Data transfer rate on tracks other than 0
+@item M
+software sector size. This parameter describes the sector size in bytes used
+by the MS-DOS file system. By default it is the physical sector size.
+@item N
+Uses the requested serial number, instead of generating one
+automatically
+@item a
+If this option is given, an Atari style serial number is generated.
+Ataris store their serial number in the OEM label.
+@item C
+creates the disk image file to install the MS-DOS file system on
+it. Obviously, this is useless on physical devices such as floppies
+and hard disk partitions, but is interesting for image files.
+@item H
+number of hidden sectors. This parameter is useful for formatting hard
+disk partition, which are not aligned on track boundaries (i.e. first
+head of first track doesn't belong to the partition, but contains a
+partition table). In that case the number of hidden sectors is in
+general the number of sectors per cylinder. This is untested.
+@item I
+Sets the fsVersion id when formatting a FAT32 drive. In order to find
+this out, run minfo on an existing FAT32 drive, and mail me about it, so
+I can include the correct value in future versions of mtools.
+@item c
+Sets the size of a cluster (in sectors). If this cluster size would
+generate a FAT that too big for its number of bits, mtools automatically
+increases the cluster size, until the FAT is small enough.
+@item d
+Sets the number of FAT copies. Default is 2. This setting can also be
+specified using the @code{MTOOLS_NFATS} environment variable.
+@item r
+Sets the size of the root directory (in sectors). Only applicable to 12
+and 16 bit FATs. This setting can also be specified using the
+@code{MTOOLS_DIR_LEN} environment variable.
+@item L
+Sets the length of the FAT.
+@item B
+Use the boot sector stored in the given file or device, instead of using
+its own. Only the geometry fields are updated to match the target disks
+parameters.
+@item k
+Keep the existing boot sector as much as possible. Only the geometry
+fields and other similar file system data are updated to match the target
+disks parameters.
+@item K
+Sets the sector number where the backup of the boot sector should be
+stored (only relevant on FAT32).
+
+@item 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{ASCII}
+converts the names to:
+
+@example
+ very_lon
+ 2xmany.dot
+ illegalx
+ good.c
+ xprn.dev
+ capital
+@end example
+
+The command:
+@example
+mkmanifest very_long_name 2.many.dots illegal: good.c prn.dev Capital >manifest
+@end example
+would produce the following:
+@example
+ mv very_lon very_long_name
+ mv 2xmany.dot 2.many.dots
+ mv illegalx illegal:
+ mv xprn.dev prn.dev
+ mv capital Capital
+@end example
+
+Notice that "good.c" did not require any conversion, so it did not
+appear in the output.
+
+Suppose I've copied these files from the diskette to another Unix
+system, and I now want the files back to their original names. If the
+file "manifest" (the output captured above) was sent along with those
+files, it could be used to convert the filenames.
+
+@subsection Bugs
+
+The short names generated by @code{mkmanifest} follow the old convention
+(from mtools-2.0.7) and not the one from Windows 95 and mtools-3.0.
+
+
+@node minfo, mlabel, mkmanifest, Commands
+@section Minfo
+@pindex minfo
+@cindex mformat parameters
+@cindex getting parameters of a MS-DOS file system
+
+The @code{minfo} command prints the parameters of a MS-DOS file system, such
+as number of sectors, heads and cylinders. It also prints an mformat
+command line which can be used to create a similar MS-DOS file system on
+another media. However, this doesn't work with 2m or XDF media, and
+with MS-DOS 1.0 file systems
+@display
+@code{minfo} @var{drive}:
+@end display
+
+Minfo supports the following option:
+@table @code
+@item v
+Prints a hexdump of the boot sector, in addition to the other information
+@end table
+
+
+@node mlabel, mmd, minfo, Commands
+@section Mlabel
+@pindex mlabel
+@cindex Labeling a disk
+@cindex Disk label
+
+The @code{mlabel} command adds a volume label to a disk. Its syntax is:
+@display
+@code{mlabel} [@code{-vcsn}] [@code{-N} @var{serial}] @var{drive}:[@var{new_label}]
+@end display
+
+@code{Mlabel} displays the current volume label, if present. If
+@var{new_label} is not given, and if neither the @code{c} nor the
+@code{s} options are set, it prompts the user for a new volume label.
+To delete an existing volume label, press return at the prompt.
+
+The label is limited to 11 single-byte characters,
+e.g. @code{Name1234567}.
+
+Reasonable care is taken to create a valid MS-DOS volume label. If an
+invalid label is specified, @code{mlabel} changes the label (and
+displays the new label if the verbose mode is set). @code{Mlabel}
+returns 0 on success or 1 on failure.
+
+Mlabel supports the following options:
+@table @code
+@item c
+Clears an existing label, without prompting the user
+@item s
+Shows the existing label, without prompting the user.
+@item n
+Assigns a new (random) serial number to the disk
+@item N @var{serial}
+Sets the supplied serial number. The serial number should be supplied as
+an 8 digit hexadecimal number, without spaces
+@end table
+
+
+@node mmd, mmount, mlabel, Commands
+@section Mmd
+@pindex mmd
+@cindex Making a directory
+@cindex Creating a directory
+@cindex Directory creation
+@cindex Subdirectory creation
+
+The @code{mmd} command is used to make an MS-DOS subdirectory. Its
+syntax is:
+
+@code{mmd} [@code{-D} @var{clash_option}] @var{msdosdirectory} [
+@var{msdosdirectories}@dots{} ]
+
+@code{Mmd} makes a new directory on an MS-DOS file system. An error occurs
+if the directory already exists.
+
+
+@node mmount, mmove, mmd, Commands
+@section Mmount
+@pindex mmount
+@cindex Linux enhancements (mmount)
+@cindex Mounting a disk
+@cindex High capacity formats, mounting
+
+The @code{mmount} command is used to mount an MS-DOS disk. It is only
+available on Linux, as it is only useful if the OS kernel allows 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 file system. Data cannot be moved from MS-DOS to Unix or
+vice-versa. If you omit the drive letter from the target file or
+directory, the same letter as for the source is assumed. If you omit
+the drive letter from all parameters, drive a: is assumed by default.
+
+@node mpartition, mrd, mmove, Commands
+@section Mpartition
+@pindex mpartition
+@cindex partitions (creating)
+@cindex Zip disks (partitioning them)
+@cindex Jaz disks (partitioning them)
+
+The @code{mpartition} command is used to create MS-DOS file systems as
+partitions. This is intended to be used on non-Linux systems,
+i.e. systems where fdisk and easy access to SCSI devices are not
+available. This command only works on drives whose partition variable
+is set.
+
+@display
+@code{mpartition} @code{-p} @var{drive}
+@code{mpartition} @code{-r} @var{drive}
+@code{mpartition} @code{-I} [@code{-B} @var{bootSector}] @var{drive}
+@code{mpartition} @code{-a} @var{drive}
+@code{mpartition} @code{-d} @var{drive}
+@code{mpartition} @code{-c} [@code{-s} @var{sectors}] [@code{-h} @var{heads}]
+[@code{-t} @var{cylinders}] [@code{-v} [@code{-T} @var{type}] [@code{-b}
+@var{begin}] [@code{-l} length] [@code{-f}]
+
+@end display
+
+Mpartition supports the following operations:
+
+@table @code
+@item p
+Prints a command line to recreate the partition for the drive. Nothing
+is printed if the partition for the drive is not defined, or an
+inconsistency has been detected. If verbose (@code{-v}) is also set,
+prints the current partition table.
+@item r
+Removes the partition described by @var{drive}.
+@item I
+Initializes the partition table, and removes all partitions.
+@item c
+Creates the partition described by @var{drive}.
+@item a
+"Activates" the partition, i.e. makes it bootable. Only one partition
+can be bootable at a time.
+@item d
+"Deactivates" the partition, i.e. makes it unbootable.
+@end table
+
+If no operation is given, the current settings are printed.
+
+For partition creations, the following options are available:
+@table @code
+@item s @var{sectors}
+The number of sectors per track of the partition (which is also the
+number of sectors per track for the whole drive).
+@item h @var{heads}
+The number of heads of the partition (which is also the number of heads
+for the whole drive). By default, the geometry information (number of
+sectors and heads) is figured out from neighboring partition table
+entries, or guessed from the size.
+@item t @var{cylinders}
+The number of cylinders of the partition (not the number of cylinders of
+the whole drive.
+@item b @var{begin}
+The starting offset of the partition, expressed in sectors. If begin is
+not given, 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 consistency 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 file system. An error occurs
+if the directory does not exist or is not empty.
+
+@node mren, mshortname, mrd, Commands
+@section Mren
+@pindex mren
+@cindex Renaming files (mren)
+@cindex Moving files (mren)
+
+The @code{mren} command is used to rename or move an existing MS-DOS
+file or subdirectory. Its syntax is:
+
+@display
+@code{mren} [@code{-voOsSrRA}] @var{sourcefile} @var{targetfile}
+@end display
+
+@code{Mren}
+renames an existing file on an MS-DOS file system.
+
+In verbose mode, @code{Mren} displays the new filename if the name
+supplied is invalid.
+
+If the first syntax is used (only one source file), and if the target
+name doesn't contain any slashes or colons, the file (or subdirectory)
+is renamed in the same directory, instead of being moved to the current
+@code{mcd} directory as would be the case with @code{mmove}. Unlike the
+MS-DOS version of @code{REN}, @code{mren} can be used to rename
+directories.
+
+@node mshortname, mshowfat, mren, Commands
+@section Mshortname
+@pindex mshortname
+
+The @code{mshortname} command is used to display the short name of a
+file. Syntax:
+
+@display
+@code{mshortname} @var{files}
+@end display
+
+The shortname is displayed as it is stored in raw format on disk,
+without any character set conversion.
+
+@node mshowfat, mtoolstest, mshortname, Commands
+@section Mshowfat
+@pindex mshowfat
+@cindex Clusters of a file
+@cindex Fat
+
+The @code{mshowfat} command is used to display the FAT entries for a
+file. Syntax:
+
+@display
+@code{mshowfat} [@code{-o} @var{offset}] @var{files}
+@end display
+
+If no offset is given, a list of all clusters occupied by the file is
+printed. If an offset is given, only the number of the cluster
+containing that offset is printed.
+
+@node mtoolstest, mtype, mshowfat, Commands
+@section Mtoolstest
+@pindex mtoolstest
+@cindex Testing configuration file for correctness
+@cindex Checking configuration file
+@cindex Verifying configuration file
+
+The @code{mtoolstest} command is used to tests the mtools configuration
+files. To invoke it, just type @code{mtoolstest} without any arguments.
+@code{Mtoolstest} reads the mtools configuration files, and prints the
+cumulative configuration to @code{stdout}. The output can be used as a
+configuration file itself (although you might want to remove redundant
+clauses). You may use this program to convert old-style configuration
+files into new style configuration files.
+
+@node mtype, mzip, mtoolstest, Commands
+@section Mtype
+
+The @code{mtype} command is used to display contents of an MS-DOS
+file. Its syntax is:
+
+@display
+@code{mtype} [@code{-ts}] @var{msdosfile} [ @var{msdosfiles}@dots{} ]
+@end display
+
+@code{Mtype} displays the specified MS-DOS file on the screen.
+
+In addition to the standard options, @code{Mtype} allows the following
+command line options:
+
+@table @code
+@item t
+Text file viewing. @code{Mtype} translates incoming carriage
+return/line feeds to line feeds.
+@item s
+@code{Mtype} strips the high bit from the data.
+@end table
+
+The @code{mcd} command may be used to establish the device and the
+current working directory (relative to MS-DOS), otherwise the default is
+@code{A:/}.
+
+@code{Mtype} returns 0 on success, 1 on utter failure, or 2 on partial
+failure.
+
+Unlike the MS-DOS version of @code{TYPE}, @code{mtype} allows multiple
+arguments.
+
+
+@node mzip, , mtype, Commands
+@section Mzip
+@cindex Zip disk (utilities)
+@cindex Jaz disk (utilities)
+@cindex Ejecting a Zip/Jaz disk
+@cindex Write protecting a Zip/Jaz disk
+@pindex mzip
+@cindex ZipTools disk
+@cindex Tools disk (Zip and Jaz drives)
+@cindex APlaceForYourStuff
+@cindex password protected Zip disks
+
+The @code{mzip} command is used to issue ZIP disk specific commands on
+Linux, Solaris or HP-UX. Its syntax is:
+
+@display
+@code{mzip} [@code{-epqrwx}]
+@end display
+
+@code{Mzip} allows the following
+command line options:
+
+@table @code
+@item e
+Ejects the disk.
+@item f
+Force eject even if the disk is mounted (must be given in addition to
+@code{-e}).
+@item r
+Write protect the disk.
+@item w
+Remove write protection.
+@item p
+Password write protect.
+@item x
+Password protect
+@item u
+Temporarily unprotect the disk until it is ejected. The disk becomes
+writable, and reverts back to its old state when ejected.
+@item q
+Queries the status
+@end table
+
+To remove the password, set it to one of the password-less modes
+@code{-r} or @code{-w}: mzip will then ask you for the password, and
+unlock the disk. If you have forgotten the password, you can get rid of
+it by low-level formatting the disk (using your SCSI adapter's BIOS
+setup).
+
+The ZipTools disk shipped with the drive is also password protected. On
+MS-DOS or on a Mac, this password is automatically removed once the
+ZipTools have been installed. From various articles posted to Usenet, I
+learned that the password for the tools disk is
+@code{APlaceForYourStuff}@footnote{To see the articles, search for
+@code{APlaceForYourStuff} using Google Groups}. Mzip knows about this
+password, and tries it first, before prompting you for a password. Thus
+@code{mzip -w z:} unlocks the tools disk@footnote{I didn't know about
+this yet when I bought my own Zip drive. Thus I ended up reformatting
+my tools disk, and hence I haven't had the opportunity to test the
+password yet. If anybody still has their tools disk with the original
+password, could you try it out? Thanks in advance}. The tools disk is
+formatted in a special way so as to be usable both in a PC and in a Mac.
+On a PC, the Mac file system appears as a hidden file named
+@file{partishn.mac}. You may erase it to reclaim the 50 Megs of space
+taken up by the Mac file system.
+
+
+@subsection Bugs
+
+This command is a big kludge. A proper implementation would take a
+rework of significant parts of mtools, but unfortunately I don't have
+the time for this right now. The main downside of this implementation is
+that it is inefficient on some architectures (several successive calls
+to mtools, which defeats mtools' caching).
+
+@node Compiling mtools, Porting mtools, Commands, Top
+@chapter Architecture specific compilation flags
+@cindex XDF disks (compile time configuration)
+@cindex Solaris (compile time configuration of vold)
+@cindex Vold (compile time configuration)
+@cindex Compile time configuration
+
+To compile mtools, first invoke @code{./configure} before
+@code{make}. In addition to the standard @code{autoconfigure} flags,
+there are two architecture specific flags available.
+
+@table @code
+@item ./configure --enable-xdf
+@itemx ./configure --disable-xdf
+Enables support for XDF disks. This is on by default. @xref{XDF},
+for details.
+@item ./configure --enable-vold
+@itemx ./configure --disable-vold
+Enables support for vold on Solaris. When used in conjunction with vold,
+mtools should use different device nodes than for direct access.
+
+@item ./configure --enable-new-vold
+@itemx ./configure --disable-new-vold
+Enables new support for vold on Solaris. This is supposed to work more
+smoothly than the old support.
+
+@item ./configure --enable-floppyd
+@itemx ./configure --disable-floppyd
+Enables support for floppyd. By default, floppyd support is enabled as
+long as the necessary X includes and libraries are available.
+@end table
+
+@node Porting mtools, Command Index, Compiling mtools, Top
+@chapter Porting mtools to architectures which are not supported yet
+@cindex Porting
+@cindex Compiled-in defaults
+
+ This chapter is only interesting for those who want to port mtools to
+an architecture which is not yet supported. For most common systems,
+default drives are already defined. If you want to add default drives
+for a still unsupported system, run configuration.guess, to see which
+identification autoconf uses for that system. This identification is
+of the form cpu-vendor-os (for example sparc-sun-sunos). The cpu and
+the OS parts are passed to the compiler as preprocessor flags.
+ The OS part is passed to the compiler in three forms.
+@enumerate
+@item
+The complete OS name, with dots replaced by underscores. SCO3.2v2 would
+yield sco3_2v2
+@item
+The base OS name. SCO3.2v2 would yield Sco
+@item
+The base OS name plus its major version. SCO3.2v2 would yield Sco3
+@end enumerate
+
+ All three versions are passed, if they are different.
+
+ To define the devices, use the entries for the systems that are already
+present as templates. In general, they have the following form:
+
+@example
+#if (defined (my_cpu) && defined(my_os))
+#define predefined_devices
+struct device devices[] = @{
+ @{ "/dev/first_drive", 'drive_letter', drive_description@},
+ @dots{}
+ @{ "/dev/last_drive", 'drive_letter', drive_description@}
+@}
+#define INIT_NOOP
+#endif
+@end example
+
+ "/dev/first_drive" is the name of the device or image file
+representing the drive. Drive_letter is a letter ranging from a to z
+giving access to the drive. Drive_description describes the type of the
+drive:
+@table @code
+@item ED312
+extra density (2.88M) 3 1/2 disk
+@item HD312
+high density 3 1/2 disk
+@item DD312
+double density 3 1/2 disk
+@item HD514
+high density 5 1/4 disk
+@item DD514
+double density 5 1/4 disk
+@item DDsmall
+8 sector double density 5 1/4 disk
+@item SS514
+single sided double density 5 1/4 disk
+@item SSsmall
+single sided 8 sector double density 5 1/4 disk
+@item GENFD
+generic floppy drive (12 bit FAT)
+@item GENHD
+generic hard disk (16 bit FAT)
+@item GEN
+generic device (all parameters match)
+@item ZIPJAZ(flags)
+generic ZIP drive using normal access. This uses partition 4.
+@code{Flags} are any special flags to be passed to open.
+@item RZIPJAZ(flags)
+generic ZIP drive using raw SCSI access. This uses partition 4.
+@code{Flags} are any special flags to be passed to open.
+@item REMOTE
+the remote drive used for floppyd. Unlike the other items, this macro
+also includes the file name ($DISPLAY) and the drive letter (X)
+@end table
+
+ Entries may be described in more detail:
+@example
+ fat_bits,open_flags,cylinders,heads,sectors,DEF_ARG
+@end example
+ or, if you need to describe an offset (file system doesn't start at
+beginning of file system)
+@example
+ fat_bits, open_flags, cylinders, heads, sectors, offset, DEF_ARG0
+@end example
+
+@table @code
+@item fat_bits
+is either 12, 16 or 0. 0 means that the device accepts both types of
+FAT.
+@item open_flags
+may include flags such as O_NDELAY, or O_RDONLY, which might be
+necessary to open the device. 0 means no special flags are needed.
+@item cylinders,heads,sectors
+describe the geometry of the disk. If cylinders is 0, the heads and sectors
+parameters are ignored, and the drive accepts any geometry.
+@item offset
+is used if the DOS file system doesn't begin at the start of the device
+or image file. This is mostly useful for Atari Ram disks (which contain
+their device driver at the beginning of the file) or for DOS emulator
+images (which may represent a partitioned device.
+@end table
+
+ Definition of defaults in the devices file should only be done if these
+same devices are found on a large number of hosts of this type. In that
+case, could you also let me know about your new definitions, so that I
+can include them into the next release. For purely local file, I
+recommend that you use the @code{@value{SYSCONFDIR}mtools.conf} and
+@code{~/.mtoolsrc} configuration files.
+
+ However, the devices files also allows to supply geometry setting
+routines. These are necessary if you want to access high capacity
+disks.
+
+ Two routines should be supplied:
+
+@enumerate
+@item
+Reading the current parameters
+@example
+static inline int get_parameters(int fd, struct generic_floppy_struct *floppy)
+@end example
+
+ This probes the current configured geometry, and return it in
+the structure generic_floppy_struct (which must also be declared).
+ Fd is an open file descriptor for the device, and buf is an already
+filled in stat structure, which may be useful.
+ This routine should return 1 if the probing fails, and 0 otherwise.
+
+@item
+Setting new parameters
+@example
+static inline int set_parameters(int fd, struct generic_floppy_struct *floppy)
+ struct stat *buf)
+@end example
+ This configures the geometry contained in floppy on the file descriptor
+fd. Buf is the result of a stat call (already filled in). This should
+return 1 if the new geometry cannot be configured, and 0 otherwise.
+@end enumerate
+
+ A certain number of preprocessor macros should also be supplied:
+
+@table @code
+@item TRACKS(floppy)
+refers to the track field in the floppy structure
+@item HEADS(floppy)
+refers to the heads field in the floppy structure
+@item SECTORS(floppy)
+refers to the sectors per track field in the floppy structure
+@item SECTORS_PER_DISK(floppy)
+refers to the sectors per disk field in the floppy structure (if
+applicable, otherwise leave undefined)
+
+@item BLOCK_MAJOR
+major number of the floppy device, when viewed as a block device
+
+@item CHAR_MAJOR
+major number of the floppy device, when viewed as a character device
+(a.k.a. "raw" device, used for fsck) (leave this undefined, if your OS
+doesn't have raw devices)
+@end table
+
+ For the truly high capacity formats (XDF, 2m, etc), there is no clean
+and documented interface yet.
+
+@comment MANskip 1
+
+@node Command Index, Variable Index, Porting mtools, Top
+@unnumbered Command Index
+@printindex pg
+
+@node Variable Index, Concept Index, Command Index, Top
+@unnumbered Variable index
+@printindex vr
+
+@node Concept Index, , Variable Index, Top
+@unnumbered Concept index
+@printindex cp
+
+@comment MANend-skip 1
+@comment MANend-skip 5
+@bye
diff --git a/mtools.tmpl.1 b/mtools.tmpl.1
new file mode 100644
index 0000000..8b62542
--- /dev/null
+++ b/mtools.tmpl.1
@@ -0,0 +1,521 @@
+'\" t
+.TH mtools 1 "09Jan13" mtools-4.0.18
+.SH Name
+mtools - utilities to access DOS disks in Unix.
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.PP
+.SH Introduction
+Mtools is a collection of tools to allow Unix systems to manipulate
+MS-DOS files: read, write, and move around files on an MS-DOS
+file system (typically a floppy disk). Where reasonable, each program
+attempts to emulate the MS-DOS equivalent command. However,
+unnecessary restrictions and oddities of DOS are not emulated. For
+instance, it is possible to move subdirectories from one subdirectory
+to another.
+.PP
+Mtools is sufficient to give access to MS-DOS file systems. For
+instance, commands such as \fR\&\f(CWmdir a:\fR work on the \fR\&\f(CWa:\fR floppy
+without any preliminary mounting or initialization (assuming the default
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR works on your machine). With mtools, one can
+change floppies too without unmounting and mounting.
+.PP
+.SH Where\ to\ get\ mtools
+.PP
+Mtools can be found at the following places (and their mirrors):
+
+.nf
+.ft 3
+.in +0.3i
+http://ftp.gnu.org/gnu/mtools/mtools-4.0.18.tar.gz
+http://mtools.linux.lu/mtools-4.0.18.tar.gz
+ftp://www.tux.org/pub/knaff/mtools/mtools-4.0.18.tar.gz
+ftp://ibiblio.unc.edu/pub/Linux/utils/disk-management/mtools-4.0.18.tar.gz
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\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
+.PP
+
+\&\fR
+.PP
+These patches are named
+\&\fR\&\f(CWmtools-\fR\fIversion\fR\fR\&\f(CW-\fR\fIddmm\fR\fR\&\f(CW.taz\fR, where version
+stands for the base version, \fIdd\fR for the day and \fImm\fR for the
+month. Due to a lack of space, I usually leave only the most recent
+patch.
+.PP
+There is an mtools mailing list at 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
+MS-DOS filenames are composed of a drive letter followed by a colon, a
+subdirectory, and a filename. Only the filename part is mandatory, the
+drive letter and the subdirectory are optional. Filenames without a
+drive letter refer to Unix files. Subdirectory names can use either the
+\&'\fR\&\f(CW/\fR' or '\fR\&\f(CW\e\fR' separator. The use of the '\fR\&\f(CW\e\fR' separator
+or wildcards requires the names to be enclosed in quotes to protect them
+from the shell. However, wildcards in Unix filenames should not be
+enclosed in quotes, because here we \fBwant\fR the shell to expand
+them.
+.PP
+The regular expression "pattern matching" routines follow the Unix-style
+rules. For example, `\fR\&\f(CW*\fR' matches all MS-DOS files in lieu of
+`\fR\&\f(CW*.*\fR'. The archive, hidden, read-only and system attribute bits
+are ignored during pattern matching.
+.PP
+All options use the \fR\&\f(CW-\fR (minus) as their first character, not
+\&\fR\&\f(CW/\fR as you'd expect in MS-DOS.
+.PP
+Most mtools commands allow multiple filename parameters, which
+doesn't follow MS-DOS conventions, but which is more user-friendly.
+.PP
+Most mtools commands allow options that instruct them how to handle file
+name clashes. See section name clashes, for more details on these. All
+commands accept the \fR\&\f(CW-V\fR flags which prints the version, and most
+accept the \fR\&\f(CW-v\fR flag, which switches on verbose mode. In verbose
+mode, these commands print out the name of the MS-DOS files upon which
+they act, unless stated otherwise. See section Commands, for a description of
+the options which are specific to each command.
+.PP
+.SS Drive\ letters
+.PP
+The meaning of the drive letters depends on the target architectures.
+However, on most target architectures, drive A is the first floppy
+drive, drive B is the second floppy drive (if available), drive J is a
+Jaz drive (if available), and drive Z is a Zip drive (if available). On
+those systems where the device name is derived from the SCSI id, the Jaz
+drive is assumed to be at SCSI target 4, and the Zip at SCSI target 5
+(factory default settings). On Linux, both drives are assumed to be the
+second drive on the SCSI bus (/dev/sdb). The default settings can be
+changes using a configuration file (see section Configuration).
+.PP
+The drive letter : (colon) has a special meaning. It is used to access
+image files which are directly specified on the command line using the
+\&\fR\&\f(CW-i\fR options.
+.PP
+Example:
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy -i my-image-file.bin ::file1 ::file2 .
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+This copies \fR\&\f(CWfile1\fR and \fR\&\f(CWfile2\fR from the image file
+(\fR\&\f(CWmy-image-file.bin\fR) to the \fR\&\f(CW/tmp\fR directory.
+.PP
+You can also supply an offset within the image file by including
+\&\fR\&\f(CW@@\fR\fIoffset\fR into the file name.
+.PP
+Example:
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy -i my-image-file.bin@@1M ::file1 ::file2 .
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+This looks for the image at the offset of 1M in the file, rather than
+at its beginning.
+.PP
+.SS Current\ working\ directory
+.PP
+The \fR\&\f(CWmcd\fR command (\(ifmcd\(is) is used to establish the device and
+the current working directory (relative to the MS-DOS file system),
+otherwise the default is assumed to be \fR\&\f(CWA:/\fR. However, unlike
+MS-DOS, there is only one working directory for all drives, and not one
+per drive.
+.PP
+.SS VFAT-style\ long\ file\ names
+.PP
+This version of mtools supports VFAT style long filenames. If a Unix
+filename is too long to fit in a short DOS name, it is stored as a
+VFAT long name, and a companion short name is generated. This short
+name is what you see when you examine the disk with a pre-7.0 version
+of DOS.
+ The following table shows some examples of short names:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+Long name MS-DOS name Reason for the change
+--------- ---------- ---------------------
+thisisatest THISIS~1 filename too long
+alain.knaff ALAIN~1.KNA extension too long
+prn.txt PRN~1.TXT PRN is a device name
+\&\&.abc ABC~1 null filename
+hot+cold HOT_CO~1 illegal character
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ As you see, the following transformations happen to derive a short
+name:
+.TP
+* \ \
+Illegal characters are replaced by underscores. The illegal characters
+are \fR\&\f(CW;+=[]',\e"*\e\e<>/?:|\fR.
+.TP
+* \ \
+Extra dots, which cannot be interpreted as a main name/extension
+separator are removed
+.TP
+* \ \
+A \fR\&\f(CW~\fR\fIn\fR number is generated,
+.TP
+* \ \
+The name is shortened so as to fit in the 8+3 limitation
+.PP
+ The initial Unix-style file name (whether long or short) is also called
+the \fIprimary\fR name, and the derived short name is also called the
+\&\fIsecondary\fR name.
+.PP
+ Example:
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy /etc/motd a:Reallylongname
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR Mtools creates a VFAT entry for Reallylongname, and uses REALLYLO as
+a short name. Reallylongname is the primary name, and REALLYLO is the
+secondary name.
+
+.nf
+.ft 3
+.in +0.3i
+ mcopy /etc/motd a:motd
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR Motd fits into the DOS filename limits. Mtools doesn't need to
+derivate another name. Motd is the primary name, and there is no
+secondary name.
+.PP
+ In a nutshell: The primary name is the long name, if one exists, or
+the short name if there is no long name.
+.PP
+ Although VFAT is much more flexible than FAT, there are still names
+that are not acceptable, even in VFAT. There are still some illegal
+characters left (\fR\&\f(CW\e"*\e\e<>/?:|\fR), and device names are still
+reserved.
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+Unix name Long name Reason for the change
+--------- ---------- ---------------------
+prn prn-1 PRN is a device name
+ab:c ab_c-1 illegal character
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+ As you see, the following transformations happen if a long name is
+illegal:
+.TP
+* \ \
+Illegal characters are replaces by underscores,
+.TP
+* \ \
+A \fR\&\f(CW-\fR\fIn\fR number is generated,
+.PP
+.SS Name\ clashes
+.PP
+When writing a file to disk, its long name or short name may collide
+with an already existing file or directory. This may happen for all
+commands which create new directory entries, such as \fR\&\f(CWmcopy\fR,
+\&\fR\&\f(CWmmd\fR, \fR\&\f(CWmren\fR, \fR\&\f(CWmmove\fR. When a name clash happens, mtools
+asks you what it should do. It offers several choices:
+.TP
+\&\fR\&\f(CWoverwrite\fR\
+Overwrites the existing file. It is not possible to overwrite a
+directory with a file.
+.TP
+\&\fR\&\f(CWrename\fR\
+Renames the newly created file. Mtools prompts for the new filename
+.TP
+\&\fR\&\f(CWautorename\fR\
+Renames the newly created file. Mtools chooses a name by itself, without
+prompting
+.TP
+\&\fR\&\f(CWskip\fR\
+Gives up on this file, and moves on to the next (if any)
+.PP
+To chose one of these actions, type its first letter at the prompt. If
+you use a lower case letter, the action only applies for this file only,
+if you use an upper case letter, the action applies to all files, and
+you won't be prompted again.
+.PP
+You may also chose actions (for all files) on the command line, when
+invoking mtools:
+.TP
+\&\fR\&\f(CW-D\ o\fR\
+Overwrites primary names by default.
+.TP
+\&\fR\&\f(CW-D\ O\fR\
+Overwrites secondary names by default.
+.TP
+\&\fR\&\f(CW-D\ r\fR\
+Renames primary name by default.
+.TP
+\&\fR\&\f(CW-D\ R\fR\
+Renames secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ a\fR\
+Autorenames primary name by default.
+.TP
+\&\fR\&\f(CW-D\ A\fR\
+Autorenames secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ s\fR\
+Skip primary name by default.
+.TP
+\&\fR\&\f(CW-D\ S\fR\
+Skip secondary name by default.
+.TP
+\&\fR\&\f(CW-D\ m\fR\
+Ask user what to do with primary name.
+.TP
+\&\fR\&\f(CW-D\ M\fR\
+Ask user what to do with secondary name.
+.PP
+Note that for command line switches lower/upper differentiates between
+primary/secondary name whereas for interactive choices, lower/upper
+differentiates between just-this-time/always.
+.PP
+The primary name is the name as displayed in Windows 95 or Windows NT:
+i.e. the long name if it exists, and the short name otherwise. The
+secondary name is the "hidden" name, i.e. the short name if a long name
+exists.
+.PP
+By default, the user is prompted if the primary name clashes, and the
+secondary name is autorenamed.
+.PP
+If a name clash occurs in a Unix directory, mtools only asks whether
+to overwrite the file, or to skip it.
+.PP
+.SS Case\ sensitivity\ of\ the\ VFAT\ file\ system
+.PP
+The VFAT file system is able to remember the case of the
+filenames. However, filenames which differ only in case are not allowed
+to coexist in the same directory. For example if you store a file called
+LongFileName on a VFAT file system, mdir shows this file as LongFileName,
+and not as Longfilename. However, if you then try to add LongFilename to
+the same directory, it is refused, because case is ignored for clash
+checks.
+.PP
+The VFAT file system allows to store the case of a filename in the
+attribute byte, if all letters of the filename are the same case, and if
+all letters of the extension are the same case too. Mtools uses this
+information when displaying the files, and also to generate the Unix
+filename when mcopying to a Unix directory. This may have unexpected
+results when applied to files written using an pre-7.0 version of DOS:
+Indeed, the old style filenames map to all upper case. This is different
+from the behavior of the old version of mtools which used to generate
+lower case Unix filenames.
+.PP
+.SS high\ capacity\ formats
+.PP
+Mtools supports a number of formats which allow to store more data on
+disk as usual. Due to different operating system abilities, these
+formats are not supported on all operating systems. Mtools recognizes
+these formats transparently where supported.
+.PP
+In order to format these disks, you need to use an operating system
+specific tool. For Linux, suitable floppy tools can be found in the
+\&\fR\&\f(CWfdutils\fR package at the following locations~:
+
+.nf
+.ft 3
+.in +0.3i
+\&\fR\&\f(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
+.PP
+
+\&\fR
+.PP
+See the manual pages included in that package for further detail: Use
+\&\fR\&\f(CWsuperformat\fR to format all formats except XDF, and use
+\&\fR\&\f(CWxdfcopy\fR to format XDF.
+.PP
+.SS \ \ More\ sectors
+.PP
+The oldest method of fitting more data on a disk is to use more sectors
+and more cylinders. Although the standard format uses 80 cylinders and
+18 sectors (on a 3 1/2 high density disk), it is possible to use up to
+83 cylinders (on most drives) and up to 21 sectors. This method allows
+to store up to 1743K on a 3 1/2 HD disk. However, 21 sector disks are
+twice as slow as the standard 18 sector disks because the sectors are
+packed so close together that we need to interleave them. This problem
+doesn't exist for 20 sector formats.
+.PP
+These formats are supported by numerous DOS shareware utilities such as
+\&\fR\&\f(CWfdformat\fR and \fR\&\f(CWvgacopy\fR. In his infinite hubris, Bill Gate$
+believed that he invented this, and called it \fR\&\f(CW\(ifDMF disks\(is\fR, or
+\&\fR\&\f(CW\(ifWindows formatted disks\(is\fR. But in reality, it has already existed
+years before! Mtools supports these formats on Linux, on SunOS and on
+the DELL Unix PC.
+.PP
+.SS \ \ Bigger\ sectors
+By using bigger sectors it is possible to go beyond the capacity which
+can be obtained by the standard 512-byte sectors. This is because of the
+sector header. The sector header has the same size, regardless of how
+many data bytes are in the sector. Thus, we save some space by using
+\&\fIfewer\fR, but bigger sectors. For example, 1 sector of 4K only takes
+up header space once, whereas 8 sectors of 512 bytes have also 8
+headers, for the same amount of useful data.
+.PP
+This method allows to store up to 1992K on a 3 1/2 HD disk.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ 2m
+.PP
+The 2m format was originally invented by Ciriaco Garcia de Celis. It
+also uses bigger sectors than usual in order to fit more data on the
+disk. However, it uses the standard format (18 sectors of 512 bytes
+each) on the first cylinder, in order to make these disks easier to
+handle by DOS. Indeed this method allows to have a standard sized
+boot sector, which contains a description of how the rest of the disk
+should be read.
+.PP
+However, the drawback of this is that the first cylinder can hold less
+data than the others. Unfortunately, DOS can only handle disks where
+each track contains the same amount of data. Thus 2m hides the fact that
+the first track contains less data by using a \fIshadow
+FAT\fR. (Usually, DOS stores the FAT in two identical copies, for
+additional safety. XDF stores only one copy, but tells DOS that it
+stores two. Thus the space that would be taken up by the second FAT copy
+is saved.) This also means that you should \fBnever use a 2m disk
+to store anything else than a DOS file system\fR.
+.PP
+Mtools supports these formats only on Linux.
+.PP
+.SS \ \ XDF
+.PP
+XDF is a high capacity format used by OS/2. It can hold 1840 K per
+disk. That's lower than the best 2m formats, but its main advantage is
+that it is fast: 600 milliseconds per track. That's faster than the 21
+sector format, and almost as fast as the standard 18 sector format. In
+order to access these disks, make sure mtools has been compiled with XDF
+support, and set the \fR\&\f(CWuse_xdf\fR variable for the drive in the
+configuration file. See section Compiling mtools, and \(ifmiscellaneous variables\(is,
+for details on how to do this. Fast XDF access is only available for
+Linux kernels which are more recent than 1.1.34.
+.PP
+Mtools supports this format only on Linux.
+.PP
+\&\fBCaution / Attention distributors\fR: If mtools is compiled on a
+Linux kernel more recent than 1.3.34, it won't run on an older
+kernel. However, if it has been compiled on an older kernel, it still
+runs on a newer kernel, except that XDF access is slower. It is
+recommended that distribution authors only include mtools binaries
+compiled on kernels older than 1.3.34 until 2.0 comes out. When 2.0 will
+be out, mtools binaries compiled on newer kernels may (and should) be
+distributed. Mtools binaries compiled on kernels older than 1.3.34 won't
+run on any 2.1 kernel or later.
+.PP
+.SS Exit\ codes
+All the Mtools commands return 0 on success, 1 on utter failure, or 2
+on partial failure. All the Mtools commands perform a few sanity
+checks before going ahead, to make sure that the disk is indeed an
+MS-DOS disk (as opposed to, say an ext2 or MINIX disk). These checks
+may reject partially corrupted disks, which might otherwise still be
+readable. To avoid these checks, set the MTOOLS_SKIP_CHECK
+environmental variable or the corresponding configuration file variable
+(see section global variables)
+.SS Bugs
+An unfortunate side effect of not guessing the proper device (when
+multiple disk capacities are supported) is an occasional error message
+from the device driver. These can be safely ignored.
+.PP
+The fat checking code chokes on 1.72 Mb disks mformatted with pre-2.0.7
+mtools. Set the environmental variable MTOOLS_FAT_COMPATIBILITY (or the
+corresponding configuration file variable, \(ifglobal variables\(is) to
+bypass the fat checking.
+.PP
+.SH See also
+floppyd_installtest
+mattrib
+mbadblocks
+mcd
+mclasserase
+mcopy
+mdel
+mdeltree
+mdir
+mdu
+mformat
+minfo
+mkmanifest
+mlabel
+mmd
+mmount
+mmove
+mrd
+mren
+mshortname
+mshowfat
+mtoolstest
+mtype
diff --git a/mtools.tmpl.5 b/mtools.tmpl.5
new file mode 100644
index 0000000..565fdd7
--- /dev/null
+++ b/mtools.tmpl.5
@@ -0,0 +1,539 @@
+'\" t
+.TH mtools 5 "09Jan13" 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.18
+.oh '\\*(St''%'
+.eh '%''\\*(St'
+.PP
+.SH Description
+.PP
+This manual page describes the configuration files for mtools. They
+are called \fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR. If
+the environmental variable \fR\&\f(CWMTOOLSRC\fR is set, its contents is used
+as the filename for a third configuration file. These configuration
+files describe the following items:
+.TP
+* \ Global\ configuration\ flags\ and\ variables\
+.TP
+* \ Per\ drive\ flags\ and\ variables\
+.PP
+.SS Location\ of\ the\ configuration\ files
+.PP
+.PP
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR is the system-wide configuration file,
+and \fR\&\f(CW\(if~/.mtoolsrc\(is\fR is the user's private configuration file.
+.PP
+On some systems, the system-wide configuration file is called
+\&\fR\&\f(CW\(if/etc/default/mtools.conf\(is\fR instead.
+.PP
+.SS \ \ General\ configuration\ file\ syntax
+.PP
+The configuration files is made up of sections. Each section starts
+with a keyword identifying the section followed by a colon.
+Then follow variable assignments and flags. Variable assignments take
+the following form:
+.ft I
+.nf
+name=value
+.fi
+.ft R
+
+Flags are lone keywords without an equal sign and value following
+them. A section either ends at the end of the file or where the next
+section begins.
+.PP
+Lines starting with a hash (\fR\&\f(CW#\fR) are comments. Newline characters
+are equivalent to whitespace (except where ending a comment). The
+configuration file is case insensitive, except for item enclosed in
+quotes (such as filenames).
+.PP
+.SS Default\ values
+For most platforms, mtools contains reasonable compiled-in defaults for
+physical floppy drives. Thus, you usually don't need to bother with the
+configuration file, if all you want to do with mtools is to access your
+floppy drives. On the other hand, the configuration file is needed if
+you also want to use mtools to access your hard disk partitions and
+DOSEMU image files.
+.PP
+.SS Global\ variables
+.PP
+Global flags may be set to 1 or to 0.
+.PP
+The following global flags are recognized:
+.TP
+\&\fR\&\f(CWMTOOLS_SKIP_CHECK\fR\
+If this is set to 1, mtools skips most of its sanity checks. This is
+needed to read some Atari disks which have been made with the earlier
+ROMs, and which would not be recognized otherwise.
+.TP
+\&\fR\&\f(CWMTOOLS_FAT_COMPATIBILITY\fR\
+If this is set to 1, mtools skips the fat size checks. Some disks have
+a bigger FAT than they really need to. These are rejected if this
+option is not set.
+.TP
+\&\fR\&\f(CWMTOOLS_LOWER_CASE\fR\
+If this is set to 1, mtools displays all-upper-case short filenames as
+lowercase. This has been done to allow a behavior which is consistent
+with older versions of mtools which didn't know about the case bits.
+.TP
+\&\fR\&\f(CWMTOOLS_NO_VFAT\fR\
+If this is set to 1, mtools won't generate VFAT entries for filenames
+which are mixed-case, but otherwise legal dos filenames. This is useful
+when working with DOS versions which can't grok VFAT long names, such as
+FreeDOS.
+.TP
+\&\fR\&\f(CWMTOOLS_DOTTED_DIR\fR\
+In a wide directory, prints the short name with a dot instead of spaces
+separating the basename and the extension.
+.TP
+\&\fR\&\f(CWMTOOLS_NAME_NUMERIC_TAIL\fR\
+If this is set to one (default), generate numeric tails for all long
+names (~1). If set to zero, only generate numeric tails if otherwise a
+clash would have happened.
+.TP
+\&\fR\&\f(CWMTOOLS_TWENTY_FOUR_HOUR_CLOCK\fR\
+If 1, uses the European notation for times (twenty four hour clock),
+else uses the UK/US notation (am/pm)
+.PP
+Example:
+Inserting the following line into your configuration file instructs
+mtools to skip the sanity checks:
+
+.nf
+.ft 3
+.in +0.3i
+ MTOOLS_SKIP_CHECK=1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+Global variables may also be set via the environment:
+
+.nf
+.ft 3
+.in +0.3i
+ export MTOOLS_SKIP_CHECK=1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+Global string variables may be set to any value:
+.TP
+\&\fR\&\f(CWMTOOLS_DATE_STRING\fR\
+The format used for printing dates of files. By default, is dd-mm-yyyy.
+.PP
+.SS Per\ drive\ flags\ and\ variables
+.PP
+.SS \ \ General\ information
+.PP
+Per drive flags and values may be described in a drive section. A
+drive section starts with
+\&\fR\&\f(CWdrive\fR "\fIdriveletter\fR" :
+.PP
+Then follow variable-value pairs and flags.
+.PP
+This is a sample drive description:
+
+.nf
+.ft 3
+.in +0.3i
+ drive a:
+ file="/dev/fd0" use_xdf=1
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+.SS \ \ Location\ information
+.PP
+For each drive, you need to describe where its data is physically
+stored (image file, physical device, partition, offset).
+.TP
+\&\fR\&\f(CWfile\fR\
+The name of the file or device holding the disk image. This is
+mandatory. The file name should be enclosed in quotes.
+.TP
+\&\fR\&\f(CWpartition\fR\
+Tells mtools to treat the drive as a partitioned device, and to use the
+given partition. Only primary partitions are accessible using this
+method, and they are numbered from 1 to 4. For logical partitions, use
+the more general \fR\&\f(CWoffset\fR variable. The \fR\&\f(CWpartition\fR variable
+is intended for removable media such as Syquest disks, ZIP drives, and
+magneto-optical disks. Although traditional DOS sees Syquest disks and
+magneto-optical disks as \fR\&\f(CW\(ifgiant floppy disks\(is\fR which are
+unpartitioned, OS/2 and Windows NT treat them like hard disks,
+i.e. partitioned devices. The \fR\&\f(CWpartition\fR flag is also useful DOSEMU
+hdimages. It is not recommended for hard disks for which direct access
+to partitions is available through mounting.
+.TP
+\&\fR\&\f(CWoffset\fR\
+Describes where in the file the MS-DOS file system starts. This is useful
+for logical partitions in DOSEMU hdimages, and for ATARI ram disks. By
+default, this is zero, meaning that the file system starts right at the
+beginning of the device or file.
+.PP
+.SS \ \ Disk\ Geometry\ Configuration
+.PP
+Geometry information describes the physical characteristics about the
+disk. Its has three purposes:
+.TP
+formatting\
+The geometry information is written into the boot sector of the newly
+made disk. However, you may also describe the geometry information on
+the command line. See section mformat, for details.
+.TP
+filtering\
+On some Unixes there are device nodes which only support one physical
+geometry. For instance, you might need a different node to access a disk
+as high density or as low density. The geometry is compared to the
+actual geometry stored on the boot sector to make sure that this device
+node is able to correctly read the disk. If the geometry doesn't match,
+this drive entry fails, and the next drive entry bearing the same drive
+letter is tried. See section multiple descriptions, for more details on
+supplying several descriptions for one drive letter.
+.IP
+If no geometry information is supplied in the configuration file, all
+disks are accepted. On Linux (and on SPARC) there exist device nodes
+with configurable geometry (\fR\&\f(CW\(if/dev/fd0\(is\fR, \fR\&\f(CW\(if/dev/fd1\(is\fR etc),
+and thus filtering is not needed (and ignored) for disk drives. (Mtools
+still does do filtering on plain files (disk images) in Linux: this is
+mainly intended for test purposes, as I don't have access to a Unix
+which would actually need filtering).
+.IP
+If you do not need filtering, but want still a default geometry for
+mformatting, you may switch off filtering using the \fR\&\f(CWmformat_only\fR
+flag.
+.IP
+If you want filtering, you should supply the \fR\&\f(CWfilter\fR flag. If you
+supply a geometry, you must supply one of both flags.
+.TP
+initial\ geometry\
+On devices that support it (usually floppy devices), the geometry
+information is also used to set the initial geometry. This initial
+geometry is applied while reading the boot sector, which contains the
+real geometry. If no geometry information is supplied in the
+configuration file, or if the \fR\&\f(CWmformat_only\fR flag is supplied, no
+initial configuration is done.
+.IP
+On Linux, initial geometry is not really needed, as the configurable
+devices are able to auto-detect the disk type accurately enough (for
+most common formats) to read the boot sector.
+.PP
+Wrong geometry information may lead to very bizarre errors. That's why I
+strongly recommend that you add the \fR\&\f(CWmformat_only\fR flag to your
+drive description, unless you really need filtering or initial geometry.
+.PP
+The following geometry related variables are available:
+.TP
+\&\fR\&\f(CWcylinders\fR\
+.TQ
+\&\fR\&\f(CWtracks\fR
+The number of cylinders. (\fR\&\f(CWcylinders\fR is the preferred form,
+\&\fR\&\f(CWtracks\fR is considered obsolete)
+.TP
+\&\fR\&\f(CWheads\fR\
+The number of heads (sides).
+.TP
+\&\fR\&\f(CWsectors\fR\
+The number of sectors per track.
+.PP
+Example: the following drive section describes a 1.44M drive:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ drive a:
+ file="/dev/fd0H1440"
+ fat_bits=12
+ cylinders=80 heads=2 sectors=18
+ mformat_only
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The following shorthand geometry descriptions are available:
+.TP
+\&\fR\&\f(CW1.44m\fR\
+high density 3 1/2 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=18\fR
+.TP
+\&\fR\&\f(CW1.2m\fR\
+high density 5 1/4 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=15\fR
+.TP
+\&\fR\&\f(CW720k\fR\
+double density 3 1/2 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=80 heads=2 sectors=9\fR
+.TP
+\&\fR\&\f(CW360k\fR\
+double density 5 1/4 disk. Equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=9\fR
+.PP
+The shorthand format descriptions may be amended. For example,
+\&\fR\&\f(CW360k sectors=8\fR
+describes a 320k disk and is equivalent to:
+\&\fR\&\f(CWfat_bits=12 cylinders=40 heads=2 sectors=8\fR
+.PP
+.SS \ \ Open\ Flags
+.PP
+Moreover, the following flags are available:
+.TP
+\&\fR\&\f(CWsync\fR\
+All i/o operations are done synchronously
+.TP
+\&\fR\&\f(CWnodelay\fR\
+The device or file is opened with the O_NDELAY flag. This is needed on
+some non-Linux architectures.
+.TP
+\&\fR\&\f(CWexclusive\fR\
+The device or file is opened with the O_EXCL flag. On Linux, this
+ensures exclusive access to the floppy drive. On most other
+architectures, and for plain files it has no effect at all.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Variables
+.PP
+The following general purpose drive variables are available. Depending
+to their type, these variables can be set to a string (precmd) or
+an integer (all others)
+.TP
+\&\fR\&\f(CWfat_bits\fR\
+The number of FAT bits. This may be 12 or 16. This is very rarely
+needed, as it can almost always be deduced from information in the
+boot sector. On the contrary, describing the number of fat bits may
+actually be harmful if you get it wrong. You should only use it if
+mtools gets the auto-detected number of fat bits wrong, or if you want
+to mformat a disk with a weird number of fat bits.
+.TP
+\&\fR\&\f(CWcodepage\fR\
+Describes the DOS code page used for short filenames. This is a number
+between 1 and 999. By default, code page 850 is used. The reason for
+this is because this code page contains most of the characters that are
+also available in ISO-Latin-1. You may also specify a global code page
+for all drives by using the global \fR\&\f(CWdefault_codepage\fR parameter
+(outside of any drive description). This parameters exists starting at
+version 4.0.0
+.TP
+\&\fR\&\f(CWprecmd\fR\
+On some variants of Solaris, it is necessary to call 'volcheck -v'
+before opening a floppy device, in order for the system to notice that
+there is indeed a disk in the drive. \fR\&\f(CWprecmd="volcheck -v"\fR in the
+drive clause establishes the desired behavior.
+.TP
+\&\fR\&\f(CWblocksize\fR\
+This parameter represents a default block size to be always used on this
+device. All I/O is done with multiples of this block size,
+independently of the sector size registered in the file system's boot
+sector. This is useful for character devices whose sector size is not
+512, such as for example CD-ROM drives on Solaris.
+.PP
+Only the \fR\&\f(CWfile\fR variable is mandatory. The other parameters may
+be left out. In that case a default value or an auto-detected value is
+used.
+.PP
+.SS \ \ General\ Purpose\ Drive\ Flags
+.PP
+A flag can either be set to 1 (enabled) or 0 (disabled). If the value is
+omitted, it is enabled. For example, \fR\&\f(CWscsi\fR is equivalent to
+\&\fR\&\f(CWscsi=1\fR
+.TP
+\&\fR\&\f(CWnolock\fR\
+Instruct mtools to not use locking on this drive. This is needed on
+systems with buggy locking semantics. However, enabling this makes
+operation less safe in cases where several users may access the same
+drive at the same time.
+.TP
+\&\fR\&\f(CWscsi\fR\
+When set to 1, this option tells mtools to use raw SCSI I/O instead of
+the standard read/write calls to access the device. Currently, this is
+supported on HP-UX, Solaris and SunOS. This is needed because on some
+architectures, such as SunOS or Solaris, PC media can't be accessed
+using the \fR\&\f(CWread\fR and \fR\&\f(CWwrite\fR system calls, because the OS expects
+them to contain a Sun specific "disk label".
+.IP
+As raw SCSI access always uses the whole device, you need to specify the
+"partition" flag in addition
+.IP
+On some architectures, such as Solaris, mtools needs root privileges to
+be able to use the \fR\&\f(CWscsi\fR option. Thus mtools should be installed
+setuid root on Solaris if you want to access Zip/Jaz drives. Thus, if
+the \fR\&\f(CWscsi\fR flag is given, \fR\&\f(CWprivileged\fR is automatically
+implied, unless explicitly disabled by \fR\&\f(CWprivileged=0\fR
+.IP
+Mtools uses its root privileges to open the device, and to issue the
+actual SCSI I/O calls. Moreover, root privileges are only used for
+drives described in a system-wide configuration file such as
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR, and not for those described in
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR or \fR\&\f(CW\(if$MTOOLSRC\(is\fR.
+.TP
+\&\fR\&\f(CWprivileged\fR\
+When set to 1, this instructs mtools to use its setuid and setgid
+privileges for opening the given drive. This option is only valid for
+drives described in the system-wide configuration files (such as
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR, not \fR\&\f(CW\(if~/.mtoolsrc\(is\fR or
+\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR). Obviously, this option is also a no op if mtools is
+not installed setuid or setgid. This option is implied by 'scsi=1', but
+again only for drives defined in system-wide configuration files.
+Privileged may also be set explicitly to 0, in order to tell mtools not
+to use its privileges for a given drive even if \fR\&\f(CWscsi=1\fR is set.
+.IP
+Mtools only needs to be installed setuid if you use the
+\&\fR\&\f(CWprivileged\fR or \fR\&\f(CWscsi\fR drive variables. If you do not use
+these options, mtools works perfectly well even when not installed
+setuid root.
+.TP
+\&\fR\&\f(CWvold\fR\
+.IP
+Instructs mtools to interpret the device name as a vold identifier
+rather than as a filename. The vold identifier is translated into a
+real filename using the \fR\&\f(CWmedia_findname()\fR and
+\&\fR\&\f(CWmedia_oldaliases()\fR functions of the \fR\&\f(CWvolmgt\fR library. This
+flag is only available if you configured mtools with the
+\&\fR\&\f(CW--enable-new-vold\fR option before compilation.
+.TP
+\&\fR\&\f(CWswap\fR\
+.IP
+Consider the media as a word-swapped Atari disk.
+.TP
+\&\fR\&\f(CWuse_xdf\fR\
+If this is set to a non-zero value, mtools also tries to access this
+disk as an XDF disk. XDF is a high capacity format used by OS/2. This
+is off by default. See section XDF, for more details.
+.TP
+\&\fR\&\f(CWmformat_only\fR\
+Tells mtools to use the geometry for this drive only for mformatting and
+not for filtering.
+.TP
+\&\fR\&\f(CWfilter\fR\
+Tells mtools to use the geometry for this drive both for mformatting and
+filtering.
+.TP
+\&\fR\&\f(CWremote\fR\
+Tells mtools to connect to floppyd (see section floppyd).
+.PP
+.SS \ \ Supplying\ multiple\ descriptions\ for\ a\ drive
+.PP
+It is possible to supply multiple descriptions for a drive. In that
+case, the descriptions are tried in order until one is found that
+fits. Descriptions may fail for several reasons:
+.TP
+1.\
+because the geometry is not appropriate,
+.TP
+2.\
+because there is no disk in the drive,
+.TP
+3.\
+or because of other problems.
+.PP
+Multiple definitions are useful when using physical devices which are
+only able to support one single disk geometry.
+Example:
+
+.nf
+.ft 3
+.in +0.3i
+ drive a: file="/dev/fd0H1440" 1.44m
+ drive a: file="/dev/fd0H720" 720k
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+This instructs mtools to use /dev/fd0H1440 for 1.44m (high density)
+disks and /dev/fd0H720 for 720k (double density) disks. On Linux, this
+feature is not really needed, as the /dev/fd0 device is able to handle
+any geometry.
+.PP
+You may also use multiple drive descriptions to access both of your
+physical drives through one drive letter:
+.PP
+
+.nf
+.ft 3
+.in +0.3i
+ drive z: file="/dev/fd0"
+ drive z: file="/dev/fd1"
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+With this description, \fR\&\f(CWmdir z:\fR accesses your first physical
+drive if it contains a disk. If the first drive doesn't contain a disk,
+mtools checks the second drive.
+.PP
+When using multiple configuration files, drive descriptions in the files
+parsed last override descriptions for the same drive in earlier
+files. In order to avoid this, use the \fR\&\f(CWdrive+\fR or \fR\&\f(CW+drive\fR
+keywords instead of \fR\&\f(CWdrive\fR. The first adds a description to the
+end of the list (i.e. it will be tried last), and the first adds it to
+the start of the list.
+.PP
+.SS Location\ of\ configuration\ files\ and\ parsing\ order
+.PP
+The configuration files are parsed in the following order:
+.TP
+1.\
+compiled-in defaults
+.TP
+2.\
+\&\fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR
+.TP
+3.\
+\&\fR\&\f(CW\(if~/.mtoolsrc\(is\fR.
+.TP
+4.\
+\&\fR\&\f(CW\(if$MTOOLSRC\(is\fR (file pointed by the \fR\&\f(CWMTOOLSRC\fR environmental
+variable)
+.PP
+Options described in the later files override those described in the
+earlier files. Drives defined in earlier files persist if they are not
+overridden in the later files. For instance, drives A and B may be
+defined in \fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR and drives C and D may be
+defined in \fR\&\f(CW\(if~/.mtoolsrc\(is\fR However, if \fR\&\f(CW\(if~/.mtoolsrc\(is\fR also
+defines drive A, this new description would override the description of
+drive A in \fR\&\f(CW\(ifSYSCONFDIRmtools.conf\(is\fR instead of adding to it. If
+you want to add a new description to a drive already described in an
+earlier file, you need to use either the \fR\&\f(CW+drive\fR or \fR\&\f(CWdrive+\fR
+keyword.
+.PP
+.SS Backwards\ compatibility\ with\ old\ configuration\ file\ syntax
+.PP
+The syntax described herein is new for version \fR\&\f(CWmtools-3.0\fR. The
+old line-oriented syntax is still supported. Each line beginning with a
+single letter is considered to be a drive description using the old
+syntax. Old style and new style drive sections may be mixed within the
+same configuration file, in order to make upgrading easier. Support for
+the old syntax will be phased out eventually, and in order to discourage
+its use, I purposefully omit its description here.
+.PP
+.SH See also
+mtools
diff --git a/mtoolsDirentry.h b/mtoolsDirentry.h
new file mode 100644
index 0000000..2f7eccc
--- /dev/null
+++ b/mtoolsDirentry.h
@@ -0,0 +1,71 @@
+#ifndef MTOOLS_DIRENTRY_H
+#define MTOOLS_DIRENTRY_H
+/* Copyright 1998,2000-2002,2005,2008-2010 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "sysincludes.h"
+#include "vfat.h"
+
+typedef struct direntry_t {
+ struct Stream_t *Dir;
+ /* struct direntry_t *parent; parent level */
+ int entry; /* slot in parent directory (-3 if root) */
+ struct directory dir; /* descriptor in parent directory (random if
+ * root)*/
+ wchar_t name[MAX_VNAMELEN+1]; /* name in its parent directory, or
+ * NULL if root */
+ int beginSlot; /* begin and end slot, for delete */
+ int endSlot;
+} direntry_t;
+
+#include "stream.h"
+
+int vfat_lookup(direntry_t *entry, const char *filename, int length,
+ int flags, char *shortname, 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);
+void low_level_dir_write_end(Stream_t *Dir, int entry);
+int fatFreeWithDirentry(direntry_t *entry);
+int labelit(struct dos_name_t *dosname,
+ char *longname,
+ void *arg0,
+ direntry_t *entry);
+int isSubdirOf(Stream_t *inside, Stream_t *outside);
+char *getPwd(direntry_t *entry);
+void fprintPwd(FILE *f, direntry_t *entry, int escape);
+void fprintShortPwd(FILE *f, direntry_t *entry);
+int write_vfat(Stream_t *, dos_name_t *, char *, int, direntry_t *);
+
+void wipeEntry(struct direntry_t *entry);
+
+void dosnameToDirentry(const struct dos_name_t *n, struct directory *dir);
+
+int lookupForInsert(Stream_t *Dir,
+ direntry_t *direntry,
+ struct dos_name_t *dosname,
+ char *longname,
+ struct scan_state *ssp,
+ int ignore_entry,
+ int source_entry,
+ int pessimisticShortRename,
+ int use_longname);
+#endif
diff --git a/mtoolsPaths.h b/mtoolsPaths.h
new file mode 100644
index 0000000..07a081a
--- /dev/null
+++ b/mtoolsPaths.h
@@ -0,0 +1,47 @@
+/* Copyright 1997,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Paths of the configuration files.
+ * This file may be changed by the user as needed.
+ * There are three empty lines between each definition.
+ * These ensure that "local" patches and official patches have
+ * only a very low probability of conflicting.
+ */
+
+
+#define CONF_FILE "/etc/mtools.conf"
+
+
+#define OLD_CONF_FILE "/etc/mtools"
+
+
+
+#define LOCAL_CONF_FILE "/etc/default/mtools.conf"
+/* Use this if you like to keep the configuration file in a non-standard
+ * place such as /etc/default, /opt/etc, /usr/etc, /usr/local/etc ...
+ */
+
+#define SYS_CONF_FILE SYSCONFDIR "/mtools.conf"
+
+#define OLD_LOCAL_CONF_FILE "/etc/default/mtools"
+
+
+
+#define CFG_FILE1 "/.mtoolsrc"
+
+
+
+/* END */
diff --git a/mtoolstest.1 b/mtoolstest.1
new file mode 100644
index 0000000..e56f68d
--- /dev/null
+++ b/mtoolstest.1
@@ -0,0 +1,90 @@
+'\" t
+.TH mtoolstest 1 "09Jan13" mtools-4.0.18
+.SH Name
+mtoolstest - tests and displays the configuration
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmtoolstest\fR command is used to tests the mtools configuration
+files. To invoke it, just type \fR\&\f(CWmtoolstest\fR without any arguments.
+\&\fR\&\f(CWMtoolstest\fR reads the mtools configuration files, and prints the
+cumulative configuration to \fR\&\f(CWstdout\fR. The output can be used as a
+configuration file itself (although you might want to remove redundant
+clauses). You may use this program to convert old-style configuration
+files into new style configuration files.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mtype.1 b/mtype.1
new file mode 100644
index 0000000..9e40fc5
--- /dev/null
+++ b/mtype.1
@@ -0,0 +1,114 @@
+'\" t
+.TH mtype 1 "09Jan13" mtools-4.0.18
+.SH Name
+mtype - display contents of an MSDOS file
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmtype\fR command is used to display contents of an MS-DOS
+file. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmtype\fR [\fR\&\f(CW-ts\fR] \fImsdosfile\fR [ \fImsdosfiles\fR\&... ]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMtype\fR displays the specified MS-DOS file on the screen.
+.PP
+In addition to the standard options, \fR\&\f(CWMtype\fR allows the following
+command line options:
+.TP
+\&\fR\&\f(CWt\fR\
+Text file viewing. \fR\&\f(CWMtype\fR translates incoming carriage
+return/line feeds to line feeds.
+.TP
+\&\fR\&\f(CWs\fR\
+\&\fR\&\f(CWMtype\fR strips the high bit from the data.
+.PP
+The \fR\&\f(CWmcd\fR command may be used to establish the device and the
+current working directory (relative to MS-DOS), otherwise the default is
+\&\fR\&\f(CWA:/\fR.
+.PP
+\&\fR\&\f(CWMtype\fR returns 0 on success, 1 on utter failure, or 2 on partial
+failure.
+.PP
+Unlike the MS-DOS version of \fR\&\f(CWTYPE\fR, \fR\&\f(CWmtype\fR allows multiple
+arguments.
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mxtar.1 b/mxtar.1
new file mode 100644
index 0000000..8fc11ab
--- /dev/null
+++ b/mxtar.1
@@ -0,0 +1,48 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for mxtar
+.\"
+.\" Copyright (C), 2003, Luis Bustamante
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Mon Mar 3 11:58:15 COT 2003 Luis Bustamante <luferbu@fluidsignal.com>
+.\"
+.TH MXTAR 1 "Mon Mar 3 11:58:15 COT 2003" "" "Mtools Users Manual"
+.SH NAME
+mxtar \- Wrapper for using GNU tar directly from a floppy disk
+.SH SYNOPSIS
+.\" The command line
+.B mxtar
+[
+.B \-
+]
+.I [ tar-options ]
+.I file
+.SH DESCRIPTION
+.B mxtar
+let you use GNU \fBtar\fR(1) on a floppy disk without mounting it using
+\fBmtools\fR(1).
+It is not strictly necessary on Debian GNU/Linux, because the GNU
+\fBtar\fR(1) program provides the same capability after copying the
+file locally with
+
+.B mcopy
+.I file
+.I destination
+
+but this utility is provided in the mtools package for other platforms and
+is retained here for completeness.
+
+.SH AUTHOR
+Luis Bustamante <luferbu@fluidsignal.com> wrote this page for the
+.I Debian/GNU
+mtools package.
+
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR tar (1),
+.BR mcopy (1)
diff --git a/mzip.1 b/mzip.1
new file mode 100644
index 0000000..2b54063
--- /dev/null
+++ b/mzip.1
@@ -0,0 +1,147 @@
+'\" t
+.TH mzip 1 "09Jan13" mtools-4.0.18
+.SH Name
+mzip - change protection mode and eject disk on Zip/Jaz drive
+'\" t
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+
+.tr \(is'
+.tr \(if`
+.tr \(pd"
+
+.SH Note\ of\ warning
+This manpage has been automatically generated from mtools's texinfo
+documentation, and may not be entirely accurate or complete. See the
+end of this man page for details.
+.PP
+.SH Description
+.PP
+The \fR\&\f(CWmzip\fR command is used to issue ZIP disk specific commands on
+Linux, Solaris or HP-UX. Its syntax is:
+.PP
+.ft I
+.nf
+\&\fR\&\f(CWmzip\fR [\fR\&\f(CW-epqrwx\fR]
+.fi
+.ft R
+
+.PP
+\&\fR\&\f(CWMzip\fR allows the following
+command line options:
+.TP
+\&\fR\&\f(CWe\fR\
+Ejects the disk.
+.TP
+\&\fR\&\f(CWf\fR\
+Force eject even if the disk is mounted (must be given in addition to
+\&\fR\&\f(CW-e\fR).
+.TP
+\&\fR\&\f(CWr\fR\
+Write protect the disk.
+.TP
+\&\fR\&\f(CWw\fR\
+Remove write protection.
+.TP
+\&\fR\&\f(CWp\fR\
+Password write protect.
+.TP
+\&\fR\&\f(CWx\fR\
+Password protect
+.TP
+\&\fR\&\f(CWu\fR\
+Temporarily unprotect the disk until it is ejected. The disk becomes
+writable, and reverts back to its old state when ejected.
+.TP
+\&\fR\&\f(CWq\fR\
+Queries the status
+.PP
+To remove the password, set it to one of the password-less modes
+\&\fR\&\f(CW-r\fR or \fR\&\f(CW-w\fR: mzip will then ask you for the password, and
+unlock the disk. If you have forgotten the password, you can get rid of
+it by low-level formatting the disk (using your SCSI adapter's BIOS
+setup).
+.PP
+The ZipTools disk shipped with the drive is also password protected. On
+MS-DOS or on a Mac, this password is automatically removed once the
+ZipTools have been installed. From various articles posted to Usenet, I
+learned that the password for the tools disk is
+\&\fR\&\f(CWAPlaceForYourStuff\fR\fR. Mzip knows about this
+password, and tries it first, before prompting you for a password. Thus
+\&\fR\&\f(CWmzip -w z:\fR unlocks the tools disk. The tools disk is
+formatted in a special way so as to be usable both in a PC and in a Mac.
+On a PC, the Mac file system appears as a hidden file named
+\&\fR\&\f(CW\(ifpartishn.mac\(is\fR. You may erase it to reclaim the 50 Megs of space
+taken up by the Mac file system.
+.PP
+.SH Bugs
+.PP
+This command is a big kludge. A proper implementation would take a
+rework of significant parts of mtools, but unfortunately I don't have
+the time for this right now. The main downside of this implementation is
+that it is inefficient on some architectures (several successive calls
+to mtools, which defeats mtools' caching).
+.PP
+.SH See\ Also
+Mtools' texinfo doc
+.SH Viewing\ the\ texi\ doc
+This manpage has been automatically generated from mtools's texinfo
+documentation. However, this process is only approximative, and some
+items, such as crossreferences, footnotes and indices are lost in this
+translation process. Indeed, these items have no appropriate
+representation in the manpage format. Moreover, not all information has
+been translated into the manpage version. Thus I strongly advise you to
+use the original texinfo doc. See the end of this manpage for
+instructions how to view the texinfo doc.
+.TP
+* \ \
+To generate a printable copy from the texinfo doc, run the following
+commands:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make dvi; dvips mtools.dvi
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.TP
+* \ \
+To generate a html copy, run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make html
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fRA premade html can be found at
+\&\fR\&\f(CW\(ifhttp://www.gnu.org/software/mtools/manual/mtools.html\(is\fR
+.TP
+* \ \
+To generate an info copy (browsable using emacs' info mode), run:
+
+.nf
+.ft 3
+.in +0.3i
+ ./configure; make info
+.fi
+.in -0.3i
+.ft R
+.PP
+
+\&\fR
+.PP
+The texinfo doc looks most pretty when printed or as html. Indeed, in
+the info version certain examples are difficult to read due to the
+quoting conventions used in info.
+.PP
diff --git a/mzip.c b/mzip.c
new file mode 100644
index 0000000..e567a4f
--- /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);
+ break;
+ case 'f':
+ if (get_real_uid()) {
+ fprintf(stderr,
+ "Only root can use force. Sorry.\n");
+ exit(1);
+ }
+ request |= ZIP_FORCE;
+ break;
+ case 'e': /* eject */
+ request |= ZIP_EJECT;
+ break;
+ case 'q': /* status query */
+ request |= ZIP_STATUS;
+ break;
+
+ case 'p': /* password read-only */
+ setMode(ZIP_RO_PW);
+ case 'r': /* read-only */
+ setMode(ZIP_RO);
+ case 'w': /* read-write */
+ setMode(ZIP_RW);
+ case 'x': /* password protected */
+ setMode(ZIP_PW);
+ case 'u': /* password protected */
+ setMode(ZIP_UNLOCK_TIL_EJECT)
+ case 'h':
+ usage(0);
+ default: /* unrecognized */
+ usage(1);
+
+ }
+ }
+
+ if (request == ZIP_NIX) request = ZIP_STATUS; /* default action */
+
+ if (argc - optind > 1 ||
+ (argc - optind == 1 &&
+ (!argv[optind][0] || argv[optind][1] != ':')))
+ usage(1);
+
+ drive = toupper(argc - optind == 1 ? argv[argc - 1][0] : ':');
+
+ for (dev = devices; dev->name; dev++) {
+ unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 };
+ struct {
+ char type,
+ type_modifier,
+ scsi_version,
+ data_format,
+ length,
+ reserved1[2],
+ capabilities,
+ vendor[8],
+ product[16],
+ revision[4],
+ vendor_specific[20],
+ reserved2[40];
+ } inq_data;
+
+ if (dev->drive != drive)
+ continue;
+ expand(dev->name, name);
+ if ((request & (ZIP_MODE_CHANGE | ZIP_EJECT)) &&
+ !(request & ZIP_FORCE) &&
+ test_mounted(name)) {
+ fprintf(stderr,
+ "Can\'t change status of/eject mounted device\n");
+ exit(1);
+ }
+ precmd(dev);
+
+ if(IS_PRIVILEGED(dev))
+ reclaim_privs();
+ fd = scsi_open(name, O_RDONLY
+#ifdef O_NDELAY
+ | O_NDELAY
+#endif
+ , 0644,
+ &extra_data);
+ if(IS_PRIVILEGED(dev))
+ drop_privs();
+
+ /* need readonly, else we can't
+ * open the drive on Solaris if
+ * write-protected */
+ if (fd == -1)
+ continue;
+ closeExec(fd);
+
+ if (!(request & (ZIP_MODE_CHANGE | ZIP_STATUS)))
+ /* if no mode change or ZIP specific status is
+ * involved, the command (eject) is applicable
+ * on all drives */
+ break;
+
+ cdb[0] = SCSI_INQUIRY;
+ cdb[4] = sizeof inq_data;
+ if (zip_cmd(IS_PRIVILEGED(dev), fd, cdb, 6, SCSI_IO_READ,
+ &inq_data, sizeof inq_data, extra_data) != 0) {
+ close(fd);
+ continue;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "device: %s\n\tvendor: %.8s\n\tproduct: %.16s\n"
+ "\trevision: %.4s\n", name, inq_data.vendor,
+ inq_data.product, inq_data.revision);
+#endif /* DEBUG */
+
+ if (strncasecmp("IOMEGA ", inq_data.vendor,
+ sizeof inq_data.vendor) ||
+ (strncasecmp("ZIP 100 ",
+ inq_data.product, sizeof inq_data.product) &&
+ strncasecmp("ZIP 100 PLUS ",
+ inq_data.product, sizeof inq_data.product) &&
+ strncasecmp("ZIP 250 ",
+ inq_data.product, sizeof inq_data.product) &&
+ strncasecmp("ZIP 750 ",
+ inq_data.product, sizeof inq_data.product) &&
+ strncasecmp("JAZ 1GB ",
+ inq_data.product, sizeof inq_data.product) &&
+ strncasecmp("JAZ 2GB ",
+ inq_data.product, sizeof inq_data.product))) {
+
+ /* debugging */
+ fprintf(stderr,"Skipping drive with vendor='");
+ fwrite(inq_data.vendor,1, sizeof(inq_data.vendor),
+ stderr);
+ fprintf(stderr,"' product='");
+ fwrite(inq_data.product,1, sizeof(inq_data.product),
+ stderr);
+ fprintf(stderr,"'\n");
+ /* end debugging */
+ close(fd);
+ continue;
+ }
+ break; /* found Zip/Jaz drive */
+ }
+
+ if (dev->drive == 0) {
+ fprintf(stderr, "%s: drive '%c:' is not a Zip or Jaz drive\n",
+ argv[0], drive);
+ exit(1);
+ }
+
+ if (request & (ZIP_MODE_CHANGE | ZIP_STATUS))
+ oldMode = get_zip_status(IS_PRIVILEGED(dev), fd, extra_data);
+
+ if (request & ZIP_MODE_CHANGE) {
+ /* request temp unlock, and disk is already unlocked */
+ if(newMode == ZIP_UNLOCK_TIL_EJECT &&
+ (oldMode & ZIP_UNLOCK_TIL_EJECT))
+ request &= ~ZIP_MODE_CHANGE;
+
+ /* no password change requested, and disk is already
+ * in the requested state */
+ if(!(newMode & 0x01) && newMode == oldMode)
+ request &= ~ZIP_MODE_CHANGE;
+ }
+
+ if (request & ZIP_MODE_CHANGE) {
+ int ret;
+ enum mode_t unlockMode, unlockMask;
+ const char *passwd;
+ char dummy[1];
+
+ if(newMode == ZIP_UNLOCK_TIL_EJECT) {
+ unlockMode = newMode | oldMode;
+ unlockMask = 9;
+ } else {
+ unlockMode = newMode & ~0x5;
+ unlockMask = 1;
+ }
+
+ if ((oldMode & unlockMask) == 1) { /* unlock first */
+ char *s;
+ passwd = "APlaceForYourStuff";
+ if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */
+ iomega_command(IS_PRIVILEGED(dev), fd, unlockMode,
+ passwd, extra_data);
+ }
+
+ if ((get_zip_status(IS_PRIVILEGED(dev), fd, extra_data) &
+ unlockMask) == 1) {
+ /* unlock first */
+ char *s;
+ passwd = getpass("Password: ");
+ if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */
+ if((ret=iomega_command(IS_PRIVILEGED(dev), fd,
+ unlockMode, passwd,
+ extra_data))){
+ if (ret == -1) perror("passwd: ");
+ else fprintf(stderr, "wrong password\n");
+ exit(1);
+ }
+ if((get_zip_status(IS_PRIVILEGED(dev),
+ fd, extra_data) &
+ unlockMask) == 1) {
+ fprintf(stderr, "wrong password\n");
+ exit(1);
+ }
+ }
+
+ if (newMode & 0x1) {
+ char first_try[_PASSWORD_LEN];
+
+ passwd = getpass("Enter new password:");
+ strncpy(first_try, passwd,_PASSWORD_LEN);
+ passwd = getpass("Re-type new password:");
+ if(strncmp(first_try, passwd, _PASSWORD_LEN)) {
+ fprintf(stderr,
+ "You mispelled it. Password not set.\n");
+ exit(1);
+ }
+ } else {
+ passwd = dummy;
+ dummy[0] = '\0';
+ }
+
+ if(newMode == ZIP_UNLOCK_TIL_EJECT)
+ newMode |= oldMode;
+
+ if((ret=iomega_command(IS_PRIVILEGED(dev), fd,
+ newMode, passwd, extra_data))){
+ if (ret == -1) perror("set passwd: ");
+ else fprintf(stderr, "password not changed\n");
+ exit(1);
+ }
+#ifdef OS_linux
+ ioctl(fd, BLKRRPART); /* revalidate the disk, so that the
+ kernel notices that its writable
+ status has changed */
+#endif
+ }
+
+ if (request & ZIP_STATUS) {
+ const char *unlocked;
+
+ if(oldMode & 8)
+ unlocked = " and unlocked until eject";
+ else
+ unlocked = "";
+ switch (oldMode & ~8) {
+ case ZIP_RW:
+ printf("Drive '%c:' is not write-protected\n",
+ drive);
+ break;
+ case ZIP_RO:
+ printf("Drive '%c:' is write-protected%s\n",
+ drive, unlocked);
+ break;
+ case ZIP_RO_PW:
+ printf("Drive '%c:' is password write-protected%s\n",
+ drive, unlocked);
+ break;
+ case ZIP_PW:
+ printf("Drive '%c:' is password protected%s\n",
+ drive, unlocked);
+ break;
+ default:
+ printf("Unknown protection mode %d of drive '%c:'\n",
+ oldMode, drive);
+ break;
+ }
+ }
+
+ if (request & ZIP_EJECT) {
+ if(request & ZIP_FORCE)
+ if(door_command(IS_PRIVILEGED(dev), fd,
+ SCSI_ALLOW_MEDIUM_REMOVAL, 0,
+ extra_data) < 0) {
+ perror("door unlock: ");
+ exit(1);
+ }
+
+ if(door_command(IS_PRIVILEGED(dev), fd,
+ SCSI_START_STOP, 1,
+ extra_data) < 0) {
+ perror("stop motor: ");
+ exit(1);
+ }
+
+ if(door_command(IS_PRIVILEGED(dev), fd,
+ SCSI_START_STOP, 2, extra_data) < 0) {
+ perror("eject: ");
+ exit(1);
+ }
+ if(door_command(IS_PRIVILEGED(dev), fd,
+ SCSI_START_STOP, 2, extra_data) < 0) {
+ perror("second eject: ");
+ exit(1);
+ }
+ }
+
+ close(fd);
+ exit(0);
+}
diff --git a/nameclash.h b/nameclash.h
new file mode 100644
index 0000000..8ebdb4c
--- /dev/null
+++ b/nameclash.h
@@ -0,0 +1,75 @@
+#ifndef MTOOLS_NAMECLASH_H
+#define MTOOLS_NAMECLASH_H
+
+/* Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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/partition.h b/partition.h
new file mode 100644
index 0000000..5c43739
--- /dev/null
+++ b/partition.h
@@ -0,0 +1,49 @@
+/* Copyright 1997,1998,2001-2003,2006,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..cfcbeee
--- /dev/null
+++ b/patchlevel.c
@@ -0,0 +1,24 @@
+/* Copyright 1999-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+const char *mversion="4.0.18";
+
+/* Multiple releases on same day should be marked with (b), (cd), (d) after
+ * date string below */
+const char *mdate = "January 9th, 2013";
+
+const char *mformat_banner = "MTOO4018";
diff --git a/plain_io.c b/plain_io.c
new file mode 100644
index 0000000..c9d8418
--- /dev/null
+++ b/plain_io.c
@@ -0,0 +1,805 @@
+/* Copyright 1995-2007,2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Io to a plain file or device
+ *
+ * written by:
+ *
+ * Alain L. Knaff
+ * alain@knaff.lu
+ *
+ */
+
+#include "sysincludes.h"
+#include "stream.h"
+#include "mtools.h"
+#include "msdos.h"
+#include "plain_io.h"
+#include "scsi.h"
+#include "partition.h"
+#include "llong.h"
+
+#ifdef HAVE_LINUX_FS_H
+# include <linux/fs.h>
+#endif
+
+typedef struct SimpleFile_t {
+ Class_t *Class;
+ int refs;
+ Stream_t *Next;
+ Stream_t *Buffer;
+ struct MT_STAT statbuf;
+ int fd;
+ mt_off_t offset;
+ mt_off_t lastwhere;
+ int seekable;
+ int privileged;
+#ifdef OS_hpux
+ int size_limited;
+#endif
+ int scsi_sector_size;
+ void *extra_data; /* extra system 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;
+}
+
+static int file_discard(Stream_t *Stream)
+{
+ int ret;
+ DeclareThis(SimpleFile_t);
+#ifdef BLKFLSBUF
+ ret= ioctl(This->fd, BLKFLSBUF);
+ if(ret < 0)
+ perror("BLKFLSBUF");
+ return ret;
+#endif
+}
+
+/* ZIP or other scsi device on Solaris or SunOS system.
+ Since Sun won't accept a non-Sun label on a scsi disk, we must
+ bypass Sun's disk interface and use low-level SCSI commands to read
+ or write the ZIP drive. We thus replace the file_read and file_write
+ routines with our own scsi_read and scsi_write routines, that use the
+ uscsi ioctl interface. By James Dugal, jpd@usl.edu, 11-96. Tested
+ under Solaris 2.5 and SunOS 4.3.1_u1 using GCC.
+
+ Note: the mtools.conf entry for a ZIP drive would look like this:
+(solaris) drive C: file="/dev/rdsk/c0t5d0s2" partition=4 FAT=16 nodelay exclusive scsi=&
+(sunos) drive C: file="/dev/rsd5c" partition=4 FAT=16 nodelay exclusive scsi=1
+
+ Note 2: Sol 2.5 wants mtools to be suid-root, to use the ioctl. SunOS is
+ happy if we just have access to the device, so making mtools sgid to a
+ group called, say, "ziprw" which has rw permission on /dev/rsd5c, is fine.
+ */
+
+#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 */
+ 0, /* dos-convert */
+ file_discard
+};
+
+
+static Class_t SimpleFileClass = {
+ file_read,
+ file_write,
+ file_flush,
+ file_free,
+ file_geom,
+ file_data,
+ 0, /* pre_allocate */
+ 0, /* dos-convert */
+ file_discard
+};
+
+
+Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
+ const char *name, int mode, char *errmsg,
+ int mode2, int locked, mt_size_t *maxSize)
+{
+ SimpleFile_t *This;
+#ifdef __EMX__
+HFILE FileHandle;
+ULONG Action;
+APIRET rc;
+#endif
+ This = New(SimpleFile_t);
+ if (!This){
+ printOom();
+ return 0;
+ }
+ memset((void*)This, 0, sizeof(SimpleFile_t));
+ This->scsi_sector_size = 512;
+ This->seekable = 1;
+#ifdef OS_hpux
+ This->size_limited = 0;
+#endif
+ This->Class = &SimpleFileClass;
+ if (!name || strcmp(name,"-") == 0 ){
+ if (mode == O_RDONLY)
+ This->fd = 0;
+ else
+ This->fd = 1;
+ This->seekable = 0;
+ This->refs = 1;
+ This->Next = 0;
+ This->Buffer = 0;
+ if (MT_FSTAT(This->fd, &This->statbuf) < 0) {
+ Free(This);
+ if(errmsg)
+#ifdef HAVE_SNPRINTF
+ snprintf(errmsg,199,"Can't stat -: %s",
+ strerror(errno));
+#else
+ sprintf(errmsg,"Can't stat -: %s",
+ strerror(errno));
+#endif
+ return NULL;
+ }
+
+ return (Stream_t *) This;
+ }
+
+
+ if(dev) {
+ if(!(mode2 & NO_PRIV))
+ This->privileged = IS_PRIVILEGED(dev);
+ mode |= dev->mode;
+ }
+
+ precmd(dev);
+ if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
+ reclaim_privs();
+
+#ifdef __EMX__
+#define DOSOPEN_FLAGS (OPEN_FLAGS_DASD | OPEN_FLAGS_WRITE_THROUGH | \
+ OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_RANDOM | \
+ OPEN_FLAGS_NO_CACHE)
+#define DOSOPEN_FD_ACCESS (OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE)
+#define DOSOPEN_HD_ACCESS (OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY)
+
+ if (isalpha(*name) && (*(name+1) == ':')) {
+ rc = DosOpen(
+ name, &FileHandle, &Action, 0L, FILE_NORMAL,
+ OPEN_ACTION_OPEN_IF_EXISTS, DOSOPEN_FLAGS |
+ (IS_NOLOCK(dev)?DOSOPEN_HD_ACCESS:DOSOPEN_FD_ACCESS),
+ 0L);
+#if DEBUG
+ if (rc != NO_ERROR) fprintf (stderr, "DosOpen() returned %d\n", rc);
+#endif
+ if (!IS_NOLOCK(dev)) {
+ rc = DosDevIOCtl(
+ FileHandle, 0x08L, DSK_LOCKDRIVE, 0, 0, 0, 0, 0, 0);
+#if DEBUG
+ if (rc != NO_ERROR) fprintf (stderr, "DosDevIOCtl() returned %d\n", rc);
+#endif
+ }
+ if (rc == NO_ERROR)
+ This->fd = _imphandle(FileHandle); else This->fd = -1;
+ } else
+#endif
+ {
+ if (IS_SCSI(dev))
+ This->fd = scsi_open(name, mode, IS_NOLOCK(dev)?0444:0666,
+ &This->extra_data);
+ else
+ This->fd = open(name, mode | O_LARGEFILE | O_BINARY,
+ IS_NOLOCK(dev)?0444:0666);
+ }
+
+ if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
+ drop_privs();
+
+ if (This->fd < 0) {
+ Free(This);
+ if(errmsg)
+#ifdef HAVE_SNPRINTF
+ snprintf(errmsg, 199, "Can't open %s: %s",
+ name, strerror(errno));
+#else
+ sprintf(errmsg, "Can't open %s: %s",
+ name, strerror(errno));
+#endif
+ return NULL;
+ }
+
+ if(IS_PRIVILEGED(dev) && !(mode2 & NO_PRIV))
+ closeExec(This->fd);
+
+#ifdef __EMX__
+ if (*(name+1) != ':')
+#endif
+ if (MT_FSTAT(This->fd, &This->statbuf) < 0
+#ifdef OS_mingw32msvc
+ && strncmp(name, "\\\\.\\", 4) != 0
+#endif
+ ) {
+ Free(This);
+ if(errmsg) {
+#ifdef HAVE_SNPRINTF
+ snprintf(errmsg,199,"Can't stat %s: %s",
+ name, strerror(errno));
+#else
+ if(strlen(name) > 50) {
+ sprintf(errmsg,"Can't stat file: %s",
+ strerror(errno));
+ } else {
+ sprintf(errmsg,"Can't stat %s: %s",
+ name, strerror(errno));
+ }
+#endif
+ }
+ return NULL;
+ }
+#ifndef __EMX__
+#ifndef __CYGWIN__
+#ifndef OS_mingw32msvc
+ /* lock the device on writes */
+ if (locked && lock_dev(This->fd, mode == O_RDWR, dev)) {
+ if(errmsg)
+#ifdef HAVE_SNPRINTF
+ snprintf(errmsg,199,
+ "plain floppy: device \"%s\" busy (%s):",
+ dev ? dev->name : "unknown", strerror(errno));
+#else
+ sprintf(errmsg,
+ "plain floppy: device \"%s\" busy (%s):",
+ (dev && strlen(dev->name) < 50) ?
+ dev->name : "unknown", strerror(errno));
+#endif
+
+ close(This->fd);
+ Free(This);
+ return NULL;
+ }
+#endif
+#endif
+#endif
+ /* set default parameters, if needed */
+ if (dev){
+ if ((!IS_MFORMAT_ONLY(dev) && dev->tracks) &&
+ init_geom(This->fd, dev, orig_dev, &This->statbuf)){
+ close(This->fd);
+ Free(This);
+ if(errmsg)
+ sprintf(errmsg,"init: set default params");
+ return NULL;
+ }
+ This->offset = (mt_off_t) dev->offset;
+ } else
+ This->offset = 0;
+
+ This->refs = 1;
+ This->Next = 0;
+ This->Buffer = 0;
+
+ if(maxSize) {
+ if (IS_SCSI(dev)) {
+ *maxSize = MAX_OFF_T_B(31+log_2(This->scsi_sector_size));
+ } else {
+ *maxSize = max_off_t_seek;
+ }
+ if(This->offset > *maxSize) {
+ close(This->fd);
+ Free(This);
+ if(errmsg)
+ sprintf(errmsg,"init: Big disks not supported");
+ return NULL;
+ }
+
+ *maxSize -= This->offset;
+ }
+ /* partitioned drive */
+
+ /* jpd@usl.edu: assume a partitioned drive on these 2 systems is a ZIP*/
+ /* or similar drive that must be accessed by low-level scsi commands */
+ /* AK: introduce new "scsi=1" statement to specifically set
+ * this option. Indeed, there could conceivably be partitioned
+ * devices where low level scsi commands will not be needed */
+ if(IS_SCSI(dev)) {
+ This->Class = &ScsiClass;
+ if(This->privileged)
+ reclaim_privs();
+ scsi_init(This);
+ if(This->privileged)
+ drop_privs();
+ }
+
+ This->swap = DO_SWAP( dev );
+
+ if(!(mode2 & NO_OFFSET) &&
+ dev && (dev->partition > 4 || dev->partition < 0))
+ fprintf(stderr,
+ "Invalid partition %d (must be between 0 and 4), ignoring it\n",
+ dev->partition);
+
+ while(!(mode2 & NO_OFFSET) &&
+ dev && dev->partition && dev->partition <= 4) {
+ int has_activated;
+ unsigned int last_end, j;
+ unsigned char buf[2048];
+ struct partition *partTable=(struct partition *)(buf+ 0x1ae);
+ size_t partOff;
+
+ /* read the first sector, or part of it */
+ if (force_read((Stream_t *)This, (char*) buf, 0, 512) != 512)
+ break;
+ if( _WORD(buf+510) != 0xaa55)
+ break;
+
+ partOff = BEGIN(partTable[dev->partition]);
+ if (maxSize) {
+ if (partOff > *maxSize >> 9) {
+ close(This->fd);
+ Free(This);
+ if(errmsg)
+ sprintf(errmsg,"init: Big disks not supported");
+ return NULL;
+ }
+ *maxSize -= (mt_off_t) partOff << 9;
+ }
+
+ This->offset += (mt_off_t) partOff << 9;
+ if(!partTable[dev->partition].sys_ind) {
+ if(errmsg)
+ sprintf(errmsg,
+ "init: non-existant partition");
+ close(This->fd);
+ Free(This);
+ return NULL;
+ }
+
+ if(!dev->tracks) {
+ dev->heads = head(partTable[dev->partition].end)+1;
+ dev->sectors = sector(partTable[dev->partition].end);
+ dev->tracks = cyl(partTable[dev->partition].end) -
+ cyl(partTable[dev->partition].start)+1;
+ }
+ dev->hidden=
+ dev->sectors*head(partTable[dev->partition].start) +
+ sector(partTable[dev->partition].start)-1;
+ if(!mtools_skip_check &&
+ consistencyCheck((struct partition *)(buf+0x1ae), 0, 0,
+ &has_activated, &last_end, &j, dev, 0)) {
+ fprintf(stderr,
+ "Warning: inconsistent partition table\n");
+ fprintf(stderr,
+ "Possibly unpartitioned device\n");
+ fprintf(stderr,
+ "\n*** Maybe try without partition=%d in "
+ "device definition ***\n\n",
+ dev->partition);
+ fprintf(stderr,
+ "If this is a PCMCIA card, or a disk "
+ "partitioned on another computer, this "
+ "message may be in error: add "
+ "mtools_skip_check=1 to your .mtoolsrc "
+ "file to suppress this warning\n");
+
+ }
+ break;
+ /* NOTREACHED */
+ }
+
+ This->lastwhere = -This->offset;
+ /* provoke a seek on those devices that don't start on a partition
+ * boundary */
+
+ return (Stream_t *) This;
+}
+
+int get_fd(Stream_t *Stream)
+{
+ Class_t *clazz;
+ DeclareThis(SimpleFile_t);
+ clazz = This->Class;
+ if(clazz != &ScsiClass &&
+ clazz != &SimpleFileClass)
+ return -1;
+ else
+ return This->fd;
+}
+
+void *get_extra_data(Stream_t *Stream)
+{
+ DeclareThis(SimpleFile_t);
+
+ return This->extra_data;
+}
diff --git a/plain_io.h b/plain_io.h
new file mode 100644
index 0000000..5abb90c
--- /dev/null
+++ b/plain_io.h
@@ -0,0 +1,38 @@
+#ifndef MTOOLS_PLAINIO_H
+#define MTOOLS_PLAINIO_H
+
+/* Copyright 1996,1997,1999,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "stream.h"
+#include "msdos.h"
+#ifdef __EMX__
+#include <io.h>
+#endif
+
+/* plain io */
+#define NO_PRIV 1
+#define NO_OFFSET 2
+
+Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev,
+ const char *name, int mode, char *errmsg, int mode2,
+ int locked, mt_size_t *maxSize);
+int check_parameters(struct device *ref, struct device *testee);
+
+int get_fd(Stream_t *Stream);
+void *get_extra_data(Stream_t *Stream);
+#endif
diff --git a/precmd.c b/precmd.c
new file mode 100644
index 0000000..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
index 0000000..c2f5c74
--- /dev/null
+++ b/privileges.c
@@ -0,0 +1,211 @@
+/* Copyright 1997,1999,2001,2002,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <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
index 0000000..e4c60f7
--- /dev/null
+++ b/privtest.c
@@ -0,0 +1,26 @@
+/* Copyright 1997,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+/* this program is used to test whether mtools drops its privileges correctly */
+
+main(int argc, char **argv)
+{
+ setuid(strtoul(argv[1], 0,0));
+ system("id");
+
+}
diff --git a/read_dword.h b/read_dword.h
new file mode 100644
index 0000000..7812c90
--- /dev/null
+++ b/read_dword.h
@@ -0,0 +1,41 @@
+#ifndef READ_DWORD
+#define READ_DWORD
+
+/* Copyright 2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+static Dword read_dword(int handle)
+{
+ Byte val[4];
+
+ if(read(handle, (char *)val, 4) < 4)
+ return -1;
+
+ return byte2dword(val);
+}
+
+UNUSED(static Qword read_qword(int handle) )
+{
+ Byte val[8];
+
+ if(read(handle, (char *)val, 8) < 8)
+ return -1;
+
+ return byte2qword(val);
+}
+
+#endif
diff --git a/scripts/add-disk b/scripts/add-disk
new file mode 100755
index 0000000..3e14e58
--- /dev/null
+++ b/scripts/add-disk
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Copyright 1997 Tim Hoogasian (hoogs@usa.net)
+# Copyright 1997,1998,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+#
+# add-disk
+# Contributed by Tim Hoogasian (hoogs@usa.net)
+#
+# Runs the commands to make Solaris locate a new disk that
+# has been plugged in after the system was booted.
+#
+
+# This script can be used on a Solaris system to add a SCSI disk
+# without needing to reboot/reconfigure the system. It's short and
+# simple, but it's quite handy -- and it saves you from having to
+# remember the individual commands.... :-)
+
+# You might also want to use the format.dat file if you don't have one
+# yet. It is in this same mtools/scripts directory, and should be
+# stored in /etc, or appended to the existing format.dat file
+
+# All you have to do is attach the Jaz drive, check to make sure there
+# isn't SCSI address conflict (Zip and Jaz media tend to default to ID
+# number 5) power it up, run "add-disk", insert the media, and GO!
+
+
+/usr/sbin/drvconfig
+/usr/sbin/devlinks
+/usr/sbin/disks # or /usr/sbin/tapes for tapes
+/usr/ucb/ucblinks # Compatibility links
+
+exit 0
diff --git a/scripts/amuFormat.sh b/scripts/amuFormat.sh
new file mode 100755
index 0000000..c9ff469
--- /dev/null
+++ b/scripts/amuFormat.sh
@@ -0,0 +1,103 @@
+#!/bin/sh
+# Copyright 2004 Feuz Stefan.
+# Copyright 2007 Adam Tkac.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+#
+# amuFormat.sh Formats various types and sizes of PC-Cards, according to the
+# AMU-specification
+#
+# parameters: $1: Card Type: The Card Type is written as disk/volume-label
+# to the boot-record
+# The string should have a length of max. 11 characters.
+#
+# $2: Drive character (b:, c:)
+#
+# 10-12-2003 lct created
+#
+vers=1.4
+
+#echo "debug: $0,$1,$2,$3,$4"
+
+#
+# main()
+#
+if [ $# -ne 2 ] ; then
+ echo "Usage: amuFormat.sh <Card Type> <drive>" >&2
+ echo "<Card Type> has to be defined in amuFormat.sh itself" >&2
+ echo "<drive> has to be defined in mtools.conf" >&2
+ exit 1
+fi
+
+echo "amuFormat $vers started..."
+
+drive="$2"
+
+case "$1" in
+8MBCARD-FW)
+ ## using the f: or g: drive for fat12 formatting...
+ ## see mtools.conf file...
+ case "$2" in
+ [bB]:) drive="f:" ;;
+ [cC]:) drive="g:" ;;
+ *) echo "Drive $2 not supported."; exit 1 ;;
+ esac
+ cylinders=245 heads=2 cluster_size=8
+ ;;
+32MBCARD-FW)
+ #from amu_toolkit_0_6:
+ #mformat -t489 -h4 -c4 -n32 -H32 -r32 -vPC-CARD -M512 -N0000 c:
+ cylinders=489 heads=4 cluster_size=4
+ ;;
+64MBCARD-FW)
+ echo "***** WARNING: untested on AvHMU, exiting *****"
+ exit 1
+ cylinders=245 heads=2 cluster_size=8
+ ;;
+1GBCARD-FW)
+ # from amu_toolkit_0_6:
+ #mformat -t2327 -h16 -c64 -n63 -H63 -r32 -v AMU-CARD -M512 -N 0000 c:
+ echo "***** WARNING: untested on AvHMU *****"
+ cylinders=2327 heads=16 cluster_size=64
+ ;;
+64MBCARDSAN)
+ # from amu_toolkit_0_6:
+ #mformat -t489 -h8 -c4 -n32 -H32 -r32 -v AMU-CARD -M512 -N 0000 c:
+ cylinders=489 heads=8 cluster_size=4
+ ;;
+#
+# insert new cards here...
+#
+*)
+ echo "Card not supported."
+ exit 1
+ ;;
+esac
+
+echo "Formatting card in slot $2 as $1"
+
+## initialise partition table
+mpartition -I "$drive"
+
+# write a partition table
+mpartition -c -t$cylinders -h$heads -s32 -b32 "$drive"
+
+## write boot-record, two FATs and a root-directory
+mformat -c$cluster_size -v "$1" "$drive"
+
+minfo "$2"
+mdir "$2"
+
+echo "done."
diff --git a/scripts/download b/scripts/download
new file mode 100755
index 0000000..142eb99
--- /dev/null
+++ b/scripts/download
@@ -0,0 +1,81 @@
+#!/bin/sh -
+
+# Copyright 1996 Carlos Duarte
+# Copyright 1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+
+## (c) Carlos Duarte ## Created: 18-Dec-96 ## Updated: 18-Dec-96 ##
+
+# main
+
+FAKE=
+DRIVE=a
+TOGGLE=0
+MDEL=:
+while [ "$1" ]
+do
+ case `echo z$1|cut -c2-` in
+ -n) FAKE=echo ;;
+ -d) DRIVE=`echo $1|cut -c3-`
+ [ "$DRIVE" = "" ] && {
+ shift
+ DRIVE=$1
+ [ "$DRIVE" = "" ] && break
+ } ;;
+ -t) TOGGLE=1 ;;
+ -rm) MDEL=mdel ;;
+ *) break ;;
+ esac
+ shift
+done
+
+if [ $# -ne 1 ] ; then
+ echo "usage: $0 [-n] [-d drive] [-rm] [-t] <ndisks>"
+ exit 1
+fi
+
+ndisks=$1
+n=0
+dir=1
+
+while test $n -lt $ndisks
+do
+
+ while [ -d $dir ]
+ do
+ dir=`expr $dir + 1`
+ done
+
+ $FAKE mkdir $dir
+ $FAKE mcopy $DRIVE:\* $dir && $FAKE $MDEL $DRIVE:\*
+
+ if [ "$TOGGLE" = "1" ] ; then
+ if [ "$DRIVE" = "a" ] ; then
+ DRIVE=b
+ else
+ DRIVE=a
+ fi
+ else
+ echo Replace disk and press return
+ read ans
+ fi
+
+ n=`expr $n + 1`
+ dir=`expr $dir + 1`
+done
+
+exit 0
diff --git a/scripts/format.dat b/scripts/format.dat
new file mode 100644
index 0000000..7fd31c1
--- /dev/null
+++ b/scripts/format.dat
@@ -0,0 +1,41 @@
+# Copyright 1997 Tim Hoogasian (hoogs@usa.net)
+# Copyright 1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+#
+# /etc/format.dat file for Accessing ZIP and Jaz disks from Solaris
+#
+# Contributed by Tim Hoogasian (thoogasi@us.oracle.com)
+#
+
+disk_type = "Iomega ZIP 100" \
+ : ctlr = SCSI \
+ : ncyl = 2406 : acyl = 2 : pcyl = 2408 : nhead = 2 \
+ : nsect = 40 : rpm = 3600 : bpt = 20480
+
+# Default Zip floppy part'n map : block 0-192480 (entire disk)
+#
+partition = "Iomega ZIP 100" \
+ : disk = "Iomega ZIP 100" : ctlr = SCSI \
+ : 2 = 0, 192480
+##
+disk_type = "Jaz 1GB" \
+ : ctlr = SCSI \
+ : ncyl = 1018 : acyl = 2 : pcyl = 1020 : nhead = 64 \
+ : nsect = 32 : rpm = 3600 : bpt = 16384
+
+partition = "Jaz 1GB" \
+ : disk = "Jaz 1GB" : ctlr = SCSI \
+ : 2 = 0,2084864
diff --git a/scripts/mcheck b/scripts/mcheck
new file mode 100755
index 0000000..f2c917f
--- /dev/null
+++ b/scripts/mcheck
@@ -0,0 +1,61 @@
+#!/bin/sh
+# Copyright 1994 David C. Niemi
+# Copyright 1994,1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+#
+# mcheck [ <DOS drive letter> ]
+#
+# Read every file on an MS-DOS formatted disk to make sure they're good.
+#
+# Requires: mdir and mread utilities from mtools in user's path.
+#
+# 1994/02/19 DCN Created
+# 1994/??/?? ALK Added case statement for results of mdir
+# 1994/09/24 DCN Cleanup (5 minutes on top of the 30 seconds creating it)
+# 1994/12/01 DCN Better comments, notices to stderr
+#
+# Copyright (C) 1994 David C. Niemi (niemi@tuxers.net)
+# The author requires that any copies or derived works include this
+# copyright notice; no other restrictions are placed on its use.
+#
+
+set -e
+set -u
+
+DRIVE=${1:-'A:'}
+mdir ${DRIVE}'*'
+case $? in
+2)
+ echo "No files on disk." >&2
+ exit 0
+ ;;
+1)
+ exit 1
+ ;;
+0)
+ ;;
+esac
+
+echo >&2; echo "Verifying files on drive ${DRIVE}..." >&2
+if mtype -/ ${DRIVE}\* > /dev/null; then
+ echo "Disk in drive ${DRIVE} is OK." >&2
+ exit 0
+else
+ echo "Disk in drive ${DRIVE} has errors." >&2
+ exit 1
+fi
+
+## NOTREACHED ##
diff --git a/scripts/mcomp b/scripts/mcomp
new file mode 100755
index 0000000..f541eb8
--- /dev/null
+++ b/scripts/mcomp
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+# Copyright 1996,1997,2001,2002,2006,2010 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+if [ $# -lt 2 ]; then
+ echo "usage: $0 dosfile [cmpoptions] unixfile"
+ exit 1
+fi
+
+dosfile=$1
+shift
+
+mcopy $dosfile - | cmp "$@"
+
diff --git a/scripts/mxtar b/scripts/mxtar
new file mode 100755
index 0000000..49acc49
--- /dev/null
+++ b/scripts/mxtar
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Copyright 1996,1997,2001,2002,2010 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+
+taropt=$1
+dosfile=$2
+shift
+shift
+
+mcopy $dosfile - | tar $taropt - "$@"
+
diff --git a/scripts/tgz b/scripts/tgz
new file mode 100755
index 0000000..8769ea6
--- /dev/null
+++ b/scripts/tgz
@@ -0,0 +1,86 @@
+#!/bin/sh
+# Copyright 1994 David C. Niemi.
+# Copyright 1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+#
+# tgz [destination [source...] ]
+#
+# Make a gzip'd tar archive $1 (or stdout) out of specified files
+# (or, if not specified, from everything in the current directory)
+#
+# Requires gzip in the user's path.
+#
+# Requires gnu tar (or something close) in the user's path
+# due to use of --exclude, --totals and -S.
+#
+# 1994/02/19 DCN Created
+# 1994/12/01 DCN Cleanup and major improvements
+#
+# Copyright (C) 1994 David C. Niemi (niemi@tuxers.net)
+# The author requires that any copies or derived works include this
+# copyright notice; no other restrictions are placed on its use.
+#
+
+set -e
+set -u
+
+Error ()
+{ echo "Error: $0: ${@-}." >&2
+ exit 1
+}
+
+if [ $# = 0 ]; then
+ dest=
+ src=.
+ tar cvf - . | gzip -9v
+ exit 0
+elif [ $# = 1 ]; then
+ dest=$1
+ src=.
+else
+ dest=$1
+ shift
+ src="${@-}"
+fi
+
+case $dest in
+"" | . | .. | */ | */. | */.. )
+ echo "Usage: $0: [destination [source...] ]" >&2
+ exit 1
+ ;;
+*.t?z | *.?z | *.z | *.Z | *.tz | *.tz? )
+ ;;
+*)
+ dest=${dest}.tgz ## Add on .tgz as default suffix
+esac
+
+if [ -h "$dest" ]; then
+ Error "Destination file \"$dest\" already exists as a symbolic link"
+elif [ -f "$dest" ]; then
+ Error "Destination \"$dest\" already exists as a file"
+elif [ -d "$dest" ]; then
+ Error "Destination \"$dest\" already exists as a directory"
+fi
+if [ -z "$dest" -o "X$dest" = 'X-' ]; then
+ echo "Writing gzipp'd tar archive to standard output." >&2
+ tar cvfS - -- $src | gzip -9v
+else
+ echo "Writing gzip'd tar archive to \"$dest\"." >&2
+ tar -cvS --totals --exclude "$dest" -f - -- $src | gzip -9v > "$dest"
+ ls -l "$dest" >&2
+fi
+
+exit 0
diff --git a/scripts/uz b/scripts/uz
new file mode 100755
index 0000000..3594130
--- /dev/null
+++ b/scripts/uz
@@ -0,0 +1,92 @@
+#!/bin/sh
+# Copyright 1994,2002 David C. Niemi.
+# Copyright 1996,1997,2001-2003,2010 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+# uz [file...]
+# lz [file...]
+#
+# If called "uz", gunzips and extracts a gzip'd tar'd archive.
+# If called "lz", gunzips and shows a listing of a gzip'd tar'd archive.
+#
+# Requires: gzip and tar in the user's path. Should work with most tars.
+# "-" is now used for backwards compatibility with antique tars, e.g. SCO.
+#
+# 1994/02/19 DCN Created (as a trivial, but useful script)
+# 1994/12/01 DCN Combined uz and lz, added suffix handling
+# 2002/09/11 DCN Added bzip2 support
+# 2010/10/16 AKN Added lzip support
+#
+# Copyright (C) 1994, 2002 David C. Niemi (niemi at tuxers dot net)
+# The author requires that any copies or derived works include this
+# copyright notice; no other restrictions are placed on its use.
+#
+
+set -e
+set -u
+
+## Default unzipping command
+uzcmd='gzip -cd'
+
+case $0 in
+*uz)
+ tarparam="-pxvf"
+ 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 tar.lz ; do
+ if [ -r "${1}$suffix" ]; then
+ found=$1$suffix
+ break
+ fi
+ done
+
+ case $found in
+ *.tar.bz2 | *.tb2)
+ uzcmd='bzip2 -cd'
+ ;;
+ *.tar.lz)
+ uzcmd='lzip -cd'
+ ;;
+ esac
+ if [ -z "$found" ]; then
+ echo "$0: could not read \"$1\"." >&2
+ else
+ echo "$action \"$found\"." >&2
+ $uzcmd -- "$found" | tar "$tarparam" -
+ fi
+ shift
+done
+
+exit 0
diff --git a/scsi.c b/scsi.c
new file mode 100644
index 0000000..7510edc
--- /dev/null
+++ b/scsi.c
@@ -0,0 +1,322 @@
+/* Copyright 1996 Grant R. Guenther, based on work of Itai Nahshon
+ * http://www.torque.net/ziptool.html
+ * Copyright 1997-1999,2001,2002,2005,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * scsi.c
+ * Iomega Zip/Jaz drive tool
+ * change protection mode and eject disk
+ */
+
+/* scis.c by Markus Gyger <mgyger@itr.ch> */
+/* This code is based on ftp://gear.torque.net/pub/ziptool.c */
+/* by Grant R. Guenther with the following copyright notice: */
+
+/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */
+/* http://www.torque.net/ziptool.html */
+
+
+/* A.K. Moved this from mzip.c to a separate file in order to share with
+ * plain_io.c */
+
+#include "sysincludes.h"
+#include "mtools.h"
+#include "scsi.h"
+
+#if defined OS_hpux
+#include <sys/scsi.h>
+#endif
+
+#ifdef OS_solaris
+#include <sys/scsi/scsi.h>
+#endif /* solaris */
+
+#ifdef OS_sunos
+#include <scsi/generic/commands.h>
+#include <scsi/impl/uscsi.h>
+#endif /* sunos */
+
+#ifdef sgi
+#include <sys/dsreq.h>
+#endif
+
+#ifdef OS_linux
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#endif
+
+#ifdef _SCO_DS
+#include <sys/scsicmd.h>
+#endif
+
+#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2)
+#include <camlib.h>
+#endif
+
+#if defined(OS_netbsd) || defined(OS_netbsdelf)
+#include <sys/scsiio.h>
+#endif
+
+int scsi_max_length(void)
+{
+#ifdef OS_linux
+ return 8;
+#else
+ return 255;
+#endif
+}
+
+int scsi_open(const char *name, int flag, 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 sg_io_hdr my_scsi_cmd;
+
+ /*
+ ** Init the command
+ */
+ memset(&scsi_cmd,0,sizeof(scsi_cmd));
+ my_scsi_cmd.interface_id = 'S';
+ my_scsi_cmd.dxfer_direction = (mode == SCSI_IO_READ)?(SG_DXFER_FROM_DEV):(SG_DXFER_TO_DEV);
+ my_scsi_cmd.cmd_len = cmdlen;
+ my_scsi_cmd.mx_sb_len = 0;
+ my_scsi_cmd.dxfer_len = len;
+ my_scsi_cmd.dxferp = data;
+ my_scsi_cmd.cmdp = cdb;
+ my_scsi_cmd.timeout = ~0; /* where is MAX_UINT defined??? */
+
+#ifdef DEBUG
+ printf("CMD(%d): %02x%02x%02x%02x%02x%02x %sdevice\n",cmdlen,cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5],
+ (mode==SCSI_IO_READ)?("<-"):("->"));
+ printf("DATA : len = %d\n",len);
+#endif
+
+ if (ioctl(fd, SG_IO,&my_scsi_cmd) < 0) {
+ perror("scsi_io");
+ return -1;
+ }
+
+ return my_scsi_cmd.status & STATUS_MASK;
+
+#elif (defined _SCO_DS) && (defined SCSIUSERCMD)
+ struct scsicmd my_scsi_cmd;
+
+ memset(my_scsi_cmd.cdb, 0, SCSICMDLEN); /* ensure zero pad */
+ memcpy(my_scsi_cmd.cdb, cdb, cmdlen);
+ my_scsi_cmd.cdb_len = cmdlen;
+ my_scsi_cmd.data_len = len;
+ my_scsi_cmd.data_ptr = data;
+ my_scsi_cmd.is_write = mode == SCSI_IO_WRITE;
+ if (ioctl(fd,SCSIUSERCMD,&my_scsi_cmd) == -1) {
+ perror("scsi_io: SCSIUSERCMD");
+ return -1;
+ }
+ if (my_scsi_cmd.host_sts != 0 || my_scsi_cmd.target_sts != 0) {
+ fprintf(stderr, "scsi_io: scsi status: host=%x; target=%x\n",
+ (unsigned)my_scsi_cmd.host_sts,(unsigned)my_scsi_cmd.target_sts);
+ return -1;
+ }
+ return 0;
+#elif defined sgi
+ struct dsreq my_scsi_cmd;
+
+ my_scsi_cmd.ds_cmdbuf = (char *)cdb;
+ my_scsi_cmd.ds_cmdlen = cmdlen;
+ my_scsi_cmd.ds_databuf = data;
+ my_scsi_cmd.ds_datalen = len;
+ switch (mode) {
+ case SCSI_IO_READ:
+ my_scsi_cmd.ds_flags = DSRQ_READ|DSRQ_SENSE;
+ break;
+ case SCSI_IO_WRITE:
+ my_scsi_cmd.ds_flags = DSRQ_WRITE|DSRQ_SENSE;
+ break;
+ }
+ my_scsi_cmd.ds_time = 10000;
+ my_scsi_cmd.ds_link = 0;
+ my_scsi_cmd.ds_synch =0;
+ my_scsi_cmd.ds_ret =0;
+ if (ioctl(fd, DS_ENTER, &my_scsi_cmd) == -1) {
+ perror("scsi_io");
+ return -1;
+ }
+
+ if(my_scsi_cmd.ds_status) {
+ errno = 0;
+ fprintf(stderr,"scsi status=%x\n",
+ (unsigned short)my_scsi_cmd.ds_status);
+ return -1;
+ }
+
+ return 0;
+#elif (defined OS_freebsd) && (__FreeBSD__ >= 2)
+#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
+ union ccb *ccb;
+ int flags;
+ int r;
+ struct cam_device *cam_dev = (struct cam_device *) extra_data;
+
+
+ if (cam_dev==NULL || cam_dev->fd!=fd)
+ {
+ fprintf(stderr,"invalid file descriptor\n");
+ return -1;
+ }
+ ccb = cam_getccb(cam_dev);
+
+ bcopy(cdb, ccb->csio.cdb_io.cdb_bytes, cmdlen);
+
+ if (mode == SCSI_IO_READ)
+ flags = CAM_DIR_IN;
+ else if (data && len)
+ flags = CAM_DIR_OUT;
+ else
+ flags = CAM_DIR_NONE;
+ cam_fill_csio(&ccb->csio,
+ /* retry */ 1,
+ /* cbfcnp */ NULL,
+ flags,
+ /* tag_action */ MSG_SIMPLE_Q_TAG,
+ /*data_ptr*/ len ? data : 0,
+ /*data_len */ data ? len : 0,
+ 96,
+ cmdlen,
+ 5000);
+
+ if (cam_send_ccb(cam_dev, ccb) < 0 ||
+ (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ return -1;
+ }
+ return 0;
+#elif defined(OS_netbsd) || defined(OS_netbsdelf)
+ struct scsireq sc;
+
+ memset(&sc, 0, sizeof(sc));
+ memcpy(sc.cmd, cdb, cmdlen);
+ sc.cmdlen = cmdlen;
+ sc.databuf = data;
+ sc.datalen = len;
+ sc.senselen = 0;
+ sc.timeout = 10000;
+ switch (mode) {
+ case SCSI_IO_READ:
+ sc.flags = SCCMD_READ;
+ break;
+ case SCSI_IO_WRITE:
+ sc.flags = SCCMD_WRITE;
+ break;
+ }
+
+ if (ioctl(fd, SCIOCCOMMAND, &sc) == -1) {
+ perror("SCIOCCOMMAND ioctl");
+ return -1;
+ }
+
+ if (sc.retsts) {
+ errno = EIO;
+ fprintf(stderr, "SCSI command failed, retsts %d\n",
+sc.retsts);
+ return -1;
+ }
+
+ return 0;
+#else
+ fprintf(stderr, "scsi_io not implemented\n");
+ return -1;
+#endif
+}
diff --git a/scsi.h b/scsi.h
new file mode 100644
index 0000000..8803989
--- /dev/null
+++ b/scsi.h
@@ -0,0 +1,37 @@
+#ifndef __mtools_scsi_h
+#define __mtools_scsi_h
+/* Copyright 1997-1999,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define SCSI_READ 0x8
+#define SCSI_WRITE 0xA
+#define SCSI_IOMEGA 0xC
+#define SCSI_INQUIRY 0x12
+#define SCSI_MODE_SENSE 0x1a
+#define SCSI_START_STOP 0x1b
+#define SCSI_ALLOW_MEDIUM_REMOVAL 0x1e
+#define SCSI_GROUP1 0x20
+#define SCSI_READ_CAPACITY 0x25
+
+
+typedef enum { SCSI_IO_READ, SCSI_IO_WRITE } scsi_io_mode_t;
+int scsi_max_length(void);
+int scsi_cmd(int fd, unsigned char cdb[6], int clen, scsi_io_mode_t mode,
+ void *data, size_t len, void *extra_data);
+int scsi_open(const char *name, int flags, int mode, void **extra_data);
+
+#endif /* __mtools_scsi_h */
diff --git a/signal.c b/signal.c
new file mode 100644
index 0000000..c8533a7
--- /dev/null
+++ b/signal.c
@@ -0,0 +1,134 @@
+/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "mtools.h"
+
+#undef got_signal
+
+int got_signal = 0;
+
+static void signal_handler(int dummy)
+{
+ got_signal = 1;
+#if 0
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+#endif
+}
+
+#if 0
+int do_gotsignal(char *f, int n)
+{
+ if(got_signal)
+ fprintf(stderr, "file=%s line=%d\n", f, n);
+ return got_signal;
+}
+#endif
+
+void setup_signal(void)
+{
+ /* catch signals */
+#ifdef SIGHUP
+ signal(SIGHUP, signal_handler);
+#endif
+#ifdef SIGINT
+ signal(SIGINT, signal_handler);
+#endif
+#ifdef SIGTERM
+ signal(SIGTERM, signal_handler);
+#endif
+#ifdef SIGQUIT
+ signal(SIGQUIT, signal_handler);
+#endif
+}
+
+#ifdef HAVE_SIGACTION
+static void _allow_interrupt(saved_sig_state *ss, int sig, int slot)
+{
+ struct sigaction new;
+
+ bzero(&new, sizeof(new));
+ new.sa_handler = signal_handler;
+ new.sa_flags &= ~SA_RESTART;
+
+ if(sigaction(sig, &new, &ss->sa[slot]) < 0) {
+ perror("sigaction");
+ exit(1);
+ }
+}
+#endif
+
+/* Allow syscalls to be interrupted by signal */
+void allow_interrupts(saved_sig_state *ss)
+{
+#ifdef HAVE_SIGACTION
+
+# ifdef SIGHUP
+ _allow_interrupt(ss, SIGINT, 0);
+# endif
+
+# ifdef SIGINT
+ _allow_interrupt(ss, SIGINT, 1);
+# endif
+
+# ifdef SIGTERM
+ _allow_interrupt(ss, SIGINT, 2);
+# endif
+
+# ifdef SIGQUIT
+ _allow_interrupt(ss, SIGINT, 3);
+# endif
+
+#endif
+}
+
+#ifdef HAVE_SIGACTION
+static void _restore_interrupt(saved_sig_state *ss, int sig, int slot)
+{
+ if(sigaction(sig, &ss->sa[slot], NULL) < 0) {
+ perror("restore sigaction");
+ exit(1);
+ }
+}
+#endif
+
+/* Restore syscalls to be interrupted by signal */
+void restore_interrupts(saved_sig_state *ss)
+{
+#ifdef HAVE_SIGACTION
+
+# ifdef SIGHUP
+ _restore_interrupt(ss, SIGINT, 0);
+# endif
+
+# ifdef SIGINT
+ _restore_interrupt(ss, SIGINT, 1);
+# endif
+
+# ifdef SIGTERM
+ _restore_interrupt(ss, SIGINT, 2);
+# endif
+
+# ifdef SIGQUIT
+ _restore_interrupt(ss, SIGINT, 3);
+# endif
+
+#endif
+}
diff --git a/stream.c b/stream.c
new file mode 100644
index 0000000..2055f12
--- /dev/null
+++ b/stream.c
@@ -0,0 +1,87 @@
+/* Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "stream.h"
+
+int batchmode = 0;
+
+int flush_stream(Stream_t *Stream)
+{
+ int ret=0;
+ if(!batchmode) {
+ if(Stream->Class->flush)
+ ret |= Stream->Class->flush(Stream);
+ if(Stream->Next)
+ ret |= flush_stream(Stream->Next);
+ }
+ return ret;
+}
+
+Stream_t *copy_stream(Stream_t *Stream)
+{
+ if(Stream)
+ Stream->refs++;
+ return Stream;
+}
+
+int free_stream(Stream_t **Stream)
+{
+ int ret=0;
+
+ if(!*Stream)
+ return -1;
+ if(! --(*Stream)->refs){
+ if((*Stream)->Class->flush)
+ ret |= (*Stream)->Class->flush(*Stream);
+ if((*Stream)->Class->freeFunc)
+ ret |= (*Stream)->Class->freeFunc(*Stream);
+ if((*Stream)->Next)
+ ret |= free_stream(&(*Stream)->Next);
+ Free(*Stream);
+ } else if ( (*Stream)->Next )
+ ret |= flush_stream((*Stream)->Next);
+ *Stream = NULL;
+ return ret;
+}
+
+
+#define GET_DATA(stream, date, size, type, address) \
+(stream)->Class->get_data( (stream), (date), (size), (type), (address) )
+
+
+int get_data_pass_through(Stream_t *Stream, time_t *date, mt_size_t *size,
+ int *type, int *address)
+{
+ return GET_DATA(Stream->Next, date, size, type, address);
+}
+
+int read_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+ return READS(Stream->Next, buf, start, len);
+}
+
+int write_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len)
+{
+ return WRITES(Stream->Next, buf, start, len);
+}
+
+doscp_t *get_dosConvert_pass_through(Stream_t *Stream)
+{
+ return GET_DOSCONVERT(Stream->Next);
+}
diff --git a/stream.h b/stream.h
new file mode 100644
index 0000000..f027ece
--- /dev/null
+++ b/stream.h
@@ -0,0 +1,107 @@
+#ifndef MTOOLS_STREAM_H
+#define MTOOLS_STREAM_H
+
+/* Copyright 1996-1999,2001,2002,2005,2006,2008,2009,2011 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct Stream_t {
+ struct Class_t *Class;
+ int refs;
+ struct Stream_t *Next;
+ struct Stream_t *Buffer;
+} Stream_t;
+
+#include "mtools.h"
+#include "msdos.h"
+
+#include "llong.h"
+
+doscp_t *get_dosConvert_pass_through(Stream_t *Stream);
+
+typedef struct Class_t {
+ int (*read)(Stream_t *, char *, mt_off_t, size_t);
+ int (*write)(Stream_t *, char *, mt_off_t, size_t);
+ int (*flush)(Stream_t *);
+ int (*freeFunc)(Stream_t *);
+ int (*set_geom)(Stream_t *, device_t *, device_t *, int media,
+ union bootsector *);
+ int (*get_data)(Stream_t *, time_t *, mt_size_t *, int *, int *);
+ int (*pre_allocate)(Stream_t *, mt_size_t);
+
+ doscp_t *(*get_dosConvert)(Stream_t *);
+
+ int (*discard)(Stream_t *);
+} Class_t;
+
+#define READS(stream, buf, address, size) \
+((stream)->Class->read)( (stream), (char *) (buf), (address), (size) )
+
+#define WRITES(stream, buf, address, size) \
+((stream)->Class->write)( (stream), (char *) (buf), (address), (size) )
+
+#define SET_GEOM(stream, dev, orig_dev, media, boot) \
+(stream)->Class->set_geom( (stream), (dev), (orig_dev), (media), (boot) )
+
+#define GET_DATA(stream, date, size, type, address) \
+(stream)->Class->get_data( (stream), (date), (size), (type), (address) )
+
+#define PRE_ALLOCATE(stream, size) \
+(stream)->Class->pre_allocate((stream), (size))
+
+#define GET_DOSCONVERT(stream) \
+ (stream)->Class->get_dosConvert((stream))
+
+#define DISCARD(stream) \
+ (stream)->Class->discard((stream))
+
+int flush_stream(Stream_t *Stream);
+Stream_t *copy_stream(Stream_t *Stream);
+int free_stream(Stream_t **Stream);
+
+#define FLUSH(stream) \
+flush_stream( (stream) )
+
+#define FREE(stream) \
+free_stream( (stream) )
+
+#define COPY(stream) \
+copy_stream( (stream) )
+
+
+#define DeclareThis(x) x *This = (x *) Stream
+
+int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+
+int get_data_pass_through(Stream_t *Stream, time_t *date, mt_size_t *size,
+ int *type, int *address);
+
+int read_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+int write_pass_through(Stream_t *Stream, char *buf, mt_off_t start, size_t len);
+
+mt_off_t sectorsToBytes(Stream_t *This, off_t off);
+
+mt_size_t getfree(Stream_t *Stream);
+int getfreeMinBytes(Stream_t *Stream, mt_size_t ref);
+
+Stream_t *find_device(char drive, int mode, struct device *out_dev,
+ union bootsector *boot,
+ char *name, int *media, mt_size_t *maxSize,
+ int *isRop);
+
+#endif
+
diff --git a/streamcache.c b/streamcache.c
new file mode 100644
index 0000000..4277ef0
--- /dev/null
+++ b/streamcache.c
@@ -0,0 +1,79 @@
+/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * streamcache.c
+ * Managing a cache of open disks
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "fs.h"
+#include "mainloop.h"
+#include "plain_io.h"
+#include "file.h"
+
+static int is_initialized = 0;
+static Stream_t *fss[256]; /* open drives */
+
+static void finish_sc(void)
+{
+ int i;
+
+ for(i=0; i<256; i++){
+ if(fss[i] && fss[i]->refs != 1 )
+ fprintf(stderr,"Streamcache allocation problem:%c %d\n",
+ i, fss[i]->refs);
+ FREE(&(fss[i]));
+ }
+}
+
+static void init_streamcache(void)
+{
+ int i;
+
+ if(is_initialized)
+ return;
+ is_initialized = 1;
+ for(i=0; i<256; i++)
+ fss[i]=0;
+ atexit(finish_sc);
+}
+
+Stream_t *open_root_dir(unsigned char drive, int flags, int *isRop)
+{
+ Stream_t *Fs;
+
+ init_streamcache();
+
+ drive = toupper(drive);
+
+ /* open the drive */
+ if(fss[drive])
+ Fs = fss[drive];
+ else {
+ Fs = fs_init(drive, flags, isRop);
+ if (!Fs){
+ fprintf(stderr, "Cannot initialize '%c:'\n", drive);
+ return NULL;
+ }
+
+ fss[drive] = Fs;
+ }
+
+ return OpenRoot(Fs);
+}
diff --git a/strip-pp.sed b/strip-pp.sed
new file mode 100644
index 0000000..1624aa0
--- /dev/null
+++ b/strip-pp.sed
@@ -0,0 +1,20 @@
+# Copyright 1997,2001,2002 Alain Knaff.
+# This file is part of mtools.
+#
+# Mtools is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Mtools is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+:1
+/^\.[IlP][pP]$/N
+s/^\.[IlP][pP]\n\(\.[IlTP][pP]\)$/\1/
+s/^\.l[pP]/.PP/
+/^\.PP$/b1
diff --git a/subdir.c b/subdir.c
new file mode 100644
index 0000000..164fc0e
--- /dev/null
+++ b/subdir.c
@@ -0,0 +1,44 @@
+/* Copyright 1986-1992 Emmet P. Gray.
+ * Copyright 1996,1997,2001,2002,2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "file.h"
+#include "buffer.h"
+
+/*
+ * Find the directory and load a new dir_chain[]. A null directory
+ * is OK. Returns a 1 on error.
+ */
+
+
+void bufferize(Stream_t **Dir)
+{
+ Stream_t *BDir;
+
+ if(!*Dir)
+ return;
+ BDir = buf_init(*Dir, 64*16384, 512, MDIR_SIZE);
+ if(!BDir){
+ FREE(Dir);
+ *Dir = NULL;
+ } else
+ *Dir = BDir;
+}
diff --git a/sysconfdir.texi b/sysconfdir.texi
new file mode 100644
index 0000000..359518f
--- /dev/null
+++ b/sysconfdir.texi
@@ -0,0 +1 @@
+@set SYSCONFDIR /etc/
diff --git a/sysincludes.h b/sysincludes.h
new file mode 100644
index 0000000..2a0e528
--- /dev/null
+++ b/sysincludes.h
@@ -0,0 +1,607 @@
+/* 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
+
+#ifndef HAVE_CADDR_T
+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
+# define UNUSEDP __attribute__ ((unused))
+# else
+# define UNUSED(x) x
+# define UNUSEDP /* */
+# endif
+# define NORETURN __attribute__ ((noreturn))
+#else
+# define UNUSED(x) x
+# define UNUSEDP /* */
+# 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
index 0000000..bd18a11
--- /dev/null
+++ b/texinfo.tex
@@ -0,0 +1,10075 @@
+% 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{2012-11-08.11}
+%
+% Copyright 1985, 1986, 1988, 1990, 1991, 1992, 1993, 1994, 1995,
+% 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+% 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 Exception is an additional permission under section 7
+% of the GNU General Public License, version 3 ("GPLv3").
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+% http://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or
+% http://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or
+% http://www.gnu.org/software/texinfo/ (the Texinfo home page)
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org. Please include 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\ptexraggedright=\raggedright
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexstar=\*
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+ \let\linenumber = \empty % Pre-3.0.
+\else
+ \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi
+\ifx\putworderror\undefined \gdef\putworderror{error}\fi
+\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi
+
+% 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\ampChar = `\&
+\chardef\colonChar = `\:
+\chardef\commaChar = `\,
+\chardef\dashChar = `\-
+\chardef\dotChar = `\.
+\chardef\exclamChar= `\!
+\chardef\hashChar = `\#
+\chardef\lquoteChar= `\`
+\chardef\questChar = `\?
+\chardef\rquoteChar= `\'
+\chardef\semiChar = `\;
+\chardef\slashChar = `\/
+\chardef\underChar = `\_
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+ Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+ ap-pen-dix bit-map bit-maps
+ data-base data-bases eshell fall-ing half-way long-est man-u-script
+ man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+ par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+ spell-ing spell-ings
+ stand-alone strong-est time-stamp time-stamps which-ever white-space
+ wide-spread wrap-around
+}
+
+% 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 }
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal. We don't just call \tracingall here,
+% since that produces some useless output on the terminal. We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+ \tracingstats2
+ \tracingpages1
+ \tracinglostchars2 % 2 gives us more in etex
+ \tracingparagraphs1
+ \tracingoutput1
+ \tracingmacros2
+ \tracingrestores1
+ \showboxbreadth\maxdimen \showboxdepth\maxdimen
+ \ifx\eTeXversion\thisisundefined\else % etex gives us more logging
+ \tracingscantokens1
+ \tracingifs1
+ \tracinggroups1
+ \tracingnesting2
+ \tracingassigns1
+ \fi
+ \tracingcommands3 % 3 gives us more in etex
+ \errorcontextlines16
+}%
+
+% @errormsg{MSG}. Do the index-like expansions on MSG, but if things
+% aren't perfect, it's not the end of the world, being an error message,
+% after all.
+%
+\def\errormsg{\begingroup \indexnofonts \doerrormsg}
+\def\doerrormsg#1{\errmessage{#1}}
+
+% add check for \lastpenalty to plain's definitions. If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+ \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+ \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+ \removelastskip\penalty-200\bigskip\fi\fi}
+
+% 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
+ outside of any environment%
+ \else
+ in environment \expandafter\string#1%
+ \fi
+}
+
+% @end foo executes the definition of \Efoo.
+% But first, it executes a specialized version of \checkenv
+%
+\parseargdef\end{%
+ \if 1\csname iscond.#1\endcsname
+ \else
+ % The general wording of \badenverr may not be ideal.
+ \expandafter\checkenv\csname#1\endcsname
+ \csname E#1\endcsname
+ \endgroup
+ \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\unskip\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=\endofsentencespacefactor\space}
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=\endofsentencespacefactor\space}
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=\endofsentencespacefactor\space}
+
+% @frenchspacing on|off says whether to put extra space after punctuation.
+%
+\def\onword{on}
+\def\offword{off}
+%
+\parseargdef\frenchspacing{%
+ \def\temp{#1}%
+ \ifx\temp\onword \plainfrenchspacing
+ \else\ifx\temp\offword \plainnonfrenchspacing
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @frenchspacing option `\temp', must be on|off}%
+ \fi\fi
+}
+
+% @w prevents a word break. Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox. We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line. According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0). If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large. This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material. In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom. The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+ \ifnum\catcode`\^^M=\active \else
+ \errhelp = \groupinvalidhelp
+ \errmessage{@group invalid in context where filling is enabled}%
+ \fi
+ \startsavinginserts
+ %
+ \setbox\groupbox = \vtop\bgroup
+ % Do @comment since we are called inside an environment such as
+ % @example, where each end-of-line in the input causes an
+ % end-of-line in the output. We don't want the end-of-line after
+ % the `@group' to put extra space in the output. Since @group
+ % should appear on a line by itself (according to the Texinfo
+ % manual), we don't worry about eating any user text.
+ \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it. Thus, space below is not quite equal to space
+% above. But it's pretty close.
+\def\Egroup{%
+ % To get correct interline space between the last line of the group
+ % and the first line afterwards, we have to propagate \prevdepth.
+ \endgraf % Not \par, as it may have been set to \lisppar.
+ \global\dimen1 = \prevdepth
+ \egroup % End the \vtop.
+ % \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
+
+\parseargdef\need{%
+ % Ensure vertical mode, so we don't make a big box in the middle of a
+ % paragraph.
+ \par
+ %
+ % If the @need value is less than one line space, it's useless.
+ \dimen0 = #1\mil
+ \dimen2 = \ht\strutbox
+ \advance\dimen2 by \dp\strutbox
+ \ifdim\dimen0 > \dimen2
+ %
+ % Do a \strut just to make the height of this box be normal, so the
+ % normal leading is inserted relative to the preceding line.
+ % And a page break here is fine.
+ \vtop to #1\mil{\strut\vfil}%
+ %
+ % TeX does not even consider page breaks if a penalty added to the
+ % main vertical list is 10000 or more. But in order to see if the
+ % empty box we just added fits on the page, we must make it consider
+ % page breaks. On the other hand, we don't want to actually break the
+ % page after the empty box. So we use a penalty of 9999.
+ %
+ % There is an extremely small chance that TeX will actually break the
+ % page at this \penalty, if there are no other feasible breakpoints in
+ % sight. (If the user is using lots of big @group commands, which
+ % almost-but-not-quite fill up a page, TeX will have a hard time doing
+ % good page breaking, for example.) However, I could not construct an
+ % example where a page broke at this \penalty; if it happens in a real
+ % document, then we can reconsider our strategy.
+ \penalty9999
+ %
+ % Back up by the size of the box, whether we did a page break or not.
+ \kern -#1\mil
+ %
+ % Do not allow a page break right after this kern.
+ \nobreak
+ \fi
+}
+
+% @br forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+ \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph. For more general purposes, use the \margin insertion
+% class. WHICH is `l' or `r'. Not documented, written for gawk manual.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+ \nobreak
+ \kern-\strutdepth
+ \vtop to \strutdepth{%
+ \baselineskip=\strutdepth
+ \vss
+ % if you have multiple lines of stuff to put here, you'll need to
+ % make the vbox yourself of the appropriate size.
+ \ifx#1l%
+ \llap{\ignorespaces #2\hskip\inmarginspacing}%
+ \else
+ \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+ \fi
+ \null
+ }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt
+ \def\lefttext{#1}% have both texts
+ \def\righttext{#2}%
+ \else
+ \def\lefttext{#1}% have only one text
+ \def\righttext{#1}%
+ \fi
+ %
+ \ifodd\pageno
+ \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+ \else
+ \def\temp{\inleftmargin\lefttext}%
+ \fi
+ \temp
+}
+
+% @| 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). This command
+% is not documented, not supported, and doesn't work.
+%
+\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
+ }%
+ }%
+}
+
+% @include FILE -- \input text of FILE.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+ \pushthisfilestack
+ \def\thisfile{#1}%
+ {%
+ \makevalueexpandable % we want to expand any @value in FILE.
+ \turnoffactive % and allow special characters in the expansion
+ \indexnofonts % Allow `@@' and other weird things in file names.
+ \wlog{texinfo.tex: doing @include of #1^^J}%
+ \edef\temp{\noexpand\input #1 }%
+ %
+ % This trickery is to read FILE outside of a group, in case it makes
+ % definitions, etc.
+ \expandafter
+ }\temp
+ \popthisfilestack
+}
+\def\filenamecatcodes{%
+ \catcode`\\=\other
+ \catcode`~=\other
+ \catcode`^=\other
+ \catcode`_=\other
+ \catcode`|=\other
+ \catcode`<=\other
+ \catcode`>=\other
+ \catcode`+=\other
+ \catcode`-=\other
+ \catcode`\`=\other
+ \catcode`\'=\other
+}
+
+\def\pushthisfilestack{%
+ \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+ \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+ \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+ the stack of filenames is empty.}}
+%
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+ \ifhmode
+ \let\centersub\centerH
+ \else
+ \let\centersub\centerV
+ \fi
+ \centersub{\hfil \ignorespaces#1\unskip \hfil}%
+ \let\centersub\relax % don't let the definition persist, just in case
+}
+\def\centerH#1{{%
+ \hfil\break
+ \advance\hsize by -\leftskip
+ \advance\hsize by -\rightskip
+ \line{#1}%
+ \break
+}}
+%
+\newcount\centerpenalty
+\def\centerV#1{%
+ % The idea here is the same as in \startdefun, \cartouche, etc.: if
+ % @center is the first thing after a section heading, we need to wipe
+ % out the negative parskip inserted by \sectionheading, but still
+ % prevent a page break here.
+ \centerpenalty = \lastpenalty
+ \ifnum\centerpenalty>10000 \vskip\parskip \fi
+ \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi
+ \line{\kern\leftskip #1\kern\rightskip}%
+}
+
+% @sp n outputs n lines of vertical space
+%
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore is another way to write a comment
+%
+\def\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 = {}%
+}
+
+
+% @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 being undefined.
+\ifx\pdfoutput\thisisundefined
+\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.
+%
+% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
+% related messages. The final outcome is that it is up to the TeX user
+% to double the backslashes and otherwise make the string valid, so
+% that's what we do. pdftex 1.30.0 (ca.2005) introduced a primitive to
+% do this reliably, so we use it.
+
+% #1 is a control sequence in which to do the replacements,
+% which we \xdef.
+\def\txiescapepdf#1{%
+ \ifx\pdfescapestring\thisisundefined
+ % No primitive available; should we give a warning or log?
+ % Many times it won't matter.
+ \else
+ % The expandable \pdfescapestring primitive escapes parentheses,
+ % backslashes, and other special chars.
+ \xdef#1{\pdfescapestring{#1}}%
+ \fi
+}
+
+\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
+with PDF output, and none of those formats could be found. (.eps cannot
+be supported due to the design of the PDF format; use regular TeX (DVI
+output) for that.)}
+
+\ifpdf
+ %
+ % Color manipulation macros 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\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+ \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+ %
+ % pdftex (and the PDF format) support .pdf, .png, .jpg (among
+ % others). Let's try in that order, PDF first since if
+ % someone has a scalable image, presumably better to use that than a
+ % bitmap.
+ \let\pdfimgext=\empty
+ \begingroup
+ \openin 1 #1.pdf \ifeof 1
+ \openin 1 #1.PDF \ifeof 1
+ \openin 1 #1.png \ifeof 1
+ \openin 1 #1.jpg \ifeof 1
+ \openin 1 #1.jpeg \ifeof 1
+ \openin 1 #1.JPG \ifeof 1
+ \errhelp = \nopdfimagehelp
+ \errmessage{Could not find image file #1 for pdf}%
+ \else \gdef\pdfimgext{JPG}%
+ \fi
+ \else \gdef\pdfimgext{jpeg}%
+ \fi
+ \else \gdef\pdfimgext{jpg}%
+ \fi
+ \else \gdef\pdfimgext{png}%
+ \fi
+ \else \gdef\pdfimgext{PDF}%
+ \fi
+ \else \gdef\pdfimgext{pdf}%
+ \fi
+ \closein 1
+ \endgroup
+ %
+ % without \immediate, ancient pdftex seg faults when the same image is
+ % included twice. (Version 3.14159-pre-1.0-unofficial-20010704.)
+ \ifnum\pdftexversion < 14
+ \immediate\pdfimage
+ \else
+ \immediate\pdfximage
+ \fi
+ \ifdim \wd0 >0pt width \pdfimagewidth \fi
+ \ifdim \wd2 >0pt height \pdfimageheight \fi
+ \ifnum\pdftexversion<13
+ #1.\pdfimgext
+ \else
+ {#1.\pdfimgext}%
+ \fi
+ \ifnum\pdftexversion < 14 \else
+ \pdfrefximage \pdflastximage
+ \fi}
+ %
+ \def\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
+ \makevalueexpandable
+ \def\pdfdestname{#1}%
+ \txiescapepdf\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.
+ \edef\pdfoutlinedest{#3}%
+ \ifx\pdfoutlinedest\empty
+ \def\pdfoutlinedest{#4}%
+ \else
+ \txiescapepdf\pdfoutlinedest
+ \fi
+ %
+ % Also escape PDF chars in the display string.
+ \edef\pdfoutlinetext{#1}%
+ \txiescapepdf\pdfoutlinetext
+ %
+ \pdfoutline goto name{\pdfmkpgn{\pdfoutlinedest}}#2{\pdfoutlinetext}%
+ }
+ %
+ \def\pdfmakeoutlines{%
+ \begingroup
+ % Read toc silently, to get counts of subentries for \pdfoutline.
+ \def\partentry##1##2##3##4{}% ignore parts in the outlines
+ \def\numchapentry##1##2##3##4{%
+ \def\thischapnum{##2}%
+ \def\thissecnum{0}%
+ \def\thissubsecnum{0}%
+ }%
+ \def\numsecentry##1##2##3##4{%
+ \advancenumber{chap\thischapnum}%
+ \def\thissecnum{##2}%
+ \def\thissubsecnum{0}%
+ }%
+ \def\numsubsecentry##1##2##3##4{%
+ \advancenumber{sec\thissecnum}%
+ \def\thissubsecnum{##2}%
+ }%
+ \def\numsubsubsecentry##1##2##3##4{%
+ \advancenumber{subsec\thissubsecnum}%
+ }%
+ \def\thischapnum{0}%
+ \def\thissecnum{0}%
+ \def\thissubsecnum{0}%
+ %
+ % use \def rather than \let here because we redefine \chapentry et
+ % al. a second time, below.
+ \def\appentry{\numchapentry}%
+ \def\appsecentry{\numsecentry}%
+ \def\appsubsecentry{\numsubsecentry}%
+ \def\appsubsubsecentry{\numsubsubsecentry}%
+ \def\unnchapentry{\numchapentry}%
+ \def\unnsecentry{\numsecentry}%
+ \def\unnsubsecentry{\numsubsecentry}%
+ \def\unnsubsubsecentry{\numsubsubsecentry}%
+ \readdatafile{toc}%
+ %
+ % Read toc second time, this time actually producing the outlines.
+ % The `-' means take the \expnumber as the absolute number of
+ % subentries, which we calculated on our first read of the .toc above.
+ %
+ % We use the node names as the destinations.
+ \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.
+ %
+ % TODO this right, we have to translate 8-bit characters to
+ % their "best" equivalent, based on the @documentencoding. Too
+ % much work for too little return. Just use the ASCII equivalents
+ % we use for the index sort strings.
+ %
+ \indexnofonts
+ \setupdatafile
+ % We can have normal brace characters in the PDF outlines, unlike
+ % Texinfo index files. So set that up.
+ \def\{{\lbracecharliteral}%
+ \def\}{\rbracecharliteral}%
+ \catcode`\\=\active \otherbackslash
+ \input \tocreadfilename
+ \endgroup
+ }
+ {\catcode`[=1 \catcode`]=2
+ \catcode`{=\other \catcode`}=\other
+ \gdef\lbracecharliteral[{]%
+ \gdef\rbracecharliteral[}]%
+ ]
+ %
+ \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+ \ifx\PP\D\let\nextsp\relax
+ \else\let\nextsp\skipspaces
+ \addtokens{\filename}{\PP}%
+ \advance\filenamelength by 1
+ \fi
+ \nextsp}
+ \def\getfilename#1{%
+ \filenamelength=0
+ % If we don't expand the argument now, \skipspaces will get
+ % snagged on things like "@value{foo}".
+ \edef\temp{#1}%
+ \expandafter\skipspaces\temp|\relax
+ }
+ \ifnum\pdftexversion < 14
+ \let \startlink \pdfannotlink
+ \else
+ \let \startlink \pdfstartlink
+ \fi
+ % make a live url in pdf output.
+ \def\pdfurl#1{%
+ \begingroup
+ % it seems we really need yet another set of dummies; have not
+ % tried to figure out what each command should do in the context
+ % of @url. for now, just make @/ a no-op, that's the only one
+ % people have actually reported a problem with.
+ %
+ \normalturnoffactive
+ \def\@{@}%
+ \let\/=\empty
+ \makevalueexpandable
+ % do we want to go so far as to use \indexnofonts instead of just
+ % special-casing \var here?
+ \def\var##1{##1}%
+ %
+ \leavevmode\setcolor{\urlcolor}%
+ \startlink attr{/Border [0 0 0]}%
+ user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+ \endgroup}
+ \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}}
+
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly. There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+% can get a sort of poor man's double spacing by redefining this.
+\def\baselinefactor{1}
+%
+\newdimen\textleading
+\def\setleading#1{%
+ \dimen0 = #1\relax
+ \normalbaselineskip = \baselinefactor\dimen0
+ \normallineskip = \lineskipfactor\normalbaselineskip
+ \normalbaselines
+ \setbox\strutbox =\hbox{%
+ \vrule width0pt height\strutheightpercent\baselineskip
+ depth \strutdepthpercent \baselineskip
+ }%
+}
+
+% PDF CMaps. See also LaTeX's t1.cmap.
+%
+% do nothing with this by default.
+\expandafter\let\csname cmapOT1\endcsname\gobble
+\expandafter\let\csname cmapOT1IT\endcsname\gobble
+\expandafter\let\csname cmapOT1TT\endcsname\gobble
+
+% if we are producing pdf, and we have \pdffontattr, then define cmaps.
+% (\pdffontattr was introduced many years ago, but people still run
+% older pdftex's; it's easy to conditionalize, so we do.)
+\ifpdf \ifx\pdffontattr\thisisundefined \else
+ \begingroup
+ \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+ \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1-0)
+%%Title: (TeX-OT1-0 TeX OT1 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<23> <26> <0023>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+40 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+ }\endgroup
+ \expandafter\edef\csname cmapOT1\endcsname#1{%
+ \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+ }%
+%
+% \cmapOT1IT
+ \begingroup
+ \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+ \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1IT-0)
+%%Title: (TeX-OT1IT-0 TeX OT1IT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1IT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1IT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<25> <26> <0025>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+42 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<23> <0023>
+<24> <00A3>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+ }\endgroup
+ \expandafter\edef\csname cmapOT1IT\endcsname#1{%
+ \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+ }%
+%
+% \cmapOT1TT
+ \begingroup
+ \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+ \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1TT-0)
+%%Title: (TeX-OT1TT-0 TeX OT1TT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1TT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1TT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+5 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<21> <26> <0021>
+<28> <5F> <0028>
+<61> <7E> <0061>
+endbfrange
+32 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <2191>
+<0C> <2193>
+<0D> <0027>
+<0E> <00A1>
+<0F> <00BF>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<20> <2423>
+<27> <2019>
+<60> <2018>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+ }\endgroup
+ \expandafter\edef\csname cmapOT1TT\endcsname#1{%
+ \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+ }%
+\fi\fi
+
+
+% Set the font macro #1 to the font named \fontprefix#2.
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit).
+% Example:
+% #1 = \textrm
+% #2 = \rmshape
+% #3 = 10
+% #4 = \mainmagstep
+% #5 = OT1
+%
+\def\setfont#1#2#3#4#5{%
+ \font#1=\fontprefix#2#3 scaled #4
+ \csname cmap#5\endcsname#1%
+}
+% This is what gets called when #5 of \setfont is empty.
+\let\cmap\gobble
+%
+% (end of cmaps)
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\thisisundefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx} % where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Definitions for a main text size of 11pt. (The default in Texinfo.)
+%
+\def\definetextfontsizexi{%
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1095}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}{OT1}
+\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
+\setfont\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}
+
+\textleading = 13.2pt % line spacing for 11pt CM
+\textfonts % reset the current fonts
+\rm
+} % end of 11pt text font size definitions, \definetextfontsizexi
+
+
+% Definitions to make the main text be 10pt Computer Modern, with
+% section, chapter, etc., sizes following suit. This is for the GNU
+% Press printing of the Emacs 22 manual. Maybe other manuals in the
+% future. Used with @smallbook, which sets the leading to 12pt.
+%
+\def\definetextfontsizex{%
+% Text fonts (10pt).
+\def\textnominalsize{10pt}
+\edef\mainmagstep{1000}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1000}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstephalf}{OT1}
+\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
+\setfont\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}
+
+\divide\parskip by 2 % reduce space between paragraphs
+\textleading = 12pt % line spacing for 10pt CM
+\textfonts % reset the current fonts
+\rm
+} % end of 10pt text font size definitions, \definetextfontsizex
+
+
+% We provide the user-level command
+% @fonttextsize 10
+% (or 11) to redefine the text font size. pt is assumed.
+%
+\def\xiword{11}
+\def\xword{10}
+\def\xwordpt{10pt}
+%
+\parseargdef\fonttextsize{%
+ \def\textsizearg{#1}%
+ %\wlog{doing @fonttextsize \textsizearg}%
+ %
+ % Set \globaldefs so that documents can use this inside @tex, since
+ % makeinfo 4.8 does not support it, but we need it nonetheless.
+ %
+ \begingroup \globaldefs=1
+ \ifx\textsizearg\xword \definetextfontsizex
+ \else \ifx\textsizearg\xiword \definetextfontsizexi
+ \else
+ \errhelp=\EMsimple
+ \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'}
+ \fi\fi
+ \endgroup
+}
+
+
+% 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{27pt}}
+\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}
+}
+
+\let\markupsetuplqcode \markupsetcodequoteleft
+\let\markupsetuprqcode \markupsetcodequoteright
+%
+\let\markupsetuplqexample \markupsetcodequoteleft
+\let\markupsetuprqexample \markupsetcodequoteright
+%
+\let\markupsetuplqkbd \markupsetcodequoteleft
+\let\markupsetuprqkbd \markupsetcodequoteright
+%
+\let\markupsetuplqsamp \markupsetcodequoteleft
+\let\markupsetuprqsamp \markupsetcodequoteright
+%
+\let\markupsetuplqverb \markupsetcodequoteleft
+\let\markupsetuprqverb \markupsetcodequoteright
+%
+\let\markupsetuplqverbatim \markupsetcodequoteleft
+\let\markupsetuprqverbatim \markupsetcodequoteright
+
+% Allow an option to not use regular directed right quote/apostrophe
+% (char 0x27), but instead the undirected quote from cmtt (char 0x0d).
+% The undirected quote is ugly, so don't make it the default, but it
+% works for pasting with more pdf viewers (at least evince), the
+% lilypond developers report. xpdf does work with the regular 0x27.
+%
+\def\codequoteright{%
+ \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
+}
+
+% Commands to set the quote options.
+%
+\parseargdef\codequoteundirected{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETtxicodequoteundirected\endcsname
+ = t%
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETtxicodequoteundirected\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}%
+ \fi\fi
+}
+%
+\parseargdef\codequotebacktick{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETtxicodequotebacktick\endcsname
+ = t%
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETtxicodequotebacktick\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}%
+ \fi\fi
+}
+
+% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font.
+\def\noligaturesquoteleft{\relax\lq}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Font commands.
+
+% #1 is the font command (\sl or \it), #2 is the text to slant.
+% If we are in a monospaced environment, however, 1) always use \ttsl,
+% and 2) do not add an italic correction.
+\def\dosmartslant#1#2{%
+ \ifusingtt
+ {{\ttsl #2}\let\next=\relax}%
+ {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+ \next
+}
+\def\smartslanted{\dosmartslant\sl}
+\def\smartitalic{\dosmartslant\it}
+
+% Output an italic correction unless \next (presumed to be the following
+% character) is such as not to need one.
+\def\smartitaliccorrection{%
+ \ifx\next,%
+ \else\ifx\next-%
+ \else\ifx\next.%
+ \else\ptexslash
+ \fi\fi\fi
+ \aftersmartic
+}
+
+% Unconditional use \ttsl, and no ic. @var is set to this for defuns.
+\def\ttslanted#1{{\ttsl #1}}
+
+% @cite is like \smartslanted except unconditionally use \sl. We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+
+\def\aftersmartic{}
+\def\var#1{%
+ \let\saveaftersmartic = \aftersmartic
+ \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
+ \smartslanted{#1}%
+}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}} % roman font
+\def\sc#1{{\smallcaps#1}} % smallcaps font
+\def\ii#1{{\it #1}} % italic font
+
+% @b, explicit bold. Also @strong.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph. Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+ \def\plainfrenchspacing{%
+ \sfcode\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}}
+
+% @indicateurl is \samp, that is, with quotes.
+\let\indicateurl=\samp
+
+% @code (and similar) prints in typewriter, but with spaces the same
+% size as normal in the surrounding text, without hyphenation, etc.
+% This is a subroutine for that.
+\def\tclose#1{%
+ {%
+ % Change normal interword space to be same as for the current font.
+ \spaceskip = \fontdimen2\font
+ %
+ % Switch to typewriter.
+ \tt
+ %
+ % But `\ ' produces the large typewriter interword space.
+ \def\ {{\spaceskip = 0pt{} }}%
+ %
+ % Turn off hyphenation.
+ \nohyphenation
+ %
+ \rawbackslash
+ \plainfrenchspacing
+ #1%
+ }%
+ \null % reset spacefactor to 1000
+}
+
+% 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\codex #1{\tclose{#1}\endgroup}
+
+\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{}{}{}}%
+ {\_}%
+}
+
+% 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', must be true|false}%
+ \fi\fi
+}
+
+% For @command, @env, @file, @option quotes seem unnecessary,
+% so use \code rather than \samp.
+\let\command=\code
+\let\env=\code
+\let\file=\code
+\let\option=\code
+
+% @uref (abbreviation for `urlref') 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.
+% (This \urefnobreak definition isn't used now, leaving it for a while
+% for comparison.)
+\def\urefnobreak#1{\dourefnobreak #1,,,\finish}
+\def\dourefnobreak#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}
+
+% This \urefbreak definition is the active one.
+\def\urefbreak{\begingroup \urefcatcodes \dourefbreak}
+\let\uref=\urefbreak
+\def\dourefbreak#1{\urefbreakfinish #1,,,\finish}
+\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example
+ \unsepspaces
+ \pdfurl{#1}%
+ \setbox0 = \hbox{\ignorespaces #3}%
+ \ifdim\wd0 > 0pt
+ \unhbox0 % third arg given, show only that
+ \else
+ \setbox0 = \hbox{\ignorespaces #2}%
+ \ifdim\wd0 > 0pt
+ \ifpdf
+ \unhbox0 % PDF: 2nd arg given, show only it
+ \else
+ \unhbox0\ (\urefcode{#1})% DVI: 2nd arg given, show both it and url
+ \fi
+ \else
+ \urefcode{#1}% only url given, so show it
+ \fi
+ \fi
+ \endlink
+\endgroup}
+
+% Allow line breaks around only a few characters (only).
+\def\urefcatcodes{%
+ \catcode\ampChar=\active \catcode\dotChar=\active
+ \catcode\hashChar=\active \catcode\questChar=\active
+ \catcode\slashChar=\active
+}
+{
+ \urefcatcodes
+ %
+ \global\def\urefcode{\begingroup
+ \setupmarkupstyle{code}%
+ \urefcatcodes
+ \let&\urefcodeamp
+ \let.\urefcodedot
+ \let#\urefcodehash
+ \let?\urefcodequest
+ \let/\urefcodeslash
+ \codex
+ }
+ %
+ % By default, they are just regular characters.
+ \global\def&{\normalamp}
+ \global\def.{\normaldot}
+ \global\def#{\normalhash}
+ \global\def?{\normalquest}
+ \global\def/{\normalslash}
+}
+
+% we put a little stretch before and after the breakable chars, to help
+% line breaking of long url's. The unequal skips make look better in
+% cmtt at least, especially for dots.
+\def\urefprestretch{\urefprebreak \hskip0pt plus.13em }
+\def\urefpoststretch{\urefpostbreak \hskip0pt plus.1em }
+%
+\def\urefcodeamp{\urefprestretch \&\urefpoststretch}
+\def\urefcodedot{\urefprestretch .\urefpoststretch}
+\def\urefcodehash{\urefprestretch \#\urefpoststretch}
+\def\urefcodequest{\urefprestretch ?\urefpoststretch}
+\def\urefcodeslash{\futurelet\next\urefcodeslashfinish}
+{
+ \catcode`\/=\active
+ \global\def\urefcodeslashfinish{%
+ \urefprestretch \slashChar
+ % Allow line break only after the final / in a sequence of
+ % slashes, to avoid line break between the slashes in http://.
+ \ifx\next/\else \urefpoststretch \fi
+ }
+}
+
+% One more complication: by default we'll break after the special
+% characters, but some people like to break before the special chars, so
+% allow that. Also allow no breaking at all, for manual control.
+%
+\parseargdef\urefbreakstyle{%
+ \def\txiarg{#1}%
+ \ifx\txiarg\wordnone
+ \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak}
+ \else\ifx\txiarg\wordbefore
+ \def\urefprebreak{\allowbreak}\def\urefpostbreak{\nobreak}
+ \else\ifx\txiarg\wordafter
+ \def\urefprebreak{\nobreak}\def\urefpostbreak{\allowbreak}
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @urefbreakstyle setting `\txiarg'}%
+ \fi\fi\fi
+}
+\def\wordafter{after}
+\def\wordbefore{before}
+\def\wordnone{none}
+
+\urefbreakstyle after
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\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
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+% `example' (@kbd uses ttsl only inside of @example and friends),
+% or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+ \def\txiarg{#1}%
+ \ifx\txiarg\worddistinct
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+ \else\ifx\txiarg\wordexample
+ \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+ \else\ifx\txiarg\wordcode
+ \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @kbdinputstyle setting `\txiarg'}%
+ \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}}
+
+\def\xkey{\key}
+\def\kbdsub#1#2#3\par{%
+ \def\one{#1}\def\three{#3}\def\threex{??}%
+ \ifx\one\xkey\ifx\threex\three \key{#2}%
+ \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+ \else{\tclose{\kbdfont\setupmarkupstyle{kbd}\look}}\fi
+}
+
+% definition of @key that produces a lozenge. Doesn't adjust to text size.
+%\setfont\keyrm\rmshape{8}{1000}{OT1}
+%\font\keysy=cmsy9
+%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+% \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+% \vbox{\hrule\kern-0.4pt
+% \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+% \kern-0.4pt\hrule}%
+% \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+
+% definition of @key with no lozenge. If the current font is already
+% monospace, don't change it; that way, we respect @kbdinputstyle. But
+% if it isn't monospace, then use \tt.
+%
+\def\key#1{{\setupmarkupstyle{key}%
+ \nohyphenation
+ \ifmonospace\else\tt\fi
+ #1}\null}
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% Typeset a dimension, e.g., `in' or `pt'. The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+% @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
+ \null % reset \spacefactor=1000
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+ {\plainfrenchspacing #1}%
+ \def\temp{#2}%
+ \ifx\temp\empty \else
+ \space ({\unsepspaces \ignorespaces \temp \unskip})%
+ \fi
+ \null % reset \spacefactor=1000
+}
+
+% @asis just yields its argument. Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}. So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+ \catcode`\_ = \active
+ \gdef\mathunderscore{%
+ \catcode`\_=\active
+ \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+ }
+}
+% Another complication: we want \\ (and @\) to output a math (or tt) \.
+% FYI, plain.tex uses \\ as a temporary control sequence (for no
+% particular reason), but this is not advertised and we don't care.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+ \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
+ }
+}
+
+% ctrl is no longer a Texinfo command, but leave this definition for fun.
+\def\ctrl #1{{\tt \rawbackslash \hat}#1}
+
+% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
+% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
+% except specified as a normal braced arg, so no newlines to worry about.
+%
+\def\outfmtnametex{tex}
+%
+\long\def\inlinefmt#1{\doinlinefmt #1,\finish}
+\long\def\doinlinefmt#1,#2,\finish{%
+ \def\inlinefmtname{#1}%
+ \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi
+}
+% For raw, must switch into @tex before parsing the argument, to avoid
+% setting catcodes prematurely. Doing it this way means that, for
+% example, @inlineraw{html, foo{bar} gets a parse error instead of being
+% ignored. But this isn't important because if people want a literal
+% *right* brace they would have to use a command anyway, so they may as
+% well use a command to get a left brace too. We could re-use the
+% delimiter character idea from \verb, but it seems like overkill.
+%
+\long\def\inlineraw{\tex \doinlineraw}
+\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish}
+\def\doinlinerawtwo#1,#2,\finish{%
+ \def\inlinerawname{#1}%
+ \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi
+ \endgroup % close group opened by \tex.
+}
+
+
+\message{glyphs,}
+% and logos.
+
+% @@ prints an @, as does @atchar{}.
+\def\@{\char64 }
+\let\atchar=\@
+
+% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
+% Unless we're in typewriter, use \ecfont because the CM text fonts do
+% not have braces, and we don't want to switch into math.
+\def\mylbrace{{\ifmonospace\else\ecfont\fi \char123}}
+\def\myrbrace{{\ifmonospace\else\ecfont\fi \char125}}
+\let\{=\mylbrace \let\lbracechar=\{
+\let\}=\myrbrace \let\rbracechar=\}
+\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\, = \ptexc
+\let\dotaccent = \ptexdot
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \ptext
+\let\ubaraccent = \ptexb
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\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{%
+ \ifx\textnominalsize\xwordpt
+ % for 10pt running text, \lllsize (8pt) is too small for the A in LaTeX.
+ % Revert to plain's \scriptsize, which is 7pt.
+ \count255=\the\fam $\fam\count255 \scriptstyle A$%
+ \else
+ % For 11pt, we can use our lllsize.
+ \selectfonts\lllsize A%
+ \fi
+ }%
+ \vss
+ }}%
+ \kern-.15em
+ \TeX
+}
+
+% 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
+}
+
+% @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 \putworderror\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+ \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+ \advance\hsize by -2\dimen2 % Rules.
+ \vbox{%
+ \hrule height\dimen2
+ \hbox{\vrule width\dimen2 \kern3pt % Space to left of text.
+ \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+ \kern3pt\vrule width\dimen2}% Space to right.
+ \hrule height\dimen2}
+ \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{{\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}%
+ \ifmonospace
+ % typewriter:
+ \font\thisecfont = ectt\ecsize \space at \nominalsize
+ \else
+ \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
+ \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\thisisundefined
+\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
+}
+
+% Settings used for typesetting titles: no hyphenation, no indentation,
+% don't worry much about spacing, ragged right. This should be used
+% inside a \vbox, and fonts need to be set appropriately first. Because
+% it is always used for titles, nothing else, we call \rmisbold. \par
+% should be specified before the end of the \vbox, since a vbox is a group.
+%
+\def\raggedtitlesettings{%
+ \rmisbold
+ \hyphenpenalty=10000
+ \parindent=0pt
+ \tolerance=5000
+ \ptexraggedright
+}
+
+% Macros to be used within @titlepage:
+
+\let\subtitlerm=\tenrm
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+ \checkenv\titlepage
+ \vbox{\titlefonts \raggedtitlesettings #1\par}%
+ % print a rule at the page bottom also.
+ \finishedtitlepagefalse
+ \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+ \checkenv\titlepage
+ {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+ \def\temp{\quotation}%
+ \ifx\thisenv\temp
+ \def\quotationauthor{#1}% printed in \Equotation.
+ \else
+ \checkenv\titlepage
+ \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+ {\secfonts\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{% non-global headings elimination
+ \evenheadline={\hfil}\evenfootline={\hfil}%
+ \oddheadline={\hfil}\oddfootline={\hfil}%
+}
+
+\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting
+\HEADINGSoff % it's the default
+
+% 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\thisisundefined
+\def\today{%
+ \number\day\space
+ \ifcase\month
+ \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+ \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+ \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+ \fi
+ \space\number\year}
+\fi
+
+% @settitle line... specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+ \advance\hsize by -\rightskip
+ \advance\hsize by -\tableindent
+ \setbox0=\hbox{\itemindicate{#1}}%
+ \itemindex{#1}%
+ \nobreak % This prevents a break before @itemx.
+ %
+ % If the item text does not fit in the space we have, put it on a line
+ % by itself, and do not allow a page break either before or after that
+ % line. We do not start a paragraph here because then if the next
+ % command is, e.g., @kindex, the whatsit would get put into the
+ % horizontal list on a line by itself, resulting in extra blank space.
+ \ifdim \wd0>\itemmax
+ %
+ % Make this a paragraph so we get the \parskip glue and wrapping,
+ % but leave it ragged-right.
+ \begingroup
+ \advance\leftskip by-\tableindent
+ \advance\hsize by\tableindent
+ \advance\rightskip by0pt plus1fil\relax
+ \leavevmode\unhbox0\par
+ \endgroup
+ %
+ % We're going to be starting a paragraph, but we don't want the
+ % \parskip glue -- logically it's part of the @item we just started.
+ \nobreak \vskip-\parskip
+ %
+ % Stop a page break at the \parskip glue coming up. However, if
+ % what follows is an environment such as @example, there will be no
+ % \parskip glue; then the negative vskip we just inserted would
+ % cause the example and the item to crash together. So we use this
+ % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+ % \parskip glue after all. Section titles are handled this way also.
+ %
+ \penalty 10001
+ \endgroup
+ \itemxneedsnegativevskipfalse
+ \else
+ % The item text fits into the space. Start a paragraph, so that the
+ % following text (if any) will end up on the same line.
+ \noindent
+ % Do this with kerns and \unhbox so that if there is a footnote in
+ % the item text, it can migrate to the main vertical list and
+ % eventually be printed.
+ \nobreak\kern-\tableindent
+ \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+ \unhbox0
+ \nobreak\kern\dimen0
+ \endgroup
+ \itemxneedsnegativevskiptrue
+ \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+ \let\itemindex\gobble
+ \tablecheck{table}%
+}
+\envdef\ftable{%
+ \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+ \tablecheck{ftable}%
+}
+\envdef\vtable{%
+ \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+ \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+ \ifnum \the\catcode`\^^M=\active
+ \endgroup
+ \errmessage{This command won't work in this context; perhaps the problem is
+ that we are \inenvironment\thisenv}%
+ \def\next{\doignore{#1}}%
+ \else
+ \let\next\tablex
+ \fi
+ \next
+}
+\def\tablex#1{%
+ \def\itemindicate{#1}%
+ \parsearg\tabley
+}
+\def\tabley#1{%
+ {%
+ \makevalueexpandable
+ \edef\temp{\noexpand\tablez #1\space\space\space}%
+ \expandafter
+ }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+ \aboveenvbreak
+ \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+ \ifnum 0#2>0 \tableindent=#2\mil \fi
+ \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+ \itemmax=\tableindent
+ \advance \itemmax by -\itemmargin
+ \advance \leftskip by \tableindent
+ \exdentamount=\tableindent
+ \parindent = 0pt
+ \parskip = \smallskipamount
+ \ifdim \parskip=0pt \parskip=2pt \fi
+ \let\item = \internalBitem
+ \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+ \aboveenvbreak
+ \itemmax=\itemindent
+ \advance\itemmax by -\itemmargin
+ \advance\leftskip by \itemindent
+ \exdentamount=\itemindent
+ \parindent=0pt
+ \parskip=\smallskipamount
+ \ifdim\parskip=0pt \parskip=2pt \fi
+ %
+ % Try typesetting the item mark 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 executes the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written
+% without the @) is in fact defined. We can only feasibly check at the
+% TeX level, so something like `mathcode' is going to considered
+% defined even though it is not a Texinfo command.
+%
+\makecond{ifcommanddefined}
+\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}}
+%
+\def\doifcmddefined#1#2{{%
+ \makevalueexpandable
+ \let\next=\empty
+ \expandafter\ifx\csname #2\endcsname\relax
+ #1% If not defined, \let\next as above.
+ \fi
+ \expandafter
+ }\next
+}
+\def\ifcmddefinedfail{\doignore{ifcommanddefined}}
+
+% @ifcommandnotdefined CMD ... handled similar to @ifclear above.
+\makecond{ifcommandnotdefined}
+\def\ifcommandnotdefined{%
+ \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}}
+\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}}
+
+% Set the `txicommandconditionals' variable, so documents have a way to
+% test if the @ifcommand...defined conditionals are available.
+\set txicommandconditionals
+
+% @dircategory CATEGORY -- specify a category of the dir file
+% which this file should belong to. Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named 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 unexpandable (because we define \tt as a dummy)
+ % definitions when @{ or @} appear in index entry text. Also, more
+ % complicated, when \tex is in effect and \{ is a \delimiter again.
+ % We can't use \lbracecmd and \rbracecmd because texindex assumes
+ % braces and backslashes are used only as delimiters. Perhaps we
+ % should define @lbrace and @rbrace commands a la @comma.
+ \def\{{{\tt\char123}}%
+ \def\}{{\tt\char125}}%
+ %
+ % 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\_%
+ \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\arrow
+ \definedummyword\bullet
+ \definedummyword\comma
+ \definedummyword\copyright
+ \definedummyword\registeredsymbol
+ \definedummyword\dots
+ \definedummyword\enddots
+ \definedummyword\entrybreak
+ \definedummyword\equiv
+ \definedummyword\error
+ \definedummyword\euro
+ \definedummyword\expansion
+ \definedummyword\geq
+ \definedummyword\guillemetleft
+ \definedummyword\guillemetright
+ \definedummyword\guilsinglleft
+ \definedummyword\guilsinglright
+ \definedummyword\lbracechar
+ \definedummyword\leq
+ \definedummyword\minus
+ \definedummyword\ogonek
+ \definedummyword\pounds
+ \definedummyword\point
+ \definedummyword\print
+ \definedummyword\quotedblbase
+ \definedummyword\quotedblleft
+ \definedummyword\quotedblright
+ \definedummyword\quoteleft
+ \definedummyword\quoteright
+ \definedummyword\quotesinglbase
+ \definedummyword\rbracechar
+ \definedummyword\result
+ \definedummyword\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\sansserif
+ \definedummyword\sc
+ \definedummyword\slanted
+ \definedummyword\t
+ %
+ % Commands that take arguments.
+ \definedummyword\abbr
+ \definedummyword\acronym
+ \definedummyword\anchor
+ \definedummyword\cite
+ \definedummyword\code
+ \definedummyword\command
+ \definedummyword\dfn
+ \definedummyword\dmn
+ \definedummyword\email
+ \definedummyword\emph
+ \definedummyword\env
+ \definedummyword\file
+ \definedummyword\image
+ \definedummyword\indicateurl
+ \definedummyword\inforef
+ \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}%
+ % All control words become @asis by default; overrides below.
+ \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\@{@}%
+ \def\_{\normalunderscore}%
+ \def\-{}% @- shouldn't affect sorting
+ %
+ % Unfortunately, texindex is not prepared to handle braces in the
+ % content at all. So for index sorting, we map @{ and @} to strings
+ % starting with |, since that ASCII character is between ASCII { and }.
+ \def\{{|a}%
+ \def\lbracechar{|a}%
+ %
+ \def\}{|b}%
+ \def\rbracechar{|b}%
+ %
+ % 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\arrow{->}%
+ \def\bullet{bullet}%
+ \def\comma{,}%
+ \def\copyright{copyright}%
+ \def\dots{...}%
+ \def\enddots{...}%
+ \def\equiv{==}%
+ \def\error{error}%
+ \def\euro{euro}%
+ \def\expansion{==>}%
+ \def\geq{>=}%
+ \def\guillemetleft{<<}%
+ \def\guillemetright{>>}%
+ \def\guilsinglleft{<}%
+ \def\guilsinglright{>}%
+ \def\leq{<=}%
+ \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}%
+ %
+ \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax
+ \else \indexlquoteignore \fi
+ %
+ % 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
+}
+
+% Undocumented (for FSFS 2nd ed.): @set txiindexlquoteignore makes us
+% ignore left quotes in the sort term.
+{\catcode`\`=\active
+ \gdef\indexlquoteignore{\let`=\empty}}
+
+\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
+ %
+ % When reading the text of entry, convert explicit line breaks
+ % from @* into spaces. The user might give these in long section
+ % titles, for instance.
+ \def\*{\unskip\space\ignorespaces}%
+ \def\entrybreak{\hfil\break}%
+ %
+ % Swallow the left brace of the text (first parameter):
+ \afterassignment\doentry
+ \let\temp =
+}
+\def\entrybreak{\unskip\space\ignorespaces}%
+\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.
+
+% Let's start with @part.
+\outer\parseargdef\part{\partzzz{#1}}
+\def\partzzz#1{%
+ \chapoddpage
+ \null
+ \vskip.3\vsize % move it down on the page a bit
+ \begingroup
+ \noindent \titlefonts\rmisbold #1\par % the text
+ \let\lastnode=\empty % no node to associate with
+ \writetocentry{part}{#1}{}% but put it in the toc
+ \headingsoff % no headline or footline on the part page
+ \chapoddpage
+ \endgroup
+}
+
+% \unnumberedno is an oxymoron. But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number". We avoid collisions with chapter
+% numbers by starting them at 10000. (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno \secno=0
+\newcount\subsecno \subsecno=0
+\newcount\subsubsecno \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+ \ifnum\appendixno=`A A%
+ \else\ifnum\appendixno=`B B%
+ \else\ifnum\appendixno=`C C%
+ \else\ifnum\appendixno=`D D%
+ \else\ifnum\appendixno=`E E%
+ \else\ifnum\appendixno=`F F%
+ \else\ifnum\appendixno=`G G%
+ \else\ifnum\appendixno=`H H%
+ \else\ifnum\appendixno=`I I%
+ \else\ifnum\appendixno=`J J%
+ \else\ifnum\appendixno=`K K%
+ \else\ifnum\appendixno=`L L%
+ \else\ifnum\appendixno=`M M%
+ \else\ifnum\appendixno=`N N%
+ \else\ifnum\appendixno=`O O%
+ \else\ifnum\appendixno=`P P%
+ \else\ifnum\appendixno=`Q Q%
+ \else\ifnum\appendixno=`R R%
+ \else\ifnum\appendixno=`S S%
+ \else\ifnum\appendixno=`T T%
+ \else\ifnum\appendixno=`U U%
+ \else\ifnum\appendixno=`V V%
+ \else\ifnum\appendixno=`W W%
+ \else\ifnum\appendixno=`X X%
+ \else\ifnum\appendixno=`Y Y%
+ \else\ifnum\appendixno=`Z Z%
+ % The \the is necessary, despite appearances, because \appendixletter is
+ % expanded while writing the .toc file. \char\appendixno is not
+ % expandable, thus it is written literally, thus all appendixes come out
+ % with the same letter (or @) in the toc without it.
+ \else\char\the\appendixno
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines these (using marks) as the number+name, number
+% and name of the chapter. Page headings and footings can use
+% these. @section does likewise.
+\def\thischapter{}
+\def\thischapternum{}
+\def\thischaptername{}
+\def\thissection{}
+\def\thissectionnum{}
+\def\thissectionname{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+\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 achieve this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unnlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+ % Compute the abs. sec. level:
+ \absseclevel=#2
+ \advance\absseclevel by \secbase
+ % Make sure \absseclevel doesn't fall outside the range:
+ \ifnum \absseclevel < 0
+ \absseclevel = 0
+ \else
+ \ifnum \absseclevel > 3
+ \absseclevel = 3
+ \fi
+ \fi
+ % The heading type:
+ \def\headtype{#1}%
+ \if \headtype U%
+ \ifnum \absseclevel < \unnlevel
+ \chardef\unnlevel = \absseclevel
+ \fi
+ \else
+ % Check for appendix sections:
+ \ifnum \absseclevel = 0
+ \edef\chapheadtype{\headtype}%
+ \else
+ \if \headtype A\if \chapheadtype N%
+ \errmessage{@appendix... within a non-appendix chapter}%
+ \fi\fi
+ \fi
+ % Check for numbered within unnumbered:
+ \ifnum \absseclevel > \unnlevel
+ \def\headtype{U}%
+ \else
+ \chardef\unnlevel = 3
+ \fi
+ \fi
+ % Now print the heading:
+ \if \headtype U%
+ \ifcase\absseclevel
+ \unnumberedzzz{#3}%
+ \or \unnumberedseczzz{#3}%
+ \or \unnumberedsubseczzz{#3}%
+ \or \unnumberedsubsubseczzz{#3}%
+ \fi
+ \else
+ \if \headtype A%
+ \ifcase\absseclevel
+ \appendixzzz{#3}%
+ \or \appendixsectionzzz{#3}%
+ \or \appendixsubseczzz{#3}%
+ \or \appendixsubsubseczzz{#3}%
+ \fi
+ \else
+ \ifcase\absseclevel
+ \chapterzzz{#3}%
+ \or \seczzz{#3}%
+ \or \numberedsubseczzz{#3}%
+ \or \numberedsubsubseczzz{#3}%
+ \fi
+ \fi
+ \fi
+ \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered. Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v. By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+ % section resetting is \global in case the chapter is in a group, such
+ % as an @include file.
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\chapno by 1
+ %
+ % Used for \float.
+ \gdef\chaplevelprefix{\the\chapno.}%
+ \resetallfloatnos
+ %
+ % \putwordChapter can contain complex things in translations.
+ \toks0=\expandafter{\putwordChapter}%
+ \message{\the\toks0 \space \the\chapno}%
+ %
+ % Write the actual heading.
+ \chapmacro{#1}{Ynumbered}{\the\chapno}%
+ %
+ % So @section and the like are numbered underneath this chapter.
+ \global\let\section = \numberedsec
+ \global\let\subsection = \numberedsubsec
+ \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz
+%
+\def\appendixzzz#1{%
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\appendixno by 1
+ \gdef\chaplevelprefix{\appendixletter.}%
+ \resetallfloatnos
+ %
+ % \putwordAppendix can contain complex things in translations.
+ \toks0=\expandafter{\putwordAppendix}%
+ \message{\the\toks0 \space \appendixletter}%
+ %
+ \chapmacro{#1}{Yappendix}{\appendixletter}%
+ %
+ \global\let\section = \appendixsec
+ \global\let\subsection = \appendixsubsec
+ \global\let\subsubsection = \appendixsubsubsec
+}
+
+% normally unnmhead0 calls unnumberedzzz:
+\outer\parseargdef\unnumbered{\unnmhead0{#1}}
+\def\unnumberedzzz#1{%
+ \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+ \global\advance\unnumberedno by 1
+ %
+ % Since an unnumbered has no number, no prefix for figures.
+ \global\let\chaplevelprefix = \empty
+ \resetallfloatnos
+ %
+ % This used to be simply \message{#1}, but TeX fully expands the
+ % argument to \message. Therefore, if #1 contained @-commands, TeX
+ % expanded them. For example, in `@unnumbered The @cite{Book}', TeX
+ % expanded @cite (which turns out to cause errors because \cite is meant
+ % to be executed, not expanded).
+ %
+ % Anyway, we don't want the fully-expanded definition of @cite to appear
+ % as a result of the \message, we just want `@cite' itself. We use
+ % \the<toks register> to achieve this: TeX expands \the<toks> only once,
+ % simply yielding the contents of <toks register>. (We also do this for
+ % the toc entries.)
+ \toks0 = {#1}%
+ \message{(\the\toks0)}%
+ %
+ \chapmacro{#1}{Ynothing}{\the\unnumberedno}%
+ %
+ \global\let\section = \unnumberedsec
+ \global\let\subsection = \unnumberedsubsec
+ \global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\parseargdef\centerchap{%
+ % 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}%
+}
+
+% normally calls appendixsectionzzz:
+\outer\parseargdef\appendixsection{\apphead1{#1}}
+\def\appendixsectionzzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+% normally calls unnumberedseczzz:
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}}
+\def\unnumberedseczzz#1{%
+ \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1
+ \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+%
+% normally calls numberedsubseczzz:
+\outer\parseargdef\numberedsubsec{\numhead2{#1}}
+\def\numberedsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+% normally calls appendixsubseczzz:
+\outer\parseargdef\appendixsubsec{\apphead2{#1}}
+\def\appendixsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Yappendix}%
+ {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+% normally calls unnumberedsubseczzz:
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}}
+\def\unnumberedsubseczzz#1{%
+ \global\subsubsecno=0 \global\advance\subsecno by 1
+ \sectionheading{#1}{subsec}{Ynothing}%
+ {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+%
+% normally numberedsubsubseczzz:
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}}
+\def\numberedsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Ynumbered}%
+ {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally appendixsubsubseczzz:
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}}
+\def\appendixsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Yappendix}%
+ {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally unnumberedsubsubseczzz:
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}}
+\def\unnumberedsubsubseczzz#1{%
+ \global\advance\subsubsecno by 1
+ \sectionheading{#1}{subsubsec}{Ynothing}%
+ {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading{%
+ {\advance\chapheadingskip by 10pt \chapbreak }%
+ \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+ \vbox{\chapfonts \raggedtitlesettings #1\par}%
+ \nobreak\bigskip \nobreak
+ \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+ \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+% Parameter controlling skip before chapter headings (if needed)
+\newskip\chapheadingskip
+
+% Define plain chapter starts, and page on/off switching for it.
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+\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
+ \headingsoff
+ \null
+ \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{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe
+ \unhbox0 #1\par}%
+ }%
+ \nobreak\bigskip % no page break after a chapter title
+ \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+ \advance\rightskip by 3\rightskip
+ \leftskip = \rightskip
+ \parfillskip = 0pt
+}
+
+
+% 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
+ \vbox{\chapfonts \raggedtitlesettings #1\par}%
+ \nobreak\bigskip\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
+ \vbox{\chapfonts \raggedtitlesettings \hfill #1\hfill}%
+ \nobreak\bigskip \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{%
+ {%
+ \checkenv{}% should not be in an environment.
+ %
+ % 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.) However, when a paragraph is not started next
+ % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out
+ % or the negative glue will cause weirdly wrong output, typically
+ % obscuring the section heading with something else.
+ \vskip-\parskip
+ %
+ % This is so the last item on the main vertical list is a known
+ % \penalty > 10000, so \startdefun, etc., can recognize the situation
+ % and do the needful.
+ \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this. The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything. This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+ \edef\writetoctype{#1}%
+ \ifx\writetoctype\omitkeyword \else
+ \iftocfileopened\else
+ \immediate\openout\tocfile = \jobname.toc
+ \global\tocfileopenedtrue
+ \fi
+ %
+ \iflinks
+ {\atdummies
+ \edef\temp{%
+ \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}%
+ \temp
+ }%
+ \fi
+ \fi
+ %
+ % Tell \shipout to create a pdf destination on each page, if we're
+ % writing pdf. These are used in the table of contents. We can't
+ % just write one on every page because the title pages are numbered
+ % 1 and 2 (the page numbers aren't printed), and so are the first
+ % two pages of the document. Thus, we'd have two destinations named
+ % `1', and two named `2'.
+ \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\partentry = \shortpartentry
+ \let\numchapentry = \shortchapentry
+ \let\appentry = \shortchapentry
+ \let\unnchapentry = \shortunnchapentry
+ % We want a true roman here for the page numbers.
+ \secfonts
+ \let\rm=\shortcontrm \let\bf=\shortcontbf
+ \let\sl=\shortcontsl \let\tt=\shortconttt
+ \rm
+ \hyphenpenalty = 10000
+ \advance\baselineskip by 1pt % Open it up a little.
+ \def\numsecentry##1##2##3##4{}
+ \let\appsecentry = \numsecentry
+ \let\unnsecentry = \numsecentry
+ \let\numsubsecentry = \numsecentry
+ \let\appsubsecentry = \numsecentry
+ \let\unnsubsecentry = \numsecentry
+ \let\numsubsubsecentry = \numsecentry
+ \let\appsubsubsecentry = \numsecentry
+ \let\unnsubsubsecentry = \numsecentry
+ \openin 1 \tocreadfilename\space
+ \ifeof 1 \else
+ \readtocfile
+ \fi
+ \closein 1
+ \vfill \eject
+ \contentsalignmacro % in case @setchapternewpage odd is in effect
+ \endgroup
+ \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, ...
+
+% Parts, in the main contents. Replace the part number, which doesn't
+% exist, with an empty box. Let's hope all the numbers have the same width.
+% Also ignore the page number, which is conventionally not printed.
+\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}}
+\def\partentry#1#2#3#4{\dochapentry{\numeralbox\labelspace#1}{}}
+%
+% Parts, in the short toc.
+\def\shortpartentry#1#2#3#4{%
+ \penalty-300
+ \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip
+ \shortchapentry{{\bf #1}}{\numeralbox}{}{}%
+}
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+%
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+ \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+ % We use M since it's probably the widest letter.
+ \setbox0 = \hbox{\putwordAppendix{} M}%
+ \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\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 @ 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=`\\
+ %
+ % ' is active in math mode (mathcode"8000). So reset it, and all our
+ % other math active characters (just in case), to plain's definitions.
+ \mathactive
+ %
+ \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%
+ %
+ % If this cartouche directly follows a sectioning command, we need the
+ % \parskip glue (backspaced over by default) or the cartouche can
+ % collide with the section heading.
+ \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi
+ %
+ \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 in one command. #1 is the env name, #2 the definition.
+\def\makedispenvdef#1#2{%
+ \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}%
+ \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}%
+ \expandafter\let\csname E#1\endcsname \afterenvbreak
+ \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two environment synonyms (#1 and #2) for an environment.
+\def\maketwodispenvdef#1#2#3{%
+ \makedispenvdef{#1}{#3}%
+ \makedispenvdef{#2}{#3}%
+}
+%
+% @lisp: indented, narrowed, typewriter font;
+% @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvdef{lisp}{example}{%
+ \nonfillstart
+ \tt\setupmarkupstyle{example}%
+ \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+ \gobble % eat return
+}
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenvdef{display}{%
+ \nonfillstart
+ \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenvdef{format}{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \advance\leftskip by 0pt plus 1fill\relax
+ \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification. From plain.tex.
+\envdef\raggedright{%
+ \rightskip0pt 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.
+%
+\makedispenvdef{quotation}{\quotationstart}
+%
+\def\quotationstart{%
+ \indentedblockstart % same as \indentedblock, but increase right margin too.
+ \ifx\nonarrowing\relax
+ \advance\rightskip by \lispnarrowing
+ \fi
+ \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+ \par
+ \ifx\quotationauthor\thisisundefined\else
+ % indent a bit.
+ \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+ \fi
+ {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallquotation{\Equotation}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+ \def\temp{#1}%
+ \ifx\temp\empty \else
+ {\bf #1: }%
+ \fi
+}
+
+% @indentedblock is like @quotation, but indents only on the left and
+% has no optional argument.
+%
+\makedispenvdef{indentedblock}{\indentedblockstart}
+%
+\def\indentedblockstart{%
+ {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+ \parindent=0pt
+ %
+ % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+ \ifx\nonarrowing\relax
+ \advance\leftskip by \lispnarrowing
+ \exdentamount = \lispnarrowing
+ \else
+ \let\nonarrowing = \relax
+ \fi
+}
+
+% Keep a nonzero parskip for the environment, since we're doing normal filling.
+%
+\def\Eindentedblock{%
+ \par
+ {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallindentedblock{\Eindentedblock}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> as delimiter,
+% we need the curly braces so that makeinfo sees the @verb command, eg:
+% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org
+%
+% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook.
+%
+% [Knuth] p.344; only we need to do the other characters Texinfo sets
+% active too. Otherwise, they get lost as the first character on a
+% verbatim line.
+\def\dospecials{%
+ \do\ \do\\\do\{\do\}\do\$\do\&%
+ \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~%
+ \do\<\do\>\do\|\do\@\do+\do\"%
+ % Don't do the quotes -- if we do, @set txicodequoteundirected and
+ % @set txicodequotebacktick will not have effect on @verb and
+ % @verbatim, and ?` and !` ligatures won't get disabled.
+ %\do\`\do\'%
+}
+%
+% [Knuth] p. 380
+\def\uncatcodespecials{%
+ \def\do##1{\catcode`##1=\other}\dospecials}
+%
+% Setup for the @verb command.
+%
+% Eight spaces for a tab
+\begingroup
+ \catcode`\^^I=\active
+ \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }}
+\endgroup
+%
+\def\setupverb{%
+ \tt % easiest (and conventionally used) font for verbatim
+ \def\par{\leavevmode\endgraf}%
+ \setupmarkupstyle{verb}%
+ \tabeightspaces
+ % Respect line breaks,
+ % print special symbols as themselves, and
+ % make each space count
+ % must do in this order:
+ \obeylines \uncatcodespecials \sepspaces
+}
+
+% Setup for the @verbatim environment
+%
+% Real tab expansion.
+\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount
+%
+% We typeset each line of the verbatim in an \hbox, so we can handle
+% tabs. The \global is in case the verbatim line starts with an accent,
+% or some other command that starts with a begin-group. Otherwise, the
+% entire \verbbox would disappear at the corresponding end-group, before
+% it is typeset. Meanwhile, we can't have nested verbatim commands
+% (can we?), so the \global won't be overwriting itself.
+\newbox\verbbox
+\def\starttabbox{\global\setbox\verbbox=\hbox\bgroup}
+%
+\begingroup
+ \catcode`\^^I=\active
+ \gdef\tabexpand{%
+ \catcode`\^^I=\active
+ \def^^I{\leavevmode\egroup
+ \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab
+ \divide\dimen\verbbox by\tabw
+ \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw
+ \advance\dimen\verbbox by\tabw % advance to next multiple of \tabw
+ \wd\verbbox=\dimen\verbbox \box\verbbox \starttabbox
+ }%
+ }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+ \let\nonarrowing = t%
+ \nonfillstart
+ \tt % easiest (and conventionally used) font for verbatim
+ % The \leavevmode here is for blank lines. Otherwise, we would
+ % never \starttabox and the \egroup would end verbatim mode.
+ \def\par{\leavevmode\egroup\box\verbbox\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.
+ \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}%
+ \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 further refinement, we avoid "club" headers by signalling
+ % with penalty of 10003 after the very first @deffn in the
+ % sequence (see above), and penalty of 10002 after any following
+ % @def command.
+ \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi
+ %
+ % Similarly, after a section heading, do not allow a break.
+ % But do insert the glue.
+ \medskip % preceded by discardable penalty, so not a breakpoint
+ \fi
+ %
+ \parindent=0in
+ \advance\leftskip by \defbodyindent
+ \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+ % First, check whether we are in the right environment:
+ \checkenv#1%
+ %
+ % As above, allow line break if we have multiple x headers in a row.
+ % It's not a great place, though.
+ \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi
+ %
+ % And now, it's time to reuse the body of the original defun:
+ \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+ \begingroup
+ % call \deffnheader:
+ #1#2 \endheader
+ % common ending:
+ \interlinepenalty = 10000
+ \advance\rightskip by 0pt plus 1fil\relax
+ \endgraf
+ \nobreak\vskip -\parskip
+ \penalty\defunpenalty % signal to \startdefun and \dodefunx
+ % Some of the @defun-type tags do not enable magic parentheses,
+ % rendering the following check redundant. But we don't optimize.
+ \checkparencounts
+ \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remaining is to define \deffnheader.
+%
+\def\makedefun#1{%
+ \expandafter\let\csname E#1\endcsname = \Edefun
+ \edef\temp{\noexpand\domakedefun
+ \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+ \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+ \envdef#1{%
+ \startdefun
+ \doingtypefnfalse % distinguish typed functions from all else
+ \parseargusing\activeparens{\printdefunline#3}%
+ }%
+ \def#2{\dodefunx#1}%
+ \def#3%
+}
+
+\newif\ifdoingtypefn % doing typed function?
+\newif\ifrettypeownline % typeset return type on its own line?
+
+% @deftypefnnewline on|off says whether the return type of typed functions
+% are printed on their own line. This affects @deftypefn, @deftypefun,
+% @deftypeop, and @deftypemethod.
+%
+\parseargdef\deftypefnnewline{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETtxideftypefnnl\endcsname
+ = \empty
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETtxideftypefnnl\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @txideftypefnnl value `\temp',
+ must be on|off}%
+ \fi\fi
+}
+
+% 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}%
+ \doingtypefntrue
+ \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+ \dosubind{vr}{\code{#4}}{#1}%
+ \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+% Types:
+
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+ \doind{tp}{\code{#2}}%
+ \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+ \par
+ % Get the values of \leftskip and \rightskip as they were outside the @def...
+ \advance\leftskip by -\defbodyindent
+ %
+ % Determine if we are typesetting the return type of a typed function
+ % on a line by itself.
+ \rettypeownlinefalse
+ \ifdoingtypefn % doing a typed function specifically?
+ % then check user option for putting return type on its own line:
+ \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
+ \rettypeownlinetrue
+ \fi
+ \fi
+ %
+ % How we'll format the category name. Putting it in brackets helps
+ % distinguish it from the body text that may end up on the next line
+ % just below it.
+ \def\temp{#1}%
+ \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+ %
+ % Figure out line sizes for the paragraph shape. We'll always have at
+ % least two.
+ \tempnum = 2
+ %
+ % The first line needs space for \box0; but if \rightskip is nonzero,
+ % we need only space for the part of \box0 which exceeds it:
+ \dimen0=\hsize \advance\dimen0 by -\wd0 \advance\dimen0 by \rightskip
+ %
+ % If doing a return type on its own line, we'll have another line.
+ \ifrettypeownline
+ \advance\tempnum by 1
+ \def\maybeshapeline{0in \hsize}%
+ \else
+ \def\maybeshapeline{}%
+ \fi
+ %
+ % The continuations:
+ \dimen2=\hsize \advance\dimen2 by -\defargsindent
+ %
+ % The final paragraph shape:
+ \parshape \tempnum 0in \dimen0 \maybeshapeline \defargsindent \dimen2
+ %
+ % Put the category name at the right margin.
+ \noindent
+ \hbox to 0pt{%
+ \hfil\box0 \kern-\hsize
+ % \hsize has to be shortened this way:
+ \kern\leftskip
+ % Intentionally do not respect \rightskip, since we need the space.
+ }%
+ %
+ % Allow all lines to be underfull without complaint:
+ \tolerance=10000 \hbadness=10000
+ \exdentamount=\defbodyindent
+ {%
+ % defun fonts. We use typewriter by default (used to be bold) because:
+ % . we're printing identifiers, they should be in tt in principle.
+ % . in languages with many accents, such as Czech or French, it's
+ % common to leave accents off identifiers. The result looks ok in
+ % tt, but exceedingly strange in rm.
+ % . we don't want -- and --- to be treated as ligatures.
+ % . this still does not fix the ?` and !` ligatures, but so far no
+ % one has made identifiers using them :).
+ \df \tt
+ \def\temp{#2}% text of the return type
+ \ifx\temp\empty\else
+ \tclose{\temp}% typeset the return type
+ \ifrettypeownline
+ % put return type on its own line; prohibit line break following:
+ \hfil\vadjust{\nobreak}\break
+ \else
+ \space % type on same line, so just followed by a space
+ \fi
+ \fi % no return type
+ #3% output function name
+ }%
+ {\rm\enskip}% hskip 0.5 em of \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. We used to recommend @var for that, so
+ % leave the code in, but it's strange for @var to lead to typewriter.
+ % Nowadays we recommend @code, since the difference between a ttsl hyphen
+ % and a tt hyphen is pretty tiny. @code also disables ?` !`.
+ \def\var##1{{\setupmarkupstyle{var}\ttslanted{##1}}}%
+ #1%
+ \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+ \catcode`\(=\active \catcode`\)=\active
+ \catcode`\[=\active \catcode`\]=\active
+ \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc. For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+ \activeparens
+ \global\let(=\lparen \global\let)=\rparen
+ \global\let[=\lbrack \global\let]=\rbrack
+ \global\let& = \&
+
+ \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+ \gdef\magicamp{\let&=\amprm}
+}
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\def\parenfont{%
+ \ifampseen
+ % At the first level, print parens in roman,
+ % otherwise use the default font.
+ \ifnum \parencount=1 \rm \fi
+ \else
+ % The \sf parens (in \boldbrax) actually are a little bolder than
+ % the contained text. This is especially needed for [ and ] .
+ \sf
+ \fi
+}
+\def\infirstlevel#1{%
+ \ifampseen
+ \ifnum\parencount=1
+ #1%
+ \fi
+ \fi
+}
+\def\bfafterword#1 {#1 \bf}
+
+\def\opnr{%
+ \global\advance\parencount by 1
+ {\parenfont(}%
+ \infirstlevel \bfafterword
+}
+\def\clnr{%
+ {\parenfont)}%
+ \infirstlevel \sl
+ \global\advance\parencount by -1
+}
+
+\newcount\brackcount
+\def\lbrb{%
+ \global\advance\brackcount by 1
+ {\bf[}%
+}
+\def\rbrb{%
+ {\bf]}%
+ \global\advance\brackcount by -1
+}
+
+\def\checkparencounts{%
+ \ifnum\parencount=0 \else \badparencount \fi
+ \ifnum\brackcount=0 \else \badbrackcount \fi
+}
+% these should not use \errmessage; the glibc manual, at least, actually
+% has such constructs (when documenting function pointers).
+\def\badparencount{%
+ \message{Warning: unbalanced parentheses in @def...}%
+ \global\parencount=0
+}
+\def\badbrackcount{%
+ \message{Warning: unbalanced square brackets in @def...}%
+ \global\brackcount=0
+}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\thisisundefined
+ \newwrite\macscribble
+ \def\scantokens#1{%
+ \toks0={#1}%
+ \immediate\openout\macscribble=\jobname.tmp
+ \immediate\write\macscribble{\the\toks0}%
+ \immediate\closeout\macscribble
+ \input \jobname.tmp
+ }
+\fi
+
+\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 for \example:
+ \spaceisspace
+ %
+ % The \empty here causes a following catcode 5 newline to be eaten as
+ % part of reading whitespace after a control sequence. It does not
+ % eat a catcode 13 newline. There's no good way to handle the two
+ % cases (untried: maybe e-TeX's \everyeof could help, though plain TeX
+ % would then have different behavior). See the Macro Details node in
+ % the manual for the workaround we recommend for macros and
+ % line-oriented commands.
+ %
+ \scantokens{#1\empty}%
+\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 \
+% to recognize macro arguments; this is the job of \mbodybackslash.
+%
+% Non-ASCII encodings make 8-bit characters active, so un-activate
+% them to avoid their expansion. Must do this non-globally, to
+% confine the change to the current group.
+%
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+%
+\def\scanctxt{% used as subroutine
+ \catcode`\"=\other
+ \catcode`\+=\other
+ \catcode`\<=\other
+ \catcode`\>=\other
+ \catcode`\@=\other
+ \catcode`\^=\other
+ \catcode`\_=\other
+ \catcode`\|=\other
+ \catcode`\~=\other
+ \ifx\declaredencoding\ascii \else \setnonasciicharscatcodenonglobal\other \fi
+}
+
+\def\scanargctxt{% used for copying and captions, not macros.
+ \scanctxt
+ \catcode`\\=\other
+ \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{% used for @macro definitions
+ \scanctxt
+ \catcode`\{=\other
+ \catcode`\}=\other
+ \catcode`\^^M=\other
+ \usembodybackslash
+}
+
+\def\macroargctxt{% used when scanning invocations
+ \scanctxt
+ \catcode`\\=0
+}
+% why catcode 0 for \ in the above? To recognize \\ \{ \} as "escapes"
+% for the single characters \ { }. Thus, we end up with the "commands"
+% that would be written @\ @{ @} in a Texinfo document.
+%
+% We already have @{ and @}. For @\, we define it here, and only for
+% this purpose, to produce a typewriter backslash (so, the @\ that we
+% define for @math can't be used with @macro calls):
+%
+\def\\{\normalbackslash}%
+%
+% We would like to do this for \, too, since that is what makeinfo does.
+% But it is not possible, because Texinfo already has a command @, for a
+% cedilla accent. Documents must use @comma{} instead.
+%
+% \anythingelse will almost certainly be an error of some kind.
+
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+%
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\margbackslash#1{\char`\#1 }
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+ \getargs{#1}% now \macname is the macname and \argl the arglist
+ \ifx\argl\empty % no arguments
+ \paramno=0\relax
+ \else
+ \expandafter\parsemargdef \argl;%
+ \if\paramno>256\relax
+ \ifx\eTeXversion\thisisundefined
+ \errhelp = \EMsimple
+ \errmessage{You need eTeX to compile a file with macros with more than 256 arguments}
+ \fi
+ \fi
+ \fi
+ \if1\csname ismacro.\the\macname\endcsname
+ \message{Warning: redefining \the\macname}%
+ \else
+ \expandafter\ifx\csname \the\macname\endcsname \relax
+ \else \errmessage{Macro name \the\macname\space already defined}\fi
+ \global\cslet{macsave.\the\macname}{\the\macname}%
+ \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+ \addtomacrolist{\the\macname}%
+ \fi
+ \begingroup \macrobodyctxt
+ \ifrecursive \expandafter\parsermacbody
+ \else \expandafter\parsemacbody
+ \fi}
+
+\parseargdef\unmacro{%
+ \if1\csname ismacro.#1\endcsname
+ \global\cslet{#1}{macsave.#1}%
+ \global\expandafter\let \csname ismacro.#1\endcsname=0%
+ % Remove the macro name from \macrolist:
+ \begingroup
+ \expandafter\let\csname#1\endcsname \relax
+ \let\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}}
+
+% For macro processing make @ a letter so that we can make Texinfo private macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
+% 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 some hook where the argument si to be expanded. If
+% there are less than 10 arguments that hook is to be replaced by ##N where N
+% is the position in that list, that is to say the macro arguments are to be
+% defined `a la TeX in the macro body.
+%
+% That gets used by \mbodybackslash (above).
+%
+% 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.
+%
+% If there are 10 or more arguments, a different technique is used, where the
+% hook remains in the body, and when macro is to be expanded the body is
+% processed again to replace the arguments.
+%
+% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the
+% argument N value and then \edef the body (nothing else will expand because of
+% the catcode regime underwhich the body was input).
+%
+% If you compile with TeX (not eTeX), and you have macros with 10 or more
+% arguments, you need that no macro has more than 256 arguments, otherwise an
+% error is produced.
+\def\parsemargdef#1;{%
+ \paramno=0\def\paramlist{}%
+ \let\hash\relax
+ \let\xeatspaces\relax
+ \parsemargdefxxx#1,;,%
+ % In case that there are 10 or more arguments we parse again the arguments
+ % list to set new definitions for the \macarg.BLAH macros corresponding to
+ % each BLAH argument. It was anyhow needed to parse already once this list
+ % in order to count the arguments, and as macros with at most 9 arguments
+ % are by far more frequent than macro with 10 or more arguments, defining
+ % twice the \macarg.BLAH macros does not cost too much processing power.
+ \ifnum\paramno<10\relax\else
+ \paramno0\relax
+ \parsemmanyargdef@@#1,;,% 10 or more arguments
+ \fi
+}
+\def\parsemargdefxxx#1,{%
+ \if#1;\let\next=\relax
+ \else \let\next=\parsemargdefxxx
+ \advance\paramno by 1
+ \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+ {\xeatspaces{\hash\the\paramno}}%
+ \edef\paramlist{\paramlist\hash\the\paramno,}%
+ \fi\next}
+
+\def\parsemmanyargdef@@#1,{%
+ \if#1;\let\next=\relax
+ \else
+ \let\next=\parsemmanyargdef@@
+ \edef\tempb{\eatspaces{#1}}%
+ \expandafter\def\expandafter\tempa
+ \expandafter{\csname macarg.\tempb\endcsname}%
+ % Note that we need some extra \noexpand\noexpand, this is because we
+ % don't want \the to be expanded in the \parsermacbody as it uses an
+ % \xdef .
+ \expandafter\edef\tempa
+ {\noexpand\noexpand\noexpand\the\toks\the\paramno}%
+ \advance\paramno by 1\relax
+ \fi\next}
+
+% These two commands read recursive and nonrecursive macro bodies.
+% (They're different since rec and nonrec macros end differently.)
+%
+
+\catcode `\@\texiatcatcode
+\long\def\parsemacbody#1@end macro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\long\def\parsermacbody#1@end rmacro%
+{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}%
+\catcode `\@=11\relax
+
+\let\endargs@\relax
+\let\nil@\relax
+\def\nilm@{\nil@}%
+\long\def\nillm@{\nil@}%
+
+% This macro is expanded during the Texinfo macro expansion, not during its
+% definition. It gets all the arguments values and assigns them to macros
+% macarg.ARGNAME
+%
+% #1 is the macro name
+% #2 is the list of argument names
+% #3 is the list of argument values
+\def\getargvals@#1#2#3{%
+ \def\macargdeflist@{}%
+ \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion.
+ \def\paramlist{#2,\nil@}%
+ \def\macroname{#1}%
+ \begingroup
+ \macroargctxt
+ \def\argvaluelist{#3,\nil@}%
+ \def\@tempa{#3}%
+ \ifx\@tempa\empty
+ \setemptyargvalues@
+ \else
+ \getargvals@@
+ \fi
+}
+
+%
+\def\getargvals@@{%
+ \ifx\paramlist\nilm@
+ % Some sanity check needed here that \argvaluelist is also empty.
+ \ifx\argvaluelist\nillm@
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Too many arguments in macro `\macroname'!}%
+ \fi
+ \let\next\macargexpandinbody@
+ \else
+ \ifx\argvaluelist\nillm@
+ % No more arguments values passed to macro. Set remaining named-arg
+ % macros to empty.
+ \let\next\setemptyargvalues@
+ \else
+ % pop current arg name into \@tempb
+ \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}%
+ \expandafter\@tempa\expandafter{\paramlist}%
+ % pop current argument value into \@tempc
+ \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}%
+ \expandafter\@tempa\expandafter{\argvaluelist}%
+ % Here \@tempb is the current arg name and \@tempc is the current arg value.
+ % First place the new argument macro definition into \@tempd
+ \expandafter\macname\expandafter{\@tempc}%
+ \expandafter\let\csname macarg.\@tempb\endcsname\relax
+ \expandafter\def\expandafter\@tempe\expandafter{%
+ \csname macarg.\@tempb\endcsname}%
+ \edef\@tempd{\long\def\@tempe{\the\macname}}%
+ \push@\@tempd\macargdeflist@
+ \let\next\getargvals@@
+ \fi
+ \fi
+ \next
+}
+
+\def\push@#1#2{%
+ \expandafter\expandafter\expandafter\def
+ \expandafter\expandafter\expandafter#2%
+ \expandafter\expandafter\expandafter{%
+ \expandafter#1#2}%
+}
+
+% Replace arguments by their values in the macro body, and place the result
+% in macro \@tempa
+\def\macvalstoargs@{%
+ % To do this we use the property that token registers that are \the'ed
+ % within an \edef expand only once. So we are going to place all argument
+ % values into respective token registers.
+ %
+ % First we save the token context, and initialize argument numbering.
+ \begingroup
+ \paramno0\relax
+ % Then, for each argument number #N, we place the corresponding argument
+ % value into a new token list register \toks#N
+ \expandafter\putargsintokens@\saveparamlist@,;,%
+ % Then, we expand the body so that argument are replaced by their
+ % values. The trick for values not to be expanded themselves is that they
+ % are within tokens and that tokens expand only once in an \edef .
+ \edef\@tempc{\csname mac.\macroname .body\endcsname}%
+ % Now we restore the token stack pointer to free the token list registers
+ % which we have used, but we make sure that expanded body is saved after
+ % group.
+ \expandafter
+ \endgroup
+ \expandafter\def\expandafter\@tempa\expandafter{\@tempc}%
+ }
+
+\def\macargexpandinbody@{%
+ %% Define the named-macro outside of this group and then close this group.
+ \expandafter
+ \endgroup
+ \macargdeflist@
+ % First the replace in body the macro arguments by their values, the result
+ % is in \@tempa .
+ \macvalstoargs@
+ % Then we point at the \norecurse or \gobble (for recursive) macro value
+ % with \@tempb .
+ \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname
+ % Depending on whether it is recursive or not, we need some tailing
+ % \egroup .
+ \ifx\@tempb\gobble
+ \let\@tempc\relax
+ \else
+ \let\@tempc\egroup
+ \fi
+ % And now we do the real job:
+ \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}%
+ \@tempd
+}
+
+\def\putargsintokens@#1,{%
+ \if#1;\let\next\relax
+ \else
+ \let\next\putargsintokens@
+ % First we allocate the new token list register, and give it a temporary
+ % alias \@tempb .
+ \toksdef\@tempb\the\paramno
+ % Then we place the argument value into that token list register.
+ \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname
+ \expandafter\@tempb\expandafter{\@tempa}%
+ \advance\paramno by 1\relax
+ \fi
+ \next
+}
+
+% Save the token stack pointer into macro #1
+\def\texisavetoksstackpoint#1{\edef#1{\the\@cclvi}}
+% Restore the token stack pointer from number in macro #1
+\def\texirestoretoksstackpoint#1{\expandafter\mathchardef\expandafter\@cclvi#1\relax}
+% newtoks that can be used non \outer .
+\def\texinonouternewtoks{\alloc@ 5\toks \toksdef \@cclvi}
+
+% Tailing missing arguments are set to empty
+\def\setemptyargvalues@{%
+ \ifx\paramlist\nilm@
+ \let\next\macargexpandinbody@
+ \else
+ \expandafter\setemptyargvaluesparser@\paramlist\endargs@
+ \let\next\setemptyargvalues@
+ \fi
+ \next
+}
+
+\def\setemptyargvaluesparser@#1,#2\endargs@{%
+ \expandafter\def\expandafter\@tempa\expandafter{%
+ \expandafter\def\csname macarg.#1\endcsname{}}%
+ \push@\@tempa\macargdeflist@
+ \def\paramlist{#2}%
+}
+
+% #1 is the element target macro
+% #2 is the list macro
+% #3,#4\endargs@ is the list value
+\def\pop@#1#2#3,#4\endargs@{%
+ \def#1{#3}%
+ \def#2{#4}%
+}
+\long\def\longpop@#1#2#3,#4\endargs@{%
+ \long\def#1{#3}%
+ \long\def#2{#4}%
+}
+
+% This defines a Texinfo @macro. There are eight cases: recursive and
+% nonrecursive macros of zero, one, up to nine, 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
+ \ifnum\paramno<10\relax % at most 9
+ \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}}%
+ \else % 10 or more
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\getargvals@{\the\macname}{\argl}%
+ }%
+ \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp
+ \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
+ \fi
+ \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 % at most 9
+ \ifnum\paramno<10\relax
+ \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}%
+ \else % 10 or more:
+ \expandafter\xdef\csname\the\macname\endcsname{%
+ \noexpand\getargvals@{\the\macname}{\argl}%
+ }%
+ \global\expandafter\let\csname mac.\the\macname .body\endcsname\temp
+ \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\norecurse
+ \fi
+ \fi
+ \fi}
+
+\catcode `\@\texiatcatcode\relax
+
+\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. 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, at \shipout
+ }%
+ \fi
+}
+
+% @xrefautosectiontitle on|off says whether @section(ing) names are used
+% automatically in xrefs, if the third arg is not explicitly specified.
+% This was provided as a "secret" @set xref-automatic-section-title
+% variable, now it's official.
+%
+\parseargdef\xrefautomaticsectiontitle{%
+ \def\temp{#1}%
+ \ifx\temp\onword
+ \expandafter\let\csname SETxref-automatic-section-title\endcsname
+ = \empty
+ \else\ifx\temp\offword
+ \expandafter\let\csname SETxref-automatic-section-title\endcsname
+ = \relax
+ \else
+ \errhelp = \EMsimple
+ \errmessage{Unknown @xrefautomaticsectiontitle value `\temp',
+ must be on|off}%
+ \fi\fi
+}
+
+%
+% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual. All but the node name can be omitted.
+%
+\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]}
+\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]}
+\def\ref#1{\xrefX[#1,,,,,,,]}
+%
+\newbox\toprefbox
+\newbox\printedrefnamebox
+\newbox\infofilenamebox
+\newbox\printedmanualbox
+%
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+ \unsepspaces
+ %
+ % Get args without leading/trailing spaces.
+ \def\printedrefname{\ignorespaces #3}%
+ \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}%
+ %
+ \def\infofilename{\ignorespaces #4}%
+ \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
+ %
+ \def\printedmanual{\ignorespaces #5}%
+ \setbox\printedmanualbox = \hbox{\printedmanual\unskip}%
+ %
+ % If the printed reference name (arg #3) was not explicitly given in
+ % the @xref, figure out what we want to use.
+ \ifdim \wd\printedrefnamebox = 0pt
+ % No printed node name was explicitly given.
+ \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax
+ % Not auto section-title: use node name inside the square brackets.
+ \def\printedrefname{\ignorespaces #1}%
+ \else
+ % Auto section-title: use chapter/section title inside
+ % the square brackets if we have it.
+ \ifdim \wd\printedmanualbox > 0pt
+ % It is in another manual, so we don't have it; use node name.
+ \def\printedrefname{\ignorespaces #1}%
+ \else
+ \ifhavexrefs
+ % We (should) know the real title if we have the xref values.
+ \def\printedrefname{\refx{#1-title}{}}%
+ \else
+ % Otherwise just copy the Info node name.
+ \def\printedrefname{\ignorespaces #1}%
+ \fi%
+ \fi
+ \fi
+ \fi
+ %
+ % Make link in pdf output.
+ \ifpdf
+ {\indexnofonts
+ \turnoffactive
+ \makevalueexpandable
+ % This expands tokens, so do it after making catcode changes, so _
+ % etc. don't get their TeX definitions. This ignores all spaces in
+ % #4, including (wrongly) those in the middle of the filename.
+ \getfilename{#4}%
+ %
+ % This (wrongly) does not take account of leading or trailing
+ % spaces in #1, which should be ignored.
+ \edef\pdfxrefdest{#1}%
+ \ifx\pdfxrefdest\empty
+ \def\pdfxrefdest{Top}% no empty targets
+ \else
+ \txiescapepdf\pdfxrefdest % escape PDF special chars
+ \fi
+ %
+ \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\wd\printedrefnamebox = 0pt
+ \refx{#1-snt}{}%
+ \else
+ \printedrefname
+ \fi
+ %
+ % If the user also gave the printed manual name (fifth arg), append
+ % "in MANUALNAME".
+ \ifdim \wd\printedmanualbox > 0pt
+ \space \putwordin{} \cite{\printedmanual}%
+ \fi
+ \else
+ % node/anchor (non-float) references.
+ %
+ % If we use \unhbox to print the node names, TeX does not insert
+ % empty discretionaries after hyphens, which means that it will not
+ % find a line break at a hyphen in a node names. Since some manuals
+ % are best written with fairly long node names, containing hyphens,
+ % this is a loss. Therefore, we give the text of the node name
+ % again, so it is as if TeX is seeing it for the first time.
+ %
+ \ifdim \wd\printedmanualbox > 0pt
+ % Cross-manual reference with a printed manual name.
+ %
+ \crossmanualxref{\cite{\printedmanual\unskip}}%
+ %
+ \else\ifdim \wd\infofilenamebox > 0pt
+ % Cross-manual reference with only an info filename (arg 4), no
+ % printed manual name (arg 5). This is essentially the same as
+ % the case above; we output the filename, since we have nothing else.
+ %
+ \crossmanualxref{\code{\infofilename\unskip}}%
+ %
+ \else
+ % Reference within this manual.
+ %
+ % _ (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 the macro below so it can be overridden.
+ \xrefprintnodename\printedrefname
+ %
+ % But we always want a comma and a space:
+ ,\space
+ %
+ % output the `page 3'.
+ \turnoffactive \putwordpage\tie\refx{#1-pg}{}%
+ \fi\fi
+ \fi
+ \endlink
+\endgroup}
+
+% Output a cross-manual xref to #1. Used just above (twice).
+%
+% Only include the text "Section ``foo'' in" if the foo is neither
+% missing or Top. Thus, @xref{,,,foo,The Foo Manual} outputs simply
+% "see The Foo Manual", the idea being to refer to the whole manual.
+%
+% But, this being TeX, we can't easily compare our node name against the
+% string "Top" while ignoring the possible spaces before and after in
+% the input. By adding the arbitrary 7sp below, we make it much less
+% likely that a real node name would have the same width as "Top" (e.g.,
+% in a monospaced font). Hopefully it will never happen in practice.
+%
+% For the same basic reason, we retypeset the "Top" at every
+% reference, since the current font is indeterminate.
+%
+\def\crossmanualxref#1{%
+ \setbox\toprefbox = \hbox{Top\kern7sp}%
+ \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}%
+ \ifdim \wd2 > 7sp % nonempty?
+ \ifdim \wd2 = \wd\toprefbox \else % same as Top?
+ \putwordSection{} ``\printedrefname'' \putwordin{}\space
+ \fi
+ \fi
+ #1%
+}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output. It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents. Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+ \ifnum\secno=0
+ \putwordChapter@tie \the\chapno
+ \else \ifnum\subsecno=0
+ \putwordSection@tie \the\chapno.\the\secno
+ \else \ifnum\subsubsecno=0
+ \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+ \else
+ \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+ \fi\fi\fi
+}
+\def\Yappendix{%
+ \ifnum\secno=0
+ \putwordAppendix@tie @char\the\appendixno{}%
+ \else \ifnum\subsecno=0
+ \putwordSection@tie @char\the\appendixno.\the\secno
+ \else \ifnum\subsubsecno=0
+ \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+ \else
+ \putwordSection@tie
+ @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+ \fi\fi\fi
+}
+
+% 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
+ {\toks0 = {#1}% avoid expansion of possibly-complex value
+ \message{\linenumber Undefined cross reference `\the\toks0'.}}%
+ \else
+ \ifwarnedxrefs\else
+ \global\warnedxrefstrue
+ \message{Cross reference values unknown; you must run TeX again.}%
+ \fi
+ \fi
+ \fi
+ \else
+ % It's defined, so just use it.
+ \thisrefX
+ \fi
+ #2% Output the suffix in any case.
+}
+
+% This is the macro invoked by entries in the aux file. 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
+ %
+ % Invoke rest of plain TeX footnote routine.
+ \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\thisisundefined
+ \ifwarnednoepsf \else
+ \errhelp = \noepsfhelp
+ \errmessage{epsf.tex not found, images will be ignored}%
+ \global\warnednoepsftrue
+ \fi
+ \else
+ \imagexxx #1,,,,,\finish
+ \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+ \catcode`\^^M = 5 % in case we're inside an example
+ \normalturnoffactive % allow _ et al. in names
+ % If the image is by itself, center it.
+ \ifvmode
+ \imagevmodetrue
+ \else \ifx\centersub\centerV
+ % for @center @image, we need a vbox so we can have our vertical space
+ \imagevmodetrue
+ \vbox\bgroup % vbox has better behavior than vtop herev
+ \fi\fi
+ %
+ \ifimagevmode
+ \nobreak\medskip
+ % Usually we'll have text after the image which will insert
+ % \parskip glue, so insert it here too to equalize the space
+ % above and below.
+ \nobreak\vskip\parskip
+ \nobreak
+ \fi
+ %
+ % Leave vertical mode so that indentation from an enclosing
+ % environment such as @quotation is respected.
+ % However, if we're at the top level, we don't want the
+ % normal paragraph indentation.
+ % On the other hand, if we are in the case of @center @image, we don't
+ % want to start a paragraph, which will create a hsize-width box and
+ % eradicate the centering.
+ \ifx\centersub\centerV\else \noindent \fi
+ %
+ % Output the image.
+ \ifpdf
+ \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 % space after a standalone image
+ \fi
+ \ifx\centersub\centerV \egroup \fi
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc. We don't actually implement floating yet, we always include the
+% float "here". But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc. Can't contain commas. If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label. Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored. It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+ \let\thiscaption=\empty
+ \let\thisshortcaption=\empty
+ %
+ % don't lose footnotes inside @float.
+ %
+ % BEWARE: when the floats start float, we have to issue warning whenever an
+ % insert appears inside a float which could possibly float. --kasal, 26may04
+ %
+ \startsavinginserts
+ %
+ % We can't be used inside a paragraph.
+ \par
+ %
+ \vtop\bgroup
+ \def\floattype{#1}%
+ \def\floatlabel{#2}%
+ \def\floatloc{#3}% we do nothing with this yet.
+ %
+ \ifx\floattype\empty
+ \let\safefloattype=\empty
+ \else
+ {%
+ % the floattype might have accents or other special characters,
+ % but we need to use it in a control sequence name.
+ \indexnofonts
+ \turnoffactive
+ \xdef\safefloattype{\floattype}%
+ }%
+ \fi
+ %
+ % If label is given but no type, we handle that as the empty type.
+ \ifx\floatlabel\empty \else
+ % We want each FLOATTYPE to be numbered separately (Figure 1,
+ % Table 1, Figure 2, ...). (And if no label, no number.)
+ %
+ \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+ \global\advance\floatno by 1
+ %
+ {%
+ % This magic value for \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{\tie}
+ \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{\guillemetright}
+ \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{\tie}
+ \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{\'{\dotless{i}}}
+ \gdef^^ee{\^{\dotless{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 very finicky about underfull hboxes, either.
+\hbadness = 6666
+
+% Following George Bush, get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything. We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize. We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+ \ifx\emergencystretch\thisisundefined
+ % Allow us to assign to \emergencystretch anyway.
+ \def\emergencystretch{\dimen0}%
+ \else
+ \emergencystretch = .15\hsize
+ \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth;
+% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip;
+% 7) physical page height; 8) physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading. The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+ \voffset = #3\relax
+ \topskip = #6\relax
+ \splittopskip = \topskip
+ %
+ \vsize = #1\relax
+ \advance\vsize by \topskip
+ \outervsize = \vsize
+ \advance\outervsize by 2\topandbottommargin
+ \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.}
+
+\def^^L{\par} % remove \outer, so ^L can appear in an @comment
+
+% DEL is a comment character, in case @c does not suffice.
+\catcode`\^^? = 14
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other \def\normaldoublequote{"}
+\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix
+\catcode`\+=\other \def\normalplus{+}
+\catcode`\<=\other \def\normalless{<}
+\catcode`\>=\other \def\normalgreater{>}
+\catcode`\^=\other \def\normalcaret{^}
+\catcode`\_=\other \def\normalunderscore{_}
+\catcode`\|=\other \def\normalverticalbar{|}
+\catcode`\~=\other \def\normaltilde{~}
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise. Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font. Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts. But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% 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 % @ for escape char from now on.
+
+% The story here is that in math mode, the \char of \backslashcurfont
+% ends up printing the roman \ from the math symbol font (because \char
+% in math mode uses the \mathcode, and plain.tex sets
+% \mathcode`\\="026E). It seems better for @backslashchar{} to always
+% print a typewriter backslash, hence we use an explicit \mathchar,
+% which is the decimal equivalent of "715c (class 7, e.g., use \fam;
+% ignored family value; char position "5C). We can't use " for the
+% usual hex value because it has already been made active.
+@def@normalbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}}
+@let@backslashchar = @normalbackslash % @backslashchar{} is for user documents.
+
+% 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. We switch back and forth between these.
+@gdef@rawbackslash{@let\=@backslashcurfont}
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.
+%
+@def@normalturnoffactive{%
+ @let"=@normaldoublequote
+ @let$=@normaldollar %$ font-lock fix
+ @let+=@normalplus
+ @let<=@normalless
+ @let>=@normalgreater
+ @let\=@normalbackslash
+ @let^=@normalcaret
+ @let_=@normalunderscore
+ @let|=@normalverticalbar
+ @let~=@normaltilde
+ @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 (along with & and #) are made active for url-breaking, so need
+% active definitions as the normal characters.
+@def@normaldot{.}
+@def@normalquest{?}
+@def@normalslash{/}
+
+% These look ok in all fonts, so just make them not special.
+% @hashchar{} gets its own user-level command, because of #line.
+@catcode`@& = @other @def@normalamp{&}
+@catcode`@# = @other @def@normalhash{#}
+@catcode`@% = @other @def@normalpercent{%}
+
+@let @hashchar = @normalhash
+
+@c Finally, make ` and ' active, so that txicodequoteundirected and
+@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}. If we
+@c don't make ` and ' active, @code will not get them as active chars.
+@c Do this last of all since we use ` in the previous @catcode assignments.
+@catcode`@'=@active
+@catcode`@`=@active
+@markupsetuplqdefault
+@markupsetuprqdefault
+
+@c Local variables:
+@c eval: (add-hook '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/tgz.1 b/tgz.1
new file mode 100644
index 0000000..fea8b17
--- /dev/null
+++ b/tgz.1
@@ -0,0 +1,56 @@
+.\" tgz.1
+.\" (c) 2001 Filip Van Raemdonck <mechanix@debian.org>
+.\"
+.\" This manpage is free documentation.
+.\" Permission is granted to copy, distribute and/or modify this document
+.\" under the terms of the GNU Free Documentation License, Version 1.1 or any
+.\" later version published by the Free Software Foundation; with no Invariant
+.\" Sections, no Front-Cover Texts, and no Back Cover Texts.
+.\"
+.\" This is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" You should have received a copy of the GNU Free Documentation License
+.\" along with this program; if not, write to:
+.\" Free Software Foundation, Inc.
+.\" 59 Temple Place - Suite 330
+.\" Boston, MA 02111-1307, USA.
+.\"
+.\"
+.ig
+A copy of the GNU Free Documentation License is available in the
+Debian package in the file /usr/share/doc/mtools/copyright.
+..
+.ig
+A copy of the GNU Free Documentation License is available in the
+Debian source package in the file debian/copyright.
+..
+.TH TGZ "1" "May 2002" "mtools 3.9.8" "Mtools Users Manual"
+.SH NAME
+tgz \- makes a gzip'd tar archive
+.SH SYNOPSIS
+.B tgz
+[
+.I destination
+[
+.I source ...
+] ]
+.SH DESCRIPTION
+Make a gzip'd tar archive with the name of the first parameter out of specified
+files or, if no source files are specified, from everything in the current
+directory.
+If the first parameter is omitted as well, the archive will be written to
+stdout.
+.SH BUGS
+.B tgz
+requires gzip in the user's path.
+It also needs gnu tar or something close due to use of --exclude, --totals
+and -S.
+.SH AUTHOR
+Filip Van Raemdonck (mechanix@debian.org) wrote this page for the
+.I Debian/GNU
+mtools package.
+.SH "SEE ALSO"
+.BR gzip (1),
+.BR tar (1)
diff --git a/tty.c b/tty.c
new file mode 100644
index 0000000..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
index 0000000..80253ea
--- /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(const char *filename)
+{
+ Dir_t *This;
+
+ This = New(Dir_t);
+
+ This->Class = &DirClass;
+ This->Next = 0;
+ This->refs = 1;
+ This->Buffer = 0;
+ This->pathname = malloc(strlen(filename)+1);
+ if(This->pathname == NULL) {
+ Free(This);
+ return NULL;
+ }
+ strcpy(This->pathname, filename);
+
+ if(MT_STAT(filename, &This->statbuf) < 0) {
+ Free(This->pathname);
+ Free(This);
+ return NULL;
+ }
+
+ This->dir = opendir(filename);
+ if(!This->dir) {
+ Free(This->pathname);
+ Free(This);
+ return NULL;
+ }
+
+ return (Stream_t *) This;
+}
diff --git a/uz.1 b/uz.1
new file mode 100644
index 0000000..08cede9
--- /dev/null
+++ b/uz.1
@@ -0,0 +1,43 @@
+'\" t
+.\" ** The above line should force tbl to be a preprocessor **
+.\" Man page for uz
+.\"
+.\" Copyright (C), 2000, Robert A.R. King
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License as specified in the file COPYING that comes with the mtools
+.\" package
+.\"
+.\" Fri Dec 1 01:50:54 EST 2000 Robert A.R. King (Robert.King@mailbox.gu.edu.au)
+.\"
+.TH UZ 1 "Wed Feb 23 00:00:00 EET 2000" "" "Mtools Users Manual"
+.SH NAME
+uz \- gunzips and extracts a gzip'd tar'd archive
+.SH SYNOPSIS
+.\" The command line
+.B uz
+.I file
+.SH DESCRIPTION
+.B uz
+extracts a gzip'd tar'd archive, that is a \fBtar\fR(1) archive
+compressed with the \fBgzip\fR(1) utility.
+It is not strictly necessary on Debian GNU/Linux, because the GNU
+\fBtar\fR(1) program provides the same capability with the command
+
+.B tar -xzf
+.I file
+
+but this utility is provided in the mtools package for other platforms and
+is retained here for completeness.
+
+.SH AUTHOR
+Robert King (Robert.King@mailbox.gu.edu.au) wrote this page for the
+.I Debian/GNU
+mtools package.
+
+
+.SH "SEE ALSO"
+.BR mtools (1),
+.BR gzip (1),
+.BR tar (1),
+.BR lz (1).
diff --git a/version.texi b/version.texi
new file mode 100644
index 0000000..97eb7cc
--- /dev/null
+++ b/version.texi
@@ -0,0 +1,3 @@
+@set EDITION 4.0.18
+@set VERSION 4.0.18
+@set UPDATED January 2013
diff --git a/vfat.c b/vfat.c
new file mode 100644
index 0000000..0406a74
--- /dev/null
+++ b/vfat.c
@@ -0,0 +1,831 @@
+/* Copyright 1995 David C. Niemi
+ * Copyright 1996-2003,2005,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * vfat.c
+ *
+ * Miscellaneous VFAT-related functions
+ */
+
+#include "sysincludes.h"
+#include "msdos.h"
+#include "mtools.h"
+#include "vfat.h"
+#include "file.h"
+#include "dirCache.h"
+#include "dirCacheP.h"
+#include "file_name.h"
+
+/* #define DEBUG */
+
+const char *short_illegals=";+=[]',\"*\\<>/?:|";
+const char *long_illegals = "\"*\\<>/?:|\005";
+
+/* Automatically derive a new name */
+static void autorename(char *name,
+ char tilda, char dot, const char *illegals,
+ int limit, int bump)
+{
+ int tildapos, dotpos;
+ unsigned int seqnum=0, maxseq=0;
+ char tmp;
+ char *p;
+
+#ifdef DEBUG
+ printf("In autorename for name=%s.\n", name);
+#endif
+ tildapos = -1;
+
+ for(p=name; *p ; p++)
+ if (strchr(illegals, *p)) {
+ *p = '_';
+ bump = 0;
+ }
+
+ for(dotpos=0;
+ name[dotpos] && dotpos < limit && name[dotpos] != dot ;
+ dotpos++) {
+ if(name[dotpos] == tilda) {
+ tildapos = dotpos;
+ seqnum = 0;
+ maxseq = 1;
+ } else if (name[dotpos] >= '0' && name[dotpos] <= '9') {
+ seqnum = seqnum * 10 + name[dotpos] - '0';
+ maxseq = maxseq * 10;
+ } else
+ tildapos = -1; /* sequence number interrupted */
+ }
+ if(tildapos == -1) {
+ /* no sequence number yet */
+ if(dotpos > limit - 2) {
+ tildapos = limit - 2;
+ dotpos = limit;
+ } else {
+ tildapos = dotpos;
+ dotpos += 2;
+ }
+ seqnum = 1;
+ } else {
+ if(bump)
+ seqnum++;
+ if(seqnum > 999999) {
+ seqnum = 1;
+ tildapos = dotpos - 2;
+ /* this matches Win95's behavior, and also guarantees
+ * us that the sequence numbers never get shorter */
+ }
+ if (seqnum == maxseq) {
+ if(dotpos >= limit)
+ tildapos--;
+ else
+ dotpos++;
+ }
+ }
+
+ tmp = name[dotpos];
+ if((bump && seqnum == 1) || seqnum > 1 || mtools_numeric_tail)
+ sprintf(name+tildapos,"%c%d",tilda, seqnum);
+ if(dot)
+ name[dotpos]=tmp;
+ /* replace the character if it wasn't a space */
+#ifdef DEBUG
+ printf("Out autorename for name=%s.\n", name);
+#endif
+}
+
+
+void autorename_short(dos_name_t *name, int bump)
+{
+ autorename(name->base, '~', ' ', short_illegals, 8, bump);
+}
+
+void autorename_long(char *name, int bump)
+{
+ autorename(name, '-', '\0', long_illegals, 255, bump);
+}
+
+
+static __inline__ int unicode_read(struct unicode_char *in,
+ wchar_t *out, int num)
+{
+ wchar_t *end_out = out+num;
+
+ while(out < end_out) {
+#ifdef HAVE_WCHAR_H
+ *out = in->lchar | ((in->uchar) << 8);
+#else
+ if (in->uchar)
+ *out = '_';
+ else
+ *out = in->lchar;
+#endif
+ ++out;
+ ++in;
+ }
+ return num;
+}
+
+
+void clear_vfat(struct vfat_state *v)
+{
+ v->subentries = 0;
+ v->status = 0;
+ v->present = 0;
+}
+
+
+/* sum_shortname
+ *
+ * Calculate the checksum that results from the short name in *dir.
+ *
+ * The sum is formed by circularly right-shifting the previous sum
+ * and adding in each character, from left to right, padding both
+ * the name and extension to maximum length with spaces and skipping
+ * the "." (hence always summing exactly 11 characters).
+ *
+ * This exact algorithm is required in order to remain compatible
+ * with Microsoft Windows-95 and Microsoft Windows NT 3.5.
+ * Thanks to Jeffrey Richter of Microsoft Systems Journal for
+ * pointing me to the correct algorithm.
+ *
+ * David C. Niemi (niemi@tuxers.net) 95.01.19
+ */
+static __inline__ unsigned char sum_shortname(const dos_name_t *dn)
+{
+ unsigned char sum;
+ const char *name=dn->base;
+ const char *end = name+11;
+
+ for (sum=0; name<end; ++name)
+ sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1)
+ + *name;
+ return(sum);
+}
+
+/* check_vfat
+ *
+ * Inspect a directory and any associated VSEs.
+ * Return 1 if the VSEs comprise a valid long file name,
+ * 0 if not.
+ */
+static __inline__ void check_vfat(struct vfat_state *v, struct directory *dir)
+{
+ dos_name_t dn;;
+
+ if (! v->subentries) {
+#ifdef DEBUG
+ fprintf(stderr, "check_vfat: no VSEs.\n");
+#endif
+ return;
+ }
+
+ memcpy(dn.base, (char *)dir->name, 8);
+ memcpy(dn.ext, (char *)dir->ext, 3);
+
+ if (v->sum != sum_shortname(&dn))
+ return;
+
+ if( (v->status & ((1<<v->subentries) - 1)) != (1<<v->subentries) - 1)
+ return; /* missing entries */
+
+ /* zero out byte following last entry, for good measure */
+ v->name[VSE_NAMELEN * v->subentries] = 0;
+ v->present = 1;
+}
+
+
+int clear_vses(Stream_t *Dir, int entrySlot, size_t last)
+{
+ direntry_t entry;
+ dirCache_t *cache;
+ int error;
+
+ entry.Dir = Dir;
+ entry.entry = entrySlot;
+
+ /*maximize(last, entry.entry + MAX_VFAT_SUBENTRIES);*/
+ cache = allocDirCache(Dir, last);
+ if(!cache) {
+ fprintf(stderr, "Out of memory error in clear_vses\n");
+ exit(1);
+ }
+ addFreeEntry(cache, entry.entry, last);
+ for (; entry.entry < (signed int) last; ++entry.entry) {
+#ifdef DEBUG
+ fprintf(stderr,"Clearing entry %d.\n", entry.entry);
+#endif
+ dir_read(&entry, &error);
+ if(error)
+ return error;
+ if(!entry.dir.name[0] || entry.dir.name[0] == DELMARK)
+ break;
+ entry.dir.name[0] = DELMARK;
+ if (entry.dir.attr == 0xf)
+ entry.dir.attr = '\0';
+ low_level_dir_write(&entry);
+ }
+ return 0;
+}
+
+int write_vfat(Stream_t *Dir, dos_name_t *shortname, char *longname, int start,
+ direntry_t *mainEntry)
+{
+ struct vfat_subentry *vse;
+ int vse_id, num_vses;
+ wchar_t *c;
+ direntry_t entry;
+ dirCache_t *cache;
+ wchar_t unixyName[13];
+ doscp_t *cp = GET_DOSCONVERT(Dir);
+
+ wchar_t wlongname[MAX_VNAMELEN+1];
+ int wlen;
+
+ if(longname) {
+#ifdef DEBUG
+ printf("Entering write_vfat with longname=\"%s\", start=%d.\n",
+ longname,start);
+#endif
+ entry.Dir = Dir;
+ vse = (struct vfat_subentry *) &entry.dir;
+ /* Fill in invariant part of vse */
+ vse->attribute = 0x0f;
+ vse->hash1 = vse->sector_l = vse->sector_u = 0;
+ vse->sum = sum_shortname(shortname);
+#ifdef DEBUG
+ printf("Wrote checksum=%d for shortname %s.%s\n",
+ vse->sum,shortname->base,shortname->ext);
+#endif
+
+ wlen = native_to_wchar(longname, wlongname, MAX_VNAMELEN+1,
+ 0, 0);
+ num_vses = (wlen + VSE_NAMELEN - 1)/VSE_NAMELEN;
+ for (vse_id = num_vses; vse_id; --vse_id) {
+ int end = 0;
+
+ c = wlongname + (vse_id - 1) * VSE_NAMELEN;
+
+ c += unicode_write(c, vse->text1, VSE1SIZE, &end);
+ c += unicode_write(c, vse->text2, VSE2SIZE, &end);
+ c += unicode_write(c, vse->text3, VSE3SIZE, &end);
+
+ vse->id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id;
+#ifdef DEBUG
+ printf("Writing longname=(%s), VSE %d (%13s) at %d, end = %d.\n",
+ longname, vse_id, longname + (vse_id-1) * VSE_NAMELEN,
+ start + num_vses - vse_id, start + num_vses);
+#endif
+
+ entry.entry = start + num_vses - vse_id;
+ low_level_dir_write(&entry);
+ }
+ } else {
+ num_vses = 0;
+ wlongname[0]='\0';
+ }
+ cache = allocDirCache(Dir, start + num_vses + 1);
+ if(!cache) {
+ fprintf(stderr, "Out of memory error\n");
+ exit(1);
+ }
+ unix_name(cp, shortname->base, shortname->ext, 0, unixyName);
+ addUsedEntry(cache, start, start + num_vses + 1, wlongname, unixyName,
+ &mainEntry->dir);
+ low_level_dir_write(mainEntry);
+ return start + num_vses;
+}
+
+void dir_write(direntry_t *entry)
+{
+ dirCacheEntry_t *dce;
+ dirCache_t *cache;
+
+ if(entry->entry == -3) {
+ fprintf(stderr, "Attempt to write root directory pointer\n");
+ exit(1);
+ }
+
+ cache = allocDirCache(entry->Dir, entry->entry + 1);
+ if(!cache) {
+ fprintf(stderr, "Out of memory error in dir_write\n");
+ exit(1);
+ }
+ dce = cache->entries[entry->entry];
+ if(dce) {
+ if(entry->dir.name[0] == DELMARK) {
+ addFreeEntry(cache, dce->beginSlot, dce->endSlot);
+ } else {
+ dce->dir = entry->dir;
+ }
+ }
+ low_level_dir_write(entry);
+}
+
+
+/*
+ * The following function translates a series of vfat_subentries into
+ * data suitable for a dircache entry
+ */
+static __inline__ void parse_vses(direntry_t *entry,
+ struct vfat_state *v)
+{
+ struct vfat_subentry *vse;
+ unsigned char id, last_flag;
+ wchar_t *c;
+
+ vse = (struct vfat_subentry *) &entry->dir;
+
+ id = vse->id & VSE_MASK;
+ last_flag = (vse->id & VSE_LAST);
+ if (id > MAX_VFAT_SUBENTRIES) {
+ fprintf(stderr, "parse_vses: invalid VSE ID %d at %d.\n",
+ id, entry->entry);
+ return;
+ }
+
+/* 950819: This code enforced finding the VSEs in order. Well, Win95
+ * likes to write them in *reverse* order for some bizarre reason! So
+ * we pretty much have to tolerate them coming in any possible order.
+ * So skip this check, we'll do without it (What does this do, Alain?).
+ *
+ * 950820: Totally rearranged code to tolerate any order but to warn if
+ * they are not in reverse order like Win95 uses.
+ *
+ * 950909: Tolerate any order. We recognize new chains by mismatching
+ * checksums. In the event that the checksums match, new entries silently
+ * overwrite old entries of the same id. This should accept all valid
+ * entries, but may fail to reject invalid entries in some rare cases.
+ */
+
+ /* bad checksum, begin new chain */
+ if(v->sum != vse->sum) {
+ clear_vfat(v);
+ v->sum = vse->sum;
+ }
+
+#ifdef DEBUG
+ if(v->status & (1 << (id-1)))
+ fprintf(stderr,
+ "parse_vses: duplicate VSE %d\n", vse->id);
+#endif
+
+ v->status |= 1 << (id-1);
+ if(last_flag)
+ v->subentries = id;
+
+#ifdef DEBUG
+ if (id > v->subentries)
+ /* simple test to detect entries preceding
+ * the "last" entry (really the first) */
+ fprintf(stderr,
+ "parse_vses: new VSE %d sans LAST flag\n",
+ vse->id);
+#endif
+
+ c = &(v->name[VSE_NAMELEN * (id-1)]);
+ c += unicode_read(vse->text1, c, VSE1SIZE);
+ c += unicode_read(vse->text2, c, VSE2SIZE);
+ c += unicode_read(vse->text3, c, VSE3SIZE);
+#ifdef DEBUG
+ printf("Read VSE %d at %d, subentries=%d, = (%13ls).\n",
+ id,entry->entry,v->subentries,&(v->name[VSE_NAMELEN * (id-1)]));
+#endif
+ if (last_flag)
+ *c = '\0'; /* Null terminate long name */
+}
+
+/**
+ * Read one complete entry from directory (main name plus any VSEs
+ * belonging to it)
+ */
+static dirCacheEntry_t *vfat_lookup_loop_common(doscp_t *cp,
+ direntry_t *direntry,
+ dirCache_t *cache,
+ int lookForFreeSpace,
+ int *io_error)
+{
+ wchar_t newfile[13];
+ int initpos = direntry->entry + 1;
+ struct vfat_state vfat;
+ wchar_t *longname;
+ int error;
+ int endmarkSeen = 0;
+
+ /* not yet cached */
+ *io_error = 0;
+ clear_vfat(&vfat);
+ while(1) {
+ ++direntry->entry;
+ if(!dir_read(direntry, &error)){
+ if(error) {
+ *io_error = error;
+ return NULL;
+ }
+ addFreeEndEntry(cache, initpos, direntry->entry,
+ endmarkSeen);
+ return addEndEntry(cache, direntry->entry);
+ }
+
+ if (endmarkSeen || direntry->dir.name[0] == ENDMARK){
+ /* the end of the directory */
+ if(lookForFreeSpace) {
+ endmarkSeen = 1;
+ continue;
+ }
+ return addEndEntry(cache, direntry->entry);
+ }
+ if(direntry->dir.name[0] != DELMARK &&
+ direntry->dir.attr == 0x0f)
+ parse_vses(direntry, &vfat);
+ else
+ /* the main entry */
+ break;
+ }
+
+ /* If we get here, it's a short name FAT entry, maybe erased.
+ * thus we should make sure that the vfat structure will be
+ * cleared before the next loop run */
+
+ /* deleted file */
+ if (direntry->dir.name[0] == DELMARK) {
+ return addFreeEntry(cache, initpos,
+ direntry->entry + 1);
+ }
+
+ check_vfat(&vfat, &direntry->dir);
+ if(!vfat.present)
+ vfat.subentries = 0;
+
+ /* mark space between last entry and this one as free */
+ addFreeEntry(cache, initpos,
+ direntry->entry - vfat.subentries);
+
+ if (direntry->dir.attr & 0x8){
+ /* Read entry as a label */
+ wchar_t *ptr = newfile;
+ 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];
+ doscp_t *cp = GET_DOSCONVERT(direntry->Dir);
+
+ if(length == -1 && filename)
+ length = strlen(filename);
+
+ if(filename != NULL)
+ length = native_to_wchar(filename, wfilename, MAX_VNAMELEN,
+ filename+length, 0);
+ else
+ length = 0;
+
+ if (direntry->entry == -2)
+ return -1;
+
+ cache = allocDirCache(direntry->Dir, direntry->entry+1);
+ if(!cache) {
+ fprintf(stderr, "Out of memory error in vfat_lookup [0]\n");
+ exit(1);
+ }
+
+ do {
+ dce = vfat_lookup_loop_for_read(cp, direntry, cache, &io_error);
+ if(!dce) {
+ if (io_error)
+ return -2;
+ fprintf(stderr, "Out of memory error in vfat_lookup\n");
+ exit(1);
+ }
+ result = checkNameForMatch(direntry, dce,
+ wfilename,
+ length, flags);
+ } while(result == RES_NOMATCH);
+
+ if(result == RES_MATCH){
+ if(longname){
+ if(dce->longName)
+ wchar_to_native(dce->longName,
+ longname, MAX_VNAMELEN);
+ 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 & 1)
+ s->size_needed = 1 +
+ (wcslen(longname) + VSE_NAMELEN - 1)/VSE_NAMELEN;
+ else
+ s->size_needed = 1;
+}
+
+/* lookup_for_insert replaces the old scandir function. It directly
+ * calls into vfat_lookup_loop, thus eliminating the overhead of the
+ * normal vfat_lookup
+ */
+int lookupForInsert(Stream_t *Dir,
+ struct direntry_t *direntry,
+ dos_name_t *dosname,
+ char *longname,
+ struct scan_state *ssp,
+ int ignore_entry,
+ int source_entry,
+ int pessimisticShortRename,
+ int use_longname)
+{
+ direntry_t entry;
+ int ignore_match;
+ dirCacheEntry_t *dce;
+ dirCache_t *cache;
+ int pos; /* position _before_ the next answered entry */
+ wchar_t shortName[13];
+ wchar_t wlongname[MAX_VNAMELEN+1];
+ doscp_t *cp = GET_DOSCONVERT(Dir);
+
+ native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, 0, 0);
+ clear_scan(wlongname, use_longname, ssp);
+
+ ignore_match = (ignore_entry == -2 );
+
+ initializeDirentry(&entry, Dir);
+ ssp->match_free = 0;
+
+ /* hash bitmap of already encountered names. Speeds up batch appends
+ * to huge directories, because in the best case, we only need to scan
+ * the new entries rather than the whole directory */
+ cache = allocDirCache(Dir, 1);
+ if(!cache) {
+ fprintf(stderr, "Out of memory error in lookupForInsert\n");
+ exit(1);
+ }
+
+ if(!ignore_match)
+ unix_name(cp, dosname->base, dosname->ext, 0, shortName);
+
+ pos = cache->nrHashed;
+ if(source_entry >= 0 ||
+ (pos && isHashed(cache, wlongname))) {
+ pos = 0;
+ } else if(pos && !ignore_match && isHashed(cache, shortName)) {
+ if(pessimisticShortRename) {
+ ssp->shortmatch = -2;
+ return 1;
+ }
+ pos = 0;
+ } else if(growDirCache(cache, pos) < 0) {
+ fprintf(stderr, "Out of memory error in vfat_looup [0]\n");
+ exit(1);
+ }
+ do {
+ dce = vfat_lookup_loop_for_insert(cp, &entry, pos, cache);
+ switch(dce->type) {
+ case DCET_FREE:
+ accountFreeSlots(ssp, dce);
+ break;
+ case DCET_USED:
+ if(!(dce->dir.attr & 0x8) &&
+ (signed int)dce->endSlot-1 == source_entry)
+ accountFreeSlots(ssp, dce);
+
+ /* labels never match, neither does the
+ * ignored entry */
+ if( (dce->dir.attr & 0x8) ||
+ ((signed int)dce->endSlot-1==ignore_entry))
+ break;
+
+ /* check long name */
+ if((dce->longName &&
+ !wcscasecmp(dce->longName, wlongname)) ||
+ (dce->shortName &&
+ !wcscasecmp(dce->shortName, wlongname))) {
+ ssp->longmatch = dce->endSlot - 1;
+ /* long match is a reason for
+ * immediate stop */
+ direntry->beginSlot = dce->beginSlot;
+ direntry->endSlot = dce->endSlot-1;
+ return 1;
+ }
+
+ /* Long name or not, always check for
+ * short name match */
+ if (!ignore_match &&
+ !wcscasecmp(shortName, dce->shortName))
+ ssp->shortmatch = dce->endSlot - 1;
+ break;
+ case DCET_END:
+ break;
+ }
+ pos = dce->endSlot;
+ } while(dce->type != DCET_END);
+ if (ssp->shortmatch > -1)
+ return 1;
+ ssp->max_entry = dce->beginSlot;
+ if (ssp->got_slots)
+ return 6; /* Success */
+
+ /* Need more room. Can we grow the directory? */
+ if(!isRootDir(Dir))
+ return 5; /* OK, try to grow the directory */
+
+ fprintf(stderr, "No directory slots\n");
+ return -1;
+}
+
+
+
+/* End vfat.c */
diff --git a/vfat.h b/vfat.h
new file mode 100644
index 0000000..ca3f8e8
--- /dev/null
+++ b/vfat.h
@@ -0,0 +1,110 @@
+#ifndef MTOOLS_VFAT_H
+#define MTOOLS_VFAT_H
+
+/* Copyright 1995 David C. Niemi
+ * Copyright 1996-1998,2000-2003,2005,2007-2009 Alain Knaff.
+ * This file is part of mtools.
+ *
+ * Mtools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mtools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msdos.h"
+
+/*
+ * VFAT-related common header file
+ */
+#define VFAT_SUPPORT
+
+struct unicode_char {
+ unsigned char lchar;
+ unsigned char uchar;
+} PACKED;
+
+
+/* #define MAX_VFAT_SUBENTRIES 32 */ /* Theoretical max # of VSEs */
+#define MAX_VFAT_SUBENTRIES 20 /* Max useful # of VSEs */
+#define VSE_NAMELEN 13
+
+#define VSE1SIZE 5
+#define VSE2SIZE 6
+#define VSE3SIZE 2
+
+#include "stream.h"
+
+struct vfat_subentry {
+ unsigned char id; /* 0x40 = last; & 0x1f = VSE ID */
+ struct unicode_char text1[VSE1SIZE];
+ unsigned char attribute; /* 0x0f for VFAT */
+ unsigned char hash1; /* Always 0? */
+ unsigned char sum; /* Checksum of short name */
+ struct unicode_char text2[VSE2SIZE];
+ unsigned char sector_l; /* 0 for VFAT */
+ unsigned char sector_u; /* 0 for VFAT */
+ struct unicode_char text3[VSE3SIZE];
+};
+
+/* Enough size for a worst case number of full VSEs plus a null */
+#define VBUFSIZE ((MAX_VFAT_SUBENTRIES*VSE_NAMELEN) + 1)
+
+/* Max legal length of a VFAT long name */
+#define MAX_VNAMELEN (255)
+
+#define VSE_PRESENT 0x01
+#define VSE_LAST 0x40
+#define VSE_MASK 0x1f
+
+struct vfat_state {
+ wchar_t name[VBUFSIZE];
+ int status; /* is now a bit map of 32 bits */
+ int subentries;
+ unsigned char sum; /* no need to remember the sum for each entry,
+ * it is the same anyways */
+ int present;
+};
+
+
+struct scan_state {
+ int match_free;
+ int shortmatch;
+ int longmatch;
+ unsigned int free_start;
+ unsigned int free_end;
+ int slot;
+ int got_slots;
+ unsigned int size_needed;
+ int max_entry;
+};
+
+#include "mtoolsDirentry.h"
+
+void clear_vfat(struct vfat_state *);
+int unicode_write(wchar_t *, struct unicode_char *, int num, int *end);
+
+int clear_vses(Stream_t *, int, size_t);
+void autorename_short(struct dos_name_t *, int);
+void autorename_long(char *, int);
+
+#define DO_OPEN 1 /* open all files that are found */
+#define ACCEPT_LABEL 0x08
+#define ACCEPT_DIR 0x10
+#define ACCEPT_PLAIN 0x20
+#define MATCH_ANY 0x40
+#define NO_MSG 0x80
+#define NO_DOTS 0x100 /* accept no dots if matched by wildcard */
+#define DO_OPEN_DIRS 0x400 /* open all directories that are found */
+#define OPEN_PARENT 0x1000 /* in target lookup, open parent
+ * instead of file itself */
+#define NO_UNIX 0x2000 /* in target lookup, consider all files to reside on
+ * the DOS fs */
+#endif
diff --git a/xdf_io.c b/xdf_io.c
new file mode 100644
index 0000000..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
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