From af0c3edb9706e470b45a9c8dd6debcc9e2d543c2 Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Wed, 9 Jan 2013 19:04:18 +0000 Subject: mtools-4.0.18 --- COPYING | 674 +++ INSTALL | 30 + Makefile.Be | 49 + Makefile.in | 335 ++ NEWS | 1094 +++++ README | 76 + README.BEBOX | 126 + Release.notes | 230 + aclocal.m4 | 34 + buffer.c | 387 ++ buffer.h | 28 + buildMingw.sh | 16 + byte_dword.h | 63 + charsetConv.c | 428 ++ cleanconfig | 20 + codepage.h | 42 + codepages.c | 117 + config.c | 806 ++++ config.guess | 1533 +++++++ config.h.Be | 56 + config.h.in | 406 ++ config.sub | 1693 ++++++++ configure | 7234 +++++++++++++++++++++++++++++++ configure-stamp | 0 configure.in | 395 ++ copyfile.c | 73 + debian/changelog | 164 + debian/compat | 1 + debian/control | 31 + debian/floppyd.files | 1 + debian/floppyd.manpages | 2 + debian/mcheck.1 | 33 + debian/mtools.conf | 25 + debian/mtools.dirs | 1 + debian/mtools.files | 1 + debian/mtools.manpages | 33 + debian/rules | 64 + devices.c | 1109 +++++ devices.h | 187 + dirCache.c | 367 ++ dirCache.h | 53 + dirCacheP.h | 14 + directory.c | 143 + direntry.c | 166 + expand.c | 108 + fat.c | 997 +++++ fat_free.c | 72 + fat_size_calculation.tex | 228 + file.c | 723 ++++ file.h | 28 + file_name.c | 220 + file_name.h | 44 + file_read.c | 55 + filter.c | 173 + floppyd.1 | 255 ++ floppyd.c | 1297 ++++++ floppyd_installtest.1 | 94 + floppyd_installtest.c | 330 ++ floppyd_io.c | 679 +++ floppyd_io.h | 65 + force_io.c | 63 + fs.h | 43 + fsP.h | 103 + hash.c | 220 + htable.h | 32 + init.c | 426 ++ install-sh | 238 ++ llong.c | 96 + llong.h | 110 + lockdev.h | 77 + lz.1 | 42 + mainloop.c | 671 +++ mainloop.h | 101 + man-warning-end.texi | 46 + man-warning.texi | 12 + man/floppyd.1 | 257 ++ man/floppyd_installtest.1 | 96 + man/mattrib.1 | 133 + man/mbadblocks.1 | 98 + man/mcat.1 | 103 + man/mcd.1 | 116 + man/mclasserase.1 | 115 + man/mcopy.1 | 183 + man/mdel.1 | 99 + man/mdeltree.1 | 100 + man/mdir.1 | 121 + man/mdu.1 | 99 + man/mformat.1 | 282 ++ man/minfo.1 | 101 + man/mkmanifest.1 | 181 + man/mlabel.1 | 117 + man/mmd.1 | 95 + man/mmount.1 | 99 + man/mmove.1 | 101 + man/mpartition.1 | 187 + man/mrd.1 | 100 + man/mren.1 | 107 + man/mshowfat.1 | 94 + man/mtools.1 | 555 +++ man/mtools.5 | 633 +++ man/mtoolstest.1 | 93 + man/mtype.1 | 113 + man/mzip.1 | 155 + match.c | 158 + mattrib.1 | 128 + mattrib.c | 258 ++ mbadblocks.1 | 115 + mbadblocks.c | 282 ++ mcat.1 | 100 + mcat.c | 162 + mcd.1 | 111 + mcd.c | 62 + mclasserase.1 | 112 + mclasserase.c | 351 ++ mcomp.1 | 44 + mcopy.1 | 177 + mcopy.c | 631 +++ mdel.1 | 96 + mdel.c | 208 + mdeltree.1 | 96 + mdir.1 | 118 + mdir.c | 617 +++ mdoctorfat.c | 183 + mdu.1 | 95 + mdu.c | 140 + mformat.1 | 290 ++ mformat.c | 1382 ++++++ minfo.1 | 99 + minfo.c | 233 + misc.c | 262 ++ missFuncs.c | 477 +++ mk_direntry.c | 709 ++++ mkdosboot | 34 + mkinstalldirs | 50 + mkmanifest.1 | 180 + mkmanifest.c | 112 + mkmanpages | 147 + mlabel.1 | 118 + mlabel.c | 331 ++ mmd.1 | 91 + mmd.c | 199 + mmount.1 | 96 + mmount.c | 107 + mmove.1 | 99 + mmove.c | 323 ++ mpartition.1 | 184 + mpartition.c | 742 ++++ mrd.1 | 95 + mren.1 | 105 + msdos.h | 279 ++ mshortname.1 | 95 + mshortname.c | 76 + mshowfat.1 | 96 + mshowfat.c | 110 + mtools.1 | 521 +++ mtools.5 | 539 +++ mtools.c | 201 + mtools.conf | 80 + mtools.h | 287 ++ mtools.info | 2801 ++++++++++++ mtools.spec | 192 + mtools.texi | 2638 ++++++++++++ mtools.tmpl.1 | 521 +++ mtools.tmpl.5 | 539 +++ mtoolsDirentry.h | 71 + mtoolsPaths.h | 47 + mtoolstest.1 | 90 + mtype.1 | 114 + mxtar.1 | 48 + mzip.1 | 147 + mzip.c | 552 +++ nameclash.h | 75 + partition.h | 49 + patchlevel.c | 24 + plain_io.c | 805 ++++ plain_io.h | 38 + precmd.c | 48 + privileges.c | 211 + privtest.c | 26 + read_dword.h | 41 + scripts/add-disk | 47 + scripts/amuFormat.sh | 103 + scripts/download | 81 + scripts/format.dat | 41 + scripts/mcheck | 61 + scripts/mcomp | 28 + scripts/mxtar | 25 + scripts/tgz | 86 + scripts/uz | 92 + scsi.c | 322 ++ scsi.h | 37 + signal.c | 134 + stream.c | 87 + stream.h | 107 + streamcache.c | 79 + strip-pp.sed | 20 + subdir.c | 44 + sysconfdir.texi | 1 + sysincludes.h | 607 +++ texinfo.tex | 10075 ++++++++++++++++++++++++++++++++++++++++++++ tgz.1 | 56 + tty.c | 222 + unixdir.c | 166 + uz.1 | 43 + version.texi | 3 + vfat.c | 831 ++++ vfat.h | 110 + xdf_io.c | 710 ++++ xdf_io.h | 33 + 209 files changed, 66842 insertions(+) create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 Makefile.Be create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 README.BEBOX create mode 100644 Release.notes create mode 100644 aclocal.m4 create mode 100644 buffer.c create mode 100644 buffer.h create mode 100755 buildMingw.sh create mode 100644 byte_dword.h create mode 100644 charsetConv.c create mode 100644 cleanconfig create mode 100644 codepage.h create mode 100644 codepages.c create mode 100644 config.c create mode 100755 config.guess create mode 100644 config.h.Be create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100644 configure-stamp create mode 100644 configure.in create mode 100644 copyfile.c create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/floppyd.files create mode 100644 debian/floppyd.manpages create mode 100644 debian/mcheck.1 create mode 100644 debian/mtools.conf create mode 100644 debian/mtools.dirs create mode 100644 debian/mtools.files create mode 100644 debian/mtools.manpages create mode 100755 debian/rules create mode 100644 devices.c create mode 100644 devices.h create mode 100644 dirCache.c create mode 100644 dirCache.h create mode 100644 dirCacheP.h create mode 100644 directory.c create mode 100644 direntry.c create mode 100644 expand.c create mode 100644 fat.c create mode 100644 fat_free.c create mode 100644 fat_size_calculation.tex create mode 100644 file.c create mode 100644 file.h create mode 100644 file_name.c create mode 100644 file_name.h create mode 100644 file_read.c create mode 100644 filter.c create mode 100644 floppyd.1 create mode 100644 floppyd.c create mode 100644 floppyd_installtest.1 create mode 100644 floppyd_installtest.c create mode 100644 floppyd_io.c create mode 100644 floppyd_io.h create mode 100644 force_io.c create mode 100644 fs.h create mode 100644 fsP.h create mode 100644 hash.c create mode 100644 htable.h create mode 100644 init.c create mode 100755 install-sh create mode 100644 llong.c create mode 100644 llong.h create mode 100644 lockdev.h create mode 100644 lz.1 create mode 100644 mainloop.c create mode 100644 mainloop.h create mode 100644 man-warning-end.texi create mode 100644 man-warning.texi create mode 100644 man/floppyd.1 create mode 100644 man/floppyd_installtest.1 create mode 100644 man/mattrib.1 create mode 100644 man/mbadblocks.1 create mode 100644 man/mcat.1 create mode 100644 man/mcd.1 create mode 100644 man/mclasserase.1 create mode 100644 man/mcopy.1 create mode 100644 man/mdel.1 create mode 100644 man/mdeltree.1 create mode 100644 man/mdir.1 create mode 100644 man/mdu.1 create mode 100644 man/mformat.1 create mode 100644 man/minfo.1 create mode 100644 man/mkmanifest.1 create mode 100644 man/mlabel.1 create mode 100644 man/mmd.1 create mode 100644 man/mmount.1 create mode 100644 man/mmove.1 create mode 100644 man/mpartition.1 create mode 100644 man/mrd.1 create mode 100644 man/mren.1 create mode 100644 man/mshowfat.1 create mode 100644 man/mtools.1 create mode 100644 man/mtools.5 create mode 100644 man/mtoolstest.1 create mode 100644 man/mtype.1 create mode 100644 man/mzip.1 create mode 100644 match.c create mode 100644 mattrib.1 create mode 100644 mattrib.c create mode 100644 mbadblocks.1 create mode 100644 mbadblocks.c create mode 100644 mcat.1 create mode 100644 mcat.c create mode 100644 mcd.1 create mode 100644 mcd.c create mode 100644 mclasserase.1 create mode 100644 mclasserase.c create mode 100644 mcomp.1 create mode 100644 mcopy.1 create mode 100644 mcopy.c create mode 100644 mdel.1 create mode 100644 mdel.c create mode 100644 mdeltree.1 create mode 100644 mdir.1 create mode 100644 mdir.c create mode 100644 mdoctorfat.c create mode 100644 mdu.1 create mode 100644 mdu.c create mode 100644 mformat.1 create mode 100644 mformat.c create mode 100644 minfo.1 create mode 100644 minfo.c create mode 100644 misc.c create mode 100644 missFuncs.c create mode 100644 mk_direntry.c create mode 100755 mkdosboot create mode 100755 mkinstalldirs create mode 100644 mkmanifest.1 create mode 100644 mkmanifest.c create mode 100755 mkmanpages create mode 100644 mlabel.1 create mode 100644 mlabel.c create mode 100644 mmd.1 create mode 100644 mmd.c create mode 100644 mmount.1 create mode 100644 mmount.c create mode 100644 mmove.1 create mode 100644 mmove.c create mode 100644 mpartition.1 create mode 100644 mpartition.c create mode 100644 mrd.1 create mode 100644 mren.1 create mode 100644 msdos.h create mode 100644 mshortname.1 create mode 100644 mshortname.c create mode 100644 mshowfat.1 create mode 100644 mshowfat.c create mode 100644 mtools.1 create mode 100644 mtools.5 create mode 100644 mtools.c create mode 100644 mtools.conf create mode 100644 mtools.h create mode 100644 mtools.info create mode 100644 mtools.spec create mode 100644 mtools.texi create mode 100644 mtools.tmpl.1 create mode 100644 mtools.tmpl.5 create mode 100644 mtoolsDirentry.h create mode 100644 mtoolsPaths.h create mode 100644 mtoolstest.1 create mode 100644 mtype.1 create mode 100644 mxtar.1 create mode 100644 mzip.1 create mode 100644 mzip.c create mode 100644 nameclash.h create mode 100644 partition.h create mode 100644 patchlevel.c create mode 100644 plain_io.c create mode 100644 plain_io.h create mode 100644 precmd.c create mode 100644 privileges.c create mode 100644 privtest.c create mode 100644 read_dword.h create mode 100755 scripts/add-disk create mode 100755 scripts/amuFormat.sh create mode 100755 scripts/download create mode 100644 scripts/format.dat create mode 100755 scripts/mcheck create mode 100755 scripts/mcomp create mode 100755 scripts/mxtar create mode 100755 scripts/tgz create mode 100755 scripts/uz create mode 100644 scsi.c create mode 100644 scsi.h create mode 100644 signal.c create mode 100644 stream.c create mode 100644 stream.h create mode 100644 streamcache.c create mode 100644 strip-pp.sed create mode 100644 subdir.c create mode 100644 sysconfdir.texi create mode 100644 sysincludes.h create mode 100644 texinfo.tex create mode 100644 tgz.1 create mode 100644 tty.c create mode 100644 unixdir.c create mode 100644 uz.1 create mode 100644 version.texi create mode 100644 vfat.c create mode 100644 vfat.h create mode 100644 xdf_io.c create mode 100644 xdf_io.h diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..db7bbb4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,30 @@ +% Copyright 1996,1997,1999,2001,2002 Alain Knaff. + +% This documentation is for Mtools which is a collection of tools to +% allow Unix systems to manipulate MS-DOS files. + +% Permission is granted to copy, distribute and/or modify this document +% under the terms of the GNU Free Documentation License, Version 1.3 or +% any later version published by the Free Software Foundation; with no +% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +% Texts. A copy of the license is included in the section entitled +% ``GNU Free Documentation License''. + +Installation of mtools is now pretty straightforward: + + 1. Run ./configure + 2. Run make + + Configuration options: + + * Use ./configure --enable-vold to compile mtools to use Solaris' +vold instead of directly accessing the floppy disk + * Use ./configure --disable-xdf to disable support for Xdf disks on Linux + * Use ./configure --enable-new-vold to compile mtools to use the *new* +vold for Solaris. With this, you no longer need precmd=volcheck, and +users don't need to type "eject" before pushing the button. + +Further doc can be found in the manpages, and in the texinfo doc. The +texinfo doc contains the same info as the manpages, but is more up to +date. To generate a printable doc, make dvi. To generate an info file, +make info. diff --git a/Makefile.Be b/Makefile.Be new file mode 100644 index 0000000..8dee7d3 --- /dev/null +++ b/Makefile.Be @@ -0,0 +1,49 @@ +# Copyright 1997 Marco Nelissen +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . +# +# Makefile for Mtools +# +# check the Configure file for some examples of device-specific setups +# Berkeley flavors of Unix should include -DBSD in the CFLAGS. Pick +# a lock method... either -DLOCKF, -DFLOCK, or -DFCNTL and put that +# string in the CFLAGS line below. + +# +# rudimentary makefile for building mtools 3.1 on the BeOS +# + +CC=mwcc -O7 + +OBJS=buffer.o codepage.o codepages.o config.o copyfile.o devices.o \ +directory.o expand.o fat.o fat_free.o file.o file_name.o file_read.o \ +filter.o force_io.o hash.o init.o match.o mainloop.o mattrib.o mbadblocks.o \ +mcd.o mcopy.o mdel.o mdir.o mformat.o minfo.o misc.o missFuncs.o \ +mk_direntry.o mlabel.o mmd.o mmount.o mmove.o mpartition.o mzip.o mtools.o \ +parse.o plain_io.o precmd.o privileges.o scsi.o signal.o stream.o \ +streamcache.o subdir.o toupper.o tty.o vfat.o xdf_io.o + +all: mtools mkmanifest + +$(OBJS): config.h + +config.h: config.h.Be + cp config.h.Be config.h + +mtools: $(OBJS) + $(CC) -o mtools $(OBJS) + +mkmanifest: mkmanifest.o + $(CC) -o mkmanifest mkmanifest.c diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..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 . +# +# 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 ) + Renamed mtest to mtoolstest to please pine. +v19961210 + Added warning about running mtools with root privs. +v19961209 + Fixed unitialized variable in fat.c and added example for Sun + mtools.conf +v19961209 + Fixed comment in scripts/tgz +v19961207 + Fixed partition handling code (yes, again!) + Added code to handle ZIP disks on Solaris/SunOS (many thanks + to James P. Dugal (jpd@usl.edu)) +v19961203 + Proper permissions for main directory. +v19961202 + Renamed scripts/gz to scripts/tgz +v19961202 + Added raw devices for Solaris, apparently more performant + Test first for tzset in autoconfigure (Solaris) +v19961202 + Segment fault due to change of buffer size fixed + E-mail adress fixed +v19961117 + Lots of portability fixes. +v19961012 + Yet another typo fix for the partition table code. Oh Gawd, + will this never stop? + Fix for proper .mcwd pathname concatenations +v19961009 + Backed out partition table "fix": the original code was right + after all +v19960920 + Corrected a few uninitialised variables +v19960918 + Corrected doc about devices file. +v19960917 + Added pointer to the doc to the README file +v19960913 + Partition table parsing fixed +v19960807 + Fujitsu DS/90 (UXP) support +v19960727 + ISC device + dispatcher cleanup in mtools.h + fat_bits 12/16 toggle fix. + More space for error message variable in mformat + Typo fix in mren.1 +v19960710 + Fix for CPU names with dots in autoconfigure + Some new device descriptions + FreeBSD fixes +v19960624 + Set XDF mode when formatting an XDF disk (makes sense, after all...) +v19960623 + XDF seems to work. Yeah! +v19960620 + More ED fixes. More parameter size fixed for 64bit. +v19960609 + Beginning of ED and 5 1/4 HD XDF support (doesn't work yet for + ED) +v19960528 + Make vold and "raw" floppy drive accesible simultaneously on + Solaris by calling one A: and the other B: + Add missing mbadblock LINK in Makefile.in +v19960527 + Inserted missing newline character +v19960525 + Treat number of heads or sectors as chars. The BIOS wouldn't + allow bigger numbers anyways, thus big numbers are probably + due to errors. +v19960524 + Pattern match fix. + Geometry setting for HP/UX +v19960522 + Changed auto array in codepage to malloc'ed one in order to + work around buggy compilers + OSF ALPHA devices + Pointers to other doc in the INSTALL file +v19960516 + Do no longer be confused by deleted VSE's + Define MAXPATHLEN for SCO + Missing lockf prototype for SCO +v19960514 + Handle DEBUG flag by autoconf + Added Host vendor to compile flags in order to handle Sinix + Better Sinix handling in devices.c + Only print duplicate VSE messages when running with DEBUG + Fix mlabel exit code + Read-only locking + Doc fixes + Xcopy fixes for Sysv +v19960512 + 3.0 released. +v19960508 + pre4-3.0. Lots of bug fixes. Texinfo file +v19960502 + pre-3.0 +v19960501 + use autoconf to get rid once and for all of those pesky OS + dependencies. +v19960429 + use sys/termio instead of sys/termios to please AIX +v19960427 + more spelling fixes. +v19960426 + Speling fixes +v19960424 + Mmount arg parsing bug fix +v19960422 + New partition configuration variable. +v19960419 + Spelling fixes, removed warning in README, IRIX floppy devices +v19960214 + More Alpha streamlining +v19960213 + Alpha patches (64 bit clean-ness) + AIX patches (built in drive names) + Raw tty patches (no need to type return when confirming an action +v19960131 + Solaris patches + Replaced include strings.h by string.h everywhere where applicable + Changed thousands separator in mdir from a dot to a space to + please both Americans and Europeans. + Fixed memory allocation bug if no "constant device" is present. + #defined strtoul to atol for SunOS +v19960121 + Minor cleanup, released 2.5.4 +v19951205 + Added "magic" header to manpages to have man run them through tbl +v19951209 + MTOOLS_LOWER_CASE is back, various small bug fixes over + Tuesday's changes +v19951205 + Bus strike in Grenoble! Well, let's do something useful and + re-arrange the configuration file syntax :-) + The syntax has become much more flexible now, and also + includes items which used to be only accessible via + environmental variables. + Moreover, it is now possible to include character translation + tables in line. +v19951126 + Fixed another Atari disk bug: Atari disks sport a bogus + "number of hidden sectors" +v19951125 + Fixed missing zero-terminator in autorenamed long names + MTOOLS_SKIP_CHECK now implies MTOOLS_FAT_COMPATIBILITY. +v19951124 + Fixed small quoted-printable-induced typo in the Makefile. + + Folks, please don't use quoted-printable. It sometimes changes + the CONTENT of your messages. Even the MIME RFC's acknowledge this. + Case in point: £400 gets transformed into =A3400, which looks + like 3400 pounds to a person unaware of this MIME "feature". + +v19951123 + Mformat now puts a 12 bit FAT on ED to better match Messy DOS' + behavior. +v19951115 + Added ability to do mcopy e: to copy all files from the root + directory of e: + New Xdf-less Linux target in the Makefile + Relaxed sanity check to let pass wonky Atari disks whose FAT + begins with 3 zero bytes. + Make the check of the initial fat bytes conditional on + mtools_skip_check + Corrected "testna=" bug + Upped minimal sector size to be 256 (instead of 128). This + helps 2m30 +v19951112 + 2m30 compatibility + Manpage update + 2m checksum bug fix + Ability to mformat 2m disks +v19951107 + Xdf bug fix (dev parameters always set to Xdf, even if it + wasn't really an Xdf disk) + Fixed YAHB (yet another hash table bug :) ) . Hope this one's + the last. + Centralizing most env-var handling. + Update of the mtools manpage. + Xdf is now optional, and only active if MTOOLS_USE_XDF is + set. Saves a few milliseconds of startup time on non Xdf + disks. + Some lawyer-proofing, just in case :) +v19951106 + Fast xdf code (finally!) + Minor performance enhancements here and there. + Names which are all lower case now generate a long name entry + (according to Steve Searle, that's how Win'95 behaves). +v19951029 + Character translation table fixes. Other name fixes. +v19951026 + Put restrictions on long names to better match Win'95. + (suggested by Steve Searle) + Reworked autorename code. Catch SIGHUP signal + Added missing file close to main loop + Changed name of the "ask for action" command line flag to 'm', + and used 'a' for 'Autorename'. +v19951024 + Removed infinite loop bug in hash.c, which occurred when the + hash table was filled with deleted entries. +v19951023 + added Atari ST-style serial numbers (they live in the banner) + fixed a troff bug in mtools.1 + Both changes were suggested by D. Hugh Redelmeier (hugh@mimosa.com) +v19950916 + v2.5.3 released (after lots of fixes) +v19950904 + v2.5.2 released +v19950904 + mdir.c: initialized "files" and "blocks" to avoid complaint by GCC + mattrib.c: initialized "code" to avoid complaint by GCC +v19950904 + Based on comments by Paul Slootman : + init.c: fs_init(): initialized disk_size to 0. The section + which previously initialized this is ifdef'd out. Why? + Makefile, device.c: Passed ETCDIR (e.g. /etc or /etc/default) + Gee, the Makefile is pretty ugly! It might be good to start + thinking about autoconfigure, or at least some cleanup. + Makefile, mformat.c: use -DSOLARIS2, use srand48()/rand48() + msdos.h, file.c, mdir.c: prefixed YEAR/MONTH/DAY/HOUR/MINUTE/ + SEC with DOS_ to avoid conflicts with on SVR4 + devices.c: use %i instead of %d to allow different bases + parse.c: Changed comment for get_name()/get_path(); need to + revisit this after deciding on default case behavior + devices.c: load_devices(): fixed bad fprintf, line 748 + parse.c, mformat.c, misc.c: replaced expressions like + "if (islower(foo)) foo=toupper(foo)" with "foo=toupper(foo)" + +v19950829 + v2.5.1 released + +v19950829 + Based on comments by Martin Kraemer : + Bug fixes for compile errors and core dumps under SINIX-D 5.41 + (Siemens SVR4): + plain_io.c + mk_direntry.c + vfat.h + +v19950822 v2.5 released + +v19950820 DCN + Change null-fill for unused remainder of VSE to 0xff fill for + both upper and lower character (just one null for termination) + This seems to better match Win95's behavior; Win95 had been + complaining about bogus characters + file_name.c: unicode_write() + +v19950820 DCN + Commented out enforcement of VSEs being in order. Win95 likes + to put them exactly backwards, so we'd better tolerate getting + them any way they might come! Not sure what is lost by losing + these checks, but it seems to be OK. + + directory.c: dir_read() + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/README b/README new file mode 100644 index 0000000..9befffd --- /dev/null +++ b/README @@ -0,0 +1,76 @@ +Compilation +----------- + + To compile mtools on Unix, first type ./configure, then make. To +compile mtools on a Bebox, refer to README.BEBOX. + +Doc +--- + + The most uptodate doc of this package is the texinfo doc. Type 'make +info' to get online info doc, and 'make dvi ; dvips mtools.dvi' to get +a printed copy. The info doc has a concept index. Make use of it. + You may get an info copy using the following command 'make info'. +This can then be viewed using emacs' info mode, or using a standalone +info viewer. + Man pages are still present, but contain less information. + If you do not have the necessary tools to view the texinfo doc, you +may also find it on the World Wide Web at the following locations: + http://ftp.gnu.org/software/mtools/manual/mtools.html + +Compiler +-------- + + Mtools should be compiled with an Ansi compiler, preferably gcc + +Authors +------- + +Original code (versions through 2.0.7?) by Emmet P. Gray (Texas, USA). +Viktor Dukhovni (at Princeton, USA) had major input into v2.0. + +Since 2.0.7: maintained primarily and until now by Alain Knaff +(Luxembourg) and David Niemi (Reston, Virginia, USA). + +Please report bugs to the mtools mailing list at mtools@www.tux.org. +Before reporting any problems, check whether they have already been +fixed in the Alpha patches at http://mtools.linux.lu and +http://www.tux.org/pub/knaff + +You may subscribe to the mtools mailing list by sending a message +containing 'subscribe mtools' in its body to majordomo@www.tux.org + +Since March 3rd 2009, mtools is now officially a GNU package. Special +thanks to Emmet P. Gray, the original developer of the program, who +supported dubbing mtools a GNU package. + +Current Status +-------------- + +Stable release 4.0.x + +Copying +------- +Mtools is a GNU program published under GPL v3.0 (code) and GNU Free +Documentation License. + +Most files of mtools bears a notice describing the copyright, and +whether it is covered by GPL or GFDL + +GPL: + +debian/control Copyright 2007 Alain Knaff + +debian/changelog Copyright 2007-2009 Alain Knaff + +NEWS Copyright 1995 David C. Niemi + Copyright 1995-2009 Alain Knaff + +mtools.spec Copyright 2003-2005,2007-2009 Alain Knaff + + +GFDL: + +README Copyright 1996-1998,2001,2002,2009 Alain Knaff. +Release.notes Copyright 1995 Alain Knaff + diff --git a/README.BEBOX b/README.BEBOX new file mode 100644 index 0000000..29e6bfa --- /dev/null +++ b/README.BEBOX @@ -0,0 +1,126 @@ +% Copyright 1997 Marco Nelissen. +% Copyright 1996-1998,2001,2002,2009 Alain Knaff. +% This documentation is for Mtools which is a collection of tools to +% allow Unix systems to manipulate MS-DOS files. + +% Permission is granted to copy, distribute and/or modify this document +% under the terms of the GNU Free Documentation License, Version 1.3 or +% any later version published by the Free Software Foundation; with no +% Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +% Texts. A copy of the license is included in the section entitled +% ``GNU Free Documentation License''. + + + +NOTE: THIS FILE ONLY REFERS TO THE BEBOX. IF YOU ARE USING UNIX, +REFER TO README. + + +This is mtools 3.6 for BeOS DR9. This release will no longer work on +DR8, which should be no problem since everybody should have upgraded +to DR9 by now. mtools 3.6 can be used as a replacement for the +version 2.0.7 mtools supplied with BeOS. mtools 3.6 supports the VFAT +filesystem (long filenames), which the Be-supplied tools do not. + +To install: + +- build the executables: type "make -f Makefile.Be" in the mtools + directory. Again, this instruction is only for the Bebox, not for any + kind of Unix. They should compile without any warnings or errors. + + WARNING: do NOT rerun the configure script. Although DR9 bash will +no longer lock up when running the configure script, the resulting +files are not entirely correct, and mtools will fail to compile. I +have hand-crafted a config.h that can be used to compile mtools. This +will be used if you just type "make -f Makefile.Be" + +- copy the "mtools" executable (and perhaps also "mkmanifest") to /bin, + or to another directory in your path. + +Since all of the mtools-commands are contained within a single +executable, you must either define aliases for each command, or create +links for them. + +To create aliases, add the following lines to the file /boot/.profile + +alias mattrib="mtools -c mattrib" +alias mbadblocks="mtools -c mbadblocks" +alias mcd="mtools -c mcd" +alias mcopy="mtools -c mcopy" +alias mdel="mtools -c mdel" +alias mdeltree="mtools -c mdeltree" +alias mdir="mtools -c mdir" +alias mformat="mtools -c mformat" +alias minfo="mtools -c minfo" +alias mlabel="mtools -c mlabel" +alias mmd="mtools -c mmd" +alias mmount="mtools -c mmount" +alias mrd="mtools -c mrd" +alias mmove="mtools -c mmove" +alias mpartition="mtools -c mpartition" +alias mren="mtools -c mren" +alias mtoolstest="mtools -c mtoolstest" +alias mtest="mtools -c mtest" +alias mtype="mtools -c mtype" +alias mzip="mtools -c mzip" + + (then close and re-open all terminals and shells, or type +". /boot/.profile" in each open terminal to activate the +aliases. Optional: remove the old mtools from the /bin directory) + + +To create links, open a shell, and type the following commands +(assuming you copied the mtools executable to /bin): + +cd /bin +rm mattrib mcd mcopy mdel mdir mformat mkmanifest mlabel mmd mrd mread mren mtype mwrite +ln -s mtools mattrib +ln -s mtools mbadblocks +ln -s mtools mcd +ln -s mtools mcopy +ln -s mtools mdel +ln -s mtools mdeltree +ln -s mtools mdir +ln -s mtools mformat +ln -s mtools minfo +ln -s mtools mlabel +ln -s mtools mmd +ln -s mtools mmount +ln -s mtools mrd +ln -s mtools mread +ln -s mtools mmove +ln -s mtools mpartition +ln -s mtools mren +ln -s mtools mtoolstest +ln -s mtools mtest +ln -s mtools mtype +ln -s mtools mwrite +ln -s mtools mzip + + +Alternatively, make multiple copies of the "mtools" executable and use +the names mdir, mdel etcetera. + +- if you want more than just floppy support, you need to make a configuration + file. An example mtools.conf.be is included in the distribution. + mtools looks in a number of standard places for its config file, such as: + /boot/.mtoolsrc + /boot/mtools.conf + /boot/system/mtools.conf + By defining the variable MTOOLSRC you can give the config file any name you + like and put it at any location. + + You need to add something like "export MTOOLSRC=/conf/mtools.cfg" to + your .profile file. + + Take care to remove or change the entries that you don't need. The provided + mtools.conf is for unix systems, with some BeOS settings at the end. + The sample entry for a ZIP disk on the BeOS has been provided by + Chris Herborth + (chrish@qnx.com). + + +- enjoy! + +Marco Nelissen +Alain Knaff diff --git a/Release.notes b/Release.notes new file mode 100644 index 0000000..f434b4a --- /dev/null +++ b/Release.notes @@ -0,0 +1,230 @@ +[See Changelog for more recent changes] + +2.5.1 29 Aug 1995 + +Bug fixes to allow compiling and running on SINIX-D 5.41, thanks to +Martin Kraemer . + +----------------------------------------------------------------------------- +2.5 21 Aug 1995 + +First public Alpha Test release of the newly rewritten Mtools. +Summary of the many major changes: + +XDF support, ANSIfication, major restructuring, and debugging (Alain Knaff) +VFAT support, new prompts for overwrites, and debugging (David Niemi) + +----------------------------------------------------------------------------- +Patch #7alk ... 4 Dec 94 + +This patch adds the following features: + + 1) mbadblocks program to mark bad blocks + 2) uses fat_type field of boot block to find out the number + of fat bits. + 3) is able to format hard disk partitions (untested) + 4) sets _all_ standard fields in boot sector, even without 2m mode. + 5) adds boot code to the boot sector (which transfers booting to + the hard drive. In most cases, that's what the user wants.) + +----------------------------------------------------------------------------- +Patch #7alk ... 4 Nov 94 + +This patch adds the following features: + + 1) Use even disk buffer size whenever possible to workaround a + bug in Linux blockdev code [???] + 2) Clearer error message on failed sanity check + 3) Removal of BOGUS Notes file + +----------------------------------------------------------------------------- +Patch #7alk quinter, 2 Nov 94 + +This patch adds the following features: + + 1) O_EXCL flag when opening the device to ensure it is not mounted + 2) Sanity checks to avoid accessing non msdos disks +Both features were suggested by Karl Eichwalder (ke@pertron.central.de) + +----------------------------------------------------------------------------- +Patch #7alk quater, 1 Oct 94 + +This patch adds the following features: + + 1) disk serial number support. + 2) mcheck works for every drive. + +----------------------------------------------------------------------------- +Patch #7alk ter, 10 Sep 94 + +This patch adds the following features: + + 1) mformat works again. + 2) mmount allows the user to pass arbitrary arguments to mount. + Floppy disks are no longer mounted by default on /mount/A /mount/B + etc. + +----------------------------------------------------------------------------- +Patch #7alk bis, 18 jul 94 + +This patch adds the following features: + + 1) Support for variable sector sizes. + 2) Support for "2m" formats. + 3) Support for formatting 16-bit fat disks. + 4) Support for formatting ED disks (Their capacity is too big to + use a 12 bit FAT and 1 sector clusters. Either use bigger + clusters or a 16 bit FAT) + 5) Mcopying from one DOS drive to another works now. (It used to + call mktemp on a non-writable string) + +----------------------------------------------------------------------------- +Patch #7alk, 16 feb 94 + +This patch adds the following features: + + 1) Mtools can now set the disk geometry on Linux. (Useful for + reading 1.72 Mb disks. This was already possible on unixpc and + SPARC ) + 2) New mmount command. Reads the boot sector, sets the geometry + and finally mounts the disk. Only available for Linux. + 3) Mwrite can now write stdout to a DOS file: mwrite - a:test + 4) Mread now also acts as mtype: mread a:test - + 5) Mtools now tries 3 sources to get its drive geometry. + configuration: first ~/.mtoolsrc, then /etc/mtools, and finally + compiled-in. ( The two first are conditional on LOADDEVS being + defined ). LOADDEVS is now compatibles with the various geometry + setting routines (init_linux, init_sparc and init_unixpc). + 6) Bug fixes for -t mode of mwrite and mread. ( For certain file sizes + the trailing DOS end-of-file character wasn't correctly written.) + 7) Bug fixes for "drive probing code." (Now failure to lock onto a disk + causes always trial of the next configuration. Before, mtools used + to abort on certain cases). Similar fixes in mformat. + 8) Optimization/bug fix of cluster/fat repartition in mformat.c + 9) Made fat checking code optional. (1.72mb disks mformatted with old + mtools were almost always rejected) To bypass fat-checking set the + environment variable MTOOLS_FAT_COMPATIBILITY + 10) Mtools now opens /dev/tty to ask for confirmation messages. This + way, it doesn't interfere with mreading/mwriting from/to stdin/stdout. + + +CAUTION: I only tested this with Sparc and Linux. Although I left #ifdefs +for other OS's in devices.c, that doesn't mean that it works on these OS's. + +----------------------------------------------------------------------------- +Patch #7+, 19 sep 93 + +This patch merges in the mods against 2.05 under Linux. Two are the main +changes: that all commands are linked as a single executable, which can +be linked as different name, and that the device specs are no longer +hardcompiled but are read dynamically from /etc/mtools (the latter change +is conditional on LOADDEVS being defined). + +----------------------------------------------------------------------------- +Patch #7, 6 Sep 92 + +This patch will change the method of determining if the FAT encoding +scheme in the devices.c file is correct. The method introduced by patch +#6 was naive and easily fooled. + +A pre-processor variable called CHK_FAT has been added to the fat_read.c +file just in case this new method isn't appropriate for all disks. + +----------------------------------------------------------------------------- +Patch #6, 21 Aug 92 + +This patch will add the following features: + + 1) Mtools commands now use advisory locks to preclude two + processes from writing to the same DOS filesystem. You must + edit the Makefile to choose one of the 3 lock methods: + -DLOCKF, -DFLOCK, or -DFCNTL. + See the Configure file for more details. + + 2) An error detection routine has been added to determine if the + FAT encoding scheme in the devices.c file is correct. + + 3) Mtools commands now return exit codes with the following + meaning: + 0 = success + 1 = utter failure + 2 = partial success/failure. (at least one successful + operation, but at least one failure) + +It also corrects a bug when Mtools is used on machines that have 16 bit +integers. However, machines with 16 bit integers are limited to FAT +tables that are less than 64k in length. +------------------------------------------------------------------------------- +Patch #5, 25 Aug 91 + +This patch will add a few new features: + + 1) Mtools will now work properly on MSDOS partitions that are + greater than 32M. + + 2) If the "current working directory" information (contained in + the $HOME/.mcwd file) is more than 6 hours old, Mtools will + issue a warning and ignore the old information. + + 3) The mcopy command will now copy files between 2 MS-DOS file + systems (such as mcopy "a:*" b:). + +------------------------------------------------------------------------------- +Patch #4, 11 Apr 91 + + This patch will fix a bug in the mmd command where directories + inherited the file name extension of the parent directory. It + also adds a feature that will allow the copying of zero length + files. + +------------------------------------------------------------------------------- +Patch #3, 28 Nov 90 + + This patch will fix a bug where Mtools sometimes bypasses the + disk "cache" and reads/writes to the disk directly. + +------------------------------------------------------------------------------- +Patch #2, 21 Nov 90 + + This patch will fix a bug in the folding of MS-DOS filenames to + lower case, and will fix a bug that could prevent the detection + of a full disk. + +------------------------------------------------------------------------------- +Patch #1, 12 Oct 90 + + This patch will fix a few problems on Berkeley flavors of Unix, + and will fix the floating point exception bug when Mtools is + used with diskettes that have been formatted under very old DOS + (or formatted by some other non-DOS system). + +------------------------------------------------------------------------------- +New in the v2.0 release.... + + 1) Support for multiple devices. Mtools now supports: + multiple floppy disks (A:, B:, etc) + DOS partitions on a hard disk + DOS "images" such as those VP/ix uses. + + 2) Wildcards are supported anywhere in a pathname (not just + in the "filename" part as before) + + 3) Reads and writes to slow devices are now "cylinder buffered" + when appropriate. + + 4) Versions of CD, FORMAT, LABEL, and ATTRIB have been added. + + 5) A Mtools.1 manual page has been added for an overview of Mtools. + + 6) The mkmanifest command has been added. Although not an 'mtool' + command, it makes life easier when fixing up Unix filenames that + get clobbered by MS-DOS file name restrictions. + + 7) The mkdfs program of the "fast-mtools" release for the Sun + SparcStation can be replaced with mformat. + + 8) The Configure file has been included to help those who must add + devices to the devices.c file. + + Many thanks to Viktor Dukhovni (viktor@math.princeton.edu) for + many of the ideas in the new release. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..50b2e21 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,34 @@ +dnl Copyright 1997,2001-2003 Alain Knaff. +dnl This file is part of mtools. +dnl +dnl Mtools is free software: you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation, either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl Mtools is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with Mtools. If not, see . +dnl +dnl Check for declaration of sys_errlist in one of stdio.h and errno.h. +dnl Declaration of sys_errlist on BSD4.4 interferes with our declaration. +dnl Reported by Keith Bostic. +AC_DEFUN([CF_SYS_ERRLIST], +[ +AC_MSG_CHECKING([declaration of sys_errlist]) +AC_CACHE_VAL(cf_cv_dcl_sys_errlist,[ + AC_TRY_COMPILE([ +#include +#include +#include ], + [char *c = (char *) *sys_errlist], + [cf_cv_dcl_sys_errlist=yes], + [cf_cv_dcl_sys_errlist=no])]) +AC_MSG_RESULT($cf_cv_dcl_sys_errlist) +test $cf_cv_dcl_sys_errlist = no || AC_DEFINE([DECL_SYS_ERRLIST],1,[Define when sys_errlist is defined in the standard include files]) +])dnl +dnl diff --git a/buffer.c b/buffer.c new file mode 100644 index 0000000..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 . + * + * 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 . + */ + +#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 . + */ + +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 . + * + * Various character set conversions used by mtools + */ +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +#include +#include +#include +#include "file_name.h" + + +#ifdef HAVE_ICONV_H +#include + +struct doscp_t { + iconv_t from; + iconv_t to; +}; + +static 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; ito, wchar, dos, len, mangled); +} + +#else + +#include "codepage.h" + +struct doscp_t { + unsigned char *from_dos; + unsigned char to_dos[0x80]; +}; + +doscp_t *cp_open(int codepage) +{ + doscp_t *ret; + int i; + Codepage_t *cp; + + if(codepage == 0) + codepage = 850; + + ret = New(doscp_t); + if(ret == NULL) + return ret; + + for(cp=codepages; cp->nr ; cp++) + if(cp->nr == codepage) { + ret->from_dos = cp->tounix; + break; + } + + if(ret->from_dos == NULL) { + fprintf(stderr, "Bad codepage %d\n", codepage); + free(ret); + return NULL; + } + + for(i=0; i<0x80; i++) { + char native = ret->from_dos[i]; + if(! (native & 0x80)) + continue; + ret->to_dos[native & 0x7f] = 0x80 | i; + } + return ret; +} + +void cp_close(doscp_t *cp) +{ + free(cp); +} + +int dos_to_wchar(doscp_t *cp, char *dos, wchar_t *wchar, size_t len) +{ + int i; + + for(i=0; i= ' ' && c <= '~') + wchar[i] = c; + else { + wchar[i] = cp->from_dos[c & 0x7f]; + } + } + wchar[i] = '\0'; + return i; +} + + +void wchar_to_dos(doscp_t *cp, + wchar_t *wchar, char *dos, size_t len, int *mangled) +{ + int i; + for(i=0; i= ' ' && c <= '~') + dos[i] = c; + else { + dos[i] = cp->to_dos[c & 0x7f]; + if(dos[i] == '\0') { + dos[i]='_'; + *mangled=1; + } + } + } +} + +#endif + + +#ifndef HAVE_WCHAR_H + +typedef int mbstate_t; + +static inline size_t wcrtomb(char *s, wchar_t wc, mbstate_t *ps) +{ + *s = wc; + return 1; +} + +static inline size_t mbrtowc(wchar_t *pwc, const char *s, + size_t n, mbstate_t *ps) +{ + *pwc = *s; + return 1; +} + +#endif + +#ifdef HAVE_ICONV_H + +#include + +static iconv_t to_native = NULL; + +static void initialize_to_native(void) +{ + char *li, *cp; + int len; + if(to_native != NULL) + return; + li = nl_langinfo(CODESET); + len = strlen(li) + 11; + if(getWcharCp() == NULL) + exit(1); + cp = safe_malloc(len); + strcpy(cp, li); + strcat(cp, "//TRANSLIT"); + to_native = iconv_open(cp, wcharCp); + if(to_native == (iconv_t) -1) + to_native = iconv_open(li, wcharCp); + if(to_native == (iconv_t) -1) + fprintf(stderr, "Could not allocate iconv for %s\n", cp); + free(cp); + if(to_native == (iconv_t) -1) + exit(1); +} + + + +#endif + + +/** + * Convert wchar string to native, converting at most len wchar characters + * Returns number of generated native characters + */ +int wchar_to_native(const wchar_t *wchar, char *native, size_t len) +{ +#ifdef HAVE_ICONV_H + int mangled; + int r; + initialize_to_native(); + len = wcsnlen(wchar,len); + r=safe_iconv(to_native, wchar, native, len, &mangled); + native[r]='\0'; + return r; +#else + int i; + char *dptr = native; + mbstate_t ps; + memset(&ps, 0, sizeof(ps)); + for(i=0; i= '\xa0' && c < '\xff') + wchar[i] = c & 0xff; + else + wchar[i] = '_'; + memset(&ps, 0, sizeof(ps)); + r=1; + } + if(r == 0) + break; + native += r; + } + if(mangled && ((end && native < end) || (!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 . + +# Removes all autoconfig related files +rm -f config.sub config.guess configure config.h.in diff --git a/codepage.h b/codepage.h new file mode 100644 index 0000000..8775865 --- /dev/null +++ b/codepage.h @@ -0,0 +1,42 @@ +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +typedef struct Codepage_l { + int nr; + unsigned char tounix[128]; +} Codepage_t; + + +typedef struct country_l { + int country; + int codepage; + int default_codepage; + int to_upper; +} country_t; + + +void init_codepage(void); +unsigned char to_dos(unsigned char c); +void to_unix(char *a, int n); +char contents_to_unix(char a); + +extern Codepage_t *Codepage; +extern char *mstoupper; +extern country_t countries[]; +extern unsigned char toucase[][128]; +extern Codepage_t codepages[]; +extern char *country_string; diff --git a/codepages.c b/codepages.c new file mode 100644 index 0000000..5558724 --- /dev/null +++ b/codepages.c @@ -0,0 +1,117 @@ +/* Copyright 1996,1997,1999,2001,2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + * + */ +#include "config.h" + +#ifndef HAVE_ICONV_H +#include "codepage.h" + +Codepage_t codepages[]= { + { 437, + "ÇüéâäàåçêëèïîìÄÅ" + "ÉæÆôöòûùÿÖÜ¢£¥Pf" + "áíóúñѪº¿r¬½¼¡«»" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__" + }, + + { 819, + "________________" + "________________" + " ¡¢£¤¥¦§¨©ª«¬­®¯" + "°±²³´µ¶·¸¹º»¼½¾¿" + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ" + "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß" + "àáâãäåæçèéêëìíîï" + "ðñòóôõö÷øùúûüýþÿ" + }, + + { 850, + "ÇüéâäàåçêëèïîìÄÅ" + "ÉæÆôöòûùÿÖÜø£Ø×_" + "áíóúñѪº¿®¬½¼¡«»" + "_____ÁÂÀ©____¢¥¬" + "______ãÃ_______¤" + "ðÐÉËÈiÍÎÏ____|I_" + "ÓßÔÒõÕµþÞÚÙýÝÞ¯´" + "­±_¾¶§÷¸°¨·¹³²__" + }, + + { 852, + "ÇüéâäucçlëÕõîZÄC" + "ÉLlôöLlSsÖÜTtL×c" + "áíóúAaZzEe zCs«»" + "_____ÁÂES____Zz¬" + "______Aa_______¤" + "ðÐDËdÑÍÎe_r__TU_" + "ÓßÔNnñSsRÚrUýÝt´" + "­~.~~§÷¸°¨·¹uRr_" + }, + + { 860, + "ÇüéâãàåçêëèÍõìÃÂ" + "ÉÀÈôõòÚùÌÕÜ¢£ÙPÓ" + "áíóúñѪº¿Ò¬½¼¡«»" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__" + }, + + { 863, + "ÇüéâÂà¶çêëèïî_À§" + "ÉÈÊôËÏûù¤ÔÜ¢£ÙÛf" + "|´óú¨ ³¯Îr¬½¼¾«»" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__" + }, + + { 865, + "ÇüéâäàåçêëèïîìÄÅ" + "ÉæÆôöòûùÿÖÜø£ØPf" + "áíóúñѪº¿r¬½¼¡«¤" + "_______________¬" + "________________" + "________________" + "abgpSsµtftodøØ_N" + "=±<>||÷~°··Vn²__", + }, + + /* Taiwanese (Chinese Complex Character) support */ + { 950, + "€‚ƒ„…†‡ˆ‰Š‹ŒŽ" + "‘’“”•–—˜™š›œžŸ" + " ¡¢£¤¥¦§¨©ª«¬­®¯" + "°±²³´µ¶·¸¹º»¼½¾¿" + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ" + "ÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß" + "àáâãäåæçèéêëìíîï" + "ðñòóôõö÷øùúûüýþÿ", + }, + + + { 0 } +}; + +#endif diff --git a/config.c b/config.c new file mode 100644 index 0000000..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 . + * + */ +#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 . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -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 /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -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 + 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 + #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' /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 + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + 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 < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.Be b/config.h.Be new file mode 100644 index 0000000..fe08c4d --- /dev/null +++ b/config.h.Be @@ -0,0 +1,56 @@ +/* + * Copyright 1997 Marco Nelissen + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#define PREFIX "/boot/system" +#define HAVE_ATEXIT +#define HAVE_FCNTL_H +#define HAVE_GETOPT_H +#define HAVE_LIMITS_H +#define HAVE_SYS_IOCTL_H +#define TIME_WITH_SYS_TIME 1 +#define HAVE_TERMIOS_H +#define HAVE_SYS_PARAM_H +#define HAVE_STRING_H +#define HAVE_MEMORY_H +#define HAVE_MALLOC_H +#define HAVE_UTIME_H +#define HAVE_SYS_WAIT_H +#define HAVE_MEMCPY +#define HAVE_MEMSET +#define HAVE_STRERROR +#define HAVE_STRNCASECMP +#define HAVE_STRCASECMP +#undef HAVE_GETPASS +#define HAVE_STDLIB_H +#define HAVE_STRCHR +#define HAVE_STRRCHR +#define HAVE_UNISTD_H +#define RETSIGTYPE void +#define HAVE_STRDUP +#define HAVE_STRPBRK +#define HAVE_STRSPN +#define HAVE_STRTOUL +#define HAVE_STRCSPN +#define HAVE_RANDOM +#define random rand +#define HAVE_SRANDOM +#define srandom srand +#define INIT_NOOP +#include +#define SYSCONFDIR "/boot/system" +#define USE_RAWTERM diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..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 header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ASSERT_H + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if you have the `basename' function. */ +#undef HAVE_BASENAME + +/* Define to 1 if 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 header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `flock' function. */ +#undef HAVE_FLOCK + +/* Define to 1 if you have the `getgroupid' function. */ +#undef HAVE_GETGROUPID + +/* Define to 1 if you have the header file. */ +#undef HAVE_GETOPT_H + +/* Define to 1 if you have the `getpass' function. */ +#undef HAVE_GETPASS + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the `getuserid' function. */ +#undef HAVE_GETUSERID + +/* Define to 1 if you have the `htons' function. */ +#undef HAVE_HTONS + +/* Define to 1 if you have the header file. */ +#undef HAVE_ICONV_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `bsd' library (-lbsd). */ +#undef HAVE_LIBBSD + +/* Define to 1 if you have the `cam' library (-lcam). */ +#undef HAVE_LIBCAM + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBC_H + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `sun' library (-lsun). */ +#undef HAVE_LIBSUN + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_FS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_UNISTD_H + +/* Define to 1 if you have the `llseek' function. */ +#undef HAVE_LLSEEK + +/* Define when you have an LLSEEK prototype */ +#undef HAVE_LLSEEK_PROTOTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the `lockf' function. */ +#undef HAVE_LOCKF + +/* Define when the compiler supports LOFF_T type */ +#undef HAVE_LOFF_T + +/* Define when the compiler supports LONG_LONG type */ +#undef HAVE_LONG_LONG + +/* Define to 1 if you have the `lseek64' function. */ +#undef HAVE_LSEEK64 + +/* Define when you have an LSEEK64 prototype */ +#undef HAVE_LSEEK64_PROTOTYPE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `media_oldaliases' function. */ +#undef HAVE_MEDIA_OLDALIASES + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_MNTENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define when the compiler supports OFFSET_T type */ +#undef HAVE_OFFSET_T + +/* Define when the system has a 64 bit off_t type */ +#undef HAVE_OFF_T_64 + +/* Define to 1 if you have the `on_exit' function. */ +#undef HAVE_ON_EXIT + +/* Define to 1 if you have the `putwc' function. */ +#undef HAVE_PUTWC + +/* Define to 1 if you have the `random' function. */ +#undef HAVE_RANDOM + +/* Define to 1 if you have the `setenv' function. */ +#undef HAVE_SETENV + +/* Define to 1 if you have the `seteuid' function. */ +#undef HAVE_SETEUID + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define to 1 if you have the `setpgrp' function. */ +#undef HAVE_SETPGRP + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the header file. */ +#undef HAVE_SGTTY_H + +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if you have the `srandom' function. */ +#undef HAVE_SRANDOM + +/* Define to 1 if you have the `stat64' function. */ +#undef HAVE_STAT64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strcspn' function. */ +#undef HAVE_STRCSPN + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strncasecmp' function. */ +#undef HAVE_STRNCASECMP + +/* Define to 1 if you have the `strnlen' function. */ +#undef HAVE_STRNLEN + +/* Define to 1 if you have the `strpbrk' function. */ +#undef HAVE_STRPBRK + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strspn' function. */ +#undef HAVE_STRSPN + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_FLOPPY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SIGNAL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSMACROS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TERMIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the `tcflush' function. */ +#undef HAVE_TCFLUSH + +/* Define to 1 if you have the `tcsetattr' function. */ +#undef HAVE_TCSETATTR + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_TERMIO_H + +/* Define to 1 if you have the `tzset' function. */ +#undef HAVE_TZSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `utime' function. */ +#undef HAVE_UTIME + +/* Define to 1 if you have the `utimes' function. */ +#undef HAVE_UTIMES + +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if you have the `wcscasecmp' function. */ +#undef HAVE_WCSCASECMP + +/* Define to 1 if you have the `wcsdup' function. */ +#undef HAVE_WCSDUP + +/* Define to 1 if you have the `wcsnlen' function. */ +#undef HAVE_WCSNLEN + +/* Define to 1 if you have the header file. */ +#undef HAVE_WCTYPE_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the 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 and . */ +#undef TIME_WITH_SYS_TIME + +/* Define to 1 if your declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Define when you want to include floppyd support */ +#undef USE_FLOPPYD + +/* Define on non Unix OS'es which don't have the concept of tty's */ +#undef USE_RAWTERM + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Define this if you want to use Xdf */ +#undef USE_XDF + +/* Define this if you use mtools together with the new Solaris' vold support + */ +#undef USING_NEW_VOLD + +/* Define this if you use mtools together with Solaris' vold */ +#undef USING_VOLD + +/* Define to 1 if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/config.sub b/config.sub new file mode 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 . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + 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 &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 +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='LTLIBOBJS +LIBOBJS +HOST_ID +SHLIB +MACHDEPLIBS +extralibdir +extraincludedir +BINFLOPPYD +FLOPPYD +X_EXTRA_LIBS +X_LIBS +X_PRE_LIBS +X_CFLAGS +XMKMF +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +INSTALL_INFO +LN_S +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +EGREP +GREP +CPP +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_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 if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + XMKMF Path to xmkmf, Makefile generator for X Window System + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +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 +#include +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 &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 declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#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 +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 +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + 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 to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#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 +_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 to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#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 +_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 +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 +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 +#include +#include +#include + +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 + +_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 + +_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 +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +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 +#include +#include +#include + +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 + +_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 + +_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 +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +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 +#include +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +int +main () +{ + int s; + wait (&s); + s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; + ; + return 0; +} +_ACEOF +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 +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 + +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 +#include +#include + +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 +#include + +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 +#include + +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 +#include + +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 +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 +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 +#include +#include +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 +_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 +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` +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 +' >$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 +' >$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 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 . +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 ], [extern int llseek(int);], + [mtools_cv_have_llseek_prototype=no], + [mtools_cv_have_llseek_prototype=yes])) +AC_MSG_RESULT($mtools_cv_have_llseek_prototype) +if test "$mtools_cv_have_llseek_prototype" = yes; then + AC_DEFINE([HAVE_LLSEEK_PROTOTYPE],1,[Define when you have an LLSEEK prototype]) +fi + +AC_MSG_CHECKING(whether lseek64 declared in unistd.h) +AC_CACHE_VAL(mtools_cv_have_lseek64_prototype, + AC_TRY_COMPILE( +[ +#include "sysincludes.h" +#include +], [extern int lseek64(int);], + [mtools_cv_have_lseek64_prototype=no], + [mtools_cv_have_lseek64_prototype=yes])) +AC_MSG_RESULT($mtools_cv_have_lseek64_prototype) +if test "$mtools_cv_have_lseek64_prototype" = yes; then + AC_DEFINE([HAVE_LSEEK64_PROTOTYPE],1,[Define when you have an LSEEK64 prototype]) +fi + + +AC_CHECK_FUNCS(htons) + +dnl Apparently termio before termios is preferred by A/UX, AIX and SCO + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM + + +dnl Checks for library functions. +AC_TYPE_SIGNAL +AC_CHECK_FUNCS(strerror random srandom strchr strrchr lockf flock \ +strcasecmp strncasecmp strnlen atexit on_exit getpass memmove \ +strdup strcspn strspn strtoul strtol memcpy strpbrk memset setenv \ +seteuid setresuid setpgrp \ +tcsetattr tcflush basename fchdir media_oldaliases llseek lseek64 \ +snprintf stat64 setlocale \ +wcsdup wcscasecmp wcsnlen putwc \ +getuserid getgroupid \ +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 +#include +],[ +switch (0) case 0: case (sizeof (off_t) <= 4):; +], sfs_cv_off_t_64=no, sfs_cv_off_t_64=yes)) +if test $sfs_cv_off_t_64 = yes; then + AC_DEFINE([HAVE_OFF_T_64],1,[Define when the system has a 64 bit off_t type]) +fi]) + + +dnl ICE_CC_LOFF_T +dnl ------------- +dnl +dnl If the CC compiler supports `loff_t' type, define `HAVE_LOFF_T'. +dnl +AC_DEFUN(ICE_CC_LOFF_T, +[ +AC_MSG_CHECKING(whether ${CC} supports loff_t type) +AC_CACHE_VAL(ice_cv_have_loff_t, +[ +AC_TRY_COMPILE([#include ],[loff_t a;], +ice_cv_have_loff_t=yes, +ice_cv_have_loff_t=no) +]) +AC_MSG_RESULT($ice_cv_have_loff_t) +if test "$ice_cv_have_loff_t" = yes; then +AC_DEFINE([HAVE_LOFF_T],1,[Define when the compiler supports LOFF_T type]) +fi +])dnl + + +dnl ICE_CC_OFFSET_T +dnl ------------- +dnl +dnl If the CC compiler supports `offset_t' type, define `HAVE_OFFSET_T'. +dnl +AC_DEFUN(ICE_CC_OFFSET_T, +[ +AC_MSG_CHECKING(whether ${CC} supports offset_t type) +AC_CACHE_VAL(ice_cv_have_offset_t, +[ +AC_TRY_COMPILE([#include ],[offset_t a;], +ice_cv_have_offset_t=yes, +ice_cv_have_offset_t=no) +]) +AC_MSG_RESULT($ice_cv_have_offset_t) +if test "$ice_cv_have_offset_t" = yes; then +AC_DEFINE([HAVE_OFFSET_T],1,[Define when the compiler supports OFFSET_T type]) +fi +])dnl + +dnl ICE_CC_LONG_LONG +dnl ------------- +dnl +dnl If the CC compiler supports `long long' type, define `HAVE_LONG_LONG'. +dnl +AC_DEFUN(ICE_CC_LONG_LONG, +[ +AC_MSG_CHECKING(whether ${CC} supports long long type) +AC_CACHE_VAL(ice_cv_have_long_long, +[ +AC_TRY_COMPILE(,[long long a;], +ice_cv_have_long_long=yes, +ice_cv_have_long_long=no) +]) +AC_MSG_RESULT($ice_cv_have_long_long) +if test "$ice_cv_have_long_long" = yes; then +AC_DEFINE([HAVE_LONG_LONG],1,[Define when the compiler supports LONG_LONG type]) +fi +])dnl + +dnl ICE_CC_OFF64_T +dnl ------------- +dnl +dnl If the CC compiler supports `long long' type, define `HAVE_OFF64_T'. +dnl +AC_DEFUN(ICE_CC_OFF64_T, +[ +AC_MSG_CHECKING(whether ${CC} supports off64_t type) +AC_CACHE_VAL(ice_cv_have_off64_t, +[ +AC_TRY_COMPILE(,[off64_t a;], +ice_cv_have_off64_t=yes, +ice_cv_have_off64_t=no) +]) +AC_MSG_RESULT($ice_cv_have_off64_t) +if test "$ice_cv_have_off64_t" = yes; then +AC_DEFINE([HAVE_OFF64_T],1,[Define when the compiler supports OFF64_T type]) +fi +])dnl + + +SFS_CHECK_OFF_T_64 +ICE_CC_LOFF_T +ICE_CC_OFFSET_T +ICE_CC_LONG_LONG + + +AC_CHECK_FUNCS(utimes utime, [break]) +AC_CHECK_FUNCS(tzset gettimeofday) + +CF_SYS_ERRLIST + +[ +host_os0=`echo $host_os | sed 's/-/_/g'` +host_os1=`echo $host_os0 | sed 's/\./_/g'` +host_os2=`echo $host_os0 | sed 's/^\([^.]*\)\..*$/\1/g'` +host_os3=`echo $host_os2 | sed 's/^\([^0-9]*\)[0-9]*$/\1/g'` +host_cpu1=`echo $host_cpu | sed 's/\./_/g'` +host_vendor1=`echo $host_vendor | sed 's/\./_/g'` +HOST_ID="-DCPU_$host_cpu1 -DVENDOR_$host_vendor1 -DOS_$host_os1" +if [ $host_os1 != $host_os2 ] ; then + HOST_ID="$HOST_ID -DOS_$host_os2" +fi +if [ $host_os1 != $host_os3 ] && [ $host_os2 != $host_os3 ] ; then + HOST_ID="$HOST_ID -DOS_$host_os3" +fi + +my_host_os=`echo $host_os1 $host_os2 $host_os3 | sort -u` +objs=`echo $srcdir/*.c | sed 's/\.c$/.o/' ` +if [ "X$GCC" = "Xyes" ] ; then + 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 . + */ +#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 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 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 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 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 Tue, 12 Oct 2010 00:19:48 +0200 +mtools (4.0.13) stable; urgency=low + + * Merged Debian patches + + -- Alain Knaff Sun, 28 Feb 2010 15:33:45 +0100 +mtools (4.0.12) stable; urgency=low + + * Mingw compatibility fixes + + -- Alain Knaff Tue, 3 Nov 2009 21:26:58 +0100 +mtools (4.0.11) stable; urgency=low + + * Fixed compiler in mlabel.c and elsewhere + * Fixed h flag in mattrib.c + * Added missing error checking in floppyd and elsewhere + + -- Alain Knaff Sat, 29 Aug 2009 14:38:19 +0200 +mtools (4.0.10) stable; urgency=low + + * More copyright stuff + * Fixed issues with max filesize (was 2GB instead of 4GB, and + warned only after copying the beginning) + + -- Alain Knaff Tue, 3 Mar 2009 22:14:04 +0100 +mtools (4.0.9) stable; urgency=low + + * More copyright stuff + + -- Alain Knaff Mon, 2 Mar 2009 22:15:54 +0100 +mtools (4.0.8) stable; urgency=low + + * Copyright notices + + -- Alain Knaff Sun, 1 Mar 2009 00:36:22 +0100 +mtools (4.0.7) stable; urgency=low + + * Fixed conversion to native on OS/2 + * Fix parsing of --help flag + + -- Alain Knaff Tue, 24 Feb 2009 19:55:46 +0100 +mtools (4.0.6) stable; urgency=low + + * Fallback for missing wchar_t iconv codepage on OS/2 + * Fixes for LSEEK64 support + * Support for --help that returns a 0 exit status + + -- Alain Knaff Sun, 22 Feb 2009 02:04:32 +0100 +mtools (4.0.5) stable; urgency=low + + * Make setpgrp() usage in floppyd conditional + * Re-instate PACKED around structure (ARM) + * LSEEK64 + + -- Alain Knaff Thu, 19 Feb 2009 23:55:04 +0100 +mtools (4.0.4) stable; urgency=low + + * BSD support: SCSI, use getuserid/getgroupid in floppyd + * Another attempt at putwc fix for OS/2 + * Further GNU fixes + * Fallback for putwc if there is wchar (OS/2) + + -- Alain Knaff Sun, 15 Feb 2009 16:18:32 +0100 +mtools (4.0.3) stable; urgency=low + + * Fix multipart pathname parsing bug in vfat.c (forgot limited length) + * Supplied fallback define for putwc + * Copyright notices in all sources + + -- Alain Knaff Mon, 9 Feb 2009 21:46:01 +0100 +mtools (4.0.2) stable; urgency=low + + * Fixed off-by-2 error in unix_name in file_name.c + + -- Alain Knaff Mon, 26 Jan 2009 22:58:06 +0100 +mtools (4.0.1) stable; urgency=low + + * Missing functions on Solaris + + -- Alain Knaff Sun, 7 Dec 2008 21:38:55 +0100 +mtools (4.0.0) stable; urgency=low + + * Offset for -i-specified image files + + -- Alain Knaff Sat, 29 Nov 2008 09:20:30 +0100 +mtools (4.0.0-pre2) stable; urgency=low + + * Use transliteration to represent characters which don't exist in + target set + + -- Alain Knaff Tue, 18 Nov 2008 22:42:23 +0100 +mtools (4.0.0-pre1) stable; urgency=low + + * Unicode support + + -- Alain Knaff Sat, 1 Nov 2008 20:52:58 +0100 +mtools (3.9.11-20071226) stable; urgency=low + + * first release of debian package + + -- Alain Knaff Tue, 28 Aug 2007 23:23:37 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..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 +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 + +This manual page was written by Rabin Vincent +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 . + */ + +/* + * Device tables. See the Configure file for a complete description. + */ + +#define NO_TERMIO +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "devices.h" + +#define INIT_NOOP + +#define DEF_ARG1(x) (x), 0x2,0,(char *)0, 0, 0 +#define DEF_ARG0(x) 0,DEF_ARG1(x) + +#define MDEF_ARG 0L,DEF_ARG0(MFORMAT_ONLY_FLAG) +#define FDEF_ARG 0L,DEF_ARG0(0) +#define VOLD_DEF_ARG 0L,DEF_ARG0(VOLD_FLAG|MFORMAT_ONLY_FLAG) + +#define MED312 12,0,80,2,36,0,MDEF_ARG /* 3 1/2 extra density */ +#define MHD312 12,0,80,2,18,0,MDEF_ARG /* 3 1/2 high density */ +#define MDD312 12,0,80,2, 9,0,MDEF_ARG /* 3 1/2 double density */ +#define MHD514 12,0,80,2,15,0,MDEF_ARG /* 5 1/4 high density */ +#define MDD514 12,0,40,2, 9,0,MDEF_ARG /* 5 1/4 double density (360k) */ +#define MSS514 12,0,40,1, 9,0,MDEF_ARG /* 5 1/4 single sided DD, (180k) */ +#define MDDsmall 12,0,40,2, 8,0,MDEF_ARG /* 5 1/4 double density (320k) */ +#define MSSsmall 12,0,40,1, 8,0,MDEF_ARG /* 5 1/4 single sided DD, (160k) */ + +#define FED312 12,0,80,2,36,0,FDEF_ARG /* 3 1/2 extra density */ +#define FHD312 12,0,80,2,18,0,FDEF_ARG /* 3 1/2 high density */ +#define FDD312 12,0,80,2, 9,0,FDEF_ARG /* 3 1/2 double density */ +#define FHD514 12,0,80,2,15,0,FDEF_ARG /* 5 1/4 high density */ +#define FDD514 12,0,40,2, 9,0,FDEF_ARG /* 5 1/4 double density (360k) */ +#define FSS514 12,0,40,1, 9,0,FDEF_ARG /* 5 1/4 single sided DD, (180k) */ +#define FDDsmall 12,0,40,2, 8,0,FDEF_ARG /* 5 1/4 double density (320k) */ +#define FSSsmall 12,0,40,1, 8,0,FDEF_ARG /* 5 1/4 single sided DD, (160k) */ + +#define GENHD 16,0, 0,0, 0,0,MDEF_ARG /* Generic 16 bit FAT fs */ +#define GENFD 12,0,80,2,18,0,MDEF_ARG /* Generic 12 bit FAT fs */ +#define VOLDFD 12,0,80,2,18,0,VOLD_DEF_ARG /* Generic 12 bit FAT fs with vold */ +#define GEN 0,0, 0,0, 0,0,MDEF_ARG /* Generic fs of any FAT bits */ + +#define ZIPJAZ(x,c,h,s,y) 16,(x),(c),(h),(s),(s),0L, 4, \ + DEF_ARG1((y)|MFORMAT_ONLY_FLAG) /* Jaz disks */ + +#define JAZ(x) ZIPJAZ(x,1021, 64, 32, 0) +#define RJAZ(x) ZIPJAZ(x,1021, 64, 32, SCSI_FLAG|PRIV_FLAG) +#define ZIP(x) ZIPJAZ(x,96, 64, 32, 0) +#define RZIP(x) ZIPJAZ(x,96, 64, 32, SCSI_FLAG|PRIV_FLAG) + +#define REMOTE {"$DISPLAY", 'X', 0,0, 0,0, 0,0,0L, DEF_ARG0(FLOPPYD_FLAG)} + + + +#if defined(INIT_GENERIC) || defined(INIT_NOOP) +static int compare_geom(struct device *dev, struct device *orig_dev) +{ + if(IS_MFORMAT_ONLY(orig_dev)) + return 0; /* geometry only for mformatting ==> ok */ + if(!orig_dev || !orig_dev->tracks || !dev || !dev->tracks) + return 0; /* no original device. This is ok */ + return(orig_dev->tracks != dev->tracks || + orig_dev->heads != dev->heads || + orig_dev->sectors != dev->sectors); +} +#endif + +#define devices const_devices + + +#ifdef __CYGWIN__ +#define predefined_devices +struct device devices[] = { + {"\\\\\\\\.\\\\A:", 'A', GENFD }, +}; +#endif /* CYGWIN */ + + +#ifdef OS_aux +#define predefined_devices +struct device devices[] = { + {"/dev/floppy0", 'A', GENFD }, + {"/dev/rdsk/c104d0s31", 'J', JAZ(O_EXCL) }, + {"/dev/rdsk/c105d0s31", 'Z', ZIP(O_EXCL) }, + REMOTE +}; +#endif /* aux */ + + +#ifdef OS_lynxos +#define predefined_devices +struct device devices[] = { + {"/dev/fd1440.0", 'A', MHD312 }, + REMOTE +}; +#endif + + +#ifdef __BEOS__ +#define predefined_devices +struct device devices[] = { + {"/dev/disk/floppy/raw", 'A', MHD312 }, + REMOTE +}; +#endif /* BEBOX */ + + +#ifdef OS_hpux + +#define predefined_devices +struct device devices[] = { +#ifdef OS_hpux10 +/* hpux10 uses different device names according to Frank Maritato + * */ + {"/dev/floppy/c0t0d0", 'A', MHD312 }, + {"/dev/floppy/c0t0d1", 'B', MHD312 }, /* guessed by me */ + {"/dev/rscsi", 'C', GENHD }, /* guessed by me */ +#else +/* Use rfloppy, according to Simao Campos */ + {"/dev/rfloppy/c201d0s0", 'A', FHD312 }, + {"/dev/rfloppy/c20Ad0s0", 'A', FHD312 }, + {"/dev/rfloppy/c201d1s0", 'B', FHD312 }, + {"/dev/rfloppy/c20Ad1s0", 'B', FHD312 }, + {"/dev/rscsi", 'C', GENHD }, +#endif + {"/dev/rdsk/c201d4", 'J', RJAZ(O_EXCL) }, + {"/dev/rdsk/c201d4s0", 'J', RJAZ(O_EXCL) }, + {"/dev/rdsk/c201d5", 'Z', RZIP(O_EXCL) }, + {"/dev/rdsk/c201d5s0", 'Z', RZIP(O_EXCL) }, + REMOTE +}; + +#ifdef HAVE_SYS_FLOPPY +/* geometry setting ioctl's contributed by Paolo Zeppegno + * , may cause "Not a typewriter" messages on other + * versions according to support@vital.com */ + +#include +#undef SSIZE + +struct generic_floppy_struct +{ + struct floppy_geometry fg; +}; + +#define BLOCK_MAJOR 24 +#define CHAR_MAJOR 112 + +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + if (ioctl(fd, FLOPPY_GET_GEOMETRY, &(floppy->fg)) != 0) { + perror("FLOPPY_GET_GEOMETRY"); + return(1); + } + + return 0; +} + +#define TRACKS(floppy) floppy.fg.tracks +#define HEADS(floppy) floppy.fg.heads +#define SECTORS(floppy) floppy.fg.sectors +#define FD_SECTSIZE(floppy) floppy.fg.sector_size +#define FD_SET_SECTSIZE(floppy,v) { floppy.fg.sector_size = v; } + +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + if (ioctl(fd, FLOPPY_SET_GEOMETRY, &(floppy->fg)) != 0) { + perror(""); + return(1); + } + + return 0; +} +#define INIT_GENERIC +#endif + +#endif /* hpux */ + + +#if (defined(OS_sinix) || defined(VENDOR_sni) || defined(SNI)) +#define predefined_devices +struct device devices[] = { +#ifdef CPU_mips /* for Siemens Nixdorf's SINIX-N/O (mips) 5.4x SVR4 */ + { "/dev/at/flp/f0t", 'A', FHD312}, + { "/dev/fd0", 'A', GENFD}, +#else +#ifdef CPU_i386 /* for Siemens Nixdorf's SINIX-D/L (intel) 5.4x SVR4 */ + { "/dev/fd0135ds18", 'A', FHD312}, + { "/dev/fd0135ds9", 'A', FDD312}, + { "/dev/fd0", 'A', GENFD}, + { "/dev/fd1135ds15", 'B', FHD514}, + { "/dev/fd1135ds9", 'B', FDD514}, + { "/dev/fd1", 'B', GENFD}, +#endif /* CPU_i386 */ +#endif /*mips*/ + REMOTE +}; +#endif + +#ifdef OS_ultrix +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0a", 'A', GENFD}, /* guessed */ + {"/dev/rfd0c", 'A', GENFD}, /* guessed */ + REMOTE +}; + +#endif + + +#ifdef OS_isc +#define predefined_devices +#if (defined(OS_isc2) && defined(OLDSTUFF)) +struct device devices[] = { + {"/dev/rdsk/f0d9dt", 'A', FDD514}, + {"/dev/rdsk/f0q15dt", 'A', FHD514}, + {"/dev/rdsk/f0d8dt", 'A', FDDsmall}, + {"/dev/rdsk/f13ht", 'B', FHD312}, + {"/dev/rdsk/f13dt", 'B', FDD312}, + {"/dev/rdsk/0p1", 'C', GENHD}, + {"/usr/vpix/defaults/C:",'D',12, 0, 0, 0, 0,8704L,DEF_ARG0}, + {"$HOME/vpix/C:", 'E', 12, 0, 0, 0, 0,8704L,MDEF_ARG}, + REMOTE +}; +#else +/* contributed by larry.jones@sdrc.com (Larry Jones) */ +struct device devices[] = { + {"/dev/rfd0", 'A', GEN}, + {"/dev/rfd1", 'B', GEN}, + {"/dev/rdsk/0p1", 'C', GEN}, + {"/usr/vpix/defaults/C:",'D', GEN, 1}, + {"$HOME/vpix/C:", 'E', GEN, 1}, + REMOTE +}; + +#include +#include +#undef SSIZE +#define BLOCK_MAJOR 1 +#define CHAR_MAJOR 1 +#define generic_floppy_struct disk_parms +int ioctl(int, int, void *); + +static int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + mt_off_t off; + char buf[512]; + + off = lseek(fd, 0, SEEK_CUR); + if(off < 0) { + perror("device seek 1"); + exit(1); + } + if (off == 0) { + /* need to read at least 1 sector to get correct info */ + read(fd, buf, sizeof buf); + if(lseek(fd, 0, SEEK_SET) < 0) { + perror("device seek 2"); + exit(1); + } + } + return ioctl(fd, V_GETPARMS, floppy); +} + +#define TRACKS(floppy) (floppy).dp_cyls +#define HEADS(floppy) (floppy).dp_heads +#define SECTORS(floppy) (floppy).dp_sectors +#define FD_SECTSIZE(floppy) (floppy).dp_secsiz +#define FD_SET_SECTSIZE(floppy,v) { (floppy).dp_secsiz = (v); } + +static int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + return 1; +} + +#define INIT_GENERIC +#endif +#endif /* isc */ + +#ifdef CPU_i370 +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0", 'A', GENFD}, + REMOTE +}; +#endif /* CPU_i370 */ + +#ifdef OS_aix +/* modified by Federico Bianchi */ +#define predefined_devices +struct device devices[] = { + {"/dev/fd0",'A',GENFD}, + REMOTE +}; +#endif /* aix */ + + +#ifdef OS_osf4 +/* modified by Chris Samuel */ +#define predefined_devices +struct device devices[] = { + {"/dev/fd0c",'A',GENFD}, + REMOTE +}; +#endif /* OS_osf4 */ + + +#ifdef OS_solaris + +#ifdef USING_NEW_VOLD + +char *alias_name = NULL; + +extern char *media_oldaliases(char *); +extern char *media_findname(char *); + +char *getVoldName(struct device *dev, char *name) +{ + char *rname; + + if(!SHOULD_USE_VOLD(dev)) + return name; + + /*** + * Solaris specific routines to use the volume management + * daemon and libraries to get the correct device name... + ***/ + rname = media_findname(name); +#ifdef HAVE_MEDIA_OLDALIASES + if (rname == NULL) { + if ((alias_name = media_oldaliases(name)) != NULL) + rname = media_findname(alias_name); + } +#endif + if (rname == NULL) { + fprintf(stderr, + "No such volume or no media in device: %s.\n", + name); + exit(1); + } + return rname; +} +#endif /* USING_NEW_VOLD */ + +#define predefined_devices +struct device devices[] = { +#ifdef USING_NEW_VOLD + {"floppy", 'A', VOLDFD }, +#elif USING_VOLD + {"/vol/dev/aliases/floppy0", 'A', GENFD}, + {"/dev/rdiskette", 'B', GENFD}, +#else /* ! USING_VOLD */ + {"/dev/rdiskette", 'A', GENFD}, + {"/vol/dev/aliases/floppy0", 'B', GENFD}, +#endif /* USING_VOLD */ + {"/dev/rdsk/c0t4d0s2", 'J', RJAZ(O_NDELAY)}, + {"/dev/rdsk/c0t5d0s2", 'Z', RZIP(O_NDELAY)}, + REMOTE +}; + + + +/* + * Ofer Licht , May 14, 1997. + */ + +#define INIT_GENERIC + +#include +#include /* for major() */ + +struct generic_floppy_struct +{ + struct fd_char fdchar; +}; + +#define BLOCK_MAJOR 36 +#define CHAR_MAJOR 36 + +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + if (ioctl(fd, FDIOGCHAR, &(floppy->fdchar)) != 0) { + perror(""); + ioctl(fd, FDEJECT, NULL); + return(1); + } + return 0; +} + +#define TRACKS(floppy) floppy.fdchar.fdc_ncyl +#define HEADS(floppy) floppy.fdchar.fdc_nhead +#define SECTORS(floppy) floppy.fdchar.fdc_secptrack +/* SECTORS_PER_DISK(floppy) not used */ +#define FD_SECTSIZE(floppy) floppy.fdchar.fdc_sec_size +#define FD_SET_SECTSIZE(floppy,v) { floppy.fdchar.fdc_sec_size = v; } + +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + if (ioctl(fd, FDIOSCHAR, &(floppy->fdchar)) != 0) { + ioctl(fd, FDEJECT, NULL); + perror(""); + return(1); + } + return 0; +} +#define INIT_GENERIC +#endif /* solaris */ + +#ifdef OS_sunos3 +#define predefined_devices +struct device devices[] = { + {"/dev/rfdl0c", 'A', FDD312}, + {"/dev/rfd0c", 'A', FHD312}, + REMOTE +}; +#endif /* OS_sunos3 */ + +#ifdef OS_xenix +#define predefined_devices +struct device devices[] = { + {"/dev/fd096ds15", 'A', FHD514}, + {"/dev/fd048ds9", 'A', FDD514}, + {"/dev/fd1135ds18", 'B', FHD312}, + {"/dev/fd1135ds9", 'B', FDD312}, + {"/dev/hd0d", 'C', GENHD}, + REMOTE +}; +#endif /* OS_xenix */ + +#ifdef OS_sco +#define predefined_devices +struct device devices[] = { + { "/dev/fd0135ds18", 'A', FHD312}, + { "/dev/fd0135ds9", 'A', FDD312}, + { "/dev/fd0", 'A', GENFD}, + { "/dev/fd1135ds15", 'B', FHD514}, + { "/dev/fd1135ds9", 'B', FDD514}, + { "/dev/fd1", 'B', GENFD}, + { "/dev/hd0d", 'C', GENHD}, + REMOTE +}; +#endif /* OS_sco */ + + +#ifdef OS_irix +#define predefined_devices +struct device devices[] = { + { "/dev/rdsk/fds0d2.3.5hi", 'A', FHD312}, + { "/dev/rdsk/fds0d2.3.5", 'A', FDD312}, + { "/dev/rdsk/fds0d2.96", 'A', FHD514}, + {"/dev/rdsk/fds0d2.48", 'A', FDD514}, + REMOTE +}; +#endif /* OS_irix */ + + +#ifdef OS_sunos4 +#include +#include + +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0c", 'A', GENFD}, + {"/dev/rsd4c", 'J', RJAZ(O_NDELAY)}, + {"/dev/rsd5c", 'Z', RZIP(O_NDELAY)}, + REMOTE +}; + +/* + * Stuffing back the floppy parameters into the driver allows for gems + * like 10 sector or single sided floppies from Atari ST systems. + * + * Martin Schulz, Universite de Moncton, N.B., Canada, March 11, 1991. + */ + +#define INIT_GENERIC + +struct generic_floppy_struct +{ + struct fdk_char dkbuf; + struct dk_map dkmap; +}; + +#define BLOCK_MAJOR 16 +#define CHAR_MAJOR 54 + +static inline int get_parameters(int fd, struct generic_floppy_struct *floppy) +{ + if (ioctl(fd, DKIOCGPART, &(floppy->dkmap)) != 0) { + perror("DKIOCGPART"); + ioctl(fd, FDKEJECT, NULL); + return(1); + } + + if (ioctl(fd, FDKIOGCHAR, &( floppy->dkbuf)) != 0) { + perror(""); + ioctl(fd, FDKEJECT, NULL); + return(1); + } + return 0; +} + +#define TRACKS(floppy) floppy.dkbuf.ncyl +#define HEADS(floppy) floppy.dkbuf.nhead +#define SECTORS(floppy) floppy.dkbuf.secptrack +#define SECTORS_PER_DISK(floppy) floppy.dkmap.dkl_nblk +#define FD_SECTSIZE(floppy) floppy.dkbuf.sec_size +#define FD_SET_SECTSIZE(floppy,v) { floppy.dkbuf.sec_size = v; } + +static inline int set_parameters(int fd, struct generic_floppy_struct *floppy, + struct MT_STAT *buf) +{ + if (ioctl(fd, FDKIOSCHAR, &(floppy->dkbuf)) != 0) { + ioctl(fd, FDKEJECT, NULL); + perror(""); + return(1); + } + + if (ioctl(fd, ( unsigned int) DKIOCSPART, &(floppy->dkmap)) != 0) { + ioctl(fd, FDKEJECT, NULL); + perror(""); + return(1); + } + return 0; +} +#define INIT_GENERIC +#endif /* sparc && sunos */ + + +#ifdef DPX1000 +#define predefined_devices +struct device devices[] = { + /* [block device]: DPX1000 has /dev/flbm60, DPX2 has /dev/easyfb */ + {"/dev/flbm60", 'A', MHD514}; + {"/dev/flbm60", 'B', MDD514}, + {"/dev/flbm60", 'C', MDDsmall}, + {"/dev/flbm60", 'D', MSS}, + {"/dev/flbm60", 'E', MSSsmall}, + REMOTE +}; +#endif /* DPX1000 */ + +#ifdef OS_bosx +#define predefined_devices +struct device devices[] = { + /* [block device]: DPX1000 has /dev/flbm60, DPX2 has /dev/easyfb */ + {"/dev/easyfb", 'A', MHD514}, + {"/dev/easyfb", 'B', MDD514}, + {"/dev/easyfb", 'C', MDDsmall}, + {"/dev/easyfb", 'D', MSS}, + {"/dev/easyfb", 'E', MSSsmall}, + REMOTE +}; +#endif /* OS_bosx */ + +#ifdef OS_linux + +const char *error_msg[22]={ +"Missing Data Address Mark", +"Bad cylinder", +"Scan not satisfied", +"Scan equal hit", +"Wrong cylinder", +"CRC error in data field", +"Control Mark = deleted", +0, + +"Missing Address Mark", +"Write Protect", +"No Data - unreadable", +0, +"OverRun", +"CRC error in data or address", +0, +"End Of Cylinder", + +0, +0, +0, +"Not ready", +"Equipment check error", +"Seek end" }; + + +static __inline__ void print_message(RawRequest_t *raw_cmd,const char *message) +{ + int i, code; + if(!message) + return; + + fprintf(stderr," "); + for (i=0; i< raw_cmd->cmd_count; i++) + fprintf(stderr,"%2.2x ", + (int)raw_cmd->cmd[i] ); + fprintf(stderr,"\n"); + for (i=0; i< raw_cmd->reply_count; i++) + fprintf(stderr,"%2.2x ", + (int)raw_cmd->reply[i] ); + fprintf(stderr,"\n"); + code = (raw_cmd->reply[0] <<16) + + (raw_cmd->reply[1] << 8) + + raw_cmd->reply[2]; + for(i=0; i<22; i++){ + if ((code & (1 << i)) && error_msg[i]) + fprintf(stderr,"%s\n", + error_msg[i]); + } +} + + +/* return values: + * -1: Fatal error, don't bother retrying. + * 0: OK + * 1: minor error, retry + */ + +int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message) +{ + if (ioctl( fd, FDRAWCMD, raw_cmd) >= 0) { + if (raw_cmd->reply_count < 7) { + fprintf(stderr,"Short reply from FDC\n"); + return -1; + } + return 0; + } + + switch(errno) { + case EBUSY: + fprintf(stderr, "FDC busy, sleeping for a second\n"); + sleep(1); + return 1; + case EIO: + fprintf(stderr,"resetting controller\n"); + if(ioctl(fd, FDRESET, 2) < 0){ + perror("reset"); + return -1; + } + return 1; + default: + perror(message); + return -1; + } +} + + +/* + * return values + * -1: error + * 0: OK, last sector + * 1: more raw commands follow + */ + +int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print) +{ + + if(raw_cmd->reply_count == 7) { + int end; + + if (raw_cmd->reply[3] != raw_cmd->cmd[2]) { + /* end of cylinder */ + end = raw_cmd->cmd[6] + 1; + } else { + end = raw_cmd->reply[5]; + } + + *bytes = end - raw_cmd->cmd[4]; + /* FIXME: over/under run */ + *bytes = *bytes << (7 + raw_cmd->cmd[5]); + } else + *bytes = 0; + + switch(raw_cmd->reply[0] & 0xc0){ + case 0x40: + if ((raw_cmd->reply[0] & 0x38) == 0 && + (raw_cmd->reply[1]) == 0x80 && + (raw_cmd->reply[2]) == 0) { + *bytes += 1 << (7 + raw_cmd->cmd[5]); + break; + } + + if ( raw_cmd->reply[1] & ST1_WP ){ + *bytes = 0; + fprintf(stderr, + "This disk is write protected\n"); + return -1; + } + if(!*bytes && do_print) + print_message(raw_cmd, ""); + return -1; + case 0x80: + *bytes = 0; + fprintf(stderr, + "invalid command given\n"); + return -1; + case 0xc0: + *bytes = 0; + fprintf(stderr, + "abnormal termination caused by polling\n"); + return -1; + default: + break; + } +#ifdef FD_RAW_MORE + if(raw_cmd->flags & FD_RAW_MORE) + return 1; +#endif + return 0; +} + +#define predefined_devices +struct device devices[] = { + {"/dev/fd0", 'A', 0, 0, 80,2, 18,0, MDEF_ARG}, + {"/dev/fd1", 'B', 0, 0, 0,0, 0,0, FDEF_ARG}, + /* we assume that the Zip or Jaz drive is the second on the SCSI bus */ + {"/dev/sdb4",'J', GENHD }, + {"/dev/sdb4",'Z', GENHD }, + /* {"/dev/sda4",'D', GENHD },*/ + REMOTE +}; + +/* + * Stuffing back the floppy parameters into the driver allows for gems + * like 21 sector or single sided floppies from Atari ST systems. + * + * Alain Knaff, Université Joseph Fourier, France, November 12, 1993. + */ + + +#define INIT_GENERIC +#define generic_floppy_struct floppy_struct +#define BLOCK_MAJOR 2 +#define SECTORS(floppy) floppy.sect +#define TRACKS(floppy) floppy.track +#define HEADS(floppy) floppy.head +#define SECTORS_PER_DISK(floppy) floppy.size +#define STRETCH(floppy) floppy.stretch +#define USE_2M(floppy) ((floppy.rate & FD_2M) ? 0xff : 0x80 ) +#define SSIZE(floppy) ((((floppy.rate & 0x38) >> 3 ) + 2) % 8) + +static __inline__ void set_2m(struct floppy_struct *floppy, int value) +{ + if (value & 0x7f) + value = FD_2M; + else + value = 0; + floppy->rate = (floppy->rate & ~FD_2M) | value; +} +#define SET_2M set_2m + +static __inline__ void set_ssize(struct floppy_struct *floppy, int value) +{ + value = (( (value & 7) + 6 ) % 8) << 3; + + floppy->rate = (floppy->rate & ~0x38) | value; +} + +#define SET_SSIZE set_ssize + +static __inline__ int set_parameters(int fd, struct floppy_struct *floppy, + struct MT_STAT *buf) +{ + if ( ( MINOR(buf->st_rdev ) & 0x7f ) > 3 ) + return 1; + + return ioctl(fd, FDSETPRM, floppy); +} + +static __inline__ int get_parameters(int fd, struct floppy_struct *floppy) +{ + return ioctl(fd, FDGETPRM, floppy); +} + +#endif /* linux */ + + +/* OS/2, gcc+emx */ +#ifdef __EMX__ +#define predefined_devices +struct device devices[] = { + {"A:", 'A', GENFD}, + {"B:", 'B', GENFD}, +}; +#define INIT_NOOP +#endif + + + +/*** /jes -- for D.O.S. 486 BL DX2/80 ***/ +/*** Jean-Marc Zucconi 2001/03/30 ***/ +#ifdef OS_freebsd +#define predefined_devices +struct device devices[] = { + {"/dev/fd0.1440", 'A', FHD312}, + {"/dev/fd0.720", 'A', FDD312}, + {"/dev/fd1.1200", 'B', MHD514}, + {"/dev/sd0s1", 'C', GENHD}, + REMOTE +}; +#endif /* __FreeBSD__ */ + +/*** /jes -- for ALR 486 DX4/100 ***/ +#if defined(OS_netbsd) || defined(OS_netbsdelf) +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0a", 'A', FHD312}, + {"/dev/rfd0f", 'A', FDD312}, + {"/dev/rfd0f", 'S', MDD312}, + {"/dev/rfd1a", 'B', FHD514}, + {"/dev/rfd1d", 'B', FDD514}, + {"/dev/rfd1d", 'T', MDD514}, + {"/dev/rwd0d", 'C', 16, 0, 0, 0, 0, 0, 63L*512L, DEF_ARG0(0)}, + REMOTE +}; +#endif /* OS_NetBSD */ + +/* fgsch@openbsd.org 2000/05/19 */ +#if defined(OS_openbsd) +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0Bc", 'A', FHD312}, + {"/dev/rfd0Fc", 'A', FDD312}, + {"/dev/rfd1Cc", 'B', FHD514}, + {"/dev/rfd1Dc", 'B', FDD514}, + {"/dev/rwd0c", 'C', 16, 0, 0, 0, 0, 0, 63L*512L, DEF_ARG0(0)}, + REMOTE +}; +#endif /* OS_openbsd */ + + + +#if (!defined(predefined_devices) && defined (CPU_m68000) && defined (OS_sysv)) +#include + +#define predefined_devices +struct device devices[] = { + {"/dev/rfp020", 'A', 12,O_NDELAY,40,2, 9, 0, MDEF_ARG}, + {"/usr/bin/DOS/dvd000", 'C', GENFD}, + REMOTE +}; + +#undef INIT_NOOP +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf) +{ + struct gdctl gdbuf; + + if (ioctl(fd, GDGETA, &gdbuf) == -1) { + ioctl(fd, GDDISMNT, &gdbuf); + return 1; + } + if((dev->use_2m & 0x7f) || (dev->ssize & 0x7f)) + return 1; + + SET_INT(gdbuf.params.cyls,dev->ntracks); + SET_INT(gdbuf.params.heads,dev->nheads); + SET_INT(gdbuf.params.psectrk,dev->nsect); + dev->ntracks = gdbuf.params.cyls; + dev->nheads = gdbuf.params.heads; + dev->nsect = gdbuf.params.psectrk; + dev->use_2m = 0x80; + dev->ssize = 0x82; + + gdbuf.params.pseccyl = gdbuf.params.psectrk * gdbuf.params.heads; + gdbuf.params.flags = 1; /* disk type flag */ + gdbuf.params.step = 0; /* step rate for controller */ + gdbuf.params.sectorsz = 512; /* sector size */ + + if (ioctl(fd, GDSETA, &gdbuf) < 0) { + ioctl(fd, GDDISMNT, &gdbuf); + return(1); + } + return(0); +} +#endif /* (defined (m68000) && defined (sysv))*/ + +#ifdef CPU_alpha +#ifndef OS_osf4 +#ifdef __osf__ +#include +#define predefined_devices +struct device devices[] = { + {"/dev/rfd0c", 'A', GENFD}, + REMOTE +}; +#endif +#endif +#endif + +#ifdef OS_osf +#ifndef predefined_devices +#define predefined_devices +struct device devices[] = { + {"/dev/fd0a", 'A', MHD312 } }; + REMOTE +#endif +#endif + + +#ifdef OS_nextstep +#define predefined_devices +struct device devices[] = { +#ifdef CPU_m68k + {"/dev/rfd0b", 'A', MED312 }, + REMOTE +#else + {"/dev/rfd0b", 'A', MHD312 }, + REMOTE +#endif +}; +#endif + + +#if (!defined(predefined_devices) && defined(OS_sysv4)) +#ifdef __uxp__ +#define predefined_devices +struct device devices[] = { + {"/dev/fpd0", 'A', FHD312}, + {"/dev/fpd0", 'A', FDD312}, + REMOTE +}; +#else +#define predefined_devices +struct device devices[] = { + {"/dev/rdsk/f1q15dt", 'B', FHD514}, + {"/dev/rdsk/f1d9dt", 'B', FDD514}, + {"/dev/rdsk/f1d8dt", 'B', FDDsmall}, + {"/dev/rdsk/f03ht", 'A', FHD312}, + {"/dev/rdsk/f03dt", 'A', FDD312}, + {"/dev/rdsk/dos", 'C', GENHD}, + REMOTE +}; +#endif +#endif /* sysv4 */ + +#ifdef OS_mingw32msvc +#define predefined_devices +struct device devices[] = { + {"\\\\.\\A:", 'A', GENFD }, +}; +#endif + +#ifdef INIT_GENERIC + +#ifndef USE_2M +#define USE_2M(x) 0x80 +#endif + +#ifndef SSIZE +#define SSIZE(x) 0x82 +#endif + +#ifndef SET_2M +#define SET_2M(x,y) return -1 +#endif + +#ifndef SET_SSIZE +#define SET_SSIZE(x,y) return -1 +#endif + +#undef INIT_NOOP +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf) +{ + struct generic_floppy_struct floppy; + int change; + + /* + * succeed if we don't have a floppy + * this is the case for dosemu floppy image files for instance + */ + if (!((S_ISBLK(statbuf->st_mode) && + major(statbuf->st_rdev) == BLOCK_MAJOR) +#ifdef CHAR_MAJOR + || (S_ISCHR(statbuf->st_mode) && + major(statbuf->st_rdev) == CHAR_MAJOR) +#endif + )) + return compare_geom(dev, orig_dev); + + /* + * We first try to get the current floppy parameters from the kernel. + * This allows us to + * 1. get the rate + * 2. skip the parameter setting if the parameters are already o.k. + */ + + if (get_parameters( fd, & floppy ) ) + /* + * autodetection failure. + * This mostly occurs because of an absent or unformatted disks. + * + * It might also occur because of bizarre formats (for example + * rate 1 on a 3 1/2 disk). + + * If this is the case, the user should do an explicit + * setfdprm before calling mtools + * + * Another cause might be pre-existing wrong parameters. The + * user should do an setfdprm -c to repair this situation. + * + * ...fail immediately... ( Theoretically, we could try to save + * the situation by trying out all rates, but it would be slow + * and awkward) + */ + return 1; + + + /* + * if we have already have the correct parameters, keep them. + * the number of tracks doesn't need to match exactly, it may be bigger. + * the number of heads and sectors must match exactly, to avoid + * miscalculation of the location of a block on the disk + */ + change = 0; + if(compare(dev->sectors, SECTORS(floppy))){ + SECTORS(floppy) = dev->sectors; + change = 1; + } else + dev->sectors = SECTORS(floppy); + + if(compare(dev->heads, HEADS(floppy))){ + HEADS(floppy) = dev->heads; + change = 1; + } else + dev->heads = HEADS(floppy); + + if(compare(dev->tracks, TRACKS(floppy))){ + TRACKS(floppy) = dev->tracks; + change = 1; + } else + dev->tracks = TRACKS(floppy); + + + if(compare(dev->use_2m, USE_2M(floppy))){ + SET_2M(&floppy, dev->use_2m); + change = 1; + } else + dev->use_2m = USE_2M(floppy); + + if( ! (dev->ssize & 0x80) ) + dev->ssize = 0; + if(compare(dev->ssize, SSIZE(floppy) + 128)){ + SET_SSIZE(&floppy, dev->ssize); + change = 1; + } else + dev->ssize = SSIZE(floppy); + + if(!change) + /* no change, succeed */ + return 0; + +#ifdef SECTORS_PER_TRACK + SECTORS_PER_TRACK(floppy) = dev->sectors * dev->heads; +#endif + +#ifdef SECTORS_PER_DISK + SECTORS_PER_DISK(floppy) = dev->sectors * dev->heads * dev->tracks; +#endif + +#ifdef STRETCH + /* ... and the stretch */ + if ( dev->tracks > 41 ) + STRETCH(floppy) = 0; + else + STRETCH(floppy) = 1; +#endif + + return set_parameters( fd, &floppy, statbuf); +} +#endif /* INIT_GENERIC */ + +#ifdef INIT_NOOP +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf) +{ + return compare_geom(dev, orig_dev); +} +#endif + +#ifdef predefined_devices +const int nr_const_devices = sizeof(const_devices) / sizeof(*const_devices); +#else +struct device devices[]={ + {"/dev/fd0", 'A', 0, O_EXCL, 0,0, 0,0, MDEF_ARG}, + /* to shut up Ultrix's native compiler, we can't make this empty :( */ +}; +const int nr_const_devices = 0; +#endif diff --git a/devices.h b/devices.h new file mode 100644 index 0000000..1d0e236 --- /dev/null +++ b/devices.h @@ -0,0 +1,187 @@ +#ifdef OS_linux + +/* Copyright 1996-2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ +#include + +#ifdef HAVE_SYS_SYSMACROS_H + +#include +#ifndef MAJOR +#define MAJOR(dev) major(dev) +#endif /* MAJOR not defined */ +#ifndef MINOR +#define MINOR(dev) minor(dev) +#endif /* MINOR not defined */ + +#else + +#include /* get MAJOR/MINOR from Linux kernel */ +#ifndef major +#define major(x) MAJOR(x) +#endif + +#endif /* HAVE_SYS_SYSMACROS_H */ + +#include +#include +#include + + +typedef struct floppy_raw_cmd RawRequest_t; + +UNUSED(static __inline__ void RR_INIT(struct floppy_raw_cmd *request)) +{ + request->data = 0; + request->length = 0; + request->cmd_count = 9; + request->flags = FD_RAW_INTR | FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK +#ifdef FD_RAW_SOFTFAILUE + | FD_RAW_SOFTFAILURE | FD_RAW_STOP_IF_FAILURE +#endif + ; + request->cmd[1] = 0; + request->cmd[6] = 0; + request->cmd[7] = 0x1b; + request->cmd[8] = 0xff; + request->reply_count = 0; +} + +UNUSED(static __inline__ void RR_SETRATE(struct floppy_raw_cmd *request, int rate)) +{ + request->rate = rate; +} + +UNUSED(static __inline__ void RR_SETDRIVE(struct floppy_raw_cmd *request,int drive)) +{ + request->cmd[1] = (request->cmd[1] & ~3) | (drive & 3); +} + +UNUSED(static __inline__ void RR_SETTRACK(struct floppy_raw_cmd *request,int track)) +{ + request->cmd[2] = track; +} + +UNUSED(static __inline__ void RR_SETPTRACK(struct floppy_raw_cmd *request, + int track)) +{ + request->track = track; +} + +UNUSED(static __inline__ void RR_SETHEAD(struct floppy_raw_cmd *request, int head)) +{ + if(head) + request->cmd[1] |= 4; + else + request->cmd[1] &= ~4; + request->cmd[3] = head; +} + +UNUSED(static __inline__ void RR_SETSECTOR(struct floppy_raw_cmd *request, + int sector)) +{ + request->cmd[4] = sector; + request->cmd[6] = sector-1; +} + +UNUSED(static __inline__ void RR_SETSIZECODE(struct floppy_raw_cmd *request, + int sizecode)) +{ + request->cmd[5] = sizecode; + request->cmd[6]++; + request->length += 128 << sizecode; +} + +#if 0 +static inline void RR_SETEND(struct floppy_raw_cmd *request, int end) +{ + request->cmd[6] = end; +} +#endif + +UNUSED(static __inline__ void RR_SETDIRECTION(struct floppy_raw_cmd *request, + int direction)) +{ + if(direction == MT_READ) { + request->flags |= FD_RAW_READ; + request->cmd[0] = FD_READ & ~0x80; + } else { + request->flags |= FD_RAW_WRITE; + request->cmd[0] = FD_WRITE & ~0x80; + } +} + + +UNUSED(static __inline__ void RR_SETDATA(struct floppy_raw_cmd *request, + caddr_t data)) +{ + request->data = data; +} + + +#if 0 +static inline void RR_SETLENGTH(struct floppy_raw_cmd *request, int length) +{ + request->length += length; +} +#endif + +UNUSED(static __inline__ void RR_SETCONT(struct floppy_raw_cmd *request)) +{ +#ifdef FD_RAW_MORE + request->flags |= FD_RAW_MORE; +#endif +} + + +UNUSED(static __inline__ int RR_SIZECODE(struct floppy_raw_cmd *request)) +{ + return request->cmd[5]; +} + + + +UNUSED(static __inline__ int RR_TRACK(struct floppy_raw_cmd *request)) +{ + return request->cmd[2]; +} + + +UNUSED(static __inline__ int GET_DRIVE(int fd)) +{ + struct MT_STAT statbuf; + + if (MT_FSTAT(fd, &statbuf) < 0 ){ + perror("stat"); + return -1; + } + + if (!S_ISBLK(statbuf.st_mode) || + MAJOR(statbuf.st_rdev) != FLOPPY_MAJOR) + return -1; + + return MINOR( statbuf.st_rdev ); +} + + + +/* void print_message(RawRequest_t *raw_cmd,char *message);*/ +int send_one_cmd(int fd, RawRequest_t *raw_cmd, const char *message); +int analyze_one_reply(RawRequest_t *raw_cmd, int *bytes, int do_print); + + +#endif diff --git a/dirCache.c b/dirCache.c new file mode 100644 index 0000000..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 . + */ +#include "sysincludes.h" +#include "vfat.h" +#include "dirCache.h" +#include "dirCacheP.h" +#include + + +#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 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; ientries[i] = entry; + } + return entry; +} + +dirCacheEntry_t *addUsedEntry(dirCache_t *cache, int beginSlot, int endSlot, + wchar_t *longName, wchar_t *shortName, + struct directory *dir) +{ + dirCacheEntry_t *entry; + + if(endSlot < beginSlot) { + fprintf(stderr, + "Bad slots %d %d in add used entry\n", + beginSlot, endSlot); + exit(1); + } + + + entry = allocDirCacheEntry(cache, beginSlot, endSlot, DCET_USED); + if(!entry) + return 0; + + entry->beginSlot = beginSlot; + entry->endSlot = endSlot; + if(longName) + entry->longName = wcsdup(longName); + entry->shortName = wcsdup(shortName); + entry->dir = *dir; + hashDce(cache, entry); + return entry; +} + +/* 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 . + */ +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 . + */ +#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 . + */ + +#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 . + * + * 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 . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "file_name.h" + +#ifdef HAVE_LONG_LONG +typedef long long fatBitMask; +#else +typedef long fatBitMask; +#endif + +typedef struct FatMap_t { + unsigned char *data; + fatBitMask dirty; + fatBitMask valid; +} FatMap_t; + +#define SECT_PER_ENTRY (sizeof(fatBitMask)*8) +#define ONE ((fatBitMask) 1) + +static __inline__ int readSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return READS(This->Next, buf, sectorsToBytes((Stream_t *)This, off), + size << This->sectorShift); +} + + +static __inline__ int forceReadSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return force_read(This->Next, buf, sectorsToBytes((Stream_t *)This, off), + size << This->sectorShift); +} + + +static __inline__ int writeSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return WRITES(This->Next, buf, sectorsToBytes((Stream_t*)This, off), + size << This->sectorShift); +} + +static __inline__ int forceWriteSector(Fs_t *This, char *buf, unsigned int off, + size_t size) +{ + return force_write(This->Next, buf, sectorsToBytes((Stream_t*)This, off), + size << This->sectorShift); +} + + +static FatMap_t *GetFatMap(Fs_t *Stream) +{ + int nr_entries,i; + FatMap_t *map; + + Stream->fat_error = 0; + nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY; + map = NewArray(nr_entries, FatMap_t); + if(!map) + return 0; + + for(i=0; i< nr_entries; i++) { + map[i].data = 0; + map[i].valid = 0; + map[i].dirty = 0; + } + + return map; +} + +static __inline__ int locate(Fs_t *Stream, size_t offset, int *slot, int *bit) +{ + if(offset >= Stream->fat_len) + return -1; + *slot = offset / SECT_PER_ENTRY; + *bit = offset % SECT_PER_ENTRY; + return 0; +} + +static __inline__ int fatReadSector(Fs_t *This, int sector, int slot, + int bit, int dupe, fatBitMask bitmap) +{ + int fat_start, ret; + int nr_sectors; + + dupe = (dupe + This->primaryFat) % This->num_fat; + fat_start = This->fat_start + This->fat_len * dupe; + + if(bitmap == 0) { + nr_sectors = SECT_PER_ENTRY - bit%SECT_PER_ENTRY; + } else { + nr_sectors = 1; + } + + /* first, read as much as the buffer can give us */ + ret = readSector(This, + (char *)(This->FatMap[slot].data+(bit<sectorShift)), + fat_start+sector, + nr_sectors); + if(ret < 0) + return 0; + + if((unsigned int) ret < This->sector_size) { + /* if we got less than one sector's worth, insist to get at + * least one sector */ + ret = forceReadSector(This, + (char *) (This->FatMap[slot].data + + (bit << This->sectorShift)), + fat_start+sector, 1); + if(ret < (int) This->sector_size) + return 0; + return 1; + } + + return ret >> This->sectorShift; +} + + +static int fatWriteSector(Fs_t *This, int sector, int slot, int bit, int dupe) +{ + int fat_start; + + dupe = (dupe + This->primaryFat) % This->num_fat; + if(dupe && !This->writeAllFats) + return This->sector_size; + + fat_start = This->fat_start + This->fat_len * dupe; + + return forceWriteSector(This, + (char *) + (This->FatMap[slot].data + bit * This->sector_size), + fat_start+sector, 1); +} + +static unsigned char *loadSector(Fs_t *This, + unsigned int sector, fatAccessMode_t mode, + int recurs) +{ + int slot, bit, ret; + + if(locate(This,sector, &slot, &bit) < 0) + return 0; +#if 0 + if (((This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY) <= slot) { + fprintf(stderr,"This should not happen\n"); + fprintf(stderr, "fat_len = %d\n", This->fat_len); + fprintf(stderr, "SECT_PER_ENTRY=%d\n", (int)SECT_PER_ENTRY); + fprintf(stderr, "sector = %d slot = %d bit=%d\n", + sector, slot, bit); + fprintf(stderr, "left = %d",(int) + ((This->fat_len+SECT_PER_ENTRY-1) / SECT_PER_ENTRY)); + return 0; + } +#endif + if(!This->FatMap[slot].data) { + /* allocate the storage space */ + This->FatMap[slot].data = + malloc(This->sector_size * SECT_PER_ENTRY); + if(!This->FatMap[slot].data) + return 0; + memset(This->FatMap[slot].data, 0xee, + This->sector_size * SECT_PER_ENTRY); + } + + if(! (This->FatMap[slot].valid & (ONE << bit))) { + unsigned int i; + ret = -1; + for(i=0; i< This->num_fat; i++) { + /* read the sector */ + ret = fatReadSector(This, sector, slot, bit, i, + This->FatMap[slot].valid); + + if(ret == 0) { + fprintf(stderr, + "Error reading fat number %d\n", i); + continue; + } + if(This->FatMap[slot].valid) + /* Set recurs if there have already been + * sectors loaded in this bitmap long + */ + recurs = 1; + break; + } + + /* all copies bad. Return error */ + if(ret == 0) + return 0; + + for(i=0; (int) i < ret; i++) + This->FatMap[slot].valid |= ONE << (bit + i); + + if(!recurs && ret == 1) + /* do some prefetching, if we happened to only + * get one sector */ + loadSector(This, sector+1, mode, 1); + if(!recurs && batchmode) + for(i=0; i < 1024; i++) + loadSector(This, sector+i, mode, 1); + } + + if(mode == FAT_ACCESS_WRITE) { + This->FatMap[slot].dirty |= ONE << bit; + This->fat_dirty = 1; + } + return This->FatMap[slot].data + (bit << This->sectorShift); +} + + +static unsigned char *getAddress(Fs_t *Stream, + unsigned int num, fatAccessMode_t mode) +{ + unsigned char *ret; + int sector; + int offset; + + sector = num >> Stream->sectorShift; + ret = 0; + if(sector == Stream->lastFatSectorNr && + Stream->lastFatAccessMode >= mode) + ret = Stream->lastFatSectorData; + if(!ret) { + ret = loadSector(Stream, sector, mode, 0); + if(!ret) + return 0; + Stream->lastFatSectorNr = sector; + Stream->lastFatSectorData = ret; + Stream->lastFatAccessMode = mode; + } + offset = num & Stream->sectorMask; + return ret+offset; +} + + +static int readByte(Fs_t *Stream, int start) +{ + unsigned char *address; + + address = getAddress(Stream, start, FAT_ACCESS_READ); + if(!address) + return -1; + return *address; +} + + +/* + * Fat 12 encoding: + * | byte n | byte n+1 | byte n+2 | + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | | | | | | | | | + * | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 | + * \_____ \____ \______/________/_____ / + * ____\______\________/ _____/ ____\_/ + * / \ \ / / \ + * | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 | + * | FAT entry k | FAT entry k+1 | + */ + + /* + * Get and decode a FAT (file allocation table) entry. Returns the cluster + * number on success or 1 on failure. + */ + +static unsigned int fat12_decode(Fs_t *Stream, unsigned int num) +{ + unsigned int start = num * 3 / 2; + int byte0 = readByte(Stream, start); + int byte1 = readByte(Stream, start+1); + + if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1) { + fprintf(stderr,"[1] Bad address %d\n", num); + return 1; + } + + if (num & 1) + return (byte1 << 4) | ((byte0 & 0xf0)>>4); + else + return ((byte1 & 0xf) << 8) | byte0; +} + + +/* + * Puts a code into the FAT table. Is the opposite of fat_decode(). No + * sanity checking is done on the code. Returns a 1 on error. + */ +static void fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + int start = num * 3 / 2; + unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE); + unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE); + + if (num & 1) { + /* (odd) not on byte boundary */ + *address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0); + *address1 = (code >> 4) & 0xff; + } else { + /* (even) on byte boundary */ + *address0 = code & 0xff; + *address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f); + } +} + + +/* + * Fat 16 encoding: + * | byte n | byte n+1 | + * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0| + * | | | | | | | | | | | | | | | | | + * | FAT entry k | + */ + +static unsigned int fat16_decode(Fs_t *Stream, unsigned int num) +{ + unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ); + if(!address) + return 1; + return _WORD(address); +} + +static void fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE); + set_word(address, code); +} + + +static unsigned int fast_fat16_decode(Fs_t *Stream, unsigned int num) +{ + unsigned short *address = + (unsigned short *) getAddress(Stream, num << 1, + FAT_ACCESS_READ); + if(!address) + return 1; + return *address; +} + +static void fast_fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned short *address = + (unsigned short *) getAddress(Stream, num << 1, + FAT_ACCESS_WRITE); + *address = code; +} + + + + +/* + * Fat 32 encoding + */ +#define FAT32_HIGH 0xf0000000 +#define FAT32_ADDR 0x0fffffff + +static unsigned int fat32_decode(Fs_t *Stream, unsigned int num) +{ + unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ); + if(!address) + return 1; + return _DWORD(address) & FAT32_ADDR; +} + +static void fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE); + set_dword(address,(code&FAT32_ADDR) | (_DWORD(address)&FAT32_HIGH)); +} + + +static unsigned int fast_fat32_decode(Fs_t *Stream, unsigned int num) +{ + unsigned int *address = + (unsigned int *) getAddress(Stream, num << 2, + FAT_ACCESS_READ); + if(!address) + return 1; + return (*address) & FAT32_ADDR; +} + +static void fast_fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code) +{ + unsigned int *address = + (unsigned int *) getAddress(Stream, num << 2, + FAT_ACCESS_WRITE); + *address = (*address & FAT32_HIGH) | (code & FAT32_ADDR); +} + + +/* + * Write the FAT table to the disk. Up to now the FAT manipulation has + * been done in memory. All errors are fatal. (Might not be too smart + * to wait till the end of the program to write the table. Oh well...) + */ + +void fat_write(Fs_t *This) +{ + unsigned int i, j, dups, bit, slot; + int ret; + + /*fprintf(stderr, "Fat write\n");*/ + + if (!This->fat_dirty) + return; + + dups = This->num_fat; + if (This->fat_error) + dups = 1; + + + for(i=0; ifat_len;slot++) { + if(!This->FatMap[slot].dirty) { + j += SECT_PER_ENTRY; + continue; + } + for(bit=0; + bit < SECT_PER_ENTRY && jfat_len; + bit++,j++) { + if(!(This->FatMap[slot].dirty & (ONE << bit))) + continue; + ret = fatWriteSector(This,j,slot, bit, i); + if (ret < (int) This->sector_size){ + if (ret < 0 ){ + perror("error in fat_write"); + exit(1); + } else { + fprintf(stderr, + "end of file in fat_write\n"); + exit(1); + } + } + /* if last dupe, zero it out */ + if(i==dups-1) + This->FatMap[slot].dirty &= ~(ONE<infoSectorLoc && This->infoSectorLoc != MAX32) { + /* initialize info sector */ + InfoSector_t *infoSector; + infoSector = (InfoSector_t *) safe_malloc(This->sector_size); + set_dword(infoSector->signature1, INFOSECT_SIGNATURE1); + memset(infoSector->filler1, 0, sizeof(infoSector->filler1)); + memset(infoSector->filler2, 0, sizeof(infoSector->filler2)); + set_dword(infoSector->signature2, INFOSECT_SIGNATURE2); + set_dword(infoSector->pos, This->last); + set_dword(infoSector->count, This->freeSpace); + set_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 . + */ + +#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 . + */ + +#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 . + */ + +#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 . + */ + +#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; juchar = out->lchar = (char) 0xff; + else { + out->uchar = *in >> 8; + out->lchar = *in; + if (! *in) { + *end_p = VSE_LAST; + } + } + + ++out; + ++in; + } + return num; +} diff --git a/file_name.h b/file_name.h new file mode 100644 index 0000000..0d9ac90 --- /dev/null +++ b/file_name.h @@ -0,0 +1,44 @@ +#ifndef FILE_NAME_H +#define FILE_NAME_H + +/* Copyright 2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include +#include "mtools.h" + +/** + * raw dos-name coming straight from the directory entry + * MYFILE TXT + */ +struct dos_name_t { + char base[8]; + char ext[3]; + char sentinel; +}; + +int dos_to_wchar(doscp_t *fromDos, char *dos, wchar_t *wchar, size_t len); +void wchar_to_dos(doscp_t *toDos, wchar_t *wchar, char *dos, size_t len, int *mangled); + +doscp_t *cp_open(int codepage); +void cp_close(doscp_t *cp); + +int wchar_to_native(const wchar_t *wchar, char *native, size_t len); +int native_to_wchar(const char *native, wchar_t *wchar, size_t len, + const char *end, int *mangled); + +#endif diff --git a/file_read.c b/file_read.c new file mode 100644 index 0000000..60e336f --- /dev/null +++ b/file_read.c @@ -0,0 +1,55 @@ +/* Copyright 1986-1992 Emmet P. Gray. + * Copyright 1996,1997,1999,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "file.h" + +/* + * Read the clusters given the beginning FAT entry. Returns 0 on success. + */ + +int file_read(FILE *fp, Stream_t *Source, int textmode, int stripmode) +{ + char buffer[16384]; + int pos; + int ret; + + if (!Source){ + fprintf(stderr,"Couldn't open source file\n"); + return -1; + } + + pos = 0; + while(1){ + ret = Source->Class->read(Source, buffer, pos, 16384); + if (ret < 0 ){ + perror("file read"); + return -1; + } + if ( ret == 0) + break; + if(!fwrite(buffer, 1, ret, fp)){ + perror("write"); + return -1; + } + pos += ret; + } + return 0; +} diff --git a/filter.c b/filter.c new file mode 100644 index 0000000..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 . + */ + +#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 . + * + * the floppyd daemon running on the local X-Server + * + * written by: + * + * Peter Schlaile + * + * udbz@rz.uni-karlsruhe.de + * + * Large parts of the network code shamelessly stolen from + * transproxy by John Saunders + * + * Rewritten in C by Alain Knaff. Apparently C++ is still not as + * portable as C. */ + +#define DEBUG 0 + +#include "sysincludes.h" +#include "llong.h" + +#ifdef USE_FLOPPYD + +#define USE_FLOPPYD_BUFFERED_IO 1 +#define FLOPPYD_DEFAULT_PORT 5703 + +#include "sysincludes.h" +#include "grp.h" +#include +#include + +#include "floppyd_io.h" + +#ifndef SIGCLD +#define SIGCLD SIGCHLD +#endif + +/* For Linux 1.2.13 */ +#ifndef SOMAXCONN +#define SOMAXCONN 5 +#endif + +/* + To compile: + + gcc -Wall floppyd.cpp -o floppyd -lX11 + + floppyd + + Communication to the clients works the following way: + + Client sends his protocol-version. If the version between server and client + differ: bail out. + + After that,we send our .Xauthority-file (a maximum of MAX_XAUTHORITY_LENGTH + Bytes long) to the server. + + The server then checks, if it already has a .Xauthority file. If so + it is interpreted as LOCK-File for the floppy-device and the communication + gets terminated. + + (What if we have 2 floppy devices? Well. Two floppy users with different + home-directories should work nicely...) + + Now, the data is written to the .Xauthority file. Then we try to open + a connection to the local X-Server. If this fails -> bail out. + + *** + + The data packets are built as follows: + + Base-packets: 1 Dword length, then data. + length is in Network-Byte order. (4 Bytes) + + Commands are: 1. Packet Opcode (length 1), 1. Data packet as parameter. + + Return: 1.Packet: 1. Dword: Bytes processed, 2. Dword: Error-Code + + *** + + TODO: + * Implement some IOCTL calls to format floppy disks or so... + * Read is somewhat dirty implemented. Tries multiple times to + read the expected bytes from the socket stream. Don't know + why this is necessary. Maybe the socket stream is nonblocking + or something IT SHOULD NOT BE! + +*/ + +typedef unsigned char Byte; +typedef unsigned long Dword; +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 + +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 . + * + * Small install-test utility to check if a floppyd-server is running on the + * X-Server-Host. + * + * written by: + * + * Peter Schlaile + * + * udbz@rz.uni-karlsruhe.de + * + */ + +#include "sysincludes.h" +#include "stream.h" +#include "mtools.h" +#include "msdos.h" +#include "scsi.h" +#include "partition.h" +#include "floppyd_io.h" + +#ifdef USE_FLOPPYD +#include +#include +#include + +/* ######################################################################## */ + +typedef unsigned char Byte; +typedef unsigned long Dword; +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 . + * + * 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 . + */ + +#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 . + * + * Force I/O to be done to complete transfer length + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" + +static int force_io(Stream_t *Stream, + char *buf, mt_off_t start, size_t len, + int (*io)(Stream_t *, char *, mt_off_t, size_t)) +{ + int ret; + int done=0; + + while(len){ + ret = io(Stream, buf, start, len); + if ( ret <= 0 ){ + if (done) + return done; + else + return ret; + } + start += ret; + done += ret; + len -= ret; + buf += ret; + } + return done; +} + +int force_write(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + return force_io(Stream, buf, start, len, + Stream->Class->write); +} + +int force_read(Stream_t *Stream, char *buf, mt_off_t start, size_t len) +{ + return force_io(Stream, buf, start, len, + Stream->Class->read); +} diff --git a/fs.h b/fs.h new file mode 100644 index 0000000..65cf466 --- /dev/null +++ b/fs.h @@ -0,0 +1,43 @@ +#ifndef MTOOLS_FS_H +#define MTOOLS_FS_H + +/* Copyright 1996,1997,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include "stream.h" + + +typedef struct FsPublic_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + int serialized; + unsigned long serial_number; + int cluster_size; + unsigned int sector_size; +} FsPublic_t; + +Stream_t *fs_init(char drive, int mode, int *isRop); +int fat_free(Stream_t *Dir, unsigned int fat); +int fatFreeWithDir(Stream_t *Dir, struct directory *dir); +int fat_error(Stream_t *Dir); +int fat32RootCluster(Stream_t *Dir); +char getDrive(Stream_t *Stream); + +#endif diff --git a/fsP.h b/fsP.h new file mode 100644 index 0000000..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 . + */ +#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 . + * + * hash.c - hash table. + */ + +#include "sysincludes.h" +#include "htable.h" +#include "mtools.h" + +struct hashtable { + T_HashFunc f1,f2; + T_ComparFunc compar; + int size; /* actual size of the array */ + int fill; /* number of deleted or in use slots */ + int inuse; /* number of slots in use */ + int max; /* maximal number of elements to keep efficient */ + T_HashTableEl *entries; +}; + +static int sizes[]={5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, + 25717, 51437, 102877, 205759, 411527, 823117, 1646237, + 3292489, 6584983, 13169977, 26339969, 52679969, 105359939, + 210719881, 421439783, 842879579, 1685759167, 0 }; +static int deleted=0; +static int unallocated=0; + +static int alloc_ht(T_HashTable *H, int size) +{ + int i; + + for(i=0; sizes[i]; i++) + if (sizes[i] > size*4 ) + break; + if (!sizes[i]) + for(i=0; sizes[i]; i++) + if (sizes[i] > size*2 ) + break; + if (!sizes[i]) + for(i=0; sizes[i]; i++) + if (sizes[i] > size) + break; + if(!sizes[i]) + return -1; + size = sizes[i]; + if(size < H->size) + size = H->size; /* never shrink the table */ + H->max = size * 4 / 5 - 2; + H->size = size; + H->fill = 0; + H->inuse = 0; + H->entries = NewArray(size, T_HashTableEl); + if (H->entries == NULL) + return -1; /* out of memory error */ + + for(i=0; i < size; i++) + H->entries[i] = &unallocated; + return 0; +} + +int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, + T_HashTable **H) +{ + *H = New(T_HashTable); + if (*H == NULL){ + return -1; /* out of memory error */ + } + + (*H)->f1 = f1; + (*H)->f2 = f2; + (*H)->compar = c; + (*H)->size = 0; + if(alloc_ht(*H,size)) + return -1; + return 0; +} + +int free_ht(T_HashTable *H, T_HashFunc entry_free) +{ + int i; + if(entry_free) + for(i=0; i< H->size; i++) + if (H->entries[i] != &unallocated && + H->entries[i] != &deleted) + entry_free(H->entries[i]); + Free(H->entries); + Free(H); + return 0; +} + +/* add into hash table without checking for repeats */ +static int _hash_add(T_HashTable *H,T_HashTableEl *E, int *hint) +{ + int f2, pos, ctr; + + pos = H->f1(E) % H->size; + f2 = -1; + ctr = 0; + while(H->entries[pos] != &unallocated && + H->entries[pos] != &deleted){ + if (f2 == -1) + f2 = H->f2(E) % (H->size - 1); + pos = (pos+f2+1) % H->size; + ctr++; + } + if(H->entries[pos] == &unallocated) + H->fill++; /* only increase fill if the previous element was not yet + * counted, i.e. unallocated */ + H->inuse++; + H->entries[pos] = E; + if(hint) + *hint = pos; + return 0; +} + +static int rehash(T_HashTable *H) +{ + int size,i; + T_HashTableEl *oldentries; + /* resize the table */ + + size = H->size; + oldentries = H->entries; + if(alloc_ht(H,((H->inuse+1)*4+H->fill)/5)) + return -1; + + for(i=0; i < size; i++){ + if(oldentries[i] != &unallocated && oldentries[i] != &deleted) + _hash_add(H, oldentries[i], 0); + } + Free(oldentries); + return 0; +} + +int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint) +{ + if (H->fill >= H->max) + rehash(H); + if (H->fill == H->size) + return -1; /*out of memory error */ + return _hash_add(H,E, hint); +} + + +/* add into hash table without checking for repeats */ +static int _hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2, + int *hint, int isIdentity) +{ + int f2, pos, upos, ttl; + + pos = H->f1(E) % H->size; + ttl = H->size; + f2 = -1; + upos = -1; + while(ttl && + H->entries[pos] != &unallocated && + (H->entries[pos] == &deleted || + ((isIdentity || H->compar(H->entries[pos], E) != 0) && + (!isIdentity || H->entries[pos] != E)))){ + if (f2 == -1) + f2 = H->f2(E) % (H->size - 1); + if (upos == -1 && H->entries[pos] == &deleted) + upos = pos; + pos = (pos+f2+1) % H->size; + ttl--; + } + if(H->entries[pos] == &unallocated || !ttl) + return -1; + if (upos != -1){ + H->entries[upos] = H->entries[pos]; + H->entries[pos] = &deleted; + pos = upos; + } + if(hint) + *hint = pos; + *E2= H->entries[pos]; + return 0; +} + + +int hash_lookup(T_HashTable *H,T_HashTableEl *E, T_HashTableEl **E2, + int *hint) +{ + return _hash_lookup(H, E, E2, hint, 0); +} + +/* add into hash table without checking for repeats */ +int hash_remove(T_HashTable *H,T_HashTableEl *E, int hint) +{ + T_HashTableEl *E2; + + if (hint >=0 && hint < H->size && + H->entries[hint] == E){ + H->inuse--; + H->entries[hint] = &deleted; + return 0; + } + + if(_hash_lookup(H, E, &E2, &hint, 1)) { + fprintf(stderr, "Removing non-existent entry\n"); + exit(1); + return -1; + } + H->inuse--; + H->entries[hint] = &deleted; + return 0; +} diff --git a/htable.h b/htable.h new file mode 100644 index 0000000..576a2b7 --- /dev/null +++ b/htable.h @@ -0,0 +1,32 @@ +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + * + * hashtable + */ + +typedef struct hashtable T_HashTable; +typedef void *T_HashTableEl; +typedef unsigned int (*T_HashFunc)(void *); +typedef int (*T_ComparFunc)(void *, void *); + + +int make_ht(T_HashFunc f1, T_HashFunc f2, T_ComparFunc c, int size, T_HashTable **H); +int hash_add(T_HashTable *H, T_HashTableEl *E, int *hint); +int hash_remove(T_HashTable *H, T_HashTableEl *E, int hint); +int hash_lookup(T_HashTable *H, T_HashTableEl *E, T_HashTableEl **E2, + int *hint); +int free_ht(T_HashTable *H, T_HashFunc entry_free); + diff --git a/init.c b/init.c new file mode 100644 index 0000000..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 . + * + * 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 . + */ + +#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 . + */ + +#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 . + * + * 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 . + * + * 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 . + */ + +#include +#include "vfat.h" +#include "mtoolsDirentry.h" + +typedef struct MainParam_t { + /* stuff needing to be initialised by the caller */ + int (*loop)(Stream_t *Dir, struct MainParam_t *mp, + const char *filename); + int (*dirCallback)(direntry_t *, struct MainParam_t *); + int (*callback)(direntry_t *, struct MainParam_t *); + int (*unixcallback)(struct MainParam_t *mp); + + void *arg; /* command-specific parameters + * to be passed to callback */ + + int openflags; /* flags used to open disk */ + int lookupflags; /* flags used to lookup up using vfat_lookup */ + int fast_quit; /* for commands manipulating multiple files, quit + * as soon as even _one_ file has a problem */ + + char *shortname; /* where to put the short name of the matched file */ + char *longname; /* where to put the long name of the matched file */ + + /* out parameters */ + Stream_t *File; + + direntry_t *direntry; /* dir of this entry */ + char *unixSourceName; /* filename of the last opened Unix source + * file (Unix equiv of Dos direntry) */ + + Stream_t *targetDir; /* directory where to place files */ + char *unixTarget; /* directory on Unix where to put files */ + + const char *targetName; /* basename of target file, or NULL if same + * basename as source should be conserved */ + + char *originalArg; /* original argument, complete with wildcards */ + int basenameHasWildcard; /* true if there are wildcards in the + * basename */ + + + /* internal data */ + char mcwd[MAX_PATH+4]; + + char *fileName; /* resolved Unix filename */ + + char targetBuffer[4*MAX_VNAMELEN+1]; /* buffer for target name */ +} MainParam_t; + +void init_mp(MainParam_t *MainParam); +int main_loop(MainParam_t *MainParam, char **argv, int argc); + +int target_lookup(MainParam_t *mp, const char *arg); + +Stream_t *open_root_dir(unsigned char drivename, int flags, int *isRop); + +const char *mpGetBasename(MainParam_t *mp); /* statically allocated + * string */ + +void mpPrintFilename(FILE *file, MainParam_t *mp); +const char *mpPickTargetName(MainParam_t *mp); /* statically allocated string */ + +char *mpBuildUnixFilename(MainParam_t *mp); /* dynamically allocated, must + * be freed */ + +int isSpecial(const char *name); +#ifdef HAVE_WCHAR_H +int isSpecialW(const wchar_t *name); +#else +#define isSpecialW isSpecial +#endif + +#define MISSED_ONE 2 /* set if one cmd line argument didn't match any files */ +#define GOT_ONE 4 /* set if a match was found, used for exit status */ +#define NO_CWD 8 /* file not found while looking for current working + * directory */ +#define ERROR_ONE 16 /* flat out error, such as problems with target file, + interrupt by user, etc. */ +#define STOP_NOW 32 /* stop as soon as possible, not necessarily an error */ + +#endif diff --git a/man-warning-end.texi b/man-warning-end.texi new file mode 100644 index 0000000..12bb530 --- /dev/null +++ b/man-warning-end.texi @@ -0,0 +1,46 @@ +@c Copyright 1998,2001,2002 Alain Knaff. +@c This file is part of mtools +@c Released under the terms of the GNU Free Documentation License, +@c Version 1.3 or any later version published by the Free Software +@c Foundation + +@c for man page version only +@unnumbered See Also +Mtools' texinfo doc +@unnumbered Viewing the texi doc +This manpage has been automatically generated from mtools's texinfo +documentation. However, this process is only approximative, and some +items, such as crossreferences, footnotes and indices are lost in this +translation process. Indeed, these items have no appropriate +representation in the manpage format. Moreover, not all information has +been translated into the manpage version. Thus I strongly advise you to +use the original texinfo doc. See the end of this manpage for +instructions how to view the texinfo doc. + +@itemize @bullet +@item +To generate a printable copy from the texinfo doc, run the following +commands: +@example + ./configure; make dvi; dvips mtools.dvi +@end example + +@item +To generate a html copy, run: +@example + ./configure; make html +@end example +A premade html can be found at +@file{http://www.gnu.org/software/mtools/manual/mtools.html} + +@item +To generate an info copy (browsable using emacs' info mode), run: +@example + ./configure; make info +@end example +@end itemize + +The texinfo doc looks most pretty when printed or as html. Indeed, in +the info version certain examples are difficult to read due to the +quoting conventions used in info. + diff --git a/man-warning.texi b/man-warning.texi new file mode 100644 index 0000000..4e3ab61 --- /dev/null +++ b/man-warning.texi @@ -0,0 +1,12 @@ +@c Copyright 1997,1998,2001,2002 Alain Knaff. +@c This file is part of mtools +@c Released under the terms of the GNU Free Documentation License, +@c Version 1.3 or any later version published by the Free Software +@c Foundation +@c for man page version only +@unnumbered Note of warning +This manpage has been automatically generated from mtools's texinfo +documentation, and may not be entirely accurate or complete. See the +end of this man page for details. + +@c skipskipskip diff --git a/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 . + * + * 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 . + * + * 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 . + * + * 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; icluster_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 . + * + * 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 . + * + * 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 . + * + * Filename: + * mclasserase.c + * + * Original Creation Date: + * 05.III.2003 + * + * Copyright: + * GPL + * + * Programmer: + * Stefan Feuz, Lukas Meyer, Thomas Locher + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "mainloop.h" +#include "fsP.h" + +#ifdef HAVE_GETOPT_H +#include +#endif + +#include "file.h" + +#include +#include + +/** + * Prints the Usage Message to STDOUT
+ * + * @author stefan feuz
+ * stefan.feuz@ruag.com + * + * @param n.a. + * + * @returns n.a. + * + */ +static void usage(int ret) NORETURN; +static void usage(int ret) +{ + fprintf(stderr, "Mtools version %s, dated %s\n", mversion, mdate); + fprintf(stderr, "Usage: %s [-d] drive:\n", progname); + exit(ret); +} + +/** + * Delete all files on a Drive.
+ * + * @author Lukas Meyer
+ * lukas.meyer@ruag.com + * @version 0.4, 11.12.2003 + * + * @param drive the drive to erase + * @param debug 1: stop after each erase cycle, 0: normal mode + * + * @returns n.a. + * + */ +static void do_mclasserase(char drive,int debug) +{ + struct device dev; /* Device information structure */ + union bootsector boot; + + int media; /* Just used to enter some in find_device */ + char name[EXPAND_BUF]; + Stream_t *Stream; + struct label_blk_t *labelBlock; + + FILE * fDevice; /* Stores device's file descriptor */ + + char cCardType[12]; + + char drivel[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 to continue\n"); + printf("Press and to abort\n"); + + if(scanf("%c",dummy) < 1) + printf("Input error\n"); + fflush( stdin ); + + if (strcmp(dummy,"x") == 0) + { + printf("exiting.\n"); + exit(0); + } + } + + fclose(fDevice); + + } + + + /* + * Format device using shell script + */ + if (debug == 0) + { + /* redirect STDERR and STDOUT to the black hole... */ + if (dup2(open("/dev/null", O_WRONLY), STDERR_FILENO) != STDERR_FILENO) + printf("Error with dup2() stdout\n"); + if (dup2(open("/dev/null", O_WRONLY), STDOUT_FILENO) != STDOUT_FILENO) + printf("Error with dup2() stdout\n"); + } + + if (debug == 1) + printf("Calling amuFormat.sh with args: %s,%s\n",cCardType,drivel); + + execlp("amuFormat.sh","",cCardType,drivel,NULL); + + /* we never come back...(we shouldn't come back ...) */ + exit(-1); + +} + + +/** + * Total Erase of Data on a Disk. After using mclasserase there wont + * be ANY bits of old files on the disk.
+ * + * @author stefan feuz
+ * thomas locher
+ * stefan.feuz@ruag.com + * thomas.locher@ruag.com + * @version 0.3, 02.12.2003 + * + * @param argc generated automatically by operating systems + * @param **argv1 generated automatically by operating systems + * @param type generated automatically by operating systems + * + * @param -d stop after each erase cycle, for testing purposes + * + * @returns int 0 if all is well done
+ * int -1 if there is something wrong + * + * @info mclasserase [-p tempFilePath] [-d] drive: + * + * + */ +void mclasserase(int argc, char **argv, int type 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 +.\" +.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 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 . + * + * 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 . + * + * 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 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 . + * + * mdir.c: + * Display an MSDOS directory + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "vfat.h" +#include "mtools.h" +#include "file.h" +#include "mainloop.h" +#include "fs.h" +#include "codepage.h" +#include "file_name.h" + +#ifdef TEST_SIZE +#include "fsP.h" +#endif + +static int recursive; +static int wide; +static int all; +static int concise; +static int fast=0; +#if 0 +static int testmode = 0; +#endif +static const char *dirPath; +static char *dynDirPath; +static char currentDrive; +static Stream_t *currentDir; + +static int filesInDir; /* files in current dir */ +static int filesOnDrive; /* files on drive */ + +static int dirsOnDrive; /* number of listed directories on this drive */ + +static int debug = 0; /* debug mode */ + +static mt_size_t bytesInDir; +static mt_size_t bytesOnDrive; +static Stream_t *RootDir; + + +static char global_shortname[13]; +static char global_longname[VBUFSIZE]; + + +/* + * Print an MSDOS directory date stamp. + */ +static __inline__ void print_date(struct directory *dir) +{ + char year[5]; + char day[3]; + char month[3]; + const char *p; + + sprintf(year, "%04d", DOS_YEAR(dir)); + sprintf(day, "%02d", DOS_DAY(dir)); + sprintf(month, "%02d", DOS_MONTH(dir)); + + for(p=mtools_date_string; *p; p++) { + if(!strncasecmp(p, "yyyy", 4)) { + printf("%04d", DOS_YEAR(dir)); + p+= 3; + continue; + } else if(!strncasecmp(p, "yy", 2)) { + printf("%02d", DOS_YEAR(dir) % 100); + p++; + continue; + } else if(!strncasecmp(p, "dd", 2)) { + printf("%02d", DOS_DAY(dir)); + p++; + continue; + } else if(!strncasecmp(p, "mm", 2)) { + printf("%02d", DOS_MONTH(dir)); + p++; + continue; + } + putchar(*p); + } +} + +/* + * Print an MSDOS directory time stamp. + */ +static __inline__ void print_time(struct directory *dir) +{ + char am_pm; + int hour = DOS_HOUR(dir); + + if(!mtools_twenty_four_hour_clock) { + am_pm = (hour >= 12) ? 'p' : 'a'; + if (hour > 12) + hour = hour - 12; + if (hour == 0) + hour = 12; + } else + am_pm = ' '; + + printf("%2d:%02d%c", hour, DOS_MINUTE(dir), am_pm); +} + +/* + * Return a number in dotted notation + */ +static const char *dotted_num(mt_size_t num, int width, char **buf) +{ + int len; + register char *srcp, *dstp; + int size; + + unsigned long numlo; + unsigned long numhi; + + if (num < 0) { + /* warn about negative numbers here. They should not occur */ + fprintf(stderr, "Invalid negative number\n"); + } + + size = width + width; + *buf = malloc(size+1); + + if (*buf == NULL) + return ""; + + /* Create the number in maximum width; make sure that the string + * length is not exceeded (in %6ld, the result can be longer than 6!) + */ + + numlo = num % 1000000000; + numhi = num / 1000000000; + + if(numhi && size > 9) { + sprintf(*buf, "%.*lu%09lu", size-9, numhi, numlo); + } else { + sprintf(*buf, "%.*lu", size, numlo); + } + + for (srcp=*buf; srcp[1] != '\0'; ++srcp) + if (srcp[0] == '0') + srcp[0] = ' '; + else + break; + + len = strlen(*buf); + srcp = (*buf)+len; + dstp = (*buf)+len+1; + + for ( ; dstp >= (*buf)+4 && isdigit (srcp[-1]); ) { + srcp -= 3; /* from here we copy three digits */ + dstp -= 4; /* that's where we put these 3 digits */ + } + + /* now finally copy the 3-byte blocks to their new place */ + while (dstp < (*buf) + len) { + dstp[0] = srcp[0]; + dstp[1] = srcp[1]; + dstp[2] = srcp[2]; + if (dstp + 3 < (*buf) + len) + /* use spaces instead of dots: they please both + * Americans and Europeans */ + dstp[3] = ' '; + srcp += 3; + dstp += 4; + } + + return (*buf) + len-width; +} + +static __inline__ int print_volume_label(Stream_t *Dir, char drive) +{ + Stream_t *Stream = GetFs(Dir); + direntry_t entry; + DeclareThis(FsPublic_t); + char shortname[13]; + char longname[VBUFSIZE]; + int r; + + RootDir = OpenRoot(Stream); + if(concise) + return 0; + + /* find the volume label */ + + initializeDirentry(&entry, RootDir); + if((r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY, + shortname, longname)) ) { + if (r == -2) { + /* I/O Error */ + return -1; + } + printf(" Volume in drive %c has no label", drive); + } else if (*longname) + printf(" Volume in drive %c is %s (abbr=%s)", + drive, longname, shortname); + else + printf(" Volume in drive %c is %s", + drive, shortname); + if(This->serialized) + printf("\n Volume Serial Number is %04lX-%04lX", + (This->serial_number >> 16) & 0xffff, + This->serial_number & 0xffff); + return 0; +} + + +static void printSummary(int files, mt_size_t bytes) +{ + if(!filesInDir) + printf("No files\n"); + else { + char *s1 = NULL; + printf(" %3d file", files); + if(files == 1) + putchar(' '); + else + putchar('s'); + printf(" %s bytes\n", + dotted_num(bytes, 13, &s1)); + if(s1) + free(s1); + } +} + +static void leaveDirectory(int haveError); + +static void leaveDrive(int haveError) +{ + if(!currentDrive) + return; + leaveDirectory(haveError); + if(!concise && !haveError) { + + if(dirsOnDrive > 1) { + printf("\nTotal files listed:\n"); + printSummary(filesOnDrive, bytesOnDrive); + } + if(RootDir && !fast) { + char *s1 = NULL; + mt_off_t bytes = getfree(RootDir); + if(bytes == -1) { + fprintf(stderr, "Fat error\n"); + goto exit_1; + } + printf(" %s bytes free\n\n", + dotted_num(bytes,17, &s1)); +#ifdef TEST_SIZE + ((Fs_t*)GetFs(RootDir))->freeSpace = 0; + bytes = getfree(RootDir); + printf(" %s bytes free\n\n", + dotted_num(bytes,17, &s1)); +#endif + if(s1) + free(s1); + } + } + exit_1: + FREE(&RootDir); + currentDrive = '\0'; +} + + +static int enterDrive(Stream_t *Dir, char drive) +{ + int r; + if(currentDrive == drive) + return 0; /* still the same */ + + leaveDrive(0); + currentDrive = drive; + + r = print_volume_label(Dir, drive); + if (r) + return r; + + + bytesOnDrive = 0; + filesOnDrive = 0; + dirsOnDrive = 0; + return 0; +} + +static const char *emptyString=""; + +static void leaveDirectory(int haveError) +{ + if(!currentDir) + return; + + if (!haveError) { + if(dirPath && dirPath != emptyString) + free(dynDirPath); + if(wide) + putchar('\n'); + + if(!concise) + printSummary(filesInDir, bytesInDir); + } + FREE(¤tDir); +} + +static int enterDirectory(Stream_t *Dir) +{ + int r; + char drive; + if(currentDir == Dir) + return 0; /* still the same directory */ + + leaveDirectory(0); + + drive = getDrive(Dir); + r=enterDrive(Dir, drive); + if(r) + return r; + currentDir = COPY(Dir); + + dynDirPath = getPwd(getDirentry(Dir)); + if(!dynDirPath) + dirPath=emptyString; + else { + if(!dynDirPath[3] && concise) + dynDirPath[2]='\0'; + dirPath=dynDirPath; + } + + /* print directory title */ + if(!concise) + printf("\nDirectory for %s\n", dirPath); + + if(!wide && !concise) + printf("\n"); + + dirsOnDrive++; + bytesInDir = 0; + filesInDir = 0; + return 0; +} + +static int list_file(direntry_t *entry, MainParam_t *mp 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(" "); + 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 . + * + * 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 . + * + * 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 . + * + * mformat.c + */ + +#define DONT_NEED_WAIT + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "mainloop.h" +#include "fsP.h" +#include "file.h" +#include "plain_io.h" +#include "floppyd_io.h" +#include "nameclash.h" +#include "buffer.h" +#ifdef HAVE_ASSERT_H +#include +#endif +#ifdef USE_XDF +#include "xdf_io.h" +#endif +#include "partition.h" +#include "file_name.h" + +#ifndef abs +#define abs(x) ((x)>0?(x):-(x)) +#endif + +#ifdef OS_linux +#include "linux/hdreg.h" + +#define _LINUX_STRING_H_ +#define kdev_t int +#include "linux/fs.h" +#undef _LINUX_STRING_H_ + +#endif + + +static int init_geometry_boot(union bootsector *boot, struct device *dev, + int sectors0, int rate_0, int rate_any, + unsigned long *tot_sectors, int keepBoot) +{ + int i; + int nb_renum; + int sector2; + int size2; + int j; + int sum; + + set_word(boot->boot.nsect, dev->sectors); + set_word(boot->boot.nheads, dev->heads); + +#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; jbytes[j];/* checksum */ + boot->boot.ext.old.CheckSum=-sum; + return bootOffset; + } else { + if(!keepBoot) { + boot->boot.jump[0] = 0xeb; + boot->boot.jump[1] = 0; + boot->boot.jump[2] = 0x90; + strncpy(boot->boot.banner, mformat_banner, 8); + /* It looks like some versions of DOS are + * rather picky about this, and assume default + * parameters without this, ignoring any + * indication about cluster size et al. */ + } + return 0; + } +} + + +static int comp_fat_bits(Fs_t *Fs, int estimate, + unsigned long tot_sectors, int fat32) +{ + int needed_fat_bits; + + needed_fat_bits = 12; + +#define MAX_DISK_SIZE(bits,clusters) \ + TOTAL_DISK_SIZE((bits), Fs->sector_size, (clusters), \ + Fs->num_fat, MAX_BYTES_PER_CLUSTER/Fs->sector_size) + + if(tot_sectors > MAX_DISK_SIZE(12, FAT12-1)) + needed_fat_bits = 16; + if(fat32 || tot_sectors > MAX_DISK_SIZE(16, FAT16-1)) + needed_fat_bits = 32; + +#undef MAX_DISK_SIZE + + if(abs(estimate) && abs(estimate) < needed_fat_bits) { + if(fat32) { + fprintf(stderr, + "Contradiction between FAT size on command line and FAT size in conf file\n"); + exit(1); + } + fprintf(stderr, + "Device too big for a %d bit FAT\n", + estimate); + exit(1); + } + + if(!estimate) { + unsigned int min_fat16_size; + + if(needed_fat_bits > 12) + return needed_fat_bits; + min_fat16_size = DISK_SIZE(16, Fs->sector_size, FAT12, + Fs->num_fat, 1); + if(tot_sectors < min_fat16_size) + return 12; + else if(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 . + * + * 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 . + * + * 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 . + */ +#include "sysincludes.h" +#include "mtools.h" + +#ifndef HAVE_STRDUP + + +char *strdup(const char *str) +{ + char *nstr; + + if (str == (char*)0) + return 0; + + nstr = (char*)malloc((strlen(str) + 1)); + + if (nstr == (char*)0) + { + (void)fprintf(stderr, "strdup(): not enough memory to duplicate `%s'\n", + str); + exit(1); + } + + (void)strcpy(nstr, str); + + return nstr; +} +#endif /* HAVE_STRDUP */ + +#ifdef HAVE_WCHAR_H +#ifndef HAVE_WCSDUP +wchar_t *wcsdup(const wchar_t *wcs) +{ + wchar_t *nwcs; + + if (wcs == (wchar_t*)0) + return 0; + + nwcs = (wchar_t*)calloc(wcslen(wcs) + 1, sizeof(wchar_t)); + + if (nwcs == (wchar_t*)0) + { + (void)fprintf(stderr, "wcsdup(): not enough memory to duplicate `%ls'\n", + wcs); + exit(1); + } + + (void)wcscpy(nwcs, wcs); + + return nwcs; +} +#endif /* HAVE_WCSDUP */ +#endif + +#ifndef HAVE_MEMCPY +/* + * Copy contents of memory (with possible overlapping). + */ +char *memcpy(char *s1, const char *s2, size_t n) +{ + bcopy(s2, s1, n); + return(s1); +} +#endif + +#ifndef HAVE_MEMSET +/* + * Copies the character c, n times to string s + */ +char *memset(char *s, char c, size_t n) +{ + char *s1 = s; + + while (n > 0) { + --n; + *s++ = c; + } + return(s1); +} +#endif /* HAVE_MEMSET */ + + +#ifndef HAVE_STRCHR + +char * strchr (const char* s, int c) +{ + if (!s) return NULL; + while (*s && *s != c) s++; + if (*s) + return (char*) s; + else + return NULL; +} + +#endif + +#ifndef HAVE_STRRCHR + +char * strrchr (const char* s1, int c) +{ + char* s = (char*) s1; + char* start = (char*) s; + if (!s) return NULL; + s += strlen(s)-1; + while (*s != c && (unsigned long) s != (unsigned long) start) s--; + if ((unsigned long) s == (unsigned long) start && *s != c) + return NULL; + else + return s; +} + +#endif + +#ifndef HAVE_STRPBRK +/* + * Return ptr to first occurrence of any character from `brkset' + * in the character string `string'; NULL if none exists. + */ +char *strpbrk(const char *string, const char *brkset) +{ + register char *p; + + if (!string || !brkset) + return(0); + do { + for (p = brkset; *p != '\0' && *p != *string; ++p) + ; + if (*p != '\0') + return(string); + } + while (*string++); + return(0); +} +#endif /* HAVE_STRPBRK */ + + +#ifndef HAVE_STRTOUL +static int getdigit(char a, int max) +{ + int dig; + + if(a < '0') + return -1; + if(a <= '9') { + dig = a - '0'; + } else if(a >= 'a') + dig = a - 'a' + 10; + else if(a >= 'A') + dig = a - 'A' + 10; + if(dig >= max) + return -1; + else + return dig; +} + +unsigned long strtoul(const char *string, char **eptr, int base) +{ + int accu, dig; + + if(base < 1 || base > 36) { + if(string[0] == '0') { + switch(string[1]) { + case 'x': + case 'X': + return strtoul(string+2, eptr, 16); + case 'b': + case 'B': + return strtoul(string+2, eptr, 2); + default: + return strtoul(string, eptr, 8); + } + } + return strtoul(string, eptr, 10); + } + if(base == 16 && string[0] == '0' && + (string[1] == 'x' || string[1] == 'X')) + string += 2; + + if(base == 2 && string[0] == '0' && + (string[1] == 'b' || string[1] == 'B')) + string += 2; + accu = 0; + while( (dig = getdigit(*string, base)) != -1 ) { + accu = accu * base + dig; + string++; + } + if(eptr) + *eptr = (char *) string; + return accu; +} +#endif /* HAVE_STRTOUL */ + +#ifndef HAVE_STRTOL +long strtol(const char *string, char **eptr, int base) +{ + long l; + + if(*string == '-') { + return -(long) strtoul(string+1, eptr, base); + } else { + if (*string == '+') + string ++; + return (long) strtoul(string, eptr, base); + } +} +#endif + + + +#ifndef HAVE_STRSPN +/* Return the length of the maximum initial segment + of S which contains only characters in ACCEPT. */ +size_t strspn(const char *s, const char *accept) +{ + register char *p; + register char *a; + register size_t count = 0; + + for (p = s; *p != '\0'; ++p) + { + for (a = accept; *a != '\0'; ++a) + if (*p == *a) + break; + if (*a == '\0') + return count; + else + ++count; + } + + return count; +} +#endif /* HAVE_STRSPN */ + +#ifndef HAVE_STRCSPN +/* Return the length of the maximum inital segment of S + which contains no characters from REJECT. */ +size_t strcspn (const char *s, const char *reject) +{ + register size_t count = 0; + + while (*s != '\0') + if (strchr (reject, *s++) == NULL) + ++count; + else + return count; + + return count; +} + +#endif /* HAVE_STRCSPN */ + +#ifndef HAVE_STRERROR + +#ifndef DECL_SYS_ERRLIST +extern char *sys_errlist[]; +#endif + +char *strerror(int errno) +{ + return sys_errlist[errno]; +} +#endif + +#ifndef HAVE_STRCASECMP +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexiographically less than, + equal to or greater than S2. */ +int strcasecmp(const char *s1, const char *s2) +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + + if (p1 == p2) + return 0; + + do + { + c1 = tolower (*p1++); + c2 = tolower (*p2++); + if (c1 == '\0') + break; + } + while (c1 == c2); + + return c1 - c2; +} +#endif + +#ifdef HAVE_WCHAR_H +#ifndef HAVE_WCSCASECMP +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexiographically less than, + equal to or greater than S2. */ +int wcscasecmp(const wchar_t *s1, const wchar_t *s2) +{ + register const wchar_t *p1 = s1; + register const wchar_t *p2 = s2; + wchar_t c1, c2; + + if (p1 == p2) + return 0; + + do + { + c1 = towlower (*p1++); + c2 = towlower (*p2++); + if (c1 == '\0') + break; + } + while (c1 == c2); + + return c1 - c2; +} +#endif +#endif + + +#ifndef HAVE_STRCASECMP +/* Compare S1 and S2, ignoring case, returning less than, equal to or + greater than zero if S1 is lexiographically less than, + equal to or greater than S2. */ +int strncasecmp(const char *s1, const char *s2, size_t n) +{ + register const unsigned char *p1 = (const unsigned char *) s1; + register const unsigned char *p2 = (const unsigned char *) s2; + unsigned char c1, c2; + + if (p1 == p2) + return 0; + + c1 = c2 = 1; + while (c1 && c1 == c2 && n-- > 0) + { + c1 = tolower (*p1++); + c2 = tolower (*p2++); + } + + return c1 - c2; +} +#endif + +#ifndef HAVE_GETPASS +char *getpass(const char *prompt) +{ + static char password[129]; + int l; + + fprintf(stderr,"%s",prompt); + fgets(password, 128, stdin); + l = strlen(password); + if(l && password[l-1] == '\n') + password[l-1] = '\0'; + return password; + +} +#endif + +#ifndef HAVE_ATEXIT + +#ifdef HAVE_ON_EXIT +int atexit(void (*function)(void)) +{ + return on_exit( (void(*)(int,void*)) function, 0); +} +#else + +typedef struct exitCallback { + void (*function) (void); + struct exitCallback *next; +} exitCallback_t; + +static exitCallback_t *callback = 0; + +int atexit(void (*function) (void)) +{ + exitCallback_t *newCallback; + + newCallback = New(exitCallback_t); + if(!newCallback) { + printOom(); + exit(1); + } + newCallback->function = function; + newCallback->next = callback; + callback = newCallback; + return 0; +} +#undef exit + +void myexit(int code) +{ + void (*function)(void); + + while(callback) { + function = callback->function; + callback = callback->next; + function(); + } + exit(code); +} + +#endif + +#endif + +static const char PATH_SEP = '/'; + +/*#ifndef HAVE_BASENAME*/ +const char *_basename(const char *filename) +{ + char *ptr; + + ptr = strrchr(filename, PATH_SEP); + if(ptr) + filename = ptr + 1; + +#ifdef OS_mingw32msvc + ptr = strrchr(filename, '\\'); + if(ptr) + filename = ptr + 1; +#endif + + return filename; +} +/*#endif*/ + +/* Strip the suffix ".exe" from the argument, if present. */ +void _stripexe(char *filename) +{ + char *ptr; + ptr = strrchr(filename, '.'); + if(ptr && !strcasecmp(ptr, ".exe")) + *ptr = '\0'; +} + +#ifndef HAVE_STRNLEN +size_t strnlen(const char *str, size_t l) +{ + size_t i; + for(i=0; i. + * + * mk_direntry.c + * Make new directory entries, and handles name clashes + * + */ + +/* + * This file is used by those commands that need to create new directory entries + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" +#include "vfat.h" +#include "nameclash.h" +#include "fs.h" +#include "stream.h" +#include "mainloop.h" +#include "file_name.h" + +/** + * Converts input to shortname + * @param un unix name (in Unix charset) + * + * @return 1 if name had to be mangled + */ +static __inline__ int convert_to_shortname(doscp_t *cp, ClashHandling_t *ch, + const char *un, dos_name_t *dn) +{ + int mangled; + + /* Then do conversion to dn */ + ch->name_converter(cp, un, 0, &mangled, dn); + dn->sentinel = '\0'; + return mangled; +} + +static __inline__ void chomp(char *line) +{ + int l = strlen(line); + while(l > 0 && (line[l-1] == '\n' || line[l-1] == '\r')) { + line[--l] = '\0'; + } +} + +/** + * Asks for an alternative new name for a file, in case of a clash + */ +static __inline__ int ask_rename(doscp_t *cp, ClashHandling_t *ch, + dos_name_t *shortname, + char *longname, + int isprimary) +{ + int mangled; + + /* TODO: Would be nice to suggest "autorenamed" version of name, press + * to get it. + */ +#if 0 + fprintf(stderr,"Entering ask_rename, isprimary=%d.\n", isprimary); +#endif + + if(!opentty(0)) + return 0; + +#define maxsize (isprimary ? MAX_VNAMELEN+1 : 11+1) +#define name (isprimary ? argname : shortname) + + mangled = 0; + do { + char tname[4*MAX_VNAMELEN+1]; + fprintf(stderr, "New %s name for \"%s\": ", + isprimary ? "primary" : "secondary", longname); + fflush(stderr); + if (! fgets(tname, 4*MAX_VNAMELEN+1, opentty(0))) + return 0; + chomp(tname); + if (isprimary) + strcpy(longname, tname); + else + mangled = convert_to_shortname(cp, + ch, tname, shortname); + } while (mangled & 1); + return 1; +#undef maxsize +#undef name +} + +/** + * This function determines the action to be taken in case there is a problem + * with target name (clash, illegal characters, or reserved) + * The decision either comes from the default (ch), or the user will be + * prompted if there is no default + */ +static __inline__ clash_action ask_namematch(doscp_t *cp, + dos_name_t *dosname, + char *longname, + int isprimary, + ClashHandling_t *ch, + int no_overwrite, + int reason) +{ + /* User's answer letter (from keyboard). Only first letter is used, + * but we allocate space for 10 in order to account for extra garbage + * that user may enter + */ + char ans[10]; + + /** + * Return value: action to be taken + */ + clash_action a; + + /** + * Should this decision be made permanent (do no longer ask same + * question) + */ + int perm; + + /** + * Buffer for shortname + */ + char name_buffer[4*13]; + + /** + * Name to be printed + */ + char *name; + +#define EXISTS 0 +#define RESERVED 1 +#define ILLEGALS 2 + + static const char *reasons[]= { + "already exists", + "is reserved", + "contains illegal character(s)"}; + + a = ch->action[isprimary]; + + if(a == NAMEMATCH_NONE && !opentty(1)) { + /* no default, and no tty either . Skip the troublesome file */ + return NAMEMATCH_SKIP; + } + + if (!isprimary) + name = unix_normalize(cp, name_buffer, dosname); + else + name = longname; + + perm = 0; + while (a == NAMEMATCH_NONE) { + fprintf(stderr, "%s file name \"%s\" %s.\n", + isprimary ? "Long" : "Short", name, reasons[reason]); + fprintf(stderr, + "a)utorename A)utorename-all r)ename R)ename-all "); + if(!no_overwrite) + fprintf(stderr,"o)verwrite O)verwrite-all"); + fprintf(stderr, + "\ns)kip S)kip-all q)uit (aArR"); + if(!no_overwrite) + fprintf(stderr,"oO"); + fprintf(stderr,"sSq): "); + fflush(stderr); + fflush(opentty(1)); + if (mtools_raw_tty) { + int rep; + rep = fgetc(opentty(1)); + fputs("\n", stderr); + if(rep == EOF) + ans[0] = 'q'; + else + ans[0] = rep; + } else { + if(fgets(ans, 9, opentty(0)) == NULL) + ans[0] = 'q'; + } + perm = isupper((unsigned char)ans[0]); + switch(tolower((unsigned char)ans[0])) { + case 'a': + a = NAMEMATCH_AUTORENAME; + break; + case 'r': + if(isprimary) + a = NAMEMATCH_PRENAME; + else + a = NAMEMATCH_RENAME; + break; + case 'o': + if(no_overwrite) + continue; + a = NAMEMATCH_OVERWRITE; + break; + case 's': + a = NAMEMATCH_SKIP; + break; + case 'q': + perm = 0; + a = NAMEMATCH_QUIT; + break; + default: + perm = 0; + } + } + + /* Keep track of this action in case this file collides again */ + ch->action[isprimary] = a; + if (perm) + ch->namematch_default[isprimary] = a; + + /* if we were asked to overwrite be careful. We can't set the action + * to overwrite, else we get won't get a chance to specify another + * action, should overwrite fail. Indeed, we'll be caught in an + * infinite loop because overwrite will fail the same way for the + * second time */ + if(a == NAMEMATCH_OVERWRITE) + ch->action[isprimary] = NAMEMATCH_NONE; + return a; +} + +/* + * Processes a name match + * dosname short dosname (ignored if is_primary) + * + * + * Returns: + * 2 if file is to be overwritten + * 1 if file was renamed + * 0 if it was skipped + * + * If a short name is involved, handle conversion between the 11-character + * fixed-length record DOS name and a literal null-terminated name (e.g. + * "COMMAND COM" (no null) <-> "COMMAND.COM" (null terminated)). + * + * Also, immediately copy the original name so that messages can use it. + */ +static __inline__ clash_action process_namematch(doscp_t *cp, + dos_name_t *dosname, + char *longname, + int isprimary, + ClashHandling_t *ch, + int no_overwrite, + int reason) +{ + clash_action action; + +#if 0 + fprintf(stderr, + "process_namematch: name=%s, default_action=%d, ask=%d.\n", + name, default_action, ch->ask); +#endif + + action = ask_namematch(cp, dosname, longname, + isprimary, ch, no_overwrite, reason); + + switch(action){ + case NAMEMATCH_QUIT: + got_signal = 1; + return NAMEMATCH_SKIP; + case NAMEMATCH_SKIP: + return NAMEMATCH_SKIP; + case NAMEMATCH_RENAME: + case NAMEMATCH_PRENAME: + /* We need to rename the file now. This means we must pass + * back through the loop, a) ensuring there isn't a potential + * new name collision, and b) finding a big enough VSE. + * Change the name, so that it won't collide again. + */ + ask_rename(cp, ch, dosname, longname, isprimary); + return action; + case NAMEMATCH_AUTORENAME: + /* Very similar to NAMEMATCH_RENAME, except that we need to + * first generate the name. + * TODO: Remember previous name so we don't + * keep trying the same one. + */ + if (isprimary) { + autorename_long(longname, 1); + return NAMEMATCH_PRENAME; + } else { + autorename_short(dosname, 1); + return NAMEMATCH_RENAME; + } + case NAMEMATCH_OVERWRITE: + if(no_overwrite) + return NAMEMATCH_SKIP; + else + return NAMEMATCH_OVERWRITE; + default: + return NAMEMATCH_NONE; + } +} + +static int contains_illegals(const char *string, const char *illegals, + int len) +{ + for(; *string && len--; string++) + if((*string < ' ' && *string != '\005' && !(*string & 0x80)) || + strchr(illegals, *string)) + return 1; + return 0; +} + +static int is_reserved(char *ans, int islong) +{ + unsigned int i; + static const char *dev3[] = {"CON", "AUX", "PRN", "NUL", " "}; + static const char *dev4[] = {"COM", "LPT" }; + + for (i = 0; i < sizeof(dev3)/sizeof(*dev3); i++) + if (!strncasecmp(ans, dev3[i], 3) && + ((islong && !ans[3]) || + (!islong && !strncmp(ans+3," ",5)))) + return 1; + + for (i = 0; i < sizeof(dev4)/sizeof(*dev4); i++) + if (!strncasecmp(ans, dev4[i], 3) && + (ans[3] >= '1' && ans[3] <= '4') && + ((islong && !ans[4]) || + (!islong && !strncmp(ans+4," ",4)))) + return 1; + + return 0; +} + +static __inline__ clash_action get_slots(Stream_t *Dir, + dos_name_t *dosname, + char *longname, + struct scan_state *ssp, + ClashHandling_t *ch) +{ + int error; + clash_action ret; + int match_pos=0; + direntry_t entry; + int isprimary; + int no_overwrite; + int reason; + int pessimisticShortRename; + doscp_t *cp = GET_DOSCONVERT(Dir); + + pessimisticShortRename = (ch->action[0] == NAMEMATCH_AUTORENAME); + + entry.Dir = Dir; + no_overwrite = 1; + if((is_reserved(longname,1)) || + longname[strspn(longname,". ")] == '\0'){ + reason = RESERVED; + isprimary = 1; + } else if(contains_illegals(longname,long_illegals,1024)) { + reason = ILLEGALS; + isprimary = 1; + } else if(is_reserved(dosname->base,0)) { + reason = RESERVED; + ch->use_longname = 1; + isprimary = 0; + } else if(contains_illegals(dosname->base,short_illegals,11)) { + reason = ILLEGALS; + ch->use_longname = 1; + isprimary = 0; + } else { + reason = EXISTS; + switch (lookupForInsert(Dir, + &entry, + dosname, longname, ssp, + ch->ignore_entry, + ch->source_entry, + pessimisticShortRename && + ch->use_longname, + ch->use_longname)) { + case -1: + return NAMEMATCH_ERROR; + + case 0: + return NAMEMATCH_SKIP; + /* Single-file error error or skip request */ + + case 5: + return NAMEMATCH_GREW; + /* Grew directory, try again */ + + case 6: + return NAMEMATCH_SUCCESS; /* Success */ + } + match_pos = -2; + if (ssp->longmatch > -1) { + /* Primary Long Name Match */ +#ifdef debug + fprintf(stderr, + "Got longmatch=%d for name %s.\n", + longmatch, longname); +#endif + match_pos = ssp->longmatch; + isprimary = 1; + } else if ((ch->use_longname & 1) && (ssp->shortmatch != -1)) { + /* Secondary Short Name Match */ +#ifdef debug + fprintf(stderr, + "Got secondary short name match for name %s.\n", + longname); +#endif + + match_pos = ssp->shortmatch; + isprimary = 0; + } else if (ssp->shortmatch >= 0) { + /* Primary Short Name Match */ +#ifdef debug + fprintf(stderr, + "Got primary short name match for name %s.\n", + longname); +#endif + match_pos = ssp->shortmatch; + isprimary = 1; + } else + return NAMEMATCH_RENAME; + + if(match_pos > -1) { + entry.entry = match_pos; + dir_read(&entry, &error); + if (error) + return NAMEMATCH_ERROR; + /* if we can't overwrite, don't propose it */ + no_overwrite = (match_pos == ch->source || IS_DIR(&entry)); + } + } + ret = process_namematch(cp, dosname, longname, + isprimary, ch, no_overwrite, reason); + + if (ret == NAMEMATCH_OVERWRITE && match_pos > -1){ + if((entry.dir.attr & 0x5) && + (ask_confirmation("file is read only, overwrite anyway (y/n) ? "))) + return NAMEMATCH_RENAME; + /* Free up the file to be overwritten */ + if(fatFreeWithDirentry(&entry)) + return NAMEMATCH_ERROR; + +#if 0 + if(isprimary && + match_pos - ssp->match_free + 1 >= ssp->size_needed){ + /* reuse old entry and old short name for overwrite */ + ssp->free_start = match_pos - ssp->size_needed + 1; + ssp->free_size = ssp->size_needed; + ssp->slot = match_pos; + ssp->got_slots = 1; + strncpy(dosname, dir.name, 3); + strncpy(dosname + 8, dir.ext, 3); + return ret; + } else +#endif + { + wipeEntry(&entry); + return NAMEMATCH_RENAME; + } + } + + return ret; +} + + +static __inline__ int write_slots(Stream_t *Dir, + dos_name_t *dosname, + char *longname, + struct scan_state *ssp, + write_data_callback *cb, + void *arg, + int Case) +{ + direntry_t entry; + + /* write the file */ + if (fat_error(Dir)) + return 0; + + entry.Dir = Dir; + entry.entry = ssp->slot; + native_to_wchar(longname, entry.name, MAX_VNAMELEN, 0, 0); + entry.name[MAX_VNAMELEN]='\0'; + entry.dir.Case = Case & (EXTCASE | BASECASE); + if (cb(dosname, longname, arg, &entry) >= 0) { + if ((ssp->size_needed > 1) && + (ssp->free_end - ssp->free_start >= ssp->size_needed)) { + ssp->slot = write_vfat(Dir, dosname, longname, + ssp->free_start, &entry); + } else { + ssp->size_needed = 1; + write_vfat(Dir, dosname, 0, + ssp->free_start, &entry); + } + /* clear_vses(Dir, ssp->free_start + ssp->size_needed, + ssp->free_end); */ + } else + return 0; + + return 1; /* Successfully wrote the file */ +} + +static void stripspaces(char *name) +{ + char *p,*non_space; + + non_space = name; + for(p=name; *p; p++) + if (*p != ' ') + non_space = p; + if(name[0]) + non_space[1] = '\0'; +} + + +static int _mwrite_one(Stream_t *Dir, + char *argname, + char *shortname, + write_data_callback *cb, + void *arg, + ClashHandling_t *ch) +{ + char longname[VBUFSIZE]; + const char *dstname; + dos_name_t dosname; + int expanded; + struct scan_state scan; + clash_action ret; + doscp_t *cp = GET_DOSCONVERT(Dir); + + expanded = 0; + + if(isSpecial(argname)) { + fprintf(stderr, "Cannot create entry named . or ..\n"); + return -1; + } + + if(ch->name_converter == dos_name) { + if(shortname) + stripspaces(shortname); + if(argname) + stripspaces(argname); + } + + if(shortname){ + convert_to_shortname(cp, ch, shortname, &dosname); + if(ch->use_longname & 1){ + /* short name mangled, treat it as a long name */ + argname = shortname; + shortname = 0; + } + } + + if (argname[0] && (argname[1] == ':')) { + /* Skip drive letter */ + dstname = argname + 2; + } else { + dstname = argname; + } + + /* Copy original argument dstname to working value longname */ + strncpy(longname, dstname, VBUFSIZE-1); + + if(shortname) { + ch->use_longname = + convert_to_shortname(cp, ch, shortname, &dosname); + if(strcmp(shortname, longname)) + ch->use_longname |= 1; + } else { + ch->use_longname = + convert_to_shortname(cp, ch, longname, &dosname); + } + + ch->action[0] = ch->namematch_default[0]; + ch->action[1] = ch->namematch_default[1]; + + while (1) { + switch((ret=get_slots(Dir, &dosname, longname, &scan, ch))){ + case NAMEMATCH_ERROR: + return -1; /* Non-file-specific error, + * quit */ + + case NAMEMATCH_SKIP: + return -1; /* Skip file (user request or + * error) */ + + case NAMEMATCH_PRENAME: + ch->use_longname = + convert_to_shortname(cp, ch, + longname, + &dosname); + continue; + case NAMEMATCH_RENAME: + continue; /* Renamed file, loop again */ + + case NAMEMATCH_GREW: + /* No collision, and not enough slots. + * Try to grow the directory + */ + if (expanded) { /* Already tried this + * once, no good */ + fprintf(stderr, + "%s: No directory slots\n", + progname); + return -1; + } + expanded = 1; + + if (dir_grow(Dir, scan.max_entry)) + return -1; + continue; + case NAMEMATCH_OVERWRITE: + case NAMEMATCH_SUCCESS: + return write_slots(Dir, &dosname, longname, + &scan, cb, arg, + ch->use_longname); + default: + fprintf(stderr, + "Internal error: clash_action=%d\n", + ret); + return -1; + } + + } +} + +int mwrite_one(Stream_t *Dir, + const char *_argname, + const char *_shortname, + write_data_callback *cb, + void *arg, + ClashHandling_t *ch) +{ + char *argname; + char *shortname; + int ret; + + if(_argname) + argname = strdup(_argname); + else + argname = 0; + if(_shortname) + shortname = strdup(_shortname); + else + shortname = 0; + ret = _mwrite_one(Dir, argname, shortname, cb, arg, ch); + if(argname) + free(argname); + if(shortname) + free(shortname); + return ret; +} + +void init_clash_handling(ClashHandling_t *ch) +{ + ch->ignore_entry = -1; + ch->source_entry = -2; + ch->nowarn = 0; /*Don't ask, just do default action if name collision */ + ch->namematch_default[0] = NAMEMATCH_AUTORENAME; + ch->namematch_default[1] = NAMEMATCH_NONE; + ch->name_converter = dos_name; /* changed by mlabel */ + ch->source = -2; +} + +int handle_clash_options(ClashHandling_t *ch, char c) +{ + int isprimary; + if(isupper(c)) + isprimary = 0; + else + isprimary = 1; + c = tolower(c); + switch(c) { + case 'o': + /* Overwrite if primary name matches */ + ch->namematch_default[isprimary] = NAMEMATCH_OVERWRITE; + return 0; + case 'r': + /* Rename primary name interactively */ + ch->namematch_default[isprimary] = NAMEMATCH_RENAME; + return 0; + case 's': + /* Skip file if primary name collides */ + ch->namematch_default[isprimary] = NAMEMATCH_SKIP; + return 0; + case 'm': + ch->namematch_default[isprimary] = NAMEMATCH_NONE; + return 0; + case 'a': + ch->namematch_default[isprimary] = NAMEMATCH_AUTORENAME; + return 0; + default: + return -1; + } +} + +void dosnameToDirentry(const struct dos_name_t *dn, struct directory *dir) { + strncpy(dir->name, dn->base, 8); + strncpy(dir->ext, dn->ext, 3); +} diff --git a/mkdosboot b/mkdosboot new file mode 100755 index 0000000..7af3f23 --- /dev/null +++ b/mkdosboot @@ -0,0 +1,34 @@ +#!/bin/sh + +# Copyright 2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . + +# Example of a script making a Doc boot disk. Image will be t.img, a +# FreeDos boot sector is expected in bootsect.dos, and diag contains +# the system files + +IMAGE=t.img +if [ $# = 1 ] ; then + IMAGE=$1 +fi + +./mformat -i $IMAGE -C -t 80 -s 18 -h 2 -B bootsect.dos :: +./mcopy -i $IMAGE diag/io.sys ::IO.SYS +./mcopy -i $IMAGE diag/msdos.sys ::MSDOS.SYS +./mcopy -i $IMAGE diag/command.com ::COMMAND.COM +./mcopy -i $IMAGE diag/drvspace.bin ::DRVSPACE.BIN + +./mattrib -i $IMAGE +s +h +r ::io.sys ::msdos.sys ::drvspace.bin diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..6a5fd0b --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,50 @@ +#! /bin/sh + +# Copyright 1993 Noah Friedman +# Copyright 1996,1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . + +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" || errstatus=$? + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/mkmanifest.1 b/mkmanifest.1 new file mode 100644 index 0000000..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 . + * + * A program to create a manifest (shipping list) that is a shell script + * to return a Unix file name to it's original state after it has been + * clobbered by MSDOS's file name restrictions. + * + * This code also used in arc, mtools, and pcomm + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +static char *dos_name2(const char *name); + +int main(int argc, char **argv) +{ + int i; + const char *name; + char *new_name; + + /* print the version */ + if(argc >= 2 && strcmp(argv[1], "-V") == 0) { + printf("Mtools version %s, dated %s\n", mversion, mdate); + return 0; + } + + if (argc == 1) { + fprintf(stderr, "Usage: mkmanifest [-V] \n"); + return 1; + } + + for (i=1; i=0; i--) { + if (buf[i] == '.' && !dot) { + dot = 1; + buf[i] = '\0'; + ext = &buf[i+1]; + } + if (isupper((unsigned char)buf[i])) + buf[i] = tolower((unsigned char)buf[i]); + } + /* if no name */ + if (*temp == '\0') + strcpy(ans, "x"); + else { + /* if name is a device */ + for (i=0; i<9; i++) { + if (!strcasecmp(temp, dev[i])) + *temp = 'x'; + } + /* name too long? */ + if (strlen(temp) > 8) + *(temp+8) = '\0'; + /* extension too long? */ + if (ext && strlen(ext) > 3) + *(ext+3) = '\0'; + /* illegal characters? */ + while ((s = strpbrk(temp, "^+=/[]:',?*\\<>|\". "))) + *s = 'x'; + + while (ext && (s = strpbrk(ext, "^+=/[]:',?*\\<>|\". "))) + *s = 'x'; + strncpy(ans, temp, 12); + } + if (ext && *ext) { + strcat(ans, "."); + strcat(ans, ext); + } + return(ans); +} diff --git a/mkmanpages b/mkmanpages new file mode 100755 index 0000000..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 . + +# 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 . + * + * 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|\".", 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 . + * + * 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 . + * + * Mount an MSDOS disk + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +#ifdef OS_linux +#include +#include "mainloop.h" +#include "fs.h" + +void mmount(int argc, char **argv, int type) +{ + char drive; + int pid; + int status; + struct device dev; + char name[EXPAND_BUF]; + int media; + union bootsector boot; + Stream_t *Stream; + + if (argc<2 || !argv[1][0] || argv[1][1] != ':' || argv[1][2]){ + fprintf(stderr,"Usage: %s -V drive:\n", argv[0]); + exit(1); + } + drive = toupper(argv[1][0]); + Stream= find_device(drive, O_RDONLY, &dev, &boot, name, &media, 0, NULL); + if(!Stream) + exit(1); + FREE(&Stream); + + destroy_privs(); + + if ( dev.partition ) { + char part_name[4]; + sprintf(part_name, "%d", dev.partition %1000); + strcat(name, part_name); + } + + /* and finally mount it */ + switch((pid=fork())){ + case -1: + fprintf(stderr,"fork failed\n"); + exit(1); + case 0: + close(2); + open("/dev/null", O_RDWR | O_BINARY | O_LARGEFILE); + argv[1] = strdup("mount"); + if ( argc > 2 ) + execvp("mount", argv + 1 ); + else + execlp("mount", "mount", name, NULL); + perror("exec mount"); + exit(1); + default: + while ( wait(&status) != pid ); + } + if ( WEXITSTATUS(status) == 0 ) + exit(0); + argv[0] = strdup("mount"); + argv[1] = strdup("-r"); + if(!argv[0] || !argv[1]){ + printOom(); + exit(1); + } + if ( argc > 2 ) + execvp("mount", argv); + else + execlp("mount", "mount","-r", name, NULL); + exit(1); +} + +#else /* linux */ + +#include "msdos.h" + +void mmount(int argc, char **argv, int type) +{ + fprintf(stderr,"This command is only available for LINUX \n"); + exit(1); +} +#endif /* linux */ + diff --git a/mmove.1 b/mmove.1 new file mode 100644 index 0000000..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 . + * + * 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. + * + * 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(ipartition && !begin_set) + begin = END(partTable[i]); + if(i>dev->partition && !end_set && !size_set) { + end = BEGIN(partTable[i]); + end_set = 1; + } + } + +#ifdef OS_linux + if(!used_dev.sectors && !used_dev.heads) { + if(!IS_SCSI(dev)) { + struct hd_geometry geom; + if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) { + used_dev.heads = geom.heads; + used_dev.sectors = geom.sectors; + } + } + } +#endif + + if(!used_dev.sectors && !used_dev.heads) { + if(tot_sectors) + setsize0(tot_sectors,&dummy2,&used_dev.heads, + &used_dev.sectors); + else { + used_dev.heads = 64; + used_dev.sectors = 32; + } + } + + if(verbose) + fprintf(stderr,"sectors: %d heads: %d %d\n", + used_dev.sectors, used_dev.heads, tot_sectors); + + sec_per_cyl = used_dev.sectors * used_dev.heads; + if(create) { + if(!end_set && tot_sectors) { + end = tot_sectors - tot_sectors % sec_per_cyl; + end_set = 1; + } + + /* if the partition starts right at the beginning of + * the disk, keep one track unused to allow place for + * the master boot record */ + if(!begin && !begin_set) + begin = used_dev.sectors; + if(!size_set && used_dev.tracks) { + size_set = 2; + length = sec_per_cyl * used_dev.tracks; + + /* round the size in order to take + * into account any "hidden" sectors */ + + /* do we anchor this at the beginning ?*/ + if(begin_set || dev->partition <= 2 || !end_set) + length -= begin % sec_per_cyl; + else if(end - length < begin) + /* truncate any overlap */ + length = end - begin; + } + if(size_set) { + if(!begin_set && dev->partition >2 && end_set) + begin = end - length; + else + end = begin + length; + } else if(!end_set) { + fprintf(stderr,"Unknown size\n"); + exit(1); + } + + setBeginEnd(&partTable[dev->partition], begin, end, + used_dev.heads, used_dev.sectors, + !has_activated, type); + } + + if(activate) { + if(!partTable[dev->partition].sys_ind) { + fprintf(stderr, + "Partition for drive %c: does not exist\n", + drive); + } else { + switch(activate) { + case 1: + partTable[dev->partition].boot_ind=0x80; + break; + case -1: + partTable[dev->partition].boot_ind=0x00; + break; + } + } + } + + + inconsistency |= consistencyCheck(partTable, doprint, verbose, + &has_activated, &last_end, &j, + &used_dev, dev->partition); + + if(doprint && !inconsistency && partTable[dev->partition].sys_ind) { + printf("The following command will recreate the partition for drive %c:\n", + drive); + used_dev.tracks = + (_DWORD(partTable[dev->partition].nr_sects) + + (BEGIN(partTable[dev->partition]) % sec_per_cyl)) / + sec_per_cyl; + printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n", + used_dev.tracks, used_dev.heads, used_dev.sectors, + BEGIN(partTable[dev->partition]), drive); + } + + if(tot_sectors && last_end >tot_sectors) { + fprintf(stderr, + "Partition %d exceeds beyond end of disk\n", + j); + exit(1); + } + + + switch(has_activated) { + case 0: + fprintf(stderr, + "Warning: no active (bootable) partition present\n"); + break; + case 1: + break; + default: + fprintf(stderr, + "Warning: %d active (bootable) partitions present\n", + has_activated); + fprintf(stderr, + "Usually, a disk should have exactly one active partition\n"); + break; + } + + if(inconsistency && !force) { + fprintf(stderr, + "inconsistency detected!\n" ); + if(dirty) + fprintf(stderr, + "Retry with the -f switch to go ahead anyways\n"); + exit(1); + } + + if(dirty) { + /* write data back to the disk */ + if(verbose>=2) + print_sector("Writing sector", buf, 512); + if (WRITES(Stream, (char *) buf, 0, 512) != 512) { + fprintf(stderr,"Error writing partition table"); + exit(1); + } + if(verbose>=3) + print_sector("Sector written", buf, 512); + } + FREE(&Stream); + exit(0); +} diff --git a/mrd.1 b/mrd.1 new file mode 100644 index 0000000..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 . + * + * 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 . + * + * 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 . + * + * 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 . + */ + +#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 " + ** where is mdir, mdel, mcopy etcetera + ** Mainly done for the BeOS, which doesn't support links yet. + */ + + if(argc >= 3 && + !strcmp(argv[1], "-c") && + !strcmp(name, "mtools")) { + argc-=2; + argv+=2; + name = argv[0]; + } + + + + /* print the version */ + if(argc >= 2 && + (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") ==0)) { + printf("%s (GNU mtools) %s\n", + name, mversion); + printf("configured with the following options: "); +#ifdef USE_XDF + printf("enable-xdf "); +#else + printf("disable-xdf "); +#endif +#ifdef USING_VOLD + printf("enable-vold "); +#else + printf("disable-vold "); +#endif +#ifdef USING_NEW_VOLD + printf("enable-new-vold "); +#else + printf("disable-new-vold "); +#endif +#ifdef DEBUG + printf("enable-debug "); +#else + printf("disable-debug "); +#endif +#ifdef USE_RAWTERM + printf("enable-raw-term "); +#else + printf("disable-raw-term "); +#endif + printf("\n"); + return 0; + } + + read_config(); + setup_signal(); + for (i = 0; i < NDISPATCH; i++) { + if (!strcmp(name,dispatch[i].cmd)) + dispatch[i].fn(argc, argv, dispatch[i].type); + } + if (strcmp(name,"mtools")) + fprintf(stderr,"Unknown mtools command '%s'\n",name); + fprintf(stderr,"Supported commands:"); + for (i = 0; i < NDISPATCH; i++) { + if (i%8 == 0) putc('\n', stderr); + else fprintf(stderr, ", "); + fprintf(stderr, "%s", dispatch[i].cmd); + } + putc('\n', stderr); + + return 1; +} + +int helpFlag(int argc, char **argv) { + return (argc > 1 && !strcmp(argv[1], "--help")); +} diff --git a/mtools.conf b/mtools.conf new file mode 100644 index 0000000..dc186df --- /dev/null +++ b/mtools.conf @@ -0,0 +1,80 @@ +# Copyright 1996-1998,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . + +# Example mtools.conf files. Uncomment the lines which correspond to +# your architecture and comment out the "SAMPLE FILE" line below +SAMPLE FILE + +# # Linux floppy drives +# drive a: file="/dev/fd0" exclusive +# drive b: file="/dev/fd1" exclusive + +# # First SCSI hard disk partition +# drive c: file="/dev/sda1" + +# # First IDE hard disk partition +# drive c: file="/dev/hda1" + +# # dosemu floppy image +# drive m: file="/var/lib/dosemu/diskimage" + +# # dosemu hdimage +# drive n: file="/var/lib/dosemu/diskimage" offset=3840 + +# # Atari ramdisk image +# drive o: file="/tmp/atari_rd" offset=136 + +# # ZIP disk for Solaris: +# Drive X is ZIP-100 at target 5 +# drive X: file="/dev/rdsk/c0t5d0s2" partition=4 scsi=1 nodelay + +# # ZIP disk for SunOS: +# # Zip drive is at target 5, which default kernel calls tape st1 !! +# drive Y: file="/dev/rsd5c" partition=4 scsi=1 nodelay + +# # autoselect zip drive/floppy on HP-UX 9/10 +# drive a: file="/dev/rdsk/c201d5" exclusive partition=4 +# drive a: file="/dev/rdsk/c201d5s0" exclusive partition=4 +# drive a: file="/dev/rfloppy/c201d0s0" exclusive + +# A/UX target 5 on 1st scsi bus jaz or zip +# drive X: file="/dev/rdsk/c105d0s31" partition=4 + + +# Some examples for BeOS. +# floppy drive. hardcoded in devices.c, so no real need to define it here +#drive a: file="/dev/floppy_disk" exclusive +# ZIP drive on SCSI ID 6 +#drive z: file="/dev/scsi_disk_060" offset=16384 fat_bits=16 + +# SCO Unix 3.2v4 +# # Floppy disk drives +# +# drive a: file="/dev/install" exclusive +# drive b: file="/dev/install1" exclusive +# +# # SCSI hard disk partitions +# +# drive c: file="/dev/dsk/0sC" +# drive d: file="/dev/dsk/0sD" +# drive e: file="/dev/dsk/0sE" +# drive f: file="/dev/dsk/0sF" +# drive g: file="/dev/dsk/0sG" +# drive h: file="/dev/dsk/0sH" + +# # uncomment the following line to display all file names in lower +# # case by default +# mtools_lower_case=1 diff --git a/mtools.h b/mtools.h new file mode 100644 index 0000000..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 . + */ +#include "msdos.h" + +typedef struct dos_name_t dos_name_t; + +#if defined(OS_sco3) +#define MAXPATHLEN 1024 +#include +extern int lockf(int, int, off_t); /* SCO has no proper include file for lockf */ +#endif + +#define SCSI_FLAG 1 +#define PRIV_FLAG 2 +#define NOLOCK_FLAG 4 +#define USE_XDF_FLAG 8 +#define MFORMAT_ONLY_FLAG 16 +#define VOLD_FLAG 32 +#define FLOPPYD_FLAG 64 +#define FILTER_FLAG 128 +#define SWAP_FLAG 256 + +#define IS_SCSI(x) ((x) && ((x)->misc_flags & SCSI_FLAG)) +#define IS_PRIVILEGED(x) ((x) && ((x)->misc_flags & PRIV_FLAG)) +#define IS_NOLOCK(x) ((x) && ((x)->misc_flags & NOLOCK_FLAG)) +#define IS_MFORMAT_ONLY(x) ((x) && ((x)->misc_flags & MFORMAT_ONLY_FLAG)) +#define SHOULD_USE_VOLD(x) ((x)&& ((x)->misc_flags & VOLD_FLAG)) +#define SHOULD_USE_XDF(x) ((x)&& ((x)->misc_flags & USE_XDF_FLAG)) +#define DO_SWAP(x) ((x) && ((x)->misc_flags & SWAP_FLAG)) + +typedef struct device { + const char *name; /* full path to device */ + + char drive; /* the drive letter */ + int fat_bits; /* FAT encoding scheme */ + + unsigned int mode; /* any special open() flags */ + unsigned int tracks; /* tracks */ + unsigned int heads; /* heads */ + unsigned int sectors; /* sectors */ + unsigned int hidden; /* number of hidden sectors. Used for + * mformatting partitioned devices */ + + off_t offset; /* skip this many bytes */ + + unsigned int partition; + + unsigned int misc_flags; + + /* Linux only stuff */ + unsigned int ssize; + unsigned int use_2m; + + char *precmd; /* command to be executed before opening + * the drive */ + + /* internal variables */ + int file_nr; /* used during parsing */ + unsigned int blocksize; /* size of disk block in bytes */ + + int codepage; /* codepage for shortname encoding */ + + const char *cfg_filename; /* used for debugging purposes */ +} device_t; + + +#ifndef OS_linux +#define BOOTSIZE 512 +#else +#define BOOTSIZE 256 +#endif + +typedef struct doscp_t doscp_t; + +#include "stream.h" + + +extern const char *short_illegals, *long_illegals; + +#define maximize(target, max) do { \ + if(max < 0) { \ + if(target > 0) \ + target = 0; \ + } else if(target > max) { \ + target = max; \ + } \ +} while(0) + +#define minimize(target, min) do { \ + if(target < min) \ + target = min; \ +} while(0) + +int init_geom(int fd, struct device *dev, struct device *orig_dev, + struct MT_STAT *statbuf); + +int readwrite_sectors(int fd, /* file descriptor */ + int *drive, + int rate, + int seektrack, + int track, int head, int sector, int size, /* address */ + char *data, + int bytes, + int direction, + int retries); + +int lock_dev(int fd, int mode, struct device *dev); + +char *unix_normalize (doscp_t *cp, char *ans, struct dos_name_t *dn); +void dos_name(doscp_t *cp, const char *filename, int verbose, int *mangled, + struct dos_name_t *); +struct directory *mk_entry(const dos_name_t *filename, char attr, + unsigned int fat, size_t size, time_t date, + struct directory *ndir); + +struct directory *mk_entry_from_base(const char *base, char attr, + unsigned int fat, size_t size, time_t date, + struct directory *ndir); + +int copyfile(Stream_t *Source, Stream_t *Target); +int getfreeMinClusters(Stream_t *Stream, size_t ref); + +FILE *opentty(int mode); + +int is_dir(Stream_t *Dir, char *path); +void bufferize(Stream_t **Dir); + +int dir_grow(Stream_t *Dir, int size); +int match(const wchar_t *, const wchar_t *, wchar_t *, int, int); + +wchar_t *unix_name(doscp_t *fromDos, + const char *base, const char *ext, char Case, + wchar_t *answer); +void *safe_malloc(size_t size); +Stream_t *open_filter(Stream_t *Next,int convertCharset); + +extern int got_signal; +/* int do_gotsignal(char *, int); +#define got_signal do_gotsignal(__FILE__, __LINE__) */ + +void setup_signal(void); +#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 +************* + +[index] +* Menu: + +File: mtools.info, Node: Variable Index, Next: Concept Index, Prev: Command Index, Up: Top + +Variable index +************** + +[index] +* Menu: + +* cylinders: geometry description. (line 61) +* drive: general information. (line 6) +* exclusive: open flags. (line 6) +* fat_bits: 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 +************* + +[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 +- 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 +- 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 +- 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 +- Added missing -i option to mshortname +* Sun Oct 17 2010 Alain Knaff +- 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 +- Merged Debian patches +* Tue Nov 03 2009 Alain Knaff +- 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 . + */ +#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 . + * + * 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 +.\" +.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 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 . + * + * mzip.c + * Iomega Zip/Jaz drive tool + * change protection mode and eject disk + */ + +/* mzip.c by Markus Gyger */ +/* This code is based on ftp://gear.torque.net/pub/ziptool.c */ +/* by Grant R. Guenther with the following copyright notice: */ + +/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */ +/* http://www.torque.net/ziptool.html */ + + +/* Unprotect-till-eject modes and mount tests added + * by Ilya Ovchinnikov + */ + +#include "sysincludes.h" +#include "mtools.h" +#include "scsi.h" + +#ifndef _PASSWORD_LEN +#define _PASSWORD_LEN 33 +#endif + +#ifdef OS_linux + +#if __GLIBC__ >=2 +#include +#else +#define _LINUX_KDEV_T_H 1 /* don't redefine MAJOR/MINOR */ +#include +#endif + +#include "devices.h" + +#endif + + +static int zip_cmd(int priv, int fd, unsigned char cdb[6], int clen, + scsi_io_mode_t mode, void *data, size_t len, + void *extra_data) +{ + int r; + + if(priv) + reclaim_privs(); + r = scsi_cmd(fd, cdb, clen, mode, data, len, extra_data); + if(priv) + drop_privs(); + return r; +} + +static int test_mounted ( char *dev ) +{ +#ifdef HAVE_MNTENT_H + struct mntent *mnt; + struct MT_STAT st_dev, st_mnt; + FILE *mtab; +/* + * Now check if any partition of this device is already mounted (this + * includes checking if the device is mounted under a different name). + */ + + if (MT_STAT (dev, &st_dev)) { + fprintf (stderr, "%s: stat(%s) failed: %s.\n", + progname, dev, strerror (errno)); + exit(1); + } + + if (!S_ISBLK (st_dev.st_mode)) /* not a block device, cannot + * be mounted */ + return 0; + +#ifndef _PATH_MOUNTED +# define _PATH_MOUNTED "/etc/mtab" +#endif + + if ((mtab = setmntent (_PATH_MOUNTED, "r")) == NULL) { + fprintf (stderr, "%s: can't open %s.\n", + progname, _PATH_MOUNTED); + exit(1); + } + + while ( ( mnt = getmntent (mtab) ) ) { + if (!mnt->mnt_fsname + +#ifdef MNTTYPE_SWAP + || !strcmp (mnt->mnt_type, MNTTYPE_SWAP) +#endif +#ifdef MNTTYPE_NFS + || !strcmp (mnt->mnt_type, MNTTYPE_NFS) +#endif + || !strcmp (mnt->mnt_type, "proc") + || !strcmp (mnt->mnt_type, "smbfs") +#ifdef MNTTYPE_IGNORE + || !strcmp (mnt->mnt_type, MNTTYPE_IGNORE) +#endif + ) + continue; + + if (MT_STAT (mnt->mnt_fsname, &st_mnt)) { + continue; + } + + if (S_ISBLK (st_mnt.st_mode)) { +#ifdef OS_linux + /* on Linux, warn also if the device is on the same + * partition */ + if (MAJOR(st_mnt.st_rdev) == MAJOR(st_dev.st_rdev) && + MINOR(st_mnt.st_rdev) >= MINOR(st_dev.st_rdev) && + MINOR(st_mnt.st_rdev) <= MINOR(st_dev.st_rdev)+15){ + fprintf (stderr, + "Device %s%d is mounted on %s.\n", + dev, + MINOR(st_mnt.st_rdev) - + MINOR(st_dev.st_rdev), + mnt->mnt_dir); +#else + if(st_mnt.st_rdev != st_dev.st_rdev) { +#endif + endmntent (mtab); + return 1; + } +#if 0 + } /* keep Emacs indentation happy */ +#endif + } + } + endmntent (mtab); +#endif + return 0; +} + + +static void usage(int ret) +{ + fprintf(stderr, + "Mtools version %s, dated %s\n", + mversion, mdate); + fprintf(stderr, + "Usage: %s [-V] [-q] [-e] [-u] [-r|-w|-p|-x] [drive:]\n" + "\t-q print status\n" + "\t-e eject disk\n" + "\t-f eject disk even when mounted\n" + "\t-r write protected (read-only)\n" + "\t-w not write-protected (read-write)\n" + "\t-p password write protected\n" + "\t-x password protected\n" + "\t-u unprotect till disk ejecting\n", + progname); + exit(ret); +} + + +enum mode_t { + ZIP_RW = 0, + ZIP_RO = 2, + ZIP_RO_PW = 3, + ZIP_PW = 5, + ZIP_UNLOCK_TIL_EJECT = 8 +}; + +static enum mode_t get_zip_status(int priv, int fd, void *extra_data) +{ + unsigned char status[128]; + unsigned char cdb[6] = { 0x06, 0, 0x02, 0, sizeof status, 0 }; + + if (zip_cmd(priv, fd, cdb, 6, SCSI_IO_READ, + status, sizeof status, extra_data) == -1) { + perror("status: "); + exit(1); + } + return status[21] & 0xf; +} + + +static int short_command(int priv, int fd, int cmd1, int cmd2, + int cmd3, const char *data, void *extra_data) +{ + unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 }; + + cdb[0] = cmd1; + cdb[1] = cmd2; + cdb[4] = cmd3; + + return zip_cmd(priv, fd, cdb, 6, SCSI_IO_WRITE, + (char *) data, data ? strlen(data) : 0, extra_data); +} + + +static int iomega_command(int priv, int fd, int mode, const char *data, + void *extra_data) +{ + return short_command(priv, fd, + SCSI_IOMEGA, mode, data ? strlen(data) : 0, + data, extra_data); +} + +static int door_command(int priv, int fd, int cmd1, int cmd2, + void *extra_data) +{ + return short_command(priv, fd, cmd1, 0, cmd2, 0, extra_data); +} + +void mzip(int argc, char **argv, int type) +{ + void *extra_data; + int c; + char drive; + device_t *dev; + int fd = -1; + char name[EXPAND_BUF]; + enum { ZIP_NIX = 0, + ZIP_STATUS = 1 << 0, + ZIP_EJECT = 1 << 1, + ZIP_MODE_CHANGE = 1 << 2, + ZIP_FORCE = 1 << 3 + } request = ZIP_NIX; + + enum mode_t newMode = ZIP_RW; + enum mode_t oldMode = ZIP_RW; + +#define setMode(x) \ + if(request & ZIP_MODE_CHANGE) usage(1); \ + request |= ZIP_MODE_CHANGE; \ + newMode = x; \ + break; + + /* get command line options */ + if(helpFlag(argc, argv)) + usage(0); + while ((c = getopt(argc, argv, "i:efpqrwxuh")) != EOF) { + switch (c) { + case 'i': + set_cmd_line_image(optarg); + break; + case 'f': + if (get_real_uid()) { + fprintf(stderr, + "Only root can use force. Sorry.\n"); + exit(1); + } + request |= ZIP_FORCE; + break; + case 'e': /* eject */ + request |= ZIP_EJECT; + break; + case 'q': /* status query */ + request |= ZIP_STATUS; + break; + + case 'p': /* password read-only */ + setMode(ZIP_RO_PW); + case 'r': /* read-only */ + setMode(ZIP_RO); + case 'w': /* read-write */ + setMode(ZIP_RW); + case 'x': /* password protected */ + setMode(ZIP_PW); + case 'u': /* password protected */ + setMode(ZIP_UNLOCK_TIL_EJECT) + case 'h': + usage(0); + default: /* unrecognized */ + usage(1); + + } + } + + if (request == ZIP_NIX) request = ZIP_STATUS; /* default action */ + + if (argc - optind > 1 || + (argc - optind == 1 && + (!argv[optind][0] || argv[optind][1] != ':'))) + usage(1); + + drive = toupper(argc - optind == 1 ? argv[argc - 1][0] : ':'); + + for (dev = devices; dev->name; dev++) { + unsigned char cdb[6] = { 0, 0, 0, 0, 0, 0 }; + struct { + char type, + type_modifier, + scsi_version, + data_format, + length, + reserved1[2], + capabilities, + vendor[8], + product[16], + revision[4], + vendor_specific[20], + reserved2[40]; + } inq_data; + + if (dev->drive != drive) + continue; + expand(dev->name, name); + if ((request & (ZIP_MODE_CHANGE | ZIP_EJECT)) && + !(request & ZIP_FORCE) && + test_mounted(name)) { + fprintf(stderr, + "Can\'t change status of/eject mounted device\n"); + exit(1); + } + precmd(dev); + + if(IS_PRIVILEGED(dev)) + reclaim_privs(); + fd = scsi_open(name, O_RDONLY +#ifdef O_NDELAY + | O_NDELAY +#endif + , 0644, + &extra_data); + if(IS_PRIVILEGED(dev)) + drop_privs(); + + /* need readonly, else we can't + * open the drive on Solaris if + * write-protected */ + if (fd == -1) + continue; + closeExec(fd); + + if (!(request & (ZIP_MODE_CHANGE | ZIP_STATUS))) + /* if no mode change or ZIP specific status is + * involved, the command (eject) is applicable + * on all drives */ + break; + + cdb[0] = SCSI_INQUIRY; + cdb[4] = sizeof inq_data; + if (zip_cmd(IS_PRIVILEGED(dev), fd, cdb, 6, SCSI_IO_READ, + &inq_data, sizeof inq_data, extra_data) != 0) { + close(fd); + continue; + } + +#ifdef DEBUG + fprintf(stderr, "device: %s\n\tvendor: %.8s\n\tproduct: %.16s\n" + "\trevision: %.4s\n", name, inq_data.vendor, + inq_data.product, inq_data.revision); +#endif /* DEBUG */ + + if (strncasecmp("IOMEGA ", inq_data.vendor, + sizeof inq_data.vendor) || + (strncasecmp("ZIP 100 ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("ZIP 100 PLUS ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("ZIP 250 ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("ZIP 750 ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("JAZ 1GB ", + inq_data.product, sizeof inq_data.product) && + strncasecmp("JAZ 2GB ", + inq_data.product, sizeof inq_data.product))) { + + /* debugging */ + fprintf(stderr,"Skipping drive with vendor='"); + fwrite(inq_data.vendor,1, sizeof(inq_data.vendor), + stderr); + fprintf(stderr,"' product='"); + fwrite(inq_data.product,1, sizeof(inq_data.product), + stderr); + fprintf(stderr,"'\n"); + /* end debugging */ + close(fd); + continue; + } + break; /* found Zip/Jaz drive */ + } + + if (dev->drive == 0) { + fprintf(stderr, "%s: drive '%c:' is not a Zip or Jaz drive\n", + argv[0], drive); + exit(1); + } + + if (request & (ZIP_MODE_CHANGE | ZIP_STATUS)) + oldMode = get_zip_status(IS_PRIVILEGED(dev), fd, extra_data); + + if (request & ZIP_MODE_CHANGE) { + /* request temp unlock, and disk is already unlocked */ + if(newMode == ZIP_UNLOCK_TIL_EJECT && + (oldMode & ZIP_UNLOCK_TIL_EJECT)) + request &= ~ZIP_MODE_CHANGE; + + /* no password change requested, and disk is already + * in the requested state */ + if(!(newMode & 0x01) && newMode == oldMode) + request &= ~ZIP_MODE_CHANGE; + } + + if (request & ZIP_MODE_CHANGE) { + int ret; + enum mode_t unlockMode, unlockMask; + const char *passwd; + char dummy[1]; + + if(newMode == ZIP_UNLOCK_TIL_EJECT) { + unlockMode = newMode | oldMode; + unlockMask = 9; + } else { + unlockMode = newMode & ~0x5; + unlockMask = 1; + } + + if ((oldMode & unlockMask) == 1) { /* unlock first */ + char *s; + passwd = "APlaceForYourStuff"; + if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */ + iomega_command(IS_PRIVILEGED(dev), fd, unlockMode, + passwd, extra_data); + } + + if ((get_zip_status(IS_PRIVILEGED(dev), fd, extra_data) & + unlockMask) == 1) { + /* unlock first */ + char *s; + passwd = getpass("Password: "); + if ((s = strchr(passwd, '\n'))) *s = '\0'; /* chomp */ + if((ret=iomega_command(IS_PRIVILEGED(dev), fd, + unlockMode, passwd, + extra_data))){ + if (ret == -1) perror("passwd: "); + else fprintf(stderr, "wrong password\n"); + exit(1); + } + if((get_zip_status(IS_PRIVILEGED(dev), + fd, extra_data) & + unlockMask) == 1) { + fprintf(stderr, "wrong password\n"); + exit(1); + } + } + + if (newMode & 0x1) { + char first_try[_PASSWORD_LEN]; + + passwd = getpass("Enter new password:"); + strncpy(first_try, passwd,_PASSWORD_LEN); + passwd = getpass("Re-type new password:"); + if(strncmp(first_try, passwd, _PASSWORD_LEN)) { + fprintf(stderr, + "You mispelled it. Password not set.\n"); + exit(1); + } + } else { + passwd = dummy; + dummy[0] = '\0'; + } + + if(newMode == ZIP_UNLOCK_TIL_EJECT) + newMode |= oldMode; + + if((ret=iomega_command(IS_PRIVILEGED(dev), fd, + newMode, passwd, extra_data))){ + if (ret == -1) perror("set passwd: "); + else fprintf(stderr, "password not changed\n"); + exit(1); + } +#ifdef OS_linux + ioctl(fd, BLKRRPART); /* revalidate the disk, so that the + kernel notices that its writable + status has changed */ +#endif + } + + if (request & ZIP_STATUS) { + const char *unlocked; + + if(oldMode & 8) + unlocked = " and unlocked until eject"; + else + unlocked = ""; + switch (oldMode & ~8) { + case ZIP_RW: + printf("Drive '%c:' is not write-protected\n", + drive); + break; + case ZIP_RO: + printf("Drive '%c:' is write-protected%s\n", + drive, unlocked); + break; + case ZIP_RO_PW: + printf("Drive '%c:' is password write-protected%s\n", + drive, unlocked); + break; + case ZIP_PW: + printf("Drive '%c:' is password protected%s\n", + drive, unlocked); + break; + default: + printf("Unknown protection mode %d of drive '%c:'\n", + oldMode, drive); + break; + } + } + + if (request & ZIP_EJECT) { + if(request & ZIP_FORCE) + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_ALLOW_MEDIUM_REMOVAL, 0, + extra_data) < 0) { + perror("door unlock: "); + exit(1); + } + + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_START_STOP, 1, + extra_data) < 0) { + perror("stop motor: "); + exit(1); + } + + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_START_STOP, 2, extra_data) < 0) { + perror("eject: "); + exit(1); + } + if(door_command(IS_PRIVILEGED(dev), fd, + SCSI_START_STOP, 2, extra_data) < 0) { + perror("second eject: "); + exit(1); + } + } + + close(fd); + exit(0); +} diff --git a/nameclash.h b/nameclash.h new file mode 100644 index 0000000..8ebdb4c --- /dev/null +++ b/nameclash.h @@ -0,0 +1,75 @@ +#ifndef MTOOLS_NAMECLASH_H +#define MTOOLS_NAMECLASH_H + +/* Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include "stream.h" + +typedef enum clash_action { + NAMEMATCH_NONE, + NAMEMATCH_AUTORENAME, + NAMEMATCH_QUIT, + NAMEMATCH_SKIP, + NAMEMATCH_RENAME, + NAMEMATCH_PRENAME, /* renaming of primary name */ + NAMEMATCH_OVERWRITE, + NAMEMATCH_ERROR, + NAMEMATCH_SUCCESS, + NAMEMATCH_GREW +} clash_action; + +/* clash handling structure */ +typedef struct ClashHandling_t { + clash_action action[2]; + clash_action namematch_default[2]; + + int nowarn; /* Don't ask, just do default action if name collision*/ + int got_slots; + int mod_time; + /* unsigned int dot; */ + char *myname; + unsigned char *dosname; + int single; + + int use_longname; + int ignore_entry; + int source; /* to prevent the source from overwriting itself */ + int source_entry; /* to account for the space freed up by the original + * name */ + void (*name_converter)(doscp_t *cp, + const char *filename, int verbose, + int *mangled, dos_name_t *ans); +} ClashHandling_t; + +/* write callback */ +typedef int (write_data_callback)(dos_name_t *,char *, void *, struct direntry_t *); + +int mwrite_one(Stream_t *Dir, + const char *argname, + const char *shortname, + write_data_callback *cb, + void *arg, + ClashHandling_t *ch); + +int handle_clash_options(ClashHandling_t *ch, char c); +void init_clash_handling(ClashHandling_t *ch); +Stream_t *createDir(Stream_t *Dir, const char *filename, ClashHandling_t *ch, + unsigned char attr, time_t mtime); + + +#endif diff --git a/partition.h b/partition.h new file mode 100644 index 0000000..5c43739 --- /dev/null +++ b/partition.h @@ -0,0 +1,49 @@ +/* Copyright 1997,1998,2001-2003,2006,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +typedef struct hsc { + unsigned char byte0; + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ +} hsc; + +#define head(x) ((unsigned int)((x).head)) +#define sector(x) ((unsigned int)((x).sector & 0x3f)) +#define cyl(x) ((unsigned int)((x).cyl | (((x).sector & 0xc0)<<2))) + +#define BEGIN(p) _DWORD((p).start_sect) +#define END(p) (_DWORD((p).start_sect)+(_DWORD((p).nr_sects))) + + +struct partition { + hsc start; + hsc end; + unsigned char start_sect[4]; /* starting sector counting from 0 */ + unsigned char nr_sects[4]; /* nr of sectors in partition */ +}; + +#define boot_ind start.byte0 +#define sys_ind end.byte0 + +int consistencyCheck(struct partition *partTable, int doprint, int verbose, + int *has_activated, unsigned int *last_end, + unsigned int *j, + struct device *used_dev, int target_partition); + +void setBeginEnd(struct partition *partTable, int begin, int end, + int heads, int sector, int activate, int type); diff --git a/patchlevel.c b/patchlevel.c new file mode 100644 index 0000000..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 . + */ + +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 . + * + * 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 +#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; ioffset; + + if (This->seekable && where != This->lastwhere ){ + if(mt_lseek( This->fd, where, SEEK_SET) < 0 ){ + perror("seek"); + This->lastwhere = (mt_off_t) -1; + return -1; + } + } + +#ifdef OS_hpux + /* + * On HP/UX, we can not write more than MAX_LEN bytes in one go. + * If more are written, the write fails with EINVAL + */ + #define MAX_SCSI_LEN (127*1024) + if(This->size_limited && len > MAX_SCSI_LEN) + len = MAX_SCSI_LEN; +#endif + ret = io(This->fd, buf, len); + +#ifdef OS_hpux + if (ret == -1 && + errno == EINVAL && /* if we got EINVAL */ + len > MAX_SCSI_LEN) { + This->size_limited = 1; + len = MAX_SCSI_LEN; + ret = io(This->fd, buf, len); + } +#endif + + if ( ret == -1 ){ + perror("plain_io"); + This->lastwhere = (mt_off_t) -1; + return -1; + } + This->lastwhere = where + ret; + return ret; +} + + + +static int file_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + DeclareThis(SimpleFile_t); + + int result = file_io(Stream, buf, where, len, (iofn) read); + + if ( This->swap ) + swap_buffer( buf, len ); + return result; +} + +static int file_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + DeclareThis(SimpleFile_t); + + if ( !This->swap ) + return file_io(Stream, buf, where, len, (iofn) write); + else { + int result; + char *swapping = malloc( len ); + memcpy( swapping, buf, len ); + swap_buffer( swapping, len ); + + result = file_io(Stream, swapping, where, len, (iofn) write); + + free(swapping); + return result; + } +} + +static int file_flush(Stream_t *Stream) +{ +#if 0 + DeclareThis(SimpleFile_t); + + return fsync(This->fd); +#endif + return 0; +} + +static int file_free(Stream_t *Stream) +{ + DeclareThis(SimpleFile_t); + + if (This->fd > 2) + return close(This->fd); + else + return 0; +} + +static int file_geom(Stream_t *Stream, struct device *dev, + struct device *orig_dev, + int media, union bootsector *boot) +{ + int ret; + DeclareThis(SimpleFile_t); + size_t tot_sectors; + int BootP, Infp0, InfpX, InfTm; + int sectors, j; + unsigned char sum; + int sect_per_track; + struct label_blk_t *labelBlock; + + dev->ssize = 2; /* allow for init_geom to change it */ + dev->use_2m = 0x80; /* disable 2m mode to begin */ + + if(media == 0xf0 || media >= 0x100){ + dev->heads = WORD(nheads); + dev->sectors = WORD(nsect); + tot_sectors = DWORD(bigsect); + SET_INT(tot_sectors, WORD(psect)); + sect_per_track = dev->heads * dev->sectors; + if(sect_per_track == 0) { + if(mtools_skip_check) { + /* add some fake values if sect_per_track is + * zero. Indeed, some atari disks lack the + * geometry values (i.e. have zeroes in their + * place). In order to avoid division by zero + * errors later on, plug 1 everywhere + */ + dev->heads = 1; + dev->sectors = 1; + sect_per_track = 1; + } else { + fprintf(stderr, "The devil is in the details: zero number of heads or sectors\n"); + exit(1); + } + } + tot_sectors += sect_per_track - 1; /* round size up */ + dev->tracks = tot_sectors / sect_per_track; + + BootP = WORD(ext.old.BootP); + Infp0 = WORD(ext.old.Infp0); + InfpX = WORD(ext.old.InfpX); + InfTm = WORD(ext.old.InfTm); + + if(WORD(fatlen)) { + labelBlock = &boot->boot.ext.old.labelBlock; + } else { + labelBlock = &boot->boot.ext.fat32.labelBlock; + } + + if (boot->boot.descr >= 0xf0 && + labelBlock->dos4 == 0x29 && + strncmp( boot->boot.banner,"2M", 2 ) == 0 && + BootP < 512 && Infp0 < 512 && InfpX < 512 && InfTm < 512 && + BootP >= InfTm + 2 && InfTm >= InfpX && InfpX >= Infp0 && + Infp0 >= 76 ){ + for (sum=0, j=63; j < BootP; j++) + sum += boot->bytes[j];/* checksum */ + dev->ssize = boot->bytes[InfTm]; + if (!sum && dev->ssize <= 7){ + dev->use_2m = 0xff; + dev->ssize |= 0x80; /* is set */ + } + } + } else if (media >= 0xf8){ + media &= 3; + dev->heads = old_dos[media].heads; + dev->tracks = old_dos[media].tracks; + dev->sectors = old_dos[media].sectors; + dev->ssize = 0x80; + dev->use_2m = ~1; + } else { + fprintf(stderr,"Unknown media type\n"); + exit(1); + } + + sectors = dev->sectors; + dev->sectors = dev->sectors * WORD(secsiz) / 512; + +#ifdef JPD + printf("file_geom:media=%0X=>cyl=%d,heads=%d,sects=%d,ssize=%d,use2m=%X\n", + media, dev->tracks, dev->heads, dev->sectors, dev->ssize, + dev->use_2m); +#endif + ret = init_geom(This->fd,dev, orig_dev, &This->statbuf); + dev->sectors = sectors; +#ifdef JPD + printf("f_geom: after init_geom(), sects=%d\n", dev->sectors); +#endif + return ret; +} + + +static int file_data(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + DeclareThis(SimpleFile_t); + + if(date) + *date = This->statbuf.st_mtime; + if(size) + *size = This->statbuf.st_size; + if(type) + *type = S_ISDIR(This->statbuf.st_mode); + if(address) + *address = 0; + return 0; +} + +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 . + */ + +#include "stream.h" +#include "msdos.h" +#ifdef __EMX__ +#include +#endif + +/* plain io */ +#define NO_PRIV 1 +#define NO_OFFSET 2 + +Stream_t *SimpleFileOpen(struct device *dev, struct device *orig_dev, + const char *name, int mode, char *errmsg, int mode2, + int locked, mt_size_t *maxSize); +int check_parameters(struct device *ref, struct device *testee); + +int get_fd(Stream_t *Stream); +void *get_extra_data(Stream_t *Stream); +#endif diff --git a/precmd.c b/precmd.c new file mode 100644 index 0000000..8d1fc96 --- /dev/null +++ b/precmd.c @@ -0,0 +1,48 @@ +/* Copyright 1997,1999,2001-2004,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + * + * Do filename expansion with the shell. + */ + +#define EXPAND_BUF 2048 + +#include "sysincludes.h" +#include "mtools.h" + +void precmd(struct device *dev) +{ +#ifndef OS_mingw32msvc + int status; + pid_t pid; + + if(!dev || !dev->precmd) + return; + + switch((pid=fork())){ + case -1: + perror("Could not fork"); + exit(1); + break; + case 0: /* the son */ + execl("/bin/sh", "sh", "-c", dev->precmd, (char *)NULL); + break; + default: + wait(&status); + break; + } +#endif +} + diff --git a/privileges.c b/privileges.c new file mode 100644 index 0000000..c2f5c74 --- /dev/null +++ b/privileges.c @@ -0,0 +1,211 @@ +/* Copyright 1997,1999,2001,2002,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "mtools.h" + +int noPrivileges=0; + +#ifdef OS_mingw32msvc +void reclaim_privs(void) +{ +} + +void drop_privs(void) +{ +} + +void destroy_privs(void) +{ +} + +uid_t get_real_uid(void) +{ + return 0; +} + +void init_privs(void) +{ +} + +void closeExec(int fd) +{ +} + +#else +/*#define PRIV_DEBUG*/ + +#if 0 +#undef HAVE_SETEUID +#define HAVE_SETRESUID +#include +int setresuid(int a, int b, int c) +{ + syscall(164, a, b, c); + +} +#endif + +static __inline__ void print_privs(const char *message) +{ +#ifdef PRIV_DEBUG + /* for debugging purposes only */ + fprintf(stderr,"%s egid=%d rgid=%d\n", message, getegid(), getgid()); + fprintf(stderr,"%s euid=%d ruid=%d\n", message, geteuid(), getuid()); +#endif +} + + +static gid_t rgid, egid; +static uid_t ruid, euid; + +/* privilege management routines for SunOS and Solaris. These are + * needed in order to issue raw SCSI read/write ioctls. Mtools drops + * its privileges at the beginning, and reclaims them just for the + * above-mentioned ioctl's. Before popen(), exec() or system, it + * drops its privileges completely, and issues a warning. + */ + + +/* group id handling is lots easyer, as long as we don't use group 0. + * If you want to use group id's, create a *new* group mtools or + * floppy. Chgrp any devices that you only want to be accessible to + * mtools to this group, and give them the appropriate privs. Make + * sure this group doesn't own any other files: be aware that any user + * with access to mtools may mformat these files! + */ + + +static __inline__ void Setuid(uid_t uid) +{ +#if defined HAVE_SETEUID || defined HAVE_SETRESUID + if(euid == 0) { +#ifdef HAVE_SETEUID + seteuid(uid); +#else + setresuid(ruid, uid, euid); +#endif + } else +#endif + setuid(uid); +} + +/* In reclaim_privs and drop privs, we have to manipulate group privileges + * when having no root privileges, else we might lose them */ + +void reclaim_privs(void) +{ + if(noPrivileges) + return; + setgid(egid); + Setuid(euid); + print_privs("after reclaim privs, both uids should be 0 "); +} + +void drop_privs(void) +{ + Setuid(ruid); + setgid(rgid); + print_privs("after drop_privs, real should be 0, effective should not "); +} + +void destroy_privs(void) +{ + +#if defined HAVE_SETEUID || defined HAVE_SETRESUID + if(euid == 0) { +#ifdef HAVE_SETEUID + setuid(0); /* get the necessary privs to drop real root id */ + setuid(ruid); /* this should be enough to get rid of the three + * ids */ + seteuid(ruid); /* for good measure... just in case we came + * accross a system which implemented sane + * semantics instead of POSIXly broken + * semantics for setuid */ +#else + setresuid(ruid, ruid, ruid); +#endif + } +#endif + + /* we also destroy group privileges */ + drop_privs(); + + /* saved set [ug]id will go away by itself on exec */ + + print_privs("destroy_privs, no uid should be zero "); +} + + +uid_t get_real_uid(void) +{ + return ruid; +} + +void init_privs(void) +{ + euid = geteuid(); + ruid = getuid(); + egid = getegid(); + rgid = getgid(); + +#ifndef F_SETFD + if(euid != ruid) { + fprintf(stderr, + "Setuid installation not supported on this platform\n"); + fprintf(stderr, + "Missing F_SETFD"); + exit(1); + } +#endif + + if(euid == 0 && ruid != 0) { +#ifdef HAVE_SETEUID + setuid(0); /* set real uid to 0 */ +#else +#ifndef HAVE_SETRESUID + /* on this machine, it is not possible to reversibly drop + * root privileges. We print an error and quit */ + + /* BEOS is no longer a special case, as both euid and ruid + * return 0, and thus we do not get any longer into this + * branch */ + fprintf(stderr, + "Seteuid call not supported on this architecture.\n"); + fprintf(stderr, + "Mtools cannot be installed setuid root.\n"); + fprintf(stderr, + "However, it can be installed setuid to a non root"); + fprintf(stderr, + "user or setgid to any id.\n"); + exit(1); +#endif +#endif + } + + drop_privs(); + print_privs("after init, real should be 0, effective should not "); +} + +void closeExec(int fd) +{ +#ifdef F_SETFD + fcntl(fd, F_SETFD, 1); +#endif +} +#endif diff --git a/privtest.c b/privtest.c new file mode 100644 index 0000000..e4c60f7 --- /dev/null +++ b/privtest.c @@ -0,0 +1,26 @@ +/* Copyright 1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include +/* this program is used to test whether mtools drops its privileges correctly */ + +main(int argc, char **argv) +{ + setuid(strtoul(argv[1], 0,0)); + system("id"); + +} diff --git a/read_dword.h b/read_dword.h new file mode 100644 index 0000000..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 . + */ + +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 . + +# +# add-disk +# Contributed by Tim Hoogasian (hoogs@usa.net) +# +# Runs the commands to make Solaris locate a new disk that +# has been plugged in after the system was booted. +# + +# This script can be used on a Solaris system to add a SCSI disk +# without needing to reboot/reconfigure the system. It's short and +# simple, but it's quite handy -- and it saves you from having to +# remember the individual commands.... :-) + +# You might also want to use the format.dat file if you don't have one +# yet. It is in this same mtools/scripts directory, and should be +# stored in /etc, or appended to the existing format.dat file + +# All you have to do is attach the Jaz drive, check to make sure there +# isn't SCSI address conflict (Zip and Jaz media tend to default to ID +# number 5) power it up, run "add-disk", insert the media, and GO! + + +/usr/sbin/drvconfig +/usr/sbin/devlinks +/usr/sbin/disks # or /usr/sbin/tapes for tapes +/usr/ucb/ucblinks # Compatibility links + +exit 0 diff --git a/scripts/amuFormat.sh b/scripts/amuFormat.sh new file mode 100755 index 0000000..c9ff469 --- /dev/null +++ b/scripts/amuFormat.sh @@ -0,0 +1,103 @@ +#!/bin/sh +# Copyright 2004 Feuz Stefan. +# Copyright 2007 Adam Tkac. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . +# +# amuFormat.sh Formats various types and sizes of PC-Cards, according to the +# AMU-specification +# +# parameters: $1: Card Type: The Card Type is written as disk/volume-label +# to the boot-record +# The string should have a length of max. 11 characters. +# +# $2: Drive character (b:, c:) +# +# 10-12-2003 lct created +# +vers=1.4 + +#echo "debug: $0,$1,$2,$3,$4" + +# +# main() +# +if [ $# -ne 2 ] ; then + echo "Usage: amuFormat.sh " >&2 + echo " has to be defined in amuFormat.sh itself" >&2 + echo " has to be defined in mtools.conf" >&2 + exit 1 +fi + +echo "amuFormat $vers started..." + +drive="$2" + +case "$1" in +8MBCARD-FW) + ## using the f: or g: drive for fat12 formatting... + ## see mtools.conf file... + case "$2" in + [bB]:) drive="f:" ;; + [cC]:) drive="g:" ;; + *) echo "Drive $2 not supported."; exit 1 ;; + esac + cylinders=245 heads=2 cluster_size=8 + ;; +32MBCARD-FW) + #from amu_toolkit_0_6: + #mformat -t489 -h4 -c4 -n32 -H32 -r32 -vPC-CARD -M512 -N0000 c: + cylinders=489 heads=4 cluster_size=4 + ;; +64MBCARD-FW) + echo "***** WARNING: untested on AvHMU, exiting *****" + exit 1 + cylinders=245 heads=2 cluster_size=8 + ;; +1GBCARD-FW) + # from amu_toolkit_0_6: + #mformat -t2327 -h16 -c64 -n63 -H63 -r32 -v AMU-CARD -M512 -N 0000 c: + echo "***** WARNING: untested on AvHMU *****" + cylinders=2327 heads=16 cluster_size=64 + ;; +64MBCARDSAN) + # from amu_toolkit_0_6: + #mformat -t489 -h8 -c4 -n32 -H32 -r32 -v AMU-CARD -M512 -N 0000 c: + cylinders=489 heads=8 cluster_size=4 + ;; +# +# insert new cards here... +# +*) + echo "Card not supported." + exit 1 + ;; +esac + +echo "Formatting card in slot $2 as $1" + +## initialise partition table +mpartition -I "$drive" + +# write a partition table +mpartition -c -t$cylinders -h$heads -s32 -b32 "$drive" + +## write boot-record, two FATs and a root-directory +mformat -c$cluster_size -v "$1" "$drive" + +minfo "$2" +mdir "$2" + +echo "done." diff --git a/scripts/download b/scripts/download new file mode 100755 index 0000000..142eb99 --- /dev/null +++ b/scripts/download @@ -0,0 +1,81 @@ +#!/bin/sh - + +# Copyright 1996 Carlos Duarte +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . + + +## (c) Carlos Duarte ## Created: 18-Dec-96 ## Updated: 18-Dec-96 ## + +# main + +FAKE= +DRIVE=a +TOGGLE=0 +MDEL=: +while [ "$1" ] +do + case `echo z$1|cut -c2-` in + -n) FAKE=echo ;; + -d) DRIVE=`echo $1|cut -c3-` + [ "$DRIVE" = "" ] && { + shift + DRIVE=$1 + [ "$DRIVE" = "" ] && break + } ;; + -t) TOGGLE=1 ;; + -rm) MDEL=mdel ;; + *) break ;; + esac + shift +done + +if [ $# -ne 1 ] ; then + echo "usage: $0 [-n] [-d drive] [-rm] [-t] " + exit 1 +fi + +ndisks=$1 +n=0 +dir=1 + +while test $n -lt $ndisks +do + + while [ -d $dir ] + do + dir=`expr $dir + 1` + done + + $FAKE mkdir $dir + $FAKE mcopy $DRIVE:\* $dir && $FAKE $MDEL $DRIVE:\* + + if [ "$TOGGLE" = "1" ] ; then + if [ "$DRIVE" = "a" ] ; then + DRIVE=b + else + DRIVE=a + fi + else + echo Replace disk and press return + read ans + fi + + n=`expr $n + 1` + dir=`expr $dir + 1` +done + +exit 0 diff --git a/scripts/format.dat b/scripts/format.dat new file mode 100644 index 0000000..7fd31c1 --- /dev/null +++ b/scripts/format.dat @@ -0,0 +1,41 @@ +# Copyright 1997 Tim Hoogasian (hoogs@usa.net) +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . +# +# /etc/format.dat file for Accessing ZIP and Jaz disks from Solaris +# +# Contributed by Tim Hoogasian (thoogasi@us.oracle.com) +# + +disk_type = "Iomega ZIP 100" \ + : ctlr = SCSI \ + : ncyl = 2406 : acyl = 2 : pcyl = 2408 : nhead = 2 \ + : nsect = 40 : rpm = 3600 : bpt = 20480 + +# Default Zip floppy part'n map : block 0-192480 (entire disk) +# +partition = "Iomega ZIP 100" \ + : disk = "Iomega ZIP 100" : ctlr = SCSI \ + : 2 = 0, 192480 +## +disk_type = "Jaz 1GB" \ + : ctlr = SCSI \ + : ncyl = 1018 : acyl = 2 : pcyl = 1020 : nhead = 64 \ + : nsect = 32 : rpm = 3600 : bpt = 16384 + +partition = "Jaz 1GB" \ + : disk = "Jaz 1GB" : ctlr = SCSI \ + : 2 = 0,2084864 diff --git a/scripts/mcheck b/scripts/mcheck new file mode 100755 index 0000000..f2c917f --- /dev/null +++ b/scripts/mcheck @@ -0,0 +1,61 @@ +#!/bin/sh +# Copyright 1994 David C. Niemi +# Copyright 1994,1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . +# +# mcheck [ ] +# +# Read every file on an MS-DOS formatted disk to make sure they're good. +# +# Requires: mdir and mread utilities from mtools in user's path. +# +# 1994/02/19 DCN Created +# 1994/??/?? ALK Added case statement for results of mdir +# 1994/09/24 DCN Cleanup (5 minutes on top of the 30 seconds creating it) +# 1994/12/01 DCN Better comments, notices to stderr +# +# Copyright (C) 1994 David C. Niemi (niemi@tuxers.net) +# The author requires that any copies or derived works include this +# copyright notice; no other restrictions are placed on its use. +# + +set -e +set -u + +DRIVE=${1:-'A:'} +mdir ${DRIVE}'*' +case $? in +2) + echo "No files on disk." >&2 + exit 0 + ;; +1) + exit 1 + ;; +0) + ;; +esac + +echo >&2; echo "Verifying files on drive ${DRIVE}..." >&2 +if mtype -/ ${DRIVE}\* > /dev/null; then + echo "Disk in drive ${DRIVE} is OK." >&2 + exit 0 +else + echo "Disk in drive ${DRIVE} has errors." >&2 + exit 1 +fi + +## NOTREACHED ## diff --git a/scripts/mcomp b/scripts/mcomp new file mode 100755 index 0000000..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 . + +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 . + +taropt=$1 +dosfile=$2 +shift +shift + +mcopy $dosfile - | tar $taropt - "$@" + diff --git a/scripts/tgz b/scripts/tgz new file mode 100755 index 0000000..8769ea6 --- /dev/null +++ b/scripts/tgz @@ -0,0 +1,86 @@ +#!/bin/sh +# Copyright 1994 David C. Niemi. +# Copyright 1997,2001,2002 Alain Knaff. +# This file is part of mtools. +# +# Mtools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Mtools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Mtools. If not, see . +# +# tgz [destination [source...] ] +# +# Make a gzip'd tar archive $1 (or stdout) out of specified files +# (or, if not specified, from everything in the current directory) +# +# Requires gzip in the user's path. +# +# Requires gnu tar (or something close) in the user's path +# due to use of --exclude, --totals and -S. +# +# 1994/02/19 DCN Created +# 1994/12/01 DCN Cleanup and major improvements +# +# Copyright (C) 1994 David C. Niemi (niemi@tuxers.net) +# The author requires that any copies or derived works include this +# copyright notice; no other restrictions are placed on its use. +# + +set -e +set -u + +Error () +{ echo "Error: $0: ${@-}." >&2 + exit 1 +} + +if [ $# = 0 ]; then + dest= + src=. + tar cvf - . | gzip -9v + exit 0 +elif [ $# = 1 ]; then + dest=$1 + src=. +else + dest=$1 + shift + src="${@-}" +fi + +case $dest in +"" | . | .. | */ | */. | */.. ) + echo "Usage: $0: [destination [source...] ]" >&2 + exit 1 + ;; +*.t?z | *.?z | *.z | *.Z | *.tz | *.tz? ) + ;; +*) + dest=${dest}.tgz ## Add on .tgz as default suffix +esac + +if [ -h "$dest" ]; then + Error "Destination file \"$dest\" already exists as a symbolic link" +elif [ -f "$dest" ]; then + Error "Destination \"$dest\" already exists as a file" +elif [ -d "$dest" ]; then + Error "Destination \"$dest\" already exists as a directory" +fi +if [ -z "$dest" -o "X$dest" = 'X-' ]; then + echo "Writing gzipp'd tar archive to standard output." >&2 + tar cvfS - -- $src | gzip -9v +else + echo "Writing gzip'd tar archive to \"$dest\"." >&2 + tar -cvS --totals --exclude "$dest" -f - -- $src | gzip -9v > "$dest" + ls -l "$dest" >&2 +fi + +exit 0 diff --git a/scripts/uz b/scripts/uz new file mode 100755 index 0000000..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 . +# 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 . + * + * scsi.c + * Iomega Zip/Jaz drive tool + * change protection mode and eject disk + */ + +/* scis.c by Markus Gyger */ +/* This code is based on ftp://gear.torque.net/pub/ziptool.c */ +/* by Grant R. Guenther with the following copyright notice: */ + +/* (c) 1996 Grant R. Guenther, based on work of Itai Nahshon */ +/* http://www.torque.net/ziptool.html */ + + +/* A.K. Moved this from mzip.c to a separate file in order to share with + * plain_io.c */ + +#include "sysincludes.h" +#include "mtools.h" +#include "scsi.h" + +#if defined OS_hpux +#include +#endif + +#ifdef OS_solaris +#include +#endif /* solaris */ + +#ifdef OS_sunos +#include +#include +#endif /* sunos */ + +#ifdef sgi +#include +#endif + +#ifdef OS_linux +#include +#include +#endif + +#ifdef _SCO_DS +#include +#endif + +#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2) +#include +#endif + +#if defined(OS_netbsd) || defined(OS_netbsdelf) +#include +#endif + +int scsi_max_length(void) +{ +#ifdef OS_linux + return 8; +#else + return 255; +#endif +} + +int scsi_open(const char *name, int flag, int mode, void **extra_data) +{ +#if (defined(OS_freebsd)) && (__FreeBSD__ >= 2) + struct cam_device *cam_dev; + cam_dev = cam_open_device(name, O_RDWR); + *extra_data = (void *) cam_dev; + if (cam_dev) + return cam_dev->fd; + else + return -1; +#else + return open(name, O_RDONLY | O_LARGEFILE | O_BINARY +#ifdef O_NDELAY + | O_NDELAY +#endif + /* O_RDONLY | dev->mode*/); +#endif +} + +int scsi_cmd(int fd, unsigned char *cdb, int cmdlen, scsi_io_mode_t mode, + void *data, size_t len, void *extra_data) +{ +#if defined OS_hpux + struct sctl_io sctl_io; + + memset(&sctl_io, 0, sizeof sctl_io); /* clear reserved fields */ + memcpy(sctl_io.cdb, cdb, cmdlen); /* copy command */ + sctl_io.cdb_length = cmdlen; /* command length */ + sctl_io.max_msecs = 2000; /* allow 2 seconds for cmd */ + + switch (mode) { + case SCSI_IO_READ: + sctl_io.flags = SCTL_READ; + sctl_io.data_length = len; + sctl_io.data = data; + break; + case SCSI_IO_WRITE: + sctl_io.flags = 0; + sctl_io.data_length = data ? len : 0; + sctl_io.data = len ? data : 0; + break; + } + + if (ioctl(fd, SIOC_IO, &sctl_io) == -1) { + perror("scsi_io"); + return -1; + } + + return sctl_io.cdb_status; + +#elif defined OS_sunos || defined OS_solaris + struct uscsi_cmd uscsi_cmd; + memset(&uscsi_cmd, 0, sizeof uscsi_cmd); + uscsi_cmd.uscsi_cdb = (char *)cdb; + uscsi_cmd.uscsi_cdblen = cmdlen; +#ifdef OS_solaris + uscsi_cmd.uscsi_timeout = 20; /* msec? */ +#endif /* solaris */ + + uscsi_cmd.uscsi_buflen = (u_int)len; + uscsi_cmd.uscsi_bufaddr = data; + + switch (mode) { + case SCSI_IO_READ: + uscsi_cmd.uscsi_flags = USCSI_READ; + break; + case SCSI_IO_WRITE: + uscsi_cmd.uscsi_flags = USCSI_WRITE; + break; + } + + if (ioctl(fd, USCSICMD, &uscsi_cmd) == -1) { + perror("scsi_io"); + return -1; + } + + if(uscsi_cmd.uscsi_status) { + errno = 0; + fprintf(stderr,"scsi status=%x\n", + (unsigned short)uscsi_cmd.uscsi_status); + return -1; + } + + return 0; + +#elif defined OS_linux + struct 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 . + */ + +#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 . + */ + +#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 . + */ + +#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 . + */ + +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 . + * + * 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 . +: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 . + */ + +#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 . + * + * 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 +#endif + + +#include + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_LINUX_UNISTD_H +# include +#endif + +#ifdef HAVE_LIBC_H +# include +#endif + +#ifdef HAVE_GETOPT_H +# include +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_LIMITS_H +# include +#endif + +#ifdef HAVE_SYS_FILE_H +# include +#endif + +#ifdef HAVE_SYS_IOCTL_H +# ifndef sunos +# include +#endif +#endif +/* if we don't have sys/ioctl.h, we rely on unistd to supply a prototype + * for it. If it doesn't, we'll only get a (harmless) warning. The idea + * is to get mtools compile on as many platforms as possible, but to not + * suppress warnings if the platform is broken, as long as these warnings do + * not prevent compilation */ + +#ifdef TIME_WITH_SYS_TIME +# include +# include +#else +# ifdef HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifndef NO_TERMIO +# ifdef HAVE_TERMIO_H +# include +# elif defined HAVE_SYS_TERMIO_H +# include +# endif +# if !defined OS_ultrix || !(defined HAVE_TERMIO_H || defined HAVE_TERMIO_H) +/* on Ultrix, avoid double inclusion of both termio and termios */ +# ifdef HAVE_TERMIOS_H +# include +# elif defined HAVE_SYS_TERMIOS_H +# include +# endif +# endif +# ifdef HAVE_STTY_H +# include +# endif +#endif + + +#if defined(OS_aux) && !defined(_SYSV_SOURCE) +/* compiled in POSIX mode, this is left out unless SYSV */ +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input modes */ + unsigned short c_oflag; /* output modes */ + unsigned short c_cflag; /* control modes */ + unsigned short c_lflag; /* line discipline modes */ + char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control chars */ +}; +extern int ioctl(int fildes, int request, void *arg); +#endif + + +#ifdef HAVE_MNTENT_H +# include +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +/* Can only be done here, as BSD is defined in sys/param.h :-( */ +#if defined BSD || defined __BEOS__ +/* on BSD and on BEOS, we prefer gettimeofday, ... */ +# ifdef HAVE_GETTIMEOFDAY +# undef HAVE_TZSET +# endif +#else /* BSD */ +/* ... elsewhere we prefer tzset */ +# ifdef HAVE_TZSET +# undef HAVE_GETTIMEOFDAY +# endif +#endif + + +#include + +#include +#ifndef errno +extern int errno; +#endif + +#ifndef OS_mingw32msvc +#include +#else +typedef unsigned int uid_t; +#endif + + +#ifdef HAVE_STRING_H +# include +#else +# ifdef HAVE_STRINGS_H +# include +# endif +#endif + +#ifdef HAVE_MEMORY_H +# include +#endif + +#ifdef HAVE_MALLOC_H +# include +#endif + +#ifdef HAVE_SIGNAL_H +# include +#else +# ifdef HAVE_SYS_SIGNAL_H +# include +# endif +#endif + +#ifdef HAVE_UTIME_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# ifndef DONT_NEED_WAIT +# include +# endif +#endif + +#ifdef HAVE_WCHAR_H +# include +# ifndef HAVE_PUTWC +# define putwc(c,f) fprintf((f),"%lc",(c)) +# endif +#else +# define wcscmp strcmp +# define wcscasecmp strcasecmp +# define wcsdup strdup +# define wcslen strlen +# define wcschr strchr +# define wcspbrk strpbrk +# define wchar_t char +# define putwc putc +#endif + +#ifdef HAVE_WCTYPE_H +# include +#else +# define towupper(x) toupper(x) +# define towlower(x) tolower(x) +# define iswupper(x) isupper(x) +# define iswlower(x) islower(x) +# define iswcntrl(x) iscntrl(x) +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef USE_FLOPPYD + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_X11_XAUTH_H +#include +#endif + +#ifdef HAVE_X11_XLIB_H +#include +#endif + +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE (-1) +#endif + + +#ifdef sgi +#define MSGIHACK __EXTENSIONS__ +#undef __EXTENSIONS__ +#endif +#include +#ifdef sgi +#define __EXTENSIONS__ MSGIHACK +#undef MSGIHACK +#endif + +/* missing functions */ +#ifndef HAVE_SRANDOM +# ifdef OS_mingw32msvc +# define srandom srand +# else +# define srandom srand48 +# endif +#endif + +#ifndef HAVE_RANDOM +# ifdef OS_mingw32msvc +# define random (long)rand +# else +# define random (long)lrand48 +# endif +#endif + +#ifndef HAVE_STRCHR +# define strchr index +#endif + +#ifndef HAVE_STRRCHR +# define strrchr rindex +#endif + + +#ifndef HAVE_STRDUP +extern char *strdup(const char *str); +#endif /* HAVE_STRDUP */ + + +#ifndef HAVE_MEMCPY +extern char *memcpy(char *s1, const char *s2, size_t n); +#endif + +#ifndef HAVE_MEMSET +extern char *memset(char *s, char c, size_t n); +#endif /* HAVE_MEMSET */ + + +#ifndef HAVE_STRPBRK +extern char *strpbrk(const char *string, const char *brkset); +#endif /* HAVE_STRPBRK */ + + +#ifndef HAVE_STRTOUL +unsigned long strtoul(const char *string, char **eptr, int base); +#endif /* HAVE_STRTOUL */ + +#ifndef HAVE_STRSPN +size_t strspn(const char *s, const char *accept); +#endif /* HAVE_STRSPN */ + +#ifndef HAVE_STRCSPN +size_t strcspn(const char *s, const char *reject); +#endif /* HAVE_STRCSPN */ + +#ifndef HAVE_STRERROR +char *strerror(int errno); +#endif + +#ifndef HAVE_ATEXIT +int atexit(void (*function)(void)); + +#ifndef HAVE_ON_EXIT +void myexit(int code) NORETURN; +#define exit myexit +#endif + +#endif + + +#ifndef HAVE_MEMMOVE +# define memmove(DST, SRC, N) bcopy(SRC, DST, N) +#endif + +#ifndef HAVE_STRCASECMP +int strcasecmp(const char *s1, const char *s2); +#endif + +#ifndef HAVE_STRNCASECMP +int strncasecmp(const char *s1, const char *s2, size_t n); +#endif + +#ifndef HAVE_GETPASS +char *getpass(const char *prompt); +#endif + +#ifdef HAVE_WCHAR_H + +# ifndef HAVE_WCSDUP +wchar_t *wcsdup(const wchar_t *wcs); +# endif + +# ifndef HAVE_WCSCASECMP +int wcscasecmp(const wchar_t *s1, const wchar_t *s2); +# endif + +# ifndef HAVE_WCSNLEN +size_t wcsnlen(const wchar_t *wcs, size_t l); +# endif + +#endif + +#if 0 +#ifndef HAVE_BASENAME +const char *basename(const char *filename); +#endif +#endif + +const char *_basename(const char *filename); + +void _stripexe(char *filename); + +#ifndef __STDC__ +# ifndef signed +# define signed /**/ +# endif +#endif /* !__STDC__ */ + + + +/***************************************************************************/ +/* */ +/* Prototypes for systems where the functions exist but not the prototypes */ +/* */ +/***************************************************************************/ + + + +/* prototypes which might be missing on some platforms, even if the functions + * are present. Do not declare argument types, in order to avoid conflict + * on platforms where the prototypes _are_ correct. Indeed, for most of + * these, there are _several_ "correct" parameter definitions, and not all + * platforms use the same. For instance, some use the const attribute for + * strings not modified by the function, and others do not. By using just + * the return type, which rarely changes, we avoid these problems. + */ + +/* Correction: Now it seems that even return values are not standardized :-( + For instance DEC-ALPHA, OSF/1 3.2d uses ssize_t as a return type for read + and write. NextStep uses a non-void return value for exit, etc. With the + advent of 64 bit system, we'll expect more of these problems in the future. + Better uncomment the lot, except on SunOS, which is known to have bad + incomplete files. Add other OS'es with incomplete include files as needed + */ +#if (defined OS_sunos || defined OS_ultrix) +int read(); +int write(); +int fflush(); +char *strdup(); +int strcasecmp(); +int strncasecmp(); +char *getenv(); +unsigned long strtoul(); +int pclose(); +void exit(); +char *getpass(); +int atoi(); +FILE *fdopen(); +FILE *popen(); +#endif + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# else +# define MAXPATHLEN 1024 +# endif +#endif + + +#ifndef OS_linux +# undef USE_XDF +#endif + +#ifdef NO_XDF +# undef USE_XDF +#endif + +#ifdef __EMX__ +#define INCL_BASE +#define INCL_DOSDEVIOCTL +#include +#endif + +#ifdef OS_nextstep +/* nextstep doesn't have this. Unfortunately, we cannot test its presence + using AC_EGREP_HEADER, as we don't know _which_ header to test, and in + the general case utime.h might be non-existent */ +struct utimbuf +{ + time_t actime,modtime; +}; +#endif + +/* NeXTStep doesn't have these */ +#if !defined(S_ISREG) && defined (_S_IFMT) && defined (_S_IFREG) +#define S_ISREG(mode) (((mode) & (_S_IFMT)) == (_S_IFREG)) +#endif + +#if !defined(S_ISDIR) && defined (_S_IFMT) && defined (_S_IFDIR) +#define S_ISDIR(mode) (((mode) & (_S_IFMT)) == (_S_IFDIR)) +#endif + + +#ifdef OS_aix +/* AIX has an offset_t time, but somehow it is not scalar ==> forget about it + */ +# undef HAVE_OFFSET_T +#endif + + +#ifdef HAVE_STAT64 +#define MT_STAT stat64 +#define MT_LSTAT lstat64 +#define MT_FSTAT fstat64 +#else +#define MT_STAT stat +#define MT_LSTAT lstat +#define MT_FSTAT fstat +#endif + + +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif + +#ifndef __GNUC__ +#ifndef __inline__ +#define __inline__ inline +#endif +#endif + +#endif diff --git a/texinfo.tex b/texinfo.tex new file mode 100644 index 0000000..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 . +% +% 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 `\^^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 . + % + \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 to achieve this: TeX expands \the only once, + % simply yielding the contents of . (We also do this for + % the toc entries.) + \toks0 = {#1}% + \message{(\the\toks0)}% + % + \chapmacro{#1}{Ynothing}{\the\unnumberedno}% + % + \global\let\section = \unnumberedsec + \global\let\subsection = \unnumberedsubsec + \global\let\subsubsection = \unnumberedsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\parseargdef\centerchap{% + % Well, we could do the following in a group, but that would break + % an assumption that \chapmacro is called at the outermost level. + % Thus we are safer this way: --kasal, 24feb04 + \let\centerparametersmaybe = \centerparameters + \unnmhead0{#1}% + \let\centerparametersmaybe = \relax +} + +% @top is like @unnumbered. +\let\top\unnumbered + +% Sections. +% +\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz +\def\seczzz#1{% + \global\subsecno=0 \global\subsubsecno=0 \global\advance\secno by 1 + \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}% +} + +% 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 + \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{...} +% If we want to allow any as delimiter, +% we need the curly braces so that makeinfo sees the @verb command, eg: +% `@verbx...x' would look like the '@verbx' command. --janneke@gnu.org +% +% [Knuth]: Donald Ervin Knuth, 1996. The TeXbook. +% +% [Knuth] p.344; only we need to do the other characters Texinfo sets +% active too. Otherwise, they get lost as the first character on a +% verbatim line. +\def\dospecials{% + \do\ \do\\\do\{\do\}\do\$\do\&% + \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~% + \do\<\do\>\do\|\do\@\do+\do\"% + % Don't do the quotes -- if we do, @set txicodequoteundirected and + % @set txicodequotebacktick will not have effect on @verb and + % @verbatim, and ?` and !` ligatures won't get disabled. + %\do\`\do\'% +} +% +% [Knuth] p. 380 +\def\uncatcodespecials{% + \def\do##1{\catcode`##1=\other}\dospecials} +% +% Setup for the @verb command. +% +% Eight spaces for a tab +\begingroup + \catcode`\^^I=\active + \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }} +\endgroup +% +\def\setupverb{% + \tt % easiest (and conventionally used) font for verbatim + \def\par{\leavevmode\endgraf}% + \setupmarkupstyle{verb}% + \tabeightspaces + % Respect line breaks, + % print special symbols as themselves, and + % make each space count + % must do in this order: + \obeylines \uncatcodespecials \sepspaces +} + +% Setup for the @verbatim environment +% +% Real tab expansion. +\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount +% +% 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'{'#1'}'{#1} +% +% [Knuth] p. 382; only eat outer {} +\begingroup + \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other + \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next] +\endgroup +% +\def\verb{\begingroup\setupverb\doverb} +% +% +% Do the @verbatim magic: define the macro \doverbatim so that +% the (first) argument ends when '@end verbatim' is reached, ie: +% +% \def\doverbatim#1@end verbatim{#1} +% +% For Texinfo it's a lot easier than for LaTeX, +% because texinfo's \verbatim doesn't stop at '\end{verbatim}': +% we need not redefine '\', '{' and '}'. +% +% Inspired by LaTeX's verbatim command set [latex.ltx] +% +\begingroup + \catcode`\ =\active + \obeylines % + % ignore everything up to the first ^^M, that's the newline at the end + % of the @verbatim input line itself. Otherwise we get an extra blank + % line in the output. + \xdef\doverbatim#1^^M#2@end verbatim{#2\noexpand\end\gobble verbatim}% + % We really want {...\end verbatim} in the body of the macro, but + % without the active space; thus we have to use \xdef and \gobble. +\endgroup +% +\envdef\verbatim{% + \setupverbatim\doverbatim +} +\let\Everbatim = \afterenvbreak + + +% @verbatiminclude FILE - insert text of file in verbatim environment. +% +\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude} +% +\def\doverbatiminclude#1{% + {% + \makevalueexpandable + \setupverbatim + \indexnofonts % Allow `@@' and other weird things in file names. + \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\ }} + +\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 +% 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 +.\" +.\" 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 . + */ + +#include +#include "sysincludes.h" +#include "mtools.h" + +static FILE *tty=NULL; +static int notty=0; +static int ttyfd=-1; +#ifdef USE_RAWTERM +int mtools_raw_tty = 1; +#else +int mtools_raw_tty = 0; +#endif + +#ifdef USE_RAWTERM +# if defined TCSANOW && defined HAVE_TCSETATTR +/* we have tcsetattr & tcgetattr. Good */ +typedef struct termios Terminal; +# define stty(a,b) (void)tcsetattr(a,TCSANOW,b) +# define gtty(a,b) (void)tcgetattr(a,b) +# define USE_TCIFLUSH + +# elif defined TCSETS && defined TCGETS +typedef struct termios Terminal; +# define stty(a,b) (void)ioctl(a,TCSETS,(char *)b) +# define gtty(a,b) (void)ioctl(a,TCGETS,(char *)b) +# define USE_TCIFLUSH + +# elif defined TCSETA && defined TCGETA +typedef struct termio Terminal; +# define stty(a,b) (void)ioctl(a,TCSETA,(char *)b) +# define gtty(a,b) (void)ioctl(a,TCGETA,(char *)b) +# define USE_TCIFLUSH + +# elif defined(HAVE_SGTTY_H) && defined(TIOCSETP) && defined(TIOCGETP) +typedef struct sgttyb Terminal; +# define stty(a,b) (void)ioctl(a,TIOCSETP,(char *)b) +# define gtty(a,b) (void)ioctl(a,TIOCGETP,(char *)b) +# define USE_SGTTY +# define discard_input(a) /**/ + +# else +/* no way to use raw terminal */ +# warning Cannot use raw terminal code (disabled) +# undef USE_RAWTERM +# endif + +#endif + +#ifdef USE_TCIFLUSH +# if defined TCIFLUSH && defined HAVE_TCFLUSH +# define discard_input(a) tcflush(a,TCIFLUSH) +# else +# define discard_input(a) /**/ +# endif +#endif + +#ifdef USE_RAWTERM + +static int tty_mode = -1; /* 1 for raw, 0 for cooked, -1 for initial */ +static int need_tty_reset = 0; +static int handlerIsSet = 0; + +#define restore_tty(a) stty(STDIN,a) + + +#define STDIN ttyfd +#define FAIL (-1) +#define DONE 0 +static Terminal in_orig; + +/*--------------- Signal Handler routines -------------*/ + +static void tty_time_out(int dummy) +{ + int exit_code; + signal(SIGALRM, SIG_IGN); + if(tty && need_tty_reset) + restore_tty (&in_orig); +#ifdef future + if (fail_on_timeout) + exit_code=SHFAIL; + else { + if (default_choice && mode_defined) { + if (yes_no) { + if ('Y' == default_choice) + exit_code=0; + else + exit_code=1; + } else + exit_code=default_choice-minc+1; + } else + exit_code=DONE; + } +#else + exit_code = DONE; +#endif + exit(exit_code); +} + +static void cleanup_tty(void) +{ + if(tty && need_tty_reset) { + restore_tty (&in_orig); + setup_signal(); + } +} + +static void set_raw_tty(int mode) +{ + Terminal in_raw; + + if(mode != tty_mode && mode != -1) { + if(!handlerIsSet) { + /* Determine existing TTY settings */ + gtty (STDIN, &in_orig); + need_tty_reset = 1; + + /* Restore original TTY settings on exit */ + atexit(cleanup_tty); + handlerIsSet = 1; + } + + + setup_signal(); + signal (SIGALRM, tty_time_out); + + /* Change STDIN settings to raw */ + + gtty (STDIN, &in_raw); + if(mode) { +#ifdef USE_SGTTY + in_raw.sg_flags |= CBREAK; +#else + in_raw.c_lflag &= ~ICANON; + in_raw.c_cc[VMIN]=1; + in_raw.c_cc[VTIME]=0; +#endif + stty (STDIN, &in_raw); + } else { +#ifdef USE_SGTTY + in_raw.sg_flags &= ~CBREAK; +#else + in_raw.c_lflag |= ICANON; +#endif + stty (STDIN, &in_raw); + } + tty_mode = mode; + discard_input(STDIN); + } +} +#endif + +FILE *opentty(int mode) +{ + if(notty) + return NULL; + if (tty == NULL) { + ttyfd = open("/dev/tty", O_RDONLY); + if(ttyfd >= 0) { + tty = fdopen(ttyfd, "r"); + } + } + if (tty == NULL){ + if ( !isatty(0) ){ + notty = 1; + return NULL; + } + ttyfd = 0; + tty = stdin; + } +#ifdef USE_RAWTERM + if(mtools_raw_tty) + set_raw_tty(mode); +#endif + return tty; +} + +int ask_confirmation(const char *format, ...) +{ + char ans[10]; + va_list ap; + + if(!opentty(-1)) + return 0; + + while (1) { + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + fflush(stderr); + fflush(opentty(-1)); + if (mtools_raw_tty) { + ans[0] = fgetc(opentty(1)); + fputs("\n", stderr); + } else { + if(fgets(ans,9, opentty(0)) == NULL) + /* Treat end-of-file as no */ + ans[0] = 'n'; + } + if (ans[0] == 'y' || ans[0] == 'Y') + return 0; + if (ans[0] == 'n' || ans[0] == 'N') + return -1; + } +} diff --git a/unixdir.c b/unixdir.c new file mode 100644 index 0000000..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 . + */ + +#include "sysincludes.h" +#include "msdos.h" +#include "stream.h" +#include "mtools.h" +#include "fsP.h" +#include "file.h" +#include "htable.h" +#include "mainloop.h" +#include + +typedef struct Dir_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + struct MT_STAT statbuf; + char *pathname; + DIR *dir; +#ifdef HAVE_FCHDIR + int fd; +#endif +} Dir_t; + +/*#define FCHDIR_MODE*/ + +static int get_dir_data(Stream_t *Stream, time_t *date, mt_size_t *size, + int *type, int *address) +{ + DeclareThis(Dir_t); + + if(date) + *date = This->statbuf.st_mtime; + if(size) + *size = (mt_size_t) This->statbuf.st_size; + if(type) + *type = 1; + if(address) + *address = 0; + return 0; +} + +static int dir_free(Stream_t *Stream) +{ + DeclareThis(Dir_t); + + Free(This->pathname); + closedir(This->dir); + return 0; +} + +static Class_t DirClass = { + 0, /* read */ + 0, /* write */ + 0, /* flush */ + dir_free, /* free */ + 0, /* get_geom */ + get_dir_data , + 0 /* pre-allocate */ +}; + +#ifdef HAVE_FCHDIR +#define FCHDIR_MODE +#endif + +int unix_dir_loop(Stream_t *Stream, MainParam_t *mp); +int unix_loop(Stream_t *Stream, MainParam_t *mp, char *arg, + int follow_dir_link); + +int unix_dir_loop(Stream_t *Stream, MainParam_t *mp) +{ + DeclareThis(Dir_t); + struct dirent *entry; + char *newName; + int ret=0; + +#ifdef FCHDIR_MODE + int fd; + + fd = open(".", O_RDONLY); + if(chdir(This->pathname) < 0) { + fprintf(stderr, "Could not chdir into %s (%s)\n", + This->pathname, strerror(errno)); + return -1; + } +#endif + while((entry=readdir(This->dir)) != NULL) { + if(got_signal) + break; + if(isSpecial(entry->d_name)) + continue; +#ifndef FCHDIR_MODE + newName = malloc(strlen(This->pathname) + 1 + + strlen(entry->d_name) + 1); + if(!newName) { + ret = ERROR_ONE; + break; + } + strcpy(newName, This->pathname); + strcat(newName, "/"); + strcat(newName, entry->d_name); +#else + newName = entry->d_name; +#endif + ret |= unix_loop(Stream, mp, newName, 0); +#ifndef FCHDIR_MODE + free(newName); +#endif + } +#ifdef FCHDIR_MODE + if(fchdir(fd) < 0) + perror("Could not chdir back to .."); + close(fd); +#endif + return ret; +} + +Stream_t *OpenDir(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 . + * + * 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> 1) + + *name; + return(sum); +} + +/* check_vfat + * + * Inspect a directory and any associated VSEs. + * Return 1 if the VSEs comprise a valid long file name, + * 0 if not. + */ +static __inline__ void check_vfat(struct vfat_state *v, struct directory *dir) +{ + dos_name_t dn;; + + if (! v->subentries) { +#ifdef DEBUG + fprintf(stderr, "check_vfat: no VSEs.\n"); +#endif + return; + } + + memcpy(dn.base, (char *)dir->name, 8); + memcpy(dn.ext, (char *)dir->ext, 3); + + if (v->sum != sum_shortname(&dn)) + return; + + if( (v->status & ((1<subentries) - 1)) != (1<subentries) - 1) + return; /* missing entries */ + + /* zero out byte following last entry, for good measure */ + v->name[VSE_NAMELEN * v->subentries] = 0; + v->present = 1; +} + + +int clear_vses(Stream_t *Dir, int entrySlot, size_t last) +{ + direntry_t entry; + dirCache_t *cache; + int error; + + entry.Dir = Dir; + entry.entry = entrySlot; + + /*maximize(last, entry.entry + MAX_VFAT_SUBENTRIES);*/ + cache = allocDirCache(Dir, last); + if(!cache) { + fprintf(stderr, "Out of memory error in clear_vses\n"); + exit(1); + } + addFreeEntry(cache, entry.entry, last); + for (; entry.entry < (signed int) last; ++entry.entry) { +#ifdef DEBUG + fprintf(stderr,"Clearing entry %d.\n", entry.entry); +#endif + dir_read(&entry, &error); + if(error) + return error; + if(!entry.dir.name[0] || entry.dir.name[0] == DELMARK) + break; + entry.dir.name[0] = DELMARK; + if (entry.dir.attr == 0xf) + entry.dir.attr = '\0'; + low_level_dir_write(&entry); + } + return 0; +} + +int write_vfat(Stream_t *Dir, dos_name_t *shortname, char *longname, int start, + direntry_t *mainEntry) +{ + struct vfat_subentry *vse; + int vse_id, num_vses; + wchar_t *c; + direntry_t entry; + dirCache_t *cache; + wchar_t unixyName[13]; + doscp_t *cp = GET_DOSCONVERT(Dir); + + wchar_t wlongname[MAX_VNAMELEN+1]; + int wlen; + + if(longname) { +#ifdef DEBUG + printf("Entering write_vfat with longname=\"%s\", start=%d.\n", + longname,start); +#endif + entry.Dir = Dir; + vse = (struct vfat_subentry *) &entry.dir; + /* Fill in invariant part of vse */ + vse->attribute = 0x0f; + vse->hash1 = vse->sector_l = vse->sector_u = 0; + vse->sum = sum_shortname(shortname); +#ifdef DEBUG + printf("Wrote checksum=%d for shortname %s.%s\n", + vse->sum,shortname->base,shortname->ext); +#endif + + wlen = native_to_wchar(longname, wlongname, MAX_VNAMELEN+1, + 0, 0); + num_vses = (wlen + VSE_NAMELEN - 1)/VSE_NAMELEN; + for (vse_id = num_vses; vse_id; --vse_id) { + int end = 0; + + c = wlongname + (vse_id - 1) * VSE_NAMELEN; + + c += unicode_write(c, vse->text1, VSE1SIZE, &end); + c += unicode_write(c, vse->text2, VSE2SIZE, &end); + c += unicode_write(c, vse->text3, VSE3SIZE, &end); + + vse->id = (vse_id == num_vses) ? (vse_id | VSE_LAST) : vse_id; +#ifdef DEBUG + printf("Writing longname=(%s), VSE %d (%13s) at %d, end = %d.\n", + longname, vse_id, longname + (vse_id-1) * VSE_NAMELEN, + start + num_vses - vse_id, start + num_vses); +#endif + + entry.entry = start + num_vses - vse_id; + low_level_dir_write(&entry); + } + } else { + num_vses = 0; + wlongname[0]='\0'; + } + cache = allocDirCache(Dir, start + num_vses + 1); + if(!cache) { + fprintf(stderr, "Out of memory error\n"); + exit(1); + } + unix_name(cp, shortname->base, shortname->ext, 0, unixyName); + addUsedEntry(cache, start, start + num_vses + 1, wlongname, unixyName, + &mainEntry->dir); + low_level_dir_write(mainEntry); + return start + num_vses; +} + +void dir_write(direntry_t *entry) +{ + dirCacheEntry_t *dce; + dirCache_t *cache; + + if(entry->entry == -3) { + fprintf(stderr, "Attempt to write root directory pointer\n"); + exit(1); + } + + cache = allocDirCache(entry->Dir, entry->entry + 1); + if(!cache) { + fprintf(stderr, "Out of memory error in dir_write\n"); + exit(1); + } + dce = cache->entries[entry->entry]; + if(dce) { + if(entry->dir.name[0] == DELMARK) { + addFreeEntry(cache, dce->beginSlot, dce->endSlot); + } else { + dce->dir = entry->dir; + } + } + low_level_dir_write(entry); +} + + +/* + * The following function translates a series of vfat_subentries into + * data suitable for a dircache entry + */ +static __inline__ void parse_vses(direntry_t *entry, + struct vfat_state *v) +{ + struct vfat_subentry *vse; + unsigned char id, last_flag; + wchar_t *c; + + vse = (struct vfat_subentry *) &entry->dir; + + id = vse->id & VSE_MASK; + last_flag = (vse->id & VSE_LAST); + if (id > MAX_VFAT_SUBENTRIES) { + fprintf(stderr, "parse_vses: invalid VSE ID %d at %d.\n", + id, entry->entry); + return; + } + +/* 950819: This code enforced finding the VSEs in order. Well, Win95 + * likes to write them in *reverse* order for some bizarre reason! So + * we pretty much have to tolerate them coming in any possible order. + * So skip this check, we'll do without it (What does this do, Alain?). + * + * 950820: Totally rearranged code to tolerate any order but to warn if + * they are not in reverse order like Win95 uses. + * + * 950909: Tolerate any order. We recognize new chains by mismatching + * checksums. In the event that the checksums match, new entries silently + * overwrite old entries of the same id. This should accept all valid + * entries, but may fail to reject invalid entries in some rare cases. + */ + + /* bad checksum, begin new chain */ + if(v->sum != vse->sum) { + clear_vfat(v); + v->sum = vse->sum; + } + +#ifdef DEBUG + if(v->status & (1 << (id-1))) + fprintf(stderr, + "parse_vses: duplicate VSE %d\n", vse->id); +#endif + + v->status |= 1 << (id-1); + if(last_flag) + v->subentries = id; + +#ifdef DEBUG + if (id > v->subentries) + /* simple test to detect entries preceding + * the "last" entry (really the first) */ + fprintf(stderr, + "parse_vses: new VSE %d sans LAST flag\n", + vse->id); +#endif + + c = &(v->name[VSE_NAMELEN * (id-1)]); + c += unicode_read(vse->text1, c, VSE1SIZE); + c += unicode_read(vse->text2, c, VSE2SIZE); + c += unicode_read(vse->text3, c, VSE3SIZE); +#ifdef DEBUG + printf("Read VSE %d at %d, subentries=%d, = (%13ls).\n", + id,entry->entry,v->subentries,&(v->name[VSE_NAMELEN * (id-1)])); +#endif + if (last_flag) + *c = '\0'; /* Null terminate long name */ +} + +/** + * 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 . + */ + +#include "msdos.h" + +/* + * VFAT-related common header file + */ +#define VFAT_SUPPORT + +struct unicode_char { + unsigned char lchar; + unsigned char uchar; +} PACKED; + + +/* #define MAX_VFAT_SUBENTRIES 32 */ /* Theoretical max # of VSEs */ +#define MAX_VFAT_SUBENTRIES 20 /* Max useful # of VSEs */ +#define VSE_NAMELEN 13 + +#define VSE1SIZE 5 +#define VSE2SIZE 6 +#define VSE3SIZE 2 + +#include "stream.h" + +struct vfat_subentry { + unsigned char id; /* 0x40 = last; & 0x1f = VSE ID */ + struct unicode_char text1[VSE1SIZE]; + unsigned char attribute; /* 0x0f for VFAT */ + unsigned char hash1; /* Always 0? */ + unsigned char sum; /* Checksum of short name */ + struct unicode_char text2[VSE2SIZE]; + unsigned char sector_l; /* 0 for VFAT */ + unsigned char sector_u; /* 0 for VFAT */ + struct unicode_char text3[VSE3SIZE]; +}; + +/* Enough size for a worst case number of full VSEs plus a null */ +#define VBUFSIZE ((MAX_VFAT_SUBENTRIES*VSE_NAMELEN) + 1) + +/* Max legal length of a VFAT long name */ +#define MAX_VNAMELEN (255) + +#define VSE_PRESENT 0x01 +#define VSE_LAST 0x40 +#define VSE_MASK 0x1f + +struct vfat_state { + wchar_t name[VBUFSIZE]; + int status; /* is now a bit map of 32 bits */ + int subentries; + unsigned char sum; /* no need to remember the sum for each entry, + * it is the same anyways */ + int present; +}; + + +struct scan_state { + int match_free; + int shortmatch; + int longmatch; + unsigned int free_start; + unsigned int free_end; + int slot; + int got_slots; + unsigned int size_needed; + int max_entry; +}; + +#include "mtoolsDirentry.h" + +void clear_vfat(struct vfat_state *); +int unicode_write(wchar_t *, struct unicode_char *, int num, int *end); + +int clear_vses(Stream_t *, int, size_t); +void autorename_short(struct dos_name_t *, int); +void autorename_long(char *, int); + +#define DO_OPEN 1 /* open all files that are found */ +#define ACCEPT_LABEL 0x08 +#define ACCEPT_DIR 0x10 +#define ACCEPT_PLAIN 0x20 +#define MATCH_ANY 0x40 +#define NO_MSG 0x80 +#define NO_DOTS 0x100 /* accept no dots if matched by wildcard */ +#define DO_OPEN_DIRS 0x400 /* open all directories that are found */ +#define OPEN_PARENT 0x1000 /* in target lookup, open parent + * instead of file itself */ +#define NO_UNIX 0x2000 /* in target lookup, consider all files to reside on + * the DOS fs */ +#endif diff --git a/xdf_io.c b/xdf_io.c new file mode 100644 index 0000000..f0db3b3 --- /dev/null +++ b/xdf_io.c @@ -0,0 +1,710 @@ +/* Copyright 1994,1996-2003,2005,2007,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + * + * Io to an xdf disk + * + * written by: + * + * Alain L. Knaff + * alain@knaff.lu + * + */ + + +#include "sysincludes.h" +#ifdef OS_linux +#include "msdos.h" +#include "mtools.h" +#include "devices.h" +#include "xdf_io.h" + +/* Algorithms can't be patented */ + +typedef struct sector_map { + unsigned int head:1; + unsigned int size:7; +} sector_map_t; + + +struct { + unsigned char track_size; + unsigned int track0_size:7; + unsigned int rootskip:1; + unsigned char rate; + sector_map_t map[9]; +} xdf_table[]= { + { + 19, 16, 0, 0, + { {0,3}, {0,6}, {1,2}, {0,2}, {1,6}, {1,3}, {0,0} } + }, + { + 23, 19, 0, 0, + { {0,3}, {0,4}, {1,6}, {0,2}, {1,2}, {0,6}, {1,4}, {1,3}, {0,0} } + }, + { + 46, 37, 1, 0x43, + { {0,3}, {0,4}, {0,5}, {0,7}, {1,3}, {1,4}, {1,5}, {1,7}, {0,0} } + }, + { + 24, 20, 1, 0, + { {0,5}, {1,6}, {0,6}, {1, 5} } + }, + { + 48, 41, 1, 0, + { {0,6}, {1,7}, {0,7}, {1, 6} } + } +}; + +#define NUMBER(x) (sizeof(x)/sizeof(x[0])) + +typedef struct { + unsigned char begin; /* where it begins */ + unsigned char end; + unsigned char sector; + unsigned char sizecode; + + unsigned int dirty:1; + unsigned int phantom:2; + unsigned int valid:1; + unsigned int head:1; +} TrackMap_t; + + + +typedef struct Xdf_t { + Class_t *Class; + int refs; + Stream_t *Next; + Stream_t *Buffer; + + int fd; + char *buffer; + + int current_track; + + sector_map_t *map; + + int track_size; + int track0_size; + int sector_size; + int FatSize; + int RootDirSize; + TrackMap_t *track_map; + + unsigned char last_sector; + unsigned char rate; + + unsigned int stretch:1; + unsigned int rootskip:1; + signed int drive:4; +} Xdf_t; + +typedef struct { + unsigned char head; + unsigned char sector; + unsigned char ptr; +} Compactify_t; + + +static int analyze_reply(RawRequest_t *raw_cmd, int do_print) +{ + int ret, bytes, newbytes; + + bytes = 0; + while(1) { + ret = analyze_one_reply(raw_cmd, &newbytes, do_print); + bytes += newbytes; + switch(ret) { + case 0: + return bytes; + case 1: + raw_cmd++; + break; + case -1: + if(bytes) + return bytes; + else + return 0; + } + } +} + + + +static int send_cmd(int fd, RawRequest_t *raw_cmd, int nr, + const char *message, int retries) +{ + int j; + int ret=-1; + + if(!nr) + return 0; + for (j=0; j< retries; j++){ + switch(send_one_cmd(fd, raw_cmd, message)) { + case -1: + return -1; + case 1: + j++; + continue; + case 0: + break; + } + if((ret=analyze_reply(raw_cmd, j)) > 0) + return ret; /* ok */ + } + if(j > 1 && j == retries) { + fprintf(stderr,"Too many errors, giving up\n"); + return 0; + } + return -1; +} + + + +#define REC (This->track_map[ptr]) +#define END(x) (This->track_map[(x)].end) +#define BEGIN(x) (This->track_map[(x)].begin) + +static int add_to_request(Xdf_t *This, int ptr, + RawRequest_t *request, int *nr, + int direction, Compactify_t *compactify) +{ +#if 0 + if(direction == MT_WRITE) { + printf("writing %d: %d %d %d %d [%02x]\n", + ptr, This->current_track, + REC.head, REC.sector, REC.sizecode, + *(This->buffer + ptr * This->sector_size)); + } else + printf(" load %d.%d\n", This->current_track, ptr); +#endif + if(REC.phantom) { + if(direction== MT_READ) + memset(This->buffer + ptr * This->sector_size, 0, + 128 << REC.sizecode); + return 0; + } + + if(*nr && + RR_SIZECODE(request+(*nr)-1) == REC.sizecode && + compactify->head == REC.head && + compactify->ptr + 1 == ptr && + compactify->sector +1 == REC.sector) { + RR_SETSIZECODE(request+(*nr)-1, REC.sizecode); + } else { + if(*nr) + RR_SETCONT(request+(*nr)-1); + RR_INIT(request+(*nr)); + RR_SETDRIVE(request+(*nr), This->drive); + RR_SETRATE(request+(*nr), This->rate); + RR_SETTRACK(request+(*nr), This->current_track); + RR_SETPTRACK(request+(*nr), + This->current_track << This->stretch); + RR_SETHEAD(request+(*nr), REC.head); + RR_SETSECTOR(request+(*nr), REC.sector); + RR_SETSIZECODE(request+(*nr), REC.sizecode); + RR_SETDIRECTION(request+(*nr), direction); + RR_SETDATA(request+(*nr), + (caddr_t) This->buffer + ptr * This->sector_size); + (*nr)++; + } + compactify->ptr = ptr; + compactify->head = REC.head; + compactify->sector = REC.sector; + return 0; +} + + +static void add_to_request_if_invalid(Xdf_t *This, int ptr, + RawRequest_t *request, int *nr, + Compactify_t *compactify) +{ + if(!REC.valid) + add_to_request(This, ptr, request, nr, MT_READ, compactify); + +} + + +static void adjust_bounds(Xdf_t *This, off_t *begin, off_t *end) +{ + /* translates begin and end from byte to sectors */ + *begin = *begin / This->sector_size; + *end = (*end + This->sector_size - 1) / This->sector_size; +} + + +static __inline__ int try_flush_dirty(Xdf_t *This) +{ + int ptr, nr, bytes; + RawRequest_t requests[100]; + Compactify_t compactify; + + if(This->current_track < 0) + return 0; + + nr = 0; + for(ptr=0; ptr < This->last_sector; ptr=REC.end) + if(REC.dirty) + add_to_request(This, ptr, + requests, &nr, + MT_WRITE, &compactify); +#if 1 + bytes = send_cmd(This->fd,requests, nr, "writing", 4); + if(bytes < 0) + return bytes; +#else + bytes = 0xffffff; +#endif + for(ptr=0; ptr < This->last_sector; ptr=REC.end) + if(REC.dirty) { + if(bytes >= REC.end - REC.begin) { + bytes -= REC.end - REC.begin; + REC.dirty = 0; + } else + return 1; + } + return 0; +} + + + +static int flush_dirty(Xdf_t *This) +{ + int ret; + + while((ret = try_flush_dirty(This))) { + if(ret < 0) + return ret; + } + return 0; +} + + +static int load_data(Xdf_t *This, off_t begin, off_t end, int retries) +{ + int ptr, nr, bytes; + RawRequest_t requests[100]; + Compactify_t compactify; + + adjust_bounds(This, &begin, &end); + + ptr = begin; + nr = 0; + for(ptr=REC.begin; ptr < end ; ptr = REC.end) + add_to_request_if_invalid(This, ptr, requests, &nr, + &compactify); + bytes = send_cmd(This->fd,requests, nr, "reading", retries); + if(bytes < 0) + return bytes; + ptr = begin; + for(ptr=REC.begin; ptr < end ; ptr = REC.end) { + if(!REC.valid) { + if(bytes >= REC.end - REC.begin) { + bytes -= REC.end - REC.begin; + REC.valid = 1; + } else if(ptr > begin) + return ptr * This->sector_size; + else + return -1; + } + } + return end * This->sector_size; +} + +static void mark_dirty(Xdf_t *This, off_t begin, off_t end) +{ + int ptr; + + adjust_bounds(This, &begin, &end); + + ptr = begin; + for(ptr=REC.begin; ptr < end ; ptr = REC.end) { + REC.valid = 1; + if(!REC.phantom) + REC.dirty = 1; + } +} + + +static int load_bounds(Xdf_t *This, off_t begin, off_t end) +{ + off_t lbegin, lend; + int endp1, endp2; + + lbegin = begin; + lend = end; + + adjust_bounds(This, &lbegin, &lend); + + if(begin != BEGIN(lbegin) * This->sector_size && + end != BEGIN(lend) * This->sector_size && + lend < END(END(lbegin))) + /* contiguous end & begin, load them in one go */ + return load_data(This, begin, end, 4); + + if(begin != BEGIN(lbegin) * This->sector_size) { + endp1 = load_data(This, begin, begin, 4); + if(endp1 < 0) + return endp1; + } + + if(end != BEGIN(lend) * This->sector_size) { + endp2 = load_data(This, end, end, 4); + if(endp2 < 0) + return BEGIN(lend) * This->sector_size; + } + return lend * This->sector_size; +} + + +static int fill_t0(Xdf_t *This, int ptr, int size, int *sector, int *head) +{ + int n; + + for(n = 0; n < size; ptr++,n++) { + REC.head = *head; + REC.sector = *sector + 129; + REC.phantom = 0; + (*sector)++; + if(!*head && *sector >= This->track0_size - 8) { + *sector = 0; + *head = 1; + } + } + return ptr; +} + + +static int fill_phantoms(Xdf_t *This, int ptr, int size) +{ + int n; + + for(n = 0; n < size; ptr++,n++) + REC.phantom = 1; + return ptr; +} + +static void decompose(Xdf_t *This, int where, int len, off_t *begin, + off_t *end, int boot) +{ + int ptr, track; + sector_map_t *map; + int lbegin, lend; + + track = where / This->track_size / 1024; + + *begin = where - track * This->track_size * 1024; + *end = where + len - track * This->track_size * 1024; + maximize(*end, This->track_size * 1024); + + if(This->current_track == track && !boot) + /* already OK, return immediately */ + return; + if(!boot) + flush_dirty(This); + This->current_track = track; + + if(track) { + for(ptr=0, map=This->map; map->size; map++) { + /* iterate through all sectors */ + lbegin = ptr; + lend = ptr + (128 << map->size) / This->sector_size; + for( ; ptr < lend ; ptr++) { + REC.begin = lbegin; + REC.end = lend; + + REC.head = map->head; + REC.sector = map->size + 128; + REC.sizecode = map->size; + + REC.valid = 0; + REC.dirty = 0; + REC.phantom = 0; + } + } + REC.begin = REC.end = ptr; + } else { + int sector, head; + + head = 0; + sector = 0; + + for(ptr=boot; ptr < 2 * This->track_size; ptr++) { + REC.begin = ptr; + REC.end = ptr+1; + + REC.sizecode = 2; + + REC.valid = 0; + REC.dirty = 0; + } + + /* boot & 1st fat */ + ptr=fill_t0(This, 0, 1 + This->FatSize, §or, &head); + + /* second fat */ + ptr=fill_phantoms(This, ptr, This->FatSize); + + /* root dir */ + ptr=fill_t0(This, ptr, This->RootDirSize, §or, &head); + + /* "bad sectors" at the beginning of the fs */ + ptr=fill_phantoms(This, ptr, 5); + + if(This->rootskip) + sector++; + + /* beginning of the file system */ + ptr = fill_t0(This, ptr, + (This->track_size - This->FatSize) * 2 - + This->RootDirSize - 6, + §or, &head); + } + This->last_sector = ptr; +} + + +static int xdf_read(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + off_t begin, end; + size_t len2; + DeclareThis(Xdf_t); + + decompose(This, truncBytes32(where), len, &begin, &end, 0); + len2 = load_data(This, begin, end, 4); + if(len2 < 0) + return len2; + len2 -= begin; + maximize(len, len2); + memcpy(buf, This->buffer + begin, len); + return end - begin; +} + +static int xdf_write(Stream_t *Stream, char *buf, mt_off_t where, size_t len) +{ + off_t begin, end; + size_t len2; + DeclareThis(Xdf_t); + + decompose(This, truncBytes32(where), len, &begin, &end, 0); + len2 = load_bounds(This, begin, end); + if(len2 < 0) + return len2; + maximize(end, (off_t)len2); + len2 -= begin; + maximize(len, (off_t)len2); + memcpy(This->buffer + begin, buf, len); + mark_dirty(This, begin, end); + return end - begin; +} + +static int xdf_flush(Stream_t *Stream) +{ + DeclareThis(Xdf_t); + + return flush_dirty(This); +} + +static int xdf_free(Stream_t *Stream) +{ + DeclareThis(Xdf_t); + Free(This->track_map); + Free(This->buffer); + return close(This->fd); +} + + +static int check_geom(struct device *dev, int media, union bootsector *boot) +{ + int sect; + + if(media >= 0xfc && media <= 0xff) + return 1; /* old DOS */ + + if (!IS_MFORMAT_ONLY(dev)) { + if(compare(dev->sectors, 19) && + compare(dev->sectors, 23) && + compare(dev->sectors, 24) && + compare(dev->sectors, 46) && + compare(dev->sectors, 48)) + return 1; + + /* check against contradictory info from configuration file */ + if(compare(dev->heads, 2)) + return 1; + } + + /* check against info from boot */ + if(boot) { + sect = WORD(nsect); + if((sect != 19 && sect != 23 && sect != 24 && + sect != 46 && sect != 48) || + (!IS_MFORMAT_ONLY(dev) && compare(dev->sectors, sect)) || + WORD(nheads) !=2) + return 1; + } + return 0; +} + +static void set_geom(union bootsector *boot, struct device *dev) +{ + /* fill in config info to be returned to user */ + dev->heads = 2; + dev->use_2m = 0xff; + if(boot) { + dev->sectors = WORD(nsect); + if(WORD(psect)) + dev->tracks = WORD(psect) / dev->sectors / 2; + } +} + +static int config_geom(Stream_t *Stream, struct device *dev, + struct device *orig_dev, int media, + union bootsector *boot) +{ + if(check_geom(dev, media, boot)) + return 1; + set_geom(boot,dev); + return 0; +} + +static Class_t XdfClass = { + xdf_read, + xdf_write, + xdf_flush, + xdf_free, + config_geom, + 0, /* get_data */ + 0 /* pre-allocate */ +}; + +Stream_t *XdfOpen(struct device *dev, char *name, + int mode, char *errmsg, struct xdf_info *info) +{ + Xdf_t *This; + off_t begin, end; + union bootsector *boot; + unsigned int type; + + if(dev && (!SHOULD_USE_XDF(dev) || check_geom(dev, 0, 0))) + return NULL; + + This = New(Xdf_t); + if (!This) + return NULL; + + This->Class = &XdfClass; + This->sector_size = 512; + This->stretch = 0; + + precmd(dev); + This->fd = open(name, mode | dev->mode | O_EXCL | O_NDELAY); + if(This->fd < 0) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"xdf floppy: open: \"%s\"", strerror(errno)); +#else + sprintf(errmsg,"xdf floppy: open: \"%s\"", strerror(errno)); +#endif + goto exit_0; + } + closeExec(This->fd); + + This->drive = GET_DRIVE(This->fd); + if(This->drive < 0) + goto exit_1; + + /* allocate buffer */ + This->buffer = (char *) malloc(96 * 512); + if (!This->buffer) + goto exit_1; + + This->current_track = -1; + This->track_map = (TrackMap_t *) + calloc(96, sizeof(TrackMap_t)); + if(!This->track_map) + goto exit_2; + + /* lock the device on writes */ + if (lock_dev(This->fd, mode == O_RDWR, dev)) { +#ifdef HAVE_SNPRINTF + snprintf(errmsg,199,"xdf floppy: device \"%s\" busy:", + dev->name); +#else + sprintf(errmsg,"xdf floppy: device \"%s\" busy:", + dev->name); +#endif + goto exit_3; + } + + /* Before reading the boot sector, assume dummy values suitable + * for reading at least the boot sector */ + This->track_size = 11; + This->track0_size = 6; + This->rate = 0; + This->FatSize = 9; + This->RootDirSize = 1; + decompose(This, 0, 512, &begin, &end, 0); + if (load_data(This, 0, 1, 1) < 0 ) { + This->rate = 0x43; + if(load_data(This, 0, 1, 1) < 0) + goto exit_3; + } + + boot = (union bootsector *) This->buffer; + This->FatSize = WORD(fatlen); + This->RootDirSize = WORD(dirents)/16; + This->track_size = WORD(nsect); + for(type=0; type < NUMBER(xdf_table); type++) { + if(xdf_table[type].track_size == This->track_size) { + This->map = xdf_table[type].map; + This->track0_size = xdf_table[type].track0_size; + This->rootskip = xdf_table[type].rootskip; + This->rate = xdf_table[type].rate; + break; + } + } + if(type == NUMBER(xdf_table)) + goto exit_3; + + if(info) { + info->RootDirSize = This->RootDirSize; + info->FatSize = This->FatSize; + info->BadSectors = 5; + } + decompose(This, 0, 512, &begin, &end, 1); + + This->refs = 1; + This->Next = 0; + This->Buffer = 0; + if(dev) + set_geom(boot, dev); + return (Stream_t *) This; + +exit_3: + Free(This->track_map); +exit_2: + Free(This->buffer); +exit_1: + close(This->fd); +exit_0: + Free(This); + return NULL; +} + +#endif + +/* Algorithms can't be patented */ + diff --git a/xdf_io.h b/xdf_io.h new file mode 100644 index 0000000..db5d52c --- /dev/null +++ b/xdf_io.h @@ -0,0 +1,33 @@ +#ifndef MTOOLS_XDFIO_H +#define MTOOLS_XDFIO_H + +/* Copyright 1996,1997,2001,2002,2009 Alain Knaff. + * This file is part of mtools. + * + * Mtools is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Mtools is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Mtools. If not, see . + */ + +#include "msdos.h" +#include "stream.h" + +struct xdf_info { + int FatSize; + int RootDirSize; + int BadSectors; +}; + +Stream_t *XdfOpen(struct device *dev, char *name, + int mode, char *errmsg, struct xdf_info *info); + +#endif -- cgit v1.2.1