summaryrefslogtreecommitdiff
path: root/mysys
diff options
context:
space:
mode:
authorbk@work.mysql.com <>2000-07-31 21:29:14 +0200
committerbk@work.mysql.com <>2000-07-31 21:29:14 +0200
commitf4c589ff6c653d1d2a09c26e46ead3c8a15655d8 (patch)
treed253a359142dfc1ed247d5d4365d86972ea31109 /mysys
parent7eec25e393727b16bb916b50d82b0aa3084e065c (diff)
downloadmariadb-git-f4c589ff6c653d1d2a09c26e46ead3c8a15655d8.tar.gz
Import changeset
Diffstat (limited to 'mysys')
-rw-r--r--mysys/.cvsignore10
-rwxr-xr-xmysys/COPYING.LIB481
-rw-r--r--mysys/ChangeLog221
-rw-r--r--mysys/Makefile.am93
-rw-r--r--mysys/array.c177
-rw-r--r--mysys/charset.c532
-rw-r--r--mysys/checksum.c30
-rw-r--r--mysys/default.c362
-rw-r--r--mysys/errors.c84
-rw-r--r--mysys/getopt.c744
-rw-r--r--mysys/getopt1.c170
-rw-r--r--mysys/getvar.c105
-rw-r--r--mysys/hash.c586
-rw-r--r--mysys/list.c116
-rwxr-xr-xmysys/make-ccc4
-rw-r--r--mysys/make-conf.c73
-rw-r--r--mysys/mf_brkhant.c76
-rw-r--r--mysys/mf_cache.c83
-rw-r--r--mysys/mf_casecnv.c252
-rw-r--r--mysys/mf_dirname.c106
-rw-r--r--mysys/mf_fn_ext.c46
-rw-r--r--mysys/mf_format.c146
-rw-r--r--mysys/mf_getdate.c59
-rw-r--r--mysys/mf_iocache.c603
-rw-r--r--mysys/mf_keycache.c753
-rw-r--r--mysys/mf_loadpath.c54
-rw-r--r--mysys/mf_pack.c528
-rw-r--r--mysys/mf_pack2.c53
-rw-r--r--mysys/mf_path.c120
-rw-r--r--mysys/mf_qsort.c258
-rw-r--r--mysys/mf_qsort2.c21
-rw-r--r--mysys/mf_radix.c56
-rw-r--r--mysys/mf_same.c38
-rw-r--r--mysys/mf_sleep.c36
-rw-r--r--mysys/mf_sort.c43
-rw-r--r--mysys/mf_soundex.c102
-rw-r--r--mysys/mf_stripp.c47
-rw-r--r--mysys/mf_unixpath.c33
-rw-r--r--mysys/mf_util.c49
-rw-r--r--mysys/mf_wcomp.c68
-rw-r--r--mysys/mf_wfile.c132
-rw-r--r--mysys/mulalloc.c53
-rw-r--r--mysys/my_alarm.c34
-rw-r--r--mysys/my_alloc.c129
-rw-r--r--mysys/my_append.c66
-rw-r--r--mysys/my_chsize.c86
-rw-r--r--mysys/my_clock.c35
-rw-r--r--mysys/my_compress.c87
-rw-r--r--mysys/my_copy.c103
-rw-r--r--mysys/my_create.c84
-rw-r--r--mysys/my_delete.c36
-rw-r--r--mysys/my_div.c31
-rw-r--r--mysys/my_error.c122
-rw-r--r--mysys/my_fopen.c165
-rw-r--r--mysys/my_fstream.c170
-rw-r--r--mysys/my_getwd.c182
-rw-r--r--mysys/my_init.c301
-rw-r--r--mysys/my_lib.c607
-rw-r--r--mysys/my_lock.c161
-rw-r--r--mysys/my_lockmem.c101
-rw-r--r--mysys/my_lread.c54
-rw-r--r--mysys/my_lwrite.c47
-rw-r--r--mysys/my_malloc.c84
-rw-r--r--mysys/my_messnc.c36
-rw-r--r--mysys/my_mkdir.c44
-rw-r--r--mysys/my_net.c49
-rw-r--r--mysys/my_once.c88
-rw-r--r--mysys/my_open.c97
-rw-r--r--mysys/my_pread.c137
-rw-r--r--mysys/my_pthread.c476
-rw-r--r--mysys/my_quick.c45
-rw-r--r--mysys/my_read.c66
-rw-r--r--mysys/my_realloc.c65
-rw-r--r--mysys/my_redel.c98
-rw-r--r--mysys/my_rename.c60
-rw-r--r--mysys/my_seek.c57
-rw-r--r--mysys/my_static.c100
-rw-r--r--mysys/my_static.h82
-rw-r--r--mysys/my_tempnam.c142
-rw-r--r--mysys/my_thr_init.c194
-rw-r--r--mysys/my_vsnprintf.c94
-rw-r--r--mysys/my_wincond.c141
-rw-r--r--mysys/my_winthread.c111
-rw-r--r--mysys/my_write.c77
-rw-r--r--mysys/mysys_priv.h31
-rw-r--r--mysys/ptr_cmp.c158
-rw-r--r--mysys/queues.c141
-rw-r--r--mysys/raid.cc809
-rw-r--r--mysys/safemalloc.c518
-rw-r--r--mysys/string.c117
-rw-r--r--mysys/test_charset.c59
-rw-r--r--mysys/test_dir.c50
-rw-r--r--mysys/test_fn.c70
-rw-r--r--mysys/test_vsnprintf.c45
-rw-r--r--mysys/testhash.c291
-rw-r--r--mysys/thr_alarm.c874
-rw-r--r--mysys/thr_lock.c1288
-rw-r--r--mysys/thr_mutex.c214
-rw-r--r--mysys/thr_rwlock.c139
-rw-r--r--mysys/tree.c513
-rw-r--r--mysys/typelib.c106
101 files changed, 17970 insertions, 0 deletions
diff --git a/mysys/.cvsignore b/mysys/.cvsignore
new file mode 100644
index 00000000000..056ecc2691c
--- /dev/null
+++ b/mysys/.cvsignore
@@ -0,0 +1,10 @@
+.deps
+.libs
+Makefile
+Makefile.in
+st35l1t6
+test_charset
+test_thr_alarm
+test_thr_lock
+test_vsnprintf
+testhash
diff --git a/mysys/COPYING.LIB b/mysys/COPYING.LIB
new file mode 100755
index 00000000000..eb685a5ec98
--- /dev/null
+++ b/mysys/COPYING.LIB
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library 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 Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/mysys/ChangeLog b/mysys/ChangeLog
new file mode 100644
index 00000000000..e24fc00b493
--- /dev/null
+++ b/mysys/ChangeLog
@@ -0,0 +1,221 @@
+2000-02-16 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added an extra argument to the compare routine for queues to allow
+ more advanced key compare functions.
+
+2000-02-10 Michael Widenius <monty@monty.pp.sci.fi>
+
+* Added THR_READ_NO_INSERT lock privilege to thr_lock.
+
+1999-08-21 Michael Widenius <monty@tik.pp.sci.fi>
+
+* Fix that '-1.49 or -1.49' is true
+* Allow negative hexadecimal numbers (like -0x0f).
+* Fixed problem with auto_increment on float and double.
+
+Wed Dec 17 02:13:58 1997 <monty@monty.pp.sci.fi>
+
+* Faster flush of keycache.
+
+Sat Dec 2 21:36:20 1995 Michael Widenius (monty@bitch)
+
+ * array.c push_element & alloc_element.
+
+Wed Mar 3 00:54:20 1993 Michael Widenius (monty@bitch)
+
+ * Removed automatic O_TRUNC from my_create.
+
+Wed Oct 28 02:10:56 1992 Michael Widenius (monty@bitch)
+
+ * Enabled ASNYNC_IO on SUN.
+
+Mon Aug 31 23:51:13 1992 Michael Widenius (monty@bitch)
+
+ * Changed tree_insert to return element if ok.
+ * Added new define tree_set_pointer().
+ * Chagned delete_queue() to not free if allready freed.
+
+Mon Aug 17 01:46:36 1992 Michael Widenius (monty@bitch)
+
+ * Added ny cashing-rutine mf_iocash for quicker io.
+
+Wed Aug 12 13:41:18 1992 Michael Widenius (monty@bitch)
+
+ * Added new function get_copy_of_memory for combined malloc/copy.
+ * Splitted my_malloc to three files.
+
+Thu Jan 23 22:02:37 1992 Michael Widenius (monty at LYNX)
+
+ * Added range-checks and aligned checks on ptrs to
+ safe_malloc:free and safe_malloc:realloc to catch more
+ error nicely without core-dumps.
+
+Wed Nov 13 01:52:18 1991 Michael Widenius (monty at LYNX)
+
+ * Added use of mysys as a shared library.
+
+Sat Nov 9 14:38:21 1991 Michael Widenius (monty at LYNX)
+
+ * Added expand of ~username to unpack_dirname.
+
+Tue Sep 17 21:15:08 1991 Michael Widenius (monty at LYNX)
+
+ * Don't free null-pointers if passed to my_free
+
+Fri May 17 20:11:27 1991 Michael Widenius (monty at LYNX)
+
+ * Changed all char * to string. (Can't change const char * because
+ of bug in C-definition.
+
+Tue Apr 30 01:32:56 1991 Michael Widenius (monty at LYNX)
+
+ * my_path now examines environment for posix variable "_" if
+ progname is given and has no path.
+
+Mon Apr 22 16:12:56 1991 Michael Widenius (monty at LYNX)
+
+ * Added function my_load_path() to fix path to a hard-path.
+
+Mon Apr 15 22:08:58 1991 Michael Widenius (monty at LYNX)
+
+ * Added more info on DBUG-stream when freeing unallocated data.
+
+Wed Apr 3 18:41:28 1991 Michael Widenius (monty at LYNX)
+
+ * Added global flag sf_malloc_no_sanity to make it possibly
+ to avoid sanity-checks in right code with uses malloc a lot.
+
+Tue Mar 26 15:09:45 1991 Mikael WIDENIUS (monty at panther)
+
+ * Made soundex look nicer
+
+Sat Mar 23 10:49:49 1991 Michael Widenius (monty at LYNX)
+
+ * Added init of alarm variables to skipp some warnings from gcc.
+
+Tue Mar 5 16:50:34 1991 Michael Widenius (monty at LYNX)
+
+ * Our qsort now only test if compare() function returns >= 0
+ and is optimized for compare() returning > 0.
+
+Fri Nov 23 23:53:46 1990 Michael Widenius (monty at LYNX)
+
+ * Added function my_set_alarm_variable to get a variable set
+ on some time.
+ my_alarm.h added for functions who want to print stat after
+ a given time or after a number of loops.
+ Changed my_lock to use new function and use defines in my_alarm.h
+
+Mon Oct 1 13:16:15 1990 Michael Widenius (monty at LYNX)
+
+ * Added use of asynchronic io in read_cash_record().
+ * Added write_cash and flush_write_cash to record cashing.
+
+Sun Sep 16 22:05:25 1990 Michael Widenius (monty at LYNX)
+
+ * Added optional alarm to my_lock if one has FCNTL_LOCK. Added new
+ defines to my_sys.h.
+
+Mon Aug 27 22:20:38 1990 Michael Widenius (monty at lynx)
+
+ * my_end() now can print output about executed program.
+ * Added parameter-defines for my_end in my_sys.h
+
+Sun Apr 1 23:29:47 1990 Monty (monty at monty)
+
+ * Changed mf_keydisk.c to have separate functions for read and write.
+ Read can now return pointer to intern key-buffer to skipp
+ unessessary memcpy-s.
+
+Fri Mar 23 23:03:39 1990 Monty (monty at monty)
+
+ * function test_if_hard_pathname() added in dirname.c
+ * my_getwd now only saves changed current dir if dir is a
+ hard pathname.
+ * changed my_path() to use test_if_hard_pathname()
+
+Thu Mar 1 14:47:59 1990 Monty (monty at monty)
+
+ * New function my_path().
+
+Sat Feb 24 02:54:35 1990 Monty (monty at monty)
+
+ * Added print of my_progname in my_mess.c
+
+Sun Feb 11 17:55:58 1990 David Axmark (davida at isil)
+
+ * Concatenated libarys my_func and my_sys because of to much
+ crosswise dependencies.
+ * Fixed varagrs code in mf_fixadr.c
+
+Mon Dec 4 17:36:16 1989 Monty (monty at monty)
+
+ * Changed safemalloc() to use my_message() if out of memory and
+ to check MY_WME if we want this error-messages.
+ * Changed my_setwd() to use dos_setdrive() insted of system().
+
+Wed Oct 25 02:56:07 1989 Monty (monty at monty)
+
+ * Changed my_mktmp1() to work like tempnam() with default dirname.
+ * Changed name of my_mktmp1.c to my_tempnam.c
+
+Thu Oct 19 16:39:27 1989 David Axmark (davida at isil)
+
+ * Removed libary mysysnc. Instead added a hook to my_error that
+ can call my_message if needed.
+
+Thu Oct 5 01:33:29 1989 David Axmark (davida at isil)
+
+ * Use MY_SEEK_{SET,CUR,END} as arguments to my_seek
+
+ * Added a a array of structs that holds properties of open files.
+ Removed include file extras.h
+
+Wed Jun 21 01:34:04 1989 Monty (monty at monty)
+
+ * Added two new malloc-functions: my_once_alloc() and
+ my_once_free(). These give easyer and quicker startup.
+
+Mon May 22 14:03:44 1989 Monty (monty at monty)
+
+ * Fixed my_getwd and my_setwd so they work.
+ * Added extern variabel curr_char[] with is set to current
+ directory after my_getwd() or my_setwd();
+
+Mon Jan 23 03:38:50 1989 Monty (monty at monty)
+
+ * Changed my_chsize to check if NO_CHSIZE is defined. If new file
+ should be shorter it fills unused part with null.
+ * Changed my_lock to not check for arg 0 (Functions should use
+ LK_TO_EOF to lock all file.
+
+Tue Dec 6 15:09:44 1988 Monty (monty at monty)
+
+ * Added DBUG_PRINT if error in my_seek.
+
+Mon Dec 5 15:58:48 1988 Monty (monty at monty)
+
+ * Added DBUG_PRINT if not all byte read/written in my_read(),
+ my_fread(), my_write() and my_fwrite();
+
+Sat Dec 3 01:48:03 1988 Monty (monty at monty)
+
+ * Fixed bug in Makefile; quick did't work.
+ * Changed safemalloc to use bmove, bfill and memcpy when handling
+ memoryblocks.
+
+Fri Dec 2 03:29:21 1988 Monty (monty at monty)
+
+ * Added more defines under MEMORY in my_func.h
+ * Added functions to llib-lmysys.
+ * Removed RCS/* files and installed ewerything as stable.
+ (Because errors in old RCS-files.
+
+Wed Nov 9 00:32:33 1988 Monty (monty at monty)
+
+ * Changed realloc for MSDOS; Previous version freed old block on
+ * error, new version (of compiler) dosn't.
+
+Wed Oct 26 21:07:27 1988 Monty (monty at monty)
+
+ * Fixed missing updateing of my_stream_opened;
diff --git a/mysys/Makefile.am b/mysys/Makefile.am
new file mode 100644
index 00000000000..658b68d6861
--- /dev/null
+++ b/mysys/Makefile.am
@@ -0,0 +1,93 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include -I..
+pkglib_LIBRARIES = libmysys.a
+LDADD = libmysys.a ../dbug/libdbug.a \
+ ../strings/libmystrings.a
+noinst_HEADERS = mysys_priv.h my_static.h
+libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
+ mf_path.c mf_loadpath.c\
+ my_open.c my_create.c my_seek.c my_read.c \
+ my_pread.c my_write.c \
+ mf_reccache.c mf_keycache.c mf_iocache.c mf_cache.c \
+ my_lock.c mf_brkhant.c my_alarm.c \
+ my_malloc.c my_realloc.c my_once.c mulalloc.c \
+ my_alloc.c safemalloc.c my_fopen.c my_fstream.c \
+ my_error.c errors.c my_div.c my_messnc.c \
+ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \
+ mf_pack.c mf_pack2.c mf_unixpath.c mf_stripp.c \
+ mf_casecnv.c mf_soundex.c mf_wcomp.c mf_wfile.c \
+ mf_qsort.c mf_qsort2.c mf_sort.c \
+ ptr_cmp.c mf_radix.c queues.c \
+ tree.c list.c hash.c array.c string.c typelib.c \
+ my_copy.c my_append.c my_lib.c \
+ my_delete.c my_rename.c my_redel.c my_tempnam.c \
+ my_chsize.c my_lread.c my_lwrite.c my_clock.c \
+ my_quick.c my_lockmem.c my_static.c \
+ getopt.c getopt1.c getvar.c my_mkdir.c \
+ default.c my_compress.c checksum.c raid.cc my_net.c \
+ my_vsnprintf.c charset.c
+EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \
+ thr_mutex.c thr_rwlock.c
+libmysys_a_LIBADD = @THREAD_LOBJECTS@
+# test_fn removed 980815 since it not upp to date test_dir
+noinst_PROGRAMS = testhash test_charset @THREAD_LPROGRAMS@
+# test_dir_DEPENDENCIES= $(LIBRARIES)
+testhash_DEPENDENCIES= $(LIBRARIES)
+test_charset_DEPENDENCIES= $(LIBRARIES)
+EXTRA_PROGRAMS =
+DEFS = -DDEFAULT_BASEDIR=\"$(prefix)\" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DDEFAULT_CHARSET_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+ @DEFS@
+
+getopt1.o: @THREAD_LOBJECTS@
+
+OMIT_DEPENDENCIES = pthread.h stdio.h __stdio.h stdlib.h __stdlib.h math.h\
+ __math.h time.h __time.h unistd.h __unistd.h types.h \
+ xtypes.h ac-types.h posix.h string.h __string.h \
+ errno.h socket.h inet.h dirent.h netdb.h \
+ cleanup.h cond.h debug_out.h fd.h kernel.h mutex.h \
+ prio_queue.h pthread_attr.h pthread_once.h queue.h\
+ sleep.h specific.h version.h pwd.h timers.h uio.h \
+ cdefs.h machdep.h signal.h __signal.h util.h
+
+# I hope this always does the right thing. Otherwise this is only test programs
+FLAGS=$(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+test_thr_alarm: thr_alarm.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/thr_alarm.c $(LDADD) $(LIBS)
+
+test_thr_lock: thr_lock.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/thr_lock.c $(LDADD) $(LIBS)
+
+test_dir: test_dir.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_dir.c $(LDADD) $(LIBS)
+
+test_charset: test_charset.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_charset.c $(LDADD) $(LIBS)
+
+test_vsnprintf: my_vsnprintf.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/my_vsnprintf.c $(LDADD) $(LIBS)
+
+test_hash: test_hash.c $(LIBRARIES)
+ $(LINK) $(FLAGS) -DMAIN $(srcdir)/test_dir.c $(LDADD) $(LIBS)
diff --git a/mysys/array.c b/mysys/array.c
new file mode 100644
index 00000000000..17e5ded322b
--- /dev/null
+++ b/mysys/array.c
@@ -0,0 +1,177 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Handling of arrays that can grow dynamicly. */
+
+#if defined(WIN32) || defined(__WIN__)
+#undef SAFEMALLOC /* Problems with threads */
+#endif
+
+#include "mysys_priv.h"
+#include "m_string.h"
+
+/*
+ Initiate array and alloc space for init_alloc elements. Array is usable
+ even if space allocation failed
+*/
+
+my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
+ uint init_alloc, uint alloc_increment)
+{
+ DBUG_ENTER("init_dynamic_array");
+ if (!alloc_increment)
+ {
+ alloc_increment=max((8192-MALLOC_OVERHEAD)/element_size,16);
+ if (init_alloc > 8 && alloc_increment > init_alloc * 2)
+ alloc_increment=init_alloc*2;
+ }
+
+ if (!init_alloc)
+ init_alloc=alloc_increment;
+ array->elements=0;
+ array->max_element=init_alloc;
+ array->alloc_increment=alloc_increment;
+ array->size_of_element=element_size;
+ if (!(array->buffer=(char*) my_malloc(element_size*init_alloc,MYF(MY_WME))))
+ {
+ array->max_element=0;
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+my_bool insert_dynamic(DYNAMIC_ARRAY *array, gptr element)
+{
+ gptr buffer;
+ if (array->elements == array->max_element)
+ { /* Call only when nessesary */
+ if (!(buffer=alloc_dynamic(array)))
+ return TRUE;
+ }
+ else
+ {
+ buffer=array->buffer+(array->elements * array->size_of_element);
+ array->elements++;
+ }
+ memcpy(buffer,element,(size_t) array->size_of_element);
+ return FALSE;
+}
+
+
+ /* Alloc room for one element */
+
+byte *alloc_dynamic(DYNAMIC_ARRAY *array)
+{
+ if (array->elements == array->max_element)
+ {
+ char *new_ptr;
+ if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
+ array->alloc_increment)*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ return 0;
+ array->buffer=new_ptr;
+ array->max_element+=array->alloc_increment;
+ }
+ return array->buffer+(array->elements++ * array->size_of_element);
+}
+
+
+ /* remove last element from array and return it */
+
+byte *pop_dynamic(DYNAMIC_ARRAY *array)
+{
+ if (array->elements)
+ return array->buffer+(--array->elements * array->size_of_element);
+ return 0;
+}
+
+
+my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+{
+ if (idx >= array->elements)
+ {
+ if (idx >= array->max_element)
+ {
+ uint size;
+ char *new_ptr;
+ size=(idx+array->alloc_increment)/array->alloc_increment;
+ size*= array->alloc_increment;
+ if (!(new_ptr=(char*) my_realloc(array->buffer,size*
+ array->size_of_element,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
+ return TRUE;
+ array->buffer=new_ptr;
+ array->max_element=size;
+ }
+ bzero((gptr) (array->buffer+array->elements*array->size_of_element),
+ (idx - array->elements)*array->size_of_element);
+ array->elements=idx+1;
+ }
+ memcpy(array->buffer+(idx * array->size_of_element),element,
+ (size_t) array->size_of_element);
+ return FALSE;
+}
+
+
+void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
+{
+ if (idx >= array->elements)
+ {
+ DBUG_PRINT("warning",("To big array idx: %d, array size is %d",
+ idx,array->elements));
+ bzero(element,array->size_of_element);
+ return;
+ }
+ memcpy(element,array->buffer+idx*array->size_of_element,
+ (size_t) array->size_of_element);
+}
+
+
+void delete_dynamic(DYNAMIC_ARRAY *array)
+{
+ if (array->buffer)
+ {
+ my_free(array->buffer,MYF(MY_WME));
+ array->buffer=0;
+ array->elements=array->max_element=0;
+ }
+}
+
+
+void delete_dynamic_element(DYNAMIC_ARRAY *array, uint idx)
+{
+ char *ptr=array->buffer+array->size_of_element*idx;
+ array->elements--;
+ memmove(ptr,ptr+array->size_of_element,
+ (array->elements-idx)*array->size_of_element);
+}
+
+
+void freeze_size(DYNAMIC_ARRAY *array)
+{
+ uint elements=max(array->elements,1);
+
+ if (array->buffer && array->max_element != elements)
+ {
+ array->buffer=(char*) my_realloc(array->buffer,
+ elements*array->size_of_element,
+ MYF(MY_WME));
+ array->max_element=elements;
+ }
+}
diff --git a/mysys/charset.c b/mysys/charset.c
new file mode 100644
index 00000000000..88b0972431e
--- /dev/null
+++ b/mysys/charset.c
@@ -0,0 +1,532 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <m_ctype.h>
+#include <m_string.h>
+#include <my_dir.h>
+
+const char *charsets_dir = NULL;
+static DYNAMIC_ARRAY cs_info_table;
+static TYPELIB available_charsets;
+static int charset_initialized=0;
+
+#define MAX_LINE 1024
+
+#define CTYPE_TABLE_SIZE 257
+#define TO_LOWER_TABLE_SIZE 256
+#define TO_UPPER_TABLE_SIZE 256
+#define SORT_ORDER_TABLE_SIZE 256
+
+struct simpleconfig_buf_st {
+ FILE *f;
+ char buf[MAX_LINE];
+ char *p;
+};
+
+/* Defined in strings/ctype.c */
+
+CHARSET_INFO *find_compiled_charset(uint cs_number);
+uint compiled_charset_number(const char *name);
+const char *compiled_charset_name(uint charset_number);
+
+
+static my_bool get_word(struct simpleconfig_buf_st *fb, char *buf)
+{
+ char *endptr=fb->p;
+
+ for (;;)
+ {
+ while (isspace(*endptr))
+ ++endptr;
+ if (*endptr && *endptr != '#') /* Not comment */
+ break; /* Found something */
+ if ((fgets(fb->buf, sizeof(fb->buf), fb->f)) == NULL)
+ return TRUE; /* end of file */
+ endptr = fb->buf;
+ }
+
+ while (!isspace(*endptr))
+ *buf++= *endptr++;
+ *buf=0;
+ fb->p = endptr;
+
+ return FALSE;
+}
+
+
+static char *get_charsets_dir(char *buf)
+{
+ const char *sharedir = SHAREDIR;
+ DBUG_ENTER("get_charsets_dir");
+
+ if (charsets_dir != NULL)
+ strnmov(buf, charsets_dir, FN_REFLEN);
+ else
+ {
+ if (test_if_hard_path(sharedir) ||
+ is_prefix(sharedir, DEFAULT_CHARSET_HOME))
+ strxmov(buf, sharedir, "/", CHARSET_DIR, NullS);
+ else
+ strxmov(buf, DEFAULT_CHARSET_HOME, "/", sharedir, "/", CHARSET_DIR,
+ NullS);
+ }
+ convert_dirname(buf);
+ DBUG_PRINT("info",("charsets dir='%s'", buf));
+ DBUG_RETURN(strend(buf));
+}
+
+
+static my_bool read_charset_index(TYPELIB *charsets, myf myflags)
+{
+ struct simpleconfig_buf_st fb;
+ char buf[MAX_LINE];
+ DYNAMIC_ARRAY cs;
+ my_string s;
+
+ strmov(get_charsets_dir(buf), "Index");
+
+ if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL)
+ return TRUE;
+ fb.buf[0] = '\0';
+ fb.p = fb.buf;
+
+ if (init_dynamic_array(&cs, sizeof(my_string), 32, 32))
+ return TRUE;
+
+ while (!get_word(&fb, buf))
+ {
+ uint length;
+ if (!(s= (char*) my_once_alloc(length=strlen(buf)+1, myflags)))
+ {
+ my_fclose(fb.f,myflags);
+ return TRUE;
+ }
+ memcpy(s,buf,length);
+ insert_dynamic(&cs, (gptr) &s);
+ }
+ my_fclose(fb.f,myflags);
+
+ /* I seriously doubt this is the best way to initialize this
+ * TYPELIB from the Index file. But it's the best way I could
+ * come up with right now. */
+
+ charsets->count = cs.elements;
+ charsets->name = "";
+ if (!(charsets->type_names =
+ (const char **) my_once_alloc((cs.elements + 1) * sizeof(const char *),
+ myflags)))
+ return TRUE;
+ /* unwarranted chumminess with dynamic_array implementation? */
+ memcpy((char*) charsets->type_names, cs.buffer,
+ cs.elements * sizeof(my_string *));
+ charsets->type_names[cs.elements] = NullS;
+ delete_dynamic(&cs);
+
+ return FALSE;
+}
+
+
+static my_bool init_available_charsets(myf myflags)
+{
+ my_bool error=0;
+ /*
+ We have to use charset_initialized to not lock on THR_LOCK_charset
+ inside get_internal_charset...
+ */
+ if (!charset_initialized)
+ {
+ /*
+ To make things thread safe we are not allowing other threads to interfere
+ while we may changing the cs_info_table
+ */
+ pthread_mutex_lock(&THR_LOCK_charset);
+ if (!cs_info_table.buffer) /* If not initialized */
+ {
+ init_dynamic_array(&cs_info_table, sizeof(CHARSET_INFO*), 16, 8);
+ error = read_charset_index(&available_charsets, myflags);
+ }
+ charset_initialized=1;
+ pthread_mutex_unlock(&THR_LOCK_charset);
+ }
+ return error || available_charsets.count == 0;
+}
+
+
+void free_charsets(void)
+{
+ delete_dynamic(&cs_info_table);
+}
+
+
+static my_bool fill_array(uchar *array, int sz, struct simpleconfig_buf_st *fb)
+{
+ char buf[MAX_LINE];
+ while (sz--)
+ {
+ if (get_word(fb, buf))
+ {
+ DBUG_PRINT("error",("get_word failed, expecting %d more words", sz + 1));
+ return 1;
+ }
+ *array++ = (uchar) strtol(buf, NULL, 16);
+ }
+ return 0;
+}
+
+
+static void get_charset_conf_name(uint cs_number, char *buf)
+{
+ strxmov(get_charsets_dir(buf),
+ get_type(&available_charsets, cs_number - 1), ".conf", NullS);
+}
+
+
+static my_bool read_charset_file(uint cs_number, CHARSET_INFO *set,
+ myf myflags)
+{
+ struct simpleconfig_buf_st fb;
+ char buf[FN_REFLEN];
+ my_bool result;
+ DBUG_ENTER("read_charset_file");
+ DBUG_PRINT("enter",("cs_number: %d", cs_number));
+
+ if (cs_number <= 0)
+ DBUG_RETURN(TRUE);
+
+ get_charset_conf_name(cs_number, buf);
+ DBUG_PRINT("info",("file name: %s", buf));
+
+ if ((fb.f = my_fopen(buf, O_RDONLY, myflags)) == NULL)
+ DBUG_RETURN(TRUE);
+
+ fb.buf[0] = '\0'; /* Init for get_word */
+ fb.p = fb.buf;
+
+ result=FALSE;
+ if (fill_array(set->ctype, CTYPE_TABLE_SIZE, &fb) ||
+ fill_array(set->to_lower, TO_LOWER_TABLE_SIZE, &fb) ||
+ fill_array(set->to_upper, TO_UPPER_TABLE_SIZE, &fb) ||
+ fill_array(set->sort_order, SORT_ORDER_TABLE_SIZE, &fb))
+ result=TRUE;
+
+ my_fclose(fb.f, MYF(0));
+ DBUG_RETURN(result);
+}
+
+
+uint get_charset_number(const char *charset_name)
+{
+ my_bool error;
+ error = init_available_charsets(MYF(0)); /* If it isn't initialized */
+ if (error)
+ return compiled_charset_number(charset_name);
+ else
+ return find_type((char*)charset_name, &available_charsets, 1);
+}
+
+const char *get_charset_name(uint charset_number)
+{
+ my_bool error;
+ error = init_available_charsets(MYF(0)); /* If it isn't initialized */
+ if (error)
+ return compiled_charset_name(charset_number);
+ else
+ return get_type(&available_charsets, charset_number - 1);
+}
+
+
+static CHARSET_INFO *find_charset(CHARSET_INFO **table, uint cs_number,
+ size_t tablesz)
+{
+ uint i;
+ for (i = 0; i < tablesz; ++i)
+ if (table[i]->number == cs_number)
+ return table[i];
+ return NULL;
+}
+
+static CHARSET_INFO *find_charset_by_name(CHARSET_INFO **table, const char *name,
+ size_t tablesz)
+{
+ uint i;
+ for (i = 0; i < tablesz; ++i)
+ if (!strcmp(table[i]->name,name))
+ return table[i];
+ return NULL;
+}
+
+static CHARSET_INFO *add_charset(uint cs_number, const char *cs_name)
+{
+ CHARSET_INFO tmp_cs,*cs;
+ uchar tmp_ctype[CTYPE_TABLE_SIZE];
+ uchar tmp_to_lower[TO_LOWER_TABLE_SIZE];
+ uchar tmp_to_upper[TO_UPPER_TABLE_SIZE];
+ uchar tmp_sort_order[SORT_ORDER_TABLE_SIZE];
+
+ /* Don't allocate memory if we are not sure we can find the char set */
+ cs= &tmp_cs;
+ bzero((char*) cs, sizeof(*cs));
+ cs->ctype=tmp_ctype;
+ cs->to_lower=tmp_to_lower;
+ cs->to_upper=tmp_to_upper;
+ cs->sort_order=tmp_sort_order;
+ if (read_charset_file(cs_number, cs, MYF(MY_WME)))
+ return NULL;
+
+ cs = (CHARSET_INFO*) my_once_alloc(sizeof(CHARSET_INFO),
+ MYF(MY_WME));
+ *cs=tmp_cs;
+ cs->name = (char *) my_once_alloc(strlen(cs_name) + 1, MYF(MY_WME));
+ cs->ctype = (uchar*) my_once_alloc(CTYPE_TABLE_SIZE, MYF(MY_WME));
+ cs->to_lower = (uchar*) my_once_alloc(TO_LOWER_TABLE_SIZE, MYF(MY_WME));
+ cs->to_upper = (uchar*) my_once_alloc(TO_UPPER_TABLE_SIZE, MYF(MY_WME));
+ cs->sort_order=(uchar*) my_once_alloc(SORT_ORDER_TABLE_SIZE, MYF(MY_WME));
+ cs->number = cs_number;
+ memcpy((char*) cs->name, (char*) cs_name, strlen(cs_name) + 1);
+ memcpy((char*) cs->ctype, (char*) tmp_ctype, sizeof(tmp_ctype));
+ memcpy((char*) cs->to_lower, (char*) tmp_to_lower, sizeof(tmp_to_lower));
+ memcpy((char*) cs->to_upper, (char*) tmp_to_upper, sizeof(tmp_to_upper));
+ memcpy((char*) cs->sort_order, (char*) tmp_sort_order,
+ sizeof(tmp_sort_order));
+ insert_dynamic(&cs_info_table, (gptr) &cs);
+ return cs;
+}
+
+static CHARSET_INFO *get_internal_charset(uint cs_number)
+{
+ CHARSET_INFO *cs;
+ /*
+ To make things thread safe we are not allowing other threads to interfere
+ while we may changing the cs_info_table
+ */
+ pthread_mutex_lock(&THR_LOCK_charset);
+ if (!(cs = find_charset((CHARSET_INFO**) cs_info_table.buffer, cs_number,
+ cs_info_table.elements)))
+ if (!(cs = find_compiled_charset(cs_number)))
+ cs=add_charset(cs_number, get_charset_name(cs_number));
+ pthread_mutex_unlock(&THR_LOCK_charset);
+ return cs;
+}
+
+
+static CHARSET_INFO *get_internal_charset_by_name(const char *name)
+{
+ CHARSET_INFO *cs;
+ /*
+ To make things thread safe we are not allowing other threads to interfere
+ while we may changing the cs_info_table
+ */
+ pthread_mutex_lock(&THR_LOCK_charset);
+ if (!(cs = find_charset_by_name((CHARSET_INFO**) cs_info_table.buffer, name,
+ cs_info_table.elements)))
+ if (!(cs = find_compiled_charset_by_name(name)))
+ cs=add_charset(get_charset_number(name), name);
+ pthread_mutex_unlock(&THR_LOCK_charset);
+ return cs;
+}
+
+
+CHARSET_INFO *get_charset(uint cs_number, myf flags)
+{
+ CHARSET_INFO *cs;
+ (void) init_available_charsets(MYF(0)); /* If it isn't initialized */
+ cs=get_internal_charset(cs_number);
+
+ if (!cs && flags & MY_WME)
+ {
+ char index_file[FN_REFLEN], cs_string[23];
+ strmov(get_charsets_dir(index_file), "Index");
+ cs_string[0]='#';
+ int10_to_str(cs_number, cs_string+1, 10);
+ my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_string, index_file);
+ }
+ return cs;
+}
+
+my_bool set_default_charset(uint cs, myf flags)
+{
+ CHARSET_INFO *new;
+ DBUG_ENTER("set_default_charset");
+ DBUG_PRINT("enter",("character set: %d",(int) cs));
+ new = get_charset(cs, flags);
+ if (!new)
+ {
+ DBUG_PRINT("error",("Couldn't set default character set"));
+ DBUG_RETURN(TRUE); /* error */
+ }
+ default_charset_info = new;
+ DBUG_RETURN(FALSE);
+}
+
+CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags)
+{
+ CHARSET_INFO *cs;
+ (void) init_available_charsets(MYF(0)); /* If it isn't initialized */
+ cs=get_internal_charset_by_name(cs_name);
+
+ if (!cs && (flags & MY_WME))
+ {
+ char index_file[FN_REFLEN];
+ strmov(get_charsets_dir(index_file), "Index");
+ my_error(EE_UNKNOWN_CHARSET, MYF(ME_BELL), cs_name, index_file);
+ }
+
+ return cs;
+}
+
+my_bool set_default_charset_by_name(const char *cs_name, myf flags)
+{
+ CHARSET_INFO *new;
+ DBUG_ENTER("set_default_charset_by_name");
+ DBUG_PRINT("enter",("character set: %s", cs_name));
+ new = get_charset_by_name(cs_name, flags);
+ if (!new)
+ {
+ DBUG_PRINT("error",("Couldn't set default character set"));
+ DBUG_RETURN(TRUE); /* error */
+ }
+
+ default_charset_info = new;
+ DBUG_RETURN(FALSE);
+}
+
+/* Only append name if it doesn't exist from before */
+
+static my_bool charset_in_string(const char *name, DYNAMIC_STRING *s)
+{
+ uint length=strlen(name);
+ const char *pos;
+ for (pos=s->str ; (pos=strstr(pos,name)) ; pos++)
+ {
+ if (! pos[length] || pos[length] == ' ')
+ return TRUE; /* Already existed */
+ }
+
+ return FALSE;
+}
+
+static void charset_append(DYNAMIC_STRING *s, const char *name)
+{
+ if (!charset_in_string(name, s)) {
+ dynstr_append(s, name);
+ dynstr_append(s, " ");
+ }
+}
+
+
+/* Returns a dynamically-allocated string listing the character sets
+ requested. The caller is responsible for freeing the memory. */
+
+char * list_charsets(myf want_flags)
+{
+ DYNAMIC_STRING s;
+ char *p;
+
+ init_dynamic_string(&s, NullS, 256, 1024);
+
+ if (want_flags & MY_COMPILED_SETS)
+ {
+ CHARSET_INFO *cs;
+ for (cs = compiled_charsets; cs->number > 0; cs++)
+ {
+ dynstr_append(&s, cs->name);
+ dynstr_append(&s, " ");
+ }
+ }
+
+ if (want_flags & MY_CONFIG_SETS)
+ {
+ uint i;
+ const char *cs_name;
+ char buf[FN_REFLEN];
+ MY_STAT stat;
+
+ for (i = 0; i < available_charsets.count; i++)
+ {
+ cs_name = get_type(&available_charsets, i);
+ if (charset_in_string(cs_name, &s))
+ continue;
+ get_charset_conf_name(i + 1, buf);
+ if (!my_stat(buf, &stat, MYF(0)))
+ continue; /* conf file doesn't exist */
+ dynstr_append(&s, cs_name);
+ dynstr_append(&s, " ");
+ }
+ }
+
+ if (want_flags & MY_INDEX_SETS)
+ {
+ uint i;
+ for (i = 0; i < available_charsets.count; i++)
+ charset_append(&s, get_type(&available_charsets, i));
+ }
+
+ if (want_flags & MY_LOADED_SETS)
+ {
+ uint i;
+ for (i = 0; i < cs_info_table.elements; i++)
+ charset_append(&s,
+ dynamic_element(&cs_info_table, i, CHARSET_INFO *)->name);
+ }
+ s.str[s.length - 1] = '\0'; /* chop trailing space */
+ p = my_strdup(s.str, MYF(MY_WME));
+ dynstr_free(&s);
+
+ return p;
+}
+
+/****************************************************************************
+* Code for debugging.
+****************************************************************************/
+
+
+static void _print_array(uint8 *data, uint size)
+{
+ uint i;
+ for (i = 0; i < size; ++i)
+ {
+ if (i == 0 || i % 16 == size % 16) printf(" ");
+ printf(" %02x", data[i]);
+ if ((i+1) % 16 == size % 16) printf("\n");
+ }
+}
+
+/* _print_csinfo is called from test_charset.c */
+void _print_csinfo(CHARSET_INFO *cs)
+{
+ printf("%s #%d\n", cs->name, cs->number);
+ printf("ctype:\n"); _print_array(cs->ctype, 257);
+ printf("to_lower:\n"); _print_array(cs->to_lower, 256);
+ printf("to_upper:\n"); _print_array(cs->to_upper, 256);
+ printf("sort_order:\n"); _print_array(cs->sort_order, 256);
+ printf("collate: %3s (%d, %p, %p, %p, %p, %p)\n",
+ cs->strxfrm_multiply ? "yes" : "no",
+ cs->strxfrm_multiply,
+ cs->strcoll,
+ cs->strxfrm,
+ cs->strnncoll,
+ cs->strnxfrm,
+ cs->like_range);
+ printf("multi-byte: %3s (%d, %p, %p, %p)\n",
+ cs->mbmaxlen ? "yes" : "no",
+ cs->mbmaxlen,
+ cs->ismbchar,
+ cs->ismbhead,
+ cs->mbcharlen);
+}
diff --git a/mysys/checksum.c b/mysys/checksum.c
new file mode 100644
index 00000000000..00861853945
--- /dev/null
+++ b/mysys/checksum.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Calculate a long checksum for a memoryblock. Used to verify pack_isam */
+
+#include <global.h>
+#include "my_sys.h"
+
+ulong checksum(const byte *mem, uint count)
+{
+ ulong crc;
+ for (crc=0; count-- ; mem++)
+ crc=((crc << 1) + *((uchar*) mem)) +
+ test(crc & ((ulong) 1L << (8*sizeof(ulong)-1)));
+ return crc;
+}
diff --git a/mysys/default.c b/mysys/default.c
new file mode 100644
index 00000000000..ae4ba5044be
--- /dev/null
+++ b/mysys/default.c
@@ -0,0 +1,362 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/****************************************************************************
+** Add all options from files named "group".cnf from the default_directories
+** before the command line arguments.
+** On Windows defaults will also search in the Windows directory for a file
+** called 'group'.ini
+** As long as the program uses the last argument for conflicting
+** options one only have to add a call to "load_defaults" to enable
+** use of default values.
+** pre- and end 'blank space' are removed from options and values. The
+** following escape sequences are recognized in values: \b \t \n \r \\
+**
+** The following arguments are handled automaticly; If used, they must be
+** first argument on the command line!
+** --no-defaults ; no options are read.
+** --print-defaults ; Print the modified command line and exit
+** --defaults-file=full-path-to-default-file ; Only this file will be read.
+****************************************************************************/
+
+#undef SAFEMALLOC /* safe_malloc is not yet initailized */
+
+#include "mysys_priv.h"
+#include "m_string.h"
+#include "m_ctype.h"
+
+/* Which directories are searched for options (and in which order) */
+
+const char *default_directories[]= {
+#ifdef __WIN__
+"C:/",
+#else
+"/etc/",
+#endif
+#ifdef DATADIR
+DATADIR,
+#endif
+#ifndef __WIN__
+"~/",
+#endif
+NullS,
+};
+
+#define default_ext ".cnf" /* extension for config file */
+#ifdef __WIN__
+#include <winbase.h>
+#define windows_ext ".ini"
+#endif
+
+static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+ const char *dir, const char *config_file,
+ const char *ext, TYPELIB *group);
+
+
+void load_defaults(const char *conf_file, const char **groups,
+ int *argc, char ***argv)
+{
+ DYNAMIC_ARRAY args;
+ const char **dirs, *extra_default_file;
+ TYPELIB group;
+ my_bool found_print_defaults=0;
+ MEM_ROOT alloc;
+ char *ptr,**res;
+ DBUG_ENTER("load_defaults");
+
+ init_alloc_root(&alloc,128);
+ if (*argc >= 2 && !strcmp(argv[0][1],"--no-defaults"))
+ {
+ /* remove the --no-defaults argument and return only the other arguments */
+ uint i;
+ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
+ (*argc + 1)*sizeof(char*))))
+ goto err;
+ res= (char**) (ptr+sizeof(alloc));
+ res[0]= **argv; /* Copy program name */
+ for (i=2 ; i < (uint) *argc ; i++)
+ res[i-1]=argv[0][i];
+ (*argc)--;
+ *argv=res;
+ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+ DBUG_VOID_RETURN;
+ }
+
+ /* Check if we want to force the use a specific default file */
+ extra_default_file=0;
+ if (*argc >= 2 && is_prefix(argv[0][1],"--defaults-file="))
+ extra_default_file=strchr(argv[0][1],'=')+1;
+
+ group.count=0;
+ group.name= "defaults";
+ group.type_names= groups;
+ for (; *groups ; groups++)
+ group.count++;
+
+ if (init_dynamic_array(&args, sizeof(char*),*argc, 32))
+ goto err;
+ if (extra_default_file)
+ {
+ if (search_default_file(&args, &alloc, "", extra_default_file, "",
+ &group))
+ goto err;
+ }
+ else if (dirname_length(conf_file))
+ {
+ if (search_default_file(&args, &alloc, NullS, conf_file, default_ext,
+ &group))
+ goto err;
+ }
+ else
+ {
+#ifdef __WIN__
+ char system_dir[FN_REFLEN];
+ GetWindowsDirectory(system_dir,sizeof(system_dir));
+ if (search_default_file(&args, &alloc, system_dir, conf_file, windows_ext,
+ &group))
+ goto err;
+#endif
+ for (dirs=default_directories ; *dirs; dirs++)
+ {
+ if (search_default_file(&args, &alloc, *dirs, conf_file, default_ext,
+ &group))
+ goto err;
+ }
+ }
+ if (!(ptr=(char*) alloc_root(&alloc,sizeof(alloc)+
+ (args.elements + *argc +1) *sizeof(char*))))
+ goto err;
+ res= (char**) (ptr+sizeof(alloc));
+
+ /* copy name + found arguments + command line arguments to new array */
+ res[0]=argv[0][0];
+ memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
+ if (extra_default_file)
+ {
+ --*argc; /* Skipp --defaults-file */
+ ++*argv;
+ }
+
+ /* Check if we wan't to see the new argument list */
+ if (*argc >= 2 && !strcmp(argv[0][1],"--print-defaults"))
+ {
+ found_print_defaults=1;
+ --*argc; ++*argv; /* skipp argument */
+ }
+
+ memcpy((gptr) (res+1+args.elements), (char*) ((*argv)+1),
+ (*argc-1)*sizeof(char*));
+ res[args.elements+ *argc]=0; /* last null */
+
+ (*argc)+=args.elements;
+ *argv= (char**) res;
+ *(MEM_ROOT*) ptr= alloc; /* Save alloc root for free */
+ delete_dynamic(&args);
+ if (found_print_defaults)
+ {
+ int i;
+ printf("%s would have been started with the following arguments:\n",
+ **argv);
+ for (i=1 ; i < *argc ; i++)
+ printf("%s ", (*argv)[i]);
+ puts("");
+ exit(1);
+ }
+ DBUG_VOID_RETURN;
+
+ err:
+ fprintf(stderr,"Program aborted\n");
+ exit(1);
+}
+
+
+void free_defaults(char **argv)
+{
+ MEM_ROOT ptr;
+ memcpy_fixed((char*) &ptr,(char *) argv - sizeof(ptr), sizeof(ptr));
+ free_root(&ptr);
+}
+
+
+static my_bool search_default_file(DYNAMIC_ARRAY *args, MEM_ROOT *alloc,
+ const char *dir, const char *config_file,
+ const char *ext, TYPELIB *group)
+{
+ char name[FN_REFLEN+10],buff[257],*ptr,*end,*value,*tmp;
+ FILE *fp;
+ uint line=0;
+ my_bool read_values=0,found_group=0;
+
+ if ((dir ? strlen(dir) : 0 )+strlen(config_file) >= FN_REFLEN-3)
+ return 0; /* Ignore wrong paths */
+ if (dir)
+ {
+ strmov(name,dir);
+ convert_dirname(name);
+ if (dir[0] == FN_HOMELIB) /* Add . to filenames in home */
+ strcat(name,".");
+ strxmov(strend(name),config_file,ext,NullS);
+ }
+ else
+ {
+ strmov(name,config_file);
+ }
+ if (!(fp = my_fopen(fn_format(name,name,"","",4),O_RDONLY,MYF(0))))
+ return 0; /* Ignore wrong files */
+
+ while (fgets(buff,sizeof(buff)-1,fp))
+ {
+ line++;
+ /* Ignore comment and empty lines */
+ for (ptr=buff ; isspace(*ptr) ; ptr++ ) ;
+ if (*ptr == '#' || *ptr == ';' || !*ptr)
+ continue;
+ if (*ptr == '[') /* Group name */
+ {
+ found_group=1;
+ if (!(end=(char *) strchr(++ptr,']')))
+ {
+ fprintf(stderr,
+ "error: Wrong group definition in config file: %s at line %d\n",
+ name,line);
+ goto err;
+ }
+ for ( ; isspace(end[-1]) ; end--) ; /* Remove end space */
+ end[0]=0;
+ read_values=find_type(ptr,group,3) > 0;
+ continue;
+ }
+ if (!found_group)
+ {
+ fprintf(stderr,
+ "error: Found option without preceding group in config file: %s at line: %d\n",
+ name,line);
+ goto err;
+ }
+ if (!read_values)
+ continue;
+ if (!(end=value=strchr(ptr,'=')))
+ end=strend(ptr); /* Option without argument */
+ for ( ; isspace(end[-1]) ; end--) ;
+ if (!value)
+ {
+ if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3)))
+ goto err;
+ strmake(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+ if (insert_dynamic(args,(gptr) &tmp))
+ goto err;
+ }
+ else
+ {
+ /* Remove pre- and end space */
+ char *value_end;
+ for (value++ ; isspace(*value); value++) ;
+ value_end=strend(value);
+ for ( ; isspace(value_end[-1]) ; value_end--) ;
+ if (value_end < value) /* Empty string */
+ value_end=value;
+ if (!(tmp=alloc_root(alloc,(uint) (end-ptr)+3 +
+ (uint) (value_end-value)+1)))
+ goto err;
+ if (insert_dynamic(args,(gptr) &tmp))
+ goto err;
+ ptr=strnmov(strmov(tmp,"--"),ptr,(uint) (end-ptr));
+ *ptr++= '=';
+ for ( ; value != value_end; value++)
+ {
+ if (*value == '\\' && value != value_end-1)
+ {
+ switch(*++value) {
+ case 'n':
+ *ptr++='\n';
+ break;
+ case 't':
+ *ptr++= '\t';
+ break;
+ case 'r':
+ *ptr++ = '\r';
+ break;
+ case 'b':
+ *ptr++ = '\b';
+ break;
+ case 's':
+ *ptr++= ' '; /* space */
+ break;
+ case '\\':
+ *ptr++= '\\';
+ break;
+ default: /* Unknown; Keep '\' */
+ *ptr++= '\\';
+ *ptr++= *value;
+ break;
+ }
+ }
+ else
+ *ptr++= *value;
+ }
+ *ptr=0;
+ }
+ }
+ my_fclose(fp,MYF(0));
+ return(0);
+
+ err:
+ my_fclose(fp,MYF(0));
+ return 1;
+}
+
+
+void print_defaults(const char *conf_file, const char **groups)
+{
+#ifdef __WIN__
+ bool have_ext=fn_ext(conf_file)[0] != 0;
+#endif
+ char name[FN_REFLEN];
+ const char **dirs;
+ puts("\nDefault options are read from the following files in the given order:");
+
+ if (dirname_length(conf_file))
+ fputs(conf_file,stdout);
+ else
+ {
+#ifdef __WIN__
+ GetWindowsDirectory(name,sizeof(name));
+ printf("%s\\%s%s ",name,conf_file,have_ext ? "" : windows_ext);
+#endif
+ for (dirs=default_directories ; *dirs; dirs++)
+ {
+ strmov(name,*dirs);
+ convert_dirname(name);
+ if (name[0] == FN_HOMELIB) /* Add . to filenames in home */
+ strcat(name,".");
+ strxmov(strend(name),conf_file,default_ext," ",NullS);
+ fputs(name,stdout);
+ }
+ puts("");
+ }
+ fputs("The following groups are read:",stdout);
+ for ( ; *groups ; groups++)
+ {
+ fputc(' ',stdout);
+ fputs(*groups,stdout);
+ }
+ puts("\nThe following options may be given as the first argument:\n\
+--print-defaults Print the program argument list and exit\n\
+--no-defaults Don't read default options from any options file\n\
+--defaults-file=# Only read default options from the given file #");
+}
+
diff --git a/mysys/errors.c b/mysys/errors.c
new file mode 100644
index 00000000000..03b0b9d7f46
--- /dev/null
+++ b/mysys/errors.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+
+#ifndef SHARED_LIBRARY
+
+const char * NEAR globerrs[GLOBERRS]=
+{
+ "File '%s' not found (Errcode: %d)",
+ "Can't create/write to file '%s' (Errcode: %d)",
+ "Error reading file '%s' (Errcode: %d)",
+ "Error writing file '%s' (Errcode: %d)",
+ "Error on close of '%s' (Errcode: %d)",
+ "Out of memory (Needed %u bytes)",
+ "Error on delete of '%s' (Errcode: %d)",
+ "Error on rename of '%s' to '%s' (Errcode: %d)",
+ "",
+ "Unexpected eof found when reading file '%s' (Errcode: %d)",
+ "Can't lock file (Errcode: %d)",
+ "Can't unlock file (Errcode: %d)",
+ "Can't read dir of '%s' (Errcode: %d)",
+ "Can't get stat of '%s' (Errcode: %d)",
+ "Can't change size of file (Errcode: %d)",
+ "Can't open stream from handle (Errcode: %d)",
+ "Can't get working dirctory (Errcode: %d)",
+ "Can't change dir to '%s' (Errcode: %d)",
+ "Warning: '%s' had %d links",
+ "%d files and %d streams is left open\n",
+ "Disk is full writing '%s'. Waiting for someone to free space...",
+ "Can't create directory '%s' (Errcode: %d)",
+ "Character set '%s' is not a compiled character set and is not specified in the '%s' file"
+};
+
+void init_glob_errs(void)
+{
+ errmsg[GLOB] = & globerrs[0];
+} /* init_glob_errs */
+
+#else
+
+void init_glob_errs()
+{
+ errmsg[GLOB] = & globerrs[0];
+
+ EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)";
+ EE(EE_CANTCREATEFILE) = "Can't create/write to file '%s' (Errcode: %d)";
+ EE(EE_READ) = "Error reading file '%s' (Errcode: %d)";
+ EE(EE_WRITE) = "Error writing file '%s' (Errcode: %d)";
+ EE(EE_BADCLOSE) = "Error on close of '%'s (Errcode: %d)";
+ EE(EE_OUTOFMEMORY) = "Out of memory (Needed %u bytes)";
+ EE(EE_DELETE) = "Error on delete of '%s' (Errcode: %d)";
+ EE(EE_LINK) = "Error on rename of '%s' to '%s' (Errcode: %d)";
+ EE(EE_EOFERR) = "Unexpected eof found when reading file '%s' (Errcode: %d)";
+ EE(EE_CANTLOCK) = "Can't lock file (Errcode: %d)";
+ EE(EE_CANTUNLOCK) = "Can't unlock file (Errcode: %d)";
+ EE(EE_DIR) = "Can't read dir of '%s' (Errcode: %d)";
+ EE(EE_STAT) = "Can't get stat of '%s' (Errcode: %d)";
+ EE(EE_CANT_CHSIZE) = "Can't change size of file (Errcode: %d)";
+ EE(EE_CANT_OPEN_STREAM)= "Can't open stream from handle (Errcode: %d)";
+ EE(EE_GETWD) = "Can't get working dirctory (Errcode: %d)";
+ EE(EE_SETWD) = "Can't change dir to '%s' (Errcode: %d)";
+ EE(EE_LINK_WARNING) = "Warning: '%s' had %d links";
+ EE(EE_OPEN_WARNING) = "%d files and %d streams is left open\n";
+ EE(EE_DISK_FULL) = "Disk is full writing '%s'. Waiting for someone to free space...";
+ EE(EE_CANT_MKDIR) ="Can't create directory '%s' (Errcode: %d)";
+ EE(EE_UNKNOWN_CHARSET)= "Character set is not a compiled character set and is not specified in the %s file";
+}
+#endif
diff --git a/mysys/getopt.c b/mysys/getopt.c
new file mode 100644
index 00000000000..88fdbff7811
--- /dev/null
+++ b/mysys/getopt.c
@@ -0,0 +1,744 @@
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94
+ Free Software Foundation, Inc.
+
+Changes by monty:
+- Added include of string.h when nessessary.
+- Removed two warnings from gcc.
+
+This file is part of the GNU C Library. Its master source is NOT part of
+the C library, however. The master source lives in /gd/gnu/lib.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+#define _NO_PROTO
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS)
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <global.h> /* Changes for mysys */
+#include <m_string.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+#include <stdlib.h>
+#endif /* GNU C library. */
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *optarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+#include <string.h>
+#define my_index strchr
+#else
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+char *getenv (const char *);
+
+static char *
+my_index (const char *str, int chr)
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return (char *) str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+#if !defined (__STDC__) || !__STDC__
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+#endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (char **argv)
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (optind - last_nonopt);
+ last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const char *
+_getopt_initialize (const char *optstring)
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = optind = 1;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `optind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns `EOF'.
+ Then `optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `optarg', otherwise `optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only)
+{
+ optarg = NULL;
+
+ if (optind == 0)
+ optstring = _getopt_initialize (optstring);
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != optind)
+ first_nonopt = optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (optind < argc
+ && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ optind++;
+ last_nonopt = optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (optind != argc && !strcmp (argv[optind], "--"))
+ {
+ optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = optind;
+ last_nonopt = argc;
+
+ optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ optind = first_nonopt;
+ return EOF;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ {
+ if (ordering == REQUIRE_ORDER)
+ return EOF;
+ optarg = argv[optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[optind] + 1
+ + (longopts != NULL && argv[optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[optind][1] == '-'
+ || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound=0; /* Keep gcc happy */
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((size_t) (nameend - nextchar) == (size_t) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' is ambiguous\n",
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ "%s: option `--%s' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ "%s: option `%c%s' doesn't allow an argument\n",
+ argv[0], argv[optind - 1][0], pfound->name);
+ }
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr, "%s: option `%s' requires an argument\n",
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ if (opterr)
+ {
+ if (argv[optind][1] == '-')
+ /* --option */
+ fprintf (stderr, "%s: unrecognized option `--%s'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, "%s: unrecognized option `%c%s'\n",
+ argv[0], argv[optind][0], nextchar);
+ }
+ nextchar = (char *) "";
+ optind++;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ char *temp = my_index (optstring, c);
+
+ /* Increment `optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
+ else
+ fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c);
+ }
+ optopt = c;
+ return '?';
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ optind++;
+ }
+ else
+ optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, "%s: option requires an argument -- %c\n",
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+getopt (int argc, char *const *argv, const char *optstring)
+{
+ return _getopt_internal (argc, argv, optstring,
+ (const struct option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+
+ c = getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/mysys/getopt1.c b/mysys/getopt1.c
new file mode 100644
index 00000000000..6068a036e7b
--- /dev/null
+++ b/mysys/getopt1.c
@@ -0,0 +1,170 @@
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
+ Free Software Foundation, Inc.
+
+This file is part of the GNU C Library. Its master source is NOT part of
+the C library, however. The master source lives in /gd/gnu/lib.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <global.h>
+#include "getopt.h"
+
+#if (!defined (__STDC__) || !__STDC__) && !defined(MSDOS)
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+
+#ifndef __WIN__
+#include <stdlib.h>
+#endif /* __WIN__ */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index)
+{
+ return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* _LIBC or not __GNU_LIBRARY__. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = optind ? optind : 1;
+ int option_index = 0;
+ static struct option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (optarg)
+ printf (" with arg %s", optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf ("%s ", argv[optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/mysys/getvar.c b/mysys/getvar.c
new file mode 100644
index 00000000000..1d452002490
--- /dev/null
+++ b/mysys/getvar.c
@@ -0,0 +1,105 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Allow use of the -O variable= option to set long variables */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <m_ctype.h>
+
+ /* set all changeable variables */
+
+void set_all_changeable_vars(CHANGEABLE_VAR *vars)
+{
+ for ( ; vars->name ; vars++)
+ *vars->varptr= vars->def_value;
+}
+
+
+my_bool set_changeable_varval(const char* var, ulong val,
+ CHANGEABLE_VAR *vars)
+{
+ char buffer[256];
+ sprintf( buffer, "%s=%lu", var, (unsigned long) val );
+ return set_changeable_var( buffer, vars );
+}
+
+
+my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
+{
+ char endchar;
+ my_string end;
+ DBUG_ENTER("set_changeable_var");
+ DBUG_PRINT("enter",("%s",str));
+
+ if (str)
+ {
+ if (!(end=strchr(str,'=')))
+ fprintf(stderr,"Can't find '=' in expression '%s' to option -O\n",str);
+ else
+ {
+ uint length=(uint) (end-str),found_count=0;
+ CHANGEABLE_VAR *var,*found;
+ const char *name;
+ long num;
+
+ for (var=vars,found=0 ; (name=var->name) ; var++)
+ {
+ if (!my_casecmp(name,str,length))
+ {
+ found=var; found_count++;
+ if (!name[length])
+ {
+ found_count=1;
+ break;
+ }
+ }
+ }
+ if (found_count == 0)
+ {
+ fprintf(stderr,"No variable match for: -O '%s'\n",str);
+ DBUG_RETURN(1);
+ }
+ if (found_count > 1)
+ {
+ fprintf(stderr,"Variable prefix '%*s' is not unique\n",length,str);
+ DBUG_RETURN(1);
+ }
+
+ num=(long) atol(end+1); endchar=strend(end+1)[-1];
+ if (endchar == 'k' || endchar == 'K')
+ num*=1024;
+ else if (endchar == 'm' || endchar == 'M')
+ num*=1024L*1024L;
+ else if (!isdigit(endchar))
+ {
+ fprintf(stderr,"Unknown prefix used for variable value '%s'\n",str);
+ DBUG_RETURN(1);
+ }
+ if (num < (long) found->min_value)
+ num=(long) found->min_value;
+ else if ((unsigned long) num >
+ (unsigned long) found->max_value)
+ num=(long) found->max_value;
+ *found->varptr=(long) ((ulong) (num-found->sub_size) /
+ (ulong) found->block_size);
+ (*found->varptr)*= (ulong) found->block_size;
+ DBUG_RETURN(0);
+ }
+ }
+ DBUG_RETURN(1);
+}
diff --git a/mysys/hash.c b/mysys/hash.c
new file mode 100644
index 00000000000..a6181443a42
--- /dev/null
+++ b/mysys/hash.c
@@ -0,0 +1,586 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* The hash functions used for saveing keys */
+/* One of key_length or key_length_offset must be given */
+/* Key length of 0 isn't allowed */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#include "hash.h"
+
+#define NO_RECORD ((uint) -1)
+#define LOWFIND 1
+#define LOWUSED 2
+#define HIGHFIND 4
+#define HIGHUSED 8
+
+static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
+static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
+static uint calc_hashnr(const byte *key,uint length);
+static uint calc_hashnr_caseup(const byte *key,uint length);
+static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length);
+
+
+my_bool hash_init(HASH *hash,uint size,uint key_offset,uint key_length,
+ hash_get_key get_key,
+ void (*free_element)(void*),uint flags)
+{
+ DBUG_ENTER("hash_init");
+ DBUG_PRINT("enter",("hash: %lx size: %d",hash,size));
+
+ hash->records=0;
+ if (init_dynamic_array(&hash->array,sizeof(HASH_LINK),size,0))
+ {
+ hash->free=0; /* Allow call to hash_free */
+ DBUG_RETURN(TRUE);
+ }
+ hash->key_offset=key_offset;
+ hash->key_length=key_length;
+ hash->blength=1;
+ hash->current_record= NO_RECORD; /* For the future */
+ hash->get_key=get_key;
+ hash->free=free_element;
+ hash->flags=flags;
+ if (flags & HASH_CASE_INSENSITIVE)
+ hash->calc_hashnr=calc_hashnr_caseup;
+ else
+ hash->calc_hashnr=calc_hashnr;
+ DBUG_RETURN(0);
+}
+
+
+void hash_free(HASH *hash)
+{
+ DBUG_ENTER("hash_free");
+ if (hash->free)
+ {
+ uint i,records;
+ HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
+ for (i=0,records=hash->records ; i < records ; i++)
+ (*hash->free)(data[i].data);
+ hash->free=0;
+ }
+ delete_dynamic(&hash->array);
+ hash->records=0;
+ DBUG_VOID_RETURN;
+}
+
+ /* some helper functions */
+
+static inline byte*
+hash_key(HASH *hash,const byte *record,uint *length,my_bool first)
+{
+ if (hash->get_key)
+ return (*hash->get_key)(record,length,first);
+ *length=hash->key_length;
+ return (byte*) record+hash->key_offset;
+}
+
+ /* Calculate pos according to keys */
+
+static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
+{
+ if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
+ return (hashnr & ((buffmax >> 1) -1));
+}
+
+static uint hash_rec_mask(HASH *hash,HASH_LINK *pos,uint buffmax,
+ uint maxlength)
+{
+ uint length;
+ byte *key=hash_key(hash,pos->data,&length,0);
+ return hash_mask((*hash->calc_hashnr)(key,length),buffmax,maxlength);
+}
+
+ /* Calc hashvalue for a key */
+
+static uint calc_hashnr(const byte *key,uint length)
+{
+ register uint nr=1, nr2=4;
+ while (length--)
+ {
+ nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);
+ nr2+=3;
+ }
+ return((uint) nr);
+}
+
+ /* Calc hashvalue for a key, case indepenently */
+
+static uint calc_hashnr_caseup(const byte *key,uint length)
+{
+ register uint nr=1, nr2=4;
+ while (length--)
+ {
+ nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);
+ nr2+=3;
+ }
+ return((uint) nr);
+}
+
+
+static inline uint rec_hashnr(HASH *hash,const byte *record)
+{
+ uint length;
+ byte *key=hash_key(hash,record,&length,0);
+ return (*hash->calc_hashnr)(key,length);
+}
+
+
+ /* Search after a record based on a key */
+ /* Sets info->current_ptr to found record */
+
+gptr hash_search(HASH *hash,const byte *key,uint length)
+{
+ HASH_LINK *pos;
+ uint flag,idx;
+ DBUG_ENTER("hash_search");
+
+ flag=1;
+ if (hash->records)
+ {
+ idx=hash_mask((*hash->calc_hashnr)(key,length ? length :
+ hash->key_length),
+ hash->blength,hash->records);
+ do
+ {
+ pos= dynamic_element(&hash->array,idx,HASH_LINK*);
+ if (!hashcmp(hash,pos,key,length))
+ {
+ DBUG_PRINT("exit",("found key at %d",idx));
+ hash->current_record= idx;
+ DBUG_RETURN (pos->data);
+ }
+ if (flag)
+ {
+ flag=0; /* Reset flag */
+ if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
+ break; /* Wrong link */
+ }
+ }
+ while ((idx=pos->next) != NO_RECORD);
+ }
+ hash->current_record= NO_RECORD;
+ DBUG_RETURN(0);
+}
+
+ /* Get next record with identical key */
+ /* Can only be called if previous calls was hash_search */
+
+gptr hash_next(HASH *hash,const byte *key,uint length)
+{
+ HASH_LINK *pos;
+ uint idx;
+
+ if (hash->current_record != NO_RECORD)
+ {
+ HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
+ for (idx=data[hash->current_record].next; idx != NO_RECORD ; idx=pos->next)
+ {
+ pos=data+idx;
+ if (!hashcmp(hash,pos,key,length))
+ {
+ hash->current_record= idx;
+ return pos->data;
+ }
+ }
+ hash->current_record=NO_RECORD;
+ }
+ return 0;
+}
+
+
+ /* Change link from pos to new_link */
+
+static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
+{
+ HASH_LINK *old_link;
+ do
+ {
+ old_link=array+next_link;
+ }
+ while ((next_link=old_link->next) != find);
+ old_link->next= newlink;
+ return;
+}
+
+ /* Compare a key in a record to a whole key. Return 0 if identical */
+
+static int hashcmp(HASH *hash,HASH_LINK *pos,const byte *key,uint length)
+{
+ uint rec_keylength;
+ byte *rec_key=hash_key(hash,pos->data,&rec_keylength,1);
+ return (length && length != rec_keylength) ||
+ (hash->flags & HASH_CASE_INSENSITIVE ?
+ my_casecmp(rec_key,key,rec_keylength) :
+ memcmp(rec_key,key,rec_keylength));
+}
+
+
+ /* Write a hash-key to the hash-index */
+
+my_bool hash_insert(HASH *info,const byte *record)
+{
+ int flag;
+ uint halfbuff,hash_nr,first_index,idx;
+ byte *ptr_to_rec,*ptr_to_rec2;
+ HASH_LINK *data,*empty,*gpos,*gpos2,*pos;
+
+ LINT_INIT(gpos); LINT_INIT(gpos2);
+ LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
+
+ flag=0;
+ if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
+ return(TRUE); /* No more memory */
+
+ info->current_record= NO_RECORD;
+ data=dynamic_element(&info->array,0,HASH_LINK*);
+ halfbuff= info->blength >> 1;
+
+ idx=first_index=info->records-halfbuff;
+ if (idx != info->records) /* If some records */
+ {
+ do
+ {
+ pos=data+idx;
+ hash_nr=rec_hashnr(info,pos->data);
+ if (flag == 0) /* First loop; Check if ok */
+ if (hash_mask(hash_nr,info->blength,info->records) != first_index)
+ break;
+ if (!(hash_nr & halfbuff))
+ { /* Key will not move */
+ if (!(flag & LOWFIND))
+ {
+ if (flag & HIGHFIND)
+ {
+ flag=LOWFIND | HIGHFIND;
+ /* key shall be moved to the current empty position */
+ gpos=empty;
+ ptr_to_rec=pos->data;
+ empty=pos; /* This place is now free */
+ }
+ else
+ {
+ flag=LOWFIND | LOWUSED; /* key isn't changed */
+ gpos=pos;
+ ptr_to_rec=pos->data;
+ }
+ }
+ else
+ {
+ if (!(flag & LOWUSED))
+ {
+ /* Change link of previous LOW-key */
+ gpos->data=ptr_to_rec;
+ gpos->next=(uint) (pos-data);
+ flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
+ }
+ gpos=pos;
+ ptr_to_rec=pos->data;
+ }
+ }
+ else
+ { /* key will be moved */
+ if (!(flag & HIGHFIND))
+ {
+ flag= (flag & LOWFIND) | HIGHFIND;
+ /* key shall be moved to the last (empty) position */
+ gpos2 = empty; empty=pos;
+ ptr_to_rec2=pos->data;
+ }
+ else
+ {
+ if (!(flag & HIGHUSED))
+ {
+ /* Change link of previous hash-key and save */
+ gpos2->data=ptr_to_rec2;
+ gpos2->next=(uint) (pos-data);
+ flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
+ }
+ gpos2=pos;
+ ptr_to_rec2=pos->data;
+ }
+ }
+ }
+ while ((idx=pos->next) != NO_RECORD);
+
+ if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
+ {
+ gpos->data=ptr_to_rec;
+ gpos->next=NO_RECORD;
+ }
+ if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
+ {
+ gpos2->data=ptr_to_rec2;
+ gpos2->next=NO_RECORD;
+ }
+ }
+ /* Check if we are at the empty position */
+
+ idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
+ pos=data+idx;
+ if (pos == empty)
+ {
+ pos->data=(byte*) record;
+ pos->next=NO_RECORD;
+ }
+ else
+ {
+ /* Check if more records in same hash-nr family */
+ empty[0]=pos[0];
+ gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
+ if (pos == gpos)
+ {
+ pos->data=(byte*) record;
+ pos->next=(uint) (empty - data);
+ }
+ else
+ {
+ pos->data=(byte*) record;
+ pos->next=NO_RECORD;
+ movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
+ }
+ }
+ if (++info->records == info->blength)
+ info->blength+= info->blength;
+ return(0);
+}
+
+
+/******************************************************************************
+** Remove one record from hash-table. The record with the same record
+** ptr is removed.
+** if there is a free-function it's called for record if found
+******************************************************************************/
+
+my_bool hash_delete(HASH *hash,byte *record)
+{
+ uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
+ HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
+ DBUG_ENTER("hash_delete");
+
+ blength=hash->blength;
+ data=dynamic_element(&hash->array,0,HASH_LINK*);
+
+ /* Search after record with key */
+ pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
+ gpos = 0;
+
+ while (pos->data != record)
+ {
+ gpos=pos;
+ if (pos->next == NO_RECORD)
+ DBUG_RETURN(1); /* Key not found */
+ pos=data+pos->next;
+ }
+
+ if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
+ hash->current_record= NO_RECORD;
+ lastpos=data+hash->records;
+
+ /* Remove link to record */
+ empty=pos; empty_index=(uint) (empty-data);
+ if (gpos)
+ gpos->next=pos->next; /* unlink current ptr */
+ else if (pos->next != NO_RECORD)
+ {
+ empty=data+(empty_index=pos->next);
+ pos->data=empty->data;
+ pos->next=empty->next;
+ }
+
+ if (empty == lastpos) /* last key at wrong pos or no next link */
+ goto exit;
+
+ /* Move the last key (lastpos) */
+ lastpos_hashnr=rec_hashnr(hash,lastpos->data);
+ /* pos is where lastpos should be */
+ pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
+ if (pos == empty) /* Move to empty position. */
+ {
+ empty[0]=lastpos[0];
+ goto exit;
+ }
+ pos_hashnr=rec_hashnr(hash,pos->data);
+ /* pos3 is where the pos should be */
+ pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
+ if (pos != pos3)
+ { /* pos is on wrong posit */
+ empty[0]=pos[0]; /* Save it here */
+ pos[0]=lastpos[0]; /* This should be here */
+ movelink(data,(uint) (pos-data),(uint) (pos3-data),empty_index);
+ goto exit;
+ }
+ pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
+ if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
+ { /* Identical key-positions */
+ if (pos2 != hash->records)
+ {
+ empty[0]=lastpos[0];
+ movelink(data,(uint) (lastpos-data),(uint) (pos-data),empty_index);
+ goto exit;
+ }
+ idx= (uint) (pos-data); /* Link pos->next after lastpos */
+ }
+ else idx= NO_RECORD; /* Different positions merge */
+
+ empty[0]=lastpos[0];
+ movelink(data,idx,empty_index,pos->next);
+ pos->next=empty_index;
+
+exit:
+ VOID(pop_dynamic(&hash->array));
+ if (hash->free)
+ (*hash->free)((byte*) record);
+ DBUG_RETURN(0);
+}
+
+ /*
+ Update keys when record has changed.
+ This is much more efficent than using a delete & insert.
+ */
+
+my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
+{
+ uint idx,new_index,new_pos_index,blength,records,empty;
+ HASH_LINK org_link,*data,*previous,*pos;
+ DBUG_ENTER("hash_update");
+
+ data=dynamic_element(&hash->array,0,HASH_LINK*);
+ blength=hash->blength; records=hash->records;
+
+ /* Search after record with key */
+
+ idx=hash_mask((*hash->calc_hashnr)(old_key,(old_key_length ?
+ old_key_length :
+ hash->key_length)),
+ blength,records);
+ new_index=hash_mask(rec_hashnr(hash,record),blength,records);
+ if (idx == new_index)
+ DBUG_RETURN(0); /* Nothing to do (No record check) */
+ previous=0;
+ for (;;)
+ {
+
+ if ((pos= data+idx)->data == record)
+ break;
+ previous=pos;
+ if ((idx=pos->next) == NO_RECORD)
+ DBUG_RETURN(1); /* Not found in links */
+ }
+ hash->current_record= NO_RECORD;
+ org_link= *pos;
+ empty=idx;
+
+ /* Relink record from current chain */
+
+ if (!previous)
+ {
+ if (pos->next != NO_RECORD)
+ {
+ empty=pos->next;
+ *pos= data[pos->next];
+ }
+ }
+ else
+ previous->next=pos->next; /* unlink pos */
+
+ /* Move data to correct position */
+ pos=data+new_index;
+ new_pos_index=hash_rec_mask(hash,pos,blength,records);
+ if (new_index != new_pos_index)
+ { /* Other record in wrong position */
+ data[empty] = *pos;
+ movelink(data,new_index,new_pos_index,empty);
+ org_link.next=NO_RECORD;
+ data[new_index]= org_link;
+ }
+ else
+ { /* Link in chain at right position */
+ org_link.next=data[new_index].next;
+ data[empty]=org_link;
+ data[new_index].next=empty;
+ }
+ DBUG_RETURN(0);
+}
+
+
+byte *hash_element(HASH *hash,uint idx)
+{
+ if (idx < hash->records)
+ return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
+ return 0;
+}
+
+
+#ifndef DBUG_OFF
+
+my_bool hash_check(HASH *hash)
+{
+ int error;
+ uint i,rec_link,found,max_links,seek,links,idx;
+ uint records,blength;
+ HASH_LINK *data,*hash_info;
+
+ records=hash->records; blength=hash->blength;
+ data=dynamic_element(&hash->array,0,HASH_LINK*);
+ error=0;
+
+ for (i=found=max_links=seek=0 ; i < records ; i++)
+ {
+ if (hash_rec_mask(hash,data+i,blength,records) == i)
+ {
+ found++; seek++; links=1;
+ for (idx=data[i].next ;
+ idx != NO_RECORD && found < records + 1;
+ idx=hash_info->next)
+ {
+ if (idx >= records)
+ {
+ DBUG_PRINT("error",
+ ("Found pointer outside array to %d from link starting at %d",
+ idx,i));
+ error=1;
+ }
+ hash_info=data+idx;
+ seek+= ++links;
+ if ((rec_link=hash_rec_mask(hash,hash_info,blength,records)) != i)
+ {
+ DBUG_PRINT("error",
+ ("Record in wrong link at %d: Start %d Record: %lx Record-link %d", idx,i,hash_info->data,rec_link));
+ error=1;
+ }
+ else
+ found++;
+ }
+ if (links > max_links) max_links=links;
+ }
+ }
+ if (found != records)
+ {
+ DBUG_PRINT("error",("Found %ld of %ld records"));
+ error=1;
+ }
+ if (records)
+ DBUG_PRINT("info",
+ ("records: %ld seeks: %d max links: %d hitrate: %.2f",
+ records,seek,max_links,(float) seek / (float) records));
+ return error;
+}
+#endif
diff --git a/mysys/list.c b/mysys/list.c
new file mode 100644
index 00000000000..0a6d900d6b9
--- /dev/null
+++ b/mysys/list.c
@@ -0,0 +1,116 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Code for handling dubble-linked lists in C
+*/
+
+#include "mysys_priv.h"
+#include <my_list.h>
+
+
+
+ /* Add a element to start of list */
+
+LIST *list_add(LIST *root, LIST *element)
+{
+ DBUG_ENTER("list_add");
+ DBUG_PRINT("enter",("root: %lx element: %lx", root, element));
+ if (root)
+ {
+ if (root->prev) /* If add in mid of list */
+ root->prev->next= element;
+ element->prev=root->prev;
+ root->prev=element;
+ }
+ else
+ element->prev=0;
+ element->next=root;
+ DBUG_RETURN(element); /* New root */
+}
+
+
+LIST *list_delete(LIST *root, LIST *element)
+{
+ if (element->prev)
+ element->prev->next=element->next;
+ else
+ root=element->next;
+ if (element->next)
+ element->next->prev=element->prev;
+ return root;
+}
+
+
+void list_free(LIST *root, pbool free_data)
+{
+ LIST *next;
+ while (root)
+ {
+ next=root->next;
+ if (free_data)
+ my_free((gptr) root->data,MYF(0));
+ my_free((gptr) root,MYF(0));
+ root=next;
+ }
+}
+
+
+LIST *list_cons(void *data, LIST *list)
+{
+ LIST *new=(LIST*) my_malloc(sizeof(LIST),MYF(MY_FAE));
+ if (!new)
+ return 0;
+ new->data=data;
+ return list_add(list,new);
+}
+
+
+LIST *list_reverse(LIST *root)
+{
+ LIST *last;
+
+ last=root;
+ while (root)
+ {
+ last=root;
+ root=root->next;
+ last->next=last->prev;
+ last->prev=root;
+ }
+ return last;
+}
+
+uint list_length(LIST *list)
+{
+ uint count;
+ for (count=0 ; list ; list=list->next, count++) ;
+ return count;
+}
+
+
+int list_walk(LIST *list, list_walk_action action, gptr argument)
+{
+ int error=0;
+ while (list)
+ {
+ if ((error = (*action)(list->data,argument)))
+ return error;
+ list=rest(list);
+ }
+ return 0;
+}
diff --git a/mysys/make-ccc b/mysys/make-ccc
new file mode 100755
index 00000000000..9c54185682a
--- /dev/null
+++ b/mysys/make-ccc
@@ -0,0 +1,4 @@
+rm -f .deps/* raid.o mf_iocache.o libmysys.a
+ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_lread.c my_lwrite.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c
+make raid.o mf_iocache.o my_lock.o
+ar -cr libmysys.a array.o raid.o mf_iocache.o my_lock.o
diff --git a/mysys/make-conf.c b/mysys/make-conf.c
new file mode 100644
index 00000000000..9db766574e2
--- /dev/null
+++ b/mysys/make-conf.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* make-conf.c
+ * make a charset .conf file out of a ctype-charset.c file.
+ */
+
+#ifndef CHARSET
+#error You must define the charset, e.g.: -DCHARSET=latin1
+#endif
+
+/* some pre-processor tricks to get us going */
+#define _STRINGIZE_HELPER(x) #x
+#define STRINGIZE(x) _STRINGIZE_HELPER(x)
+
+#define _JOIN_WORDS_HELPER(a, b) a ## b
+#define JOIN_WORDS(a, b) _JOIN_WORDS_HELPER(a, b)
+
+#define CH_SRC ctype- ## CHARSET ## .c
+#define CH_INCLUDE STRINGIZE(CH_SRC)
+
+/* aaaah, that's better */
+#include <my_global.h>
+#include CH_INCLUDE
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ROW_LEN 16
+
+void print_array(const char *name, const uchar *array, uint size);
+
+int main(void)
+{
+ printf("# Configuration file for the "
+ STRINGIZE(CHARSET)
+ " character set.\n");
+
+ print_array("ctype", JOIN_WORDS(ctype_, CHARSET), 257);
+ print_array("to_lower", JOIN_WORDS(to_lower_, CHARSET), 256);
+ print_array("to_upper", JOIN_WORDS(to_upper_, CHARSET), 256);
+ print_array("sort_order", JOIN_WORDS(sort_order_, CHARSET), 256);
+
+ exit(EXIT_SUCCESS);
+}
+
+void print_array(const char *name, const uchar *array, uint size)
+{
+ uint i;
+
+ printf("\n# The %s array must have %d elements.\n", name, size);
+
+ for (i = 0; i < size; ++i) {
+ printf(" %02X", array[i]);
+
+ if ((i+1) % ROW_LEN == size % ROW_LEN)
+ printf("\n");
+ }
+}
diff --git a/mysys/mf_brkhant.c b/mysys/mf_brkhant.c
new file mode 100644
index 00000000000..4e4bc2410f9
--- /dev/null
+++ b/mysys/mf_brkhant.c
@@ -0,0 +1,76 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Dont let the user break when you are doing something important */
+/* Remembers if it got 'SIGINT' and executes it on allow_break */
+/* A static buffer is used; don't call dont_break() twice in a row */
+
+#include "mysys_priv.h"
+#include "my_static.h"
+
+ /* Set variable that we can't break */
+
+void dont_break(void)
+{
+#if !defined(THREAD)
+ my_dont_interrupt=1;
+#endif
+ return;
+} /* dont_break */
+
+void allow_break(void)
+{
+#if !defined(THREAD)
+ {
+ reg1 int index;
+
+ my_dont_interrupt=0;
+ if (_my_signals)
+ {
+ if (_my_signals > MAX_SIGNALS)
+ _my_signals=MAX_SIGNALS;
+ for (index=0 ; index < _my_signals ; index++)
+ {
+ if (_my_sig_remember[index].func) /* Safequard */
+ {
+ (*_my_sig_remember[index].func)(_my_sig_remember[index].number);
+ _my_sig_remember[index].func=0;
+ }
+ }
+ _my_signals=0;
+ }
+ }
+#endif
+} /* dont_break */
+
+ /* Set old status */
+
+#if !defined(THREAD)
+void my_remember_signal(int signal_number, sig_handler (*func) (int))
+{
+#ifndef __WIN__
+ reg1 int index;
+
+ index=_my_signals++; /* Nobody can break a ++ ? */
+ if (index < MAX_SIGNALS)
+ {
+ _my_sig_remember[index].number=signal_number;
+ _my_sig_remember[index].func=func;
+ }
+#endif /* __WIN__ */
+} /* my_remember_signal */
+#endif /* THREAD */
diff --git a/mysys/mf_cache.c b/mysys/mf_cache.c
new file mode 100644
index 00000000000..c40cfa386d3
--- /dev/null
+++ b/mysys/mf_cache.c
@@ -0,0 +1,83 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Open a temporary file and cache it with io_cache. Delete it on close */
+
+#include "mysys_priv.h"
+
+ /*
+ ** Open a cached tempfile by IO_CACHE
+ ** Should be used when no seeks are done (only reinit_io_buff)
+ ** Return 0 if cache is inited ok
+ ** The actual file is created when the IO_CACHE buffer gets filled
+ */
+
+my_bool open_cached_file(IO_CACHE *cache, const char* dir, const char *prefix,
+ uint cache_size, myf cache_myflags)
+{
+ DBUG_ENTER("open_cached_file");
+
+ cache->buffer=0; /* Mark that not open */
+ if (!(cache->file_name=my_tempnam(dir,prefix,MYF(MY_WME))))
+ DBUG_RETURN(1);
+ if (!init_io_cache(cache,-1,cache_size,WRITE_CACHE,0L,0,
+ MYF(cache_myflags | MY_NABP)))
+ {
+ DBUG_RETURN(0);
+ }
+ (*free)(cache->file_name); /* my_tempnam uses malloc() */
+ cache->file_name=0;
+ DBUG_RETURN(0);
+}
+
+
+my_bool real_open_cached_file(IO_CACHE *cache)
+{
+ DBUG_ENTER("real_open_cached_file");
+ if ((cache->file=my_create(cache->file_name,0,
+ (int) (O_RDWR | O_BINARY | O_TRUNC | O_TEMPORARY |
+ O_SHORT_LIVED),
+ MYF(MY_WME))) >= 0)
+ {
+#if O_TEMPORARY == 0 && !defined(CANT_DELETE_OPEN_FILES)
+ VOID(my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT)));
+#endif
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(1);
+}
+
+
+void close_cached_file(IO_CACHE *cache)
+{
+ DBUG_ENTER("close_cached_file");
+
+ if (my_b_inited(cache))
+ {
+ VOID(end_io_cache(cache));
+ if (cache->file >= 0)
+ {
+ VOID(my_close(cache->file,MYF(MY_WME)));
+#ifdef CANT_DELETE_OPEN_FILES
+ VOID(my_delete(cache->file_name,MYF(MY_WME | ME_NOINPUT)));
+#endif
+ }
+ if (cache->file_name)
+ (*free)(cache->file_name); /* my_tempnam uses malloc() */
+ }
+ DBUG_VOID_RETURN;
+}
diff --git a/mysys/mf_casecnv.c b/mysys/mf_casecnv.c
new file mode 100644
index 00000000000..705e1361937
--- /dev/null
+++ b/mysys/mf_casecnv.c
@@ -0,0 +1,252 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Functions to convert to lover_case and to upper_case in scandinavia.
+
+ case_sort converts a character string to a representaion that can
+ be compared by strcmp to find with is alfabetical bigger.
+ (lower- and uppercase letters is compared as the same)
+*/
+
+#include "mysys_priv.h"
+#include <m_ctype.h>
+
+ /* string to uppercase */
+
+void caseup_str(my_string str)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+strlen(str);
+ if (use_mb(default_charset_info))
+ while (*str)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=toupper(*str),++str;
+ }
+ else
+#endif
+ while ((*str = toupper(*str)) != 0)
+ str++;
+} /* caseup_str */
+
+ /* string to lowercase */
+
+void casedn_str(my_string str)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+strlen(str);
+ if (use_mb(default_charset_info))
+ while (*str)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=tolower(*str),++str;
+ }
+ else
+#endif
+ while ((*str= tolower(*str)) != 0)
+ str++;
+} /* casedn_str */
+
+
+ /* to uppercase */
+
+void caseup(my_string str, uint length)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+length;
+ if (use_mb(default_charset_info))
+ while (str<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=toupper(*str),++str;
+ }
+ else
+#endif
+ for ( ; length>0 ; length--, str++)
+ *str= toupper(*str);
+} /* caseup */
+
+ /* to lowercase */
+
+void casedn(my_string str, uint length)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register char *end=str+length;
+ if (use_mb(default_charset_info))
+ while (str<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, str,end))) str+=l;
+ else *str=tolower(*str),++str;
+ }
+ else
+#endif
+ for ( ; length>0 ; length--, str++)
+ *str= tolower(*str);
+} /* casedn */
+
+ /* to sort-string that can be compared to get text in order */
+
+void case_sort(my_string str, uint length)
+{
+ for ( ; length>0 ; length--, str++)
+ *str= (char) my_sort_order[(uchar) *str];
+} /* case_sort */
+
+ /* find string in another with no case_sensivity */
+
+/* ToDo: This function should be modified to support multibyte charset.
+ However it is not used untill 3.23.5.
+ Wei He (hewei@mail.ied.ac.cn)
+*/
+
+my_string my_strcasestr(const char *str, const char *search)
+{
+ uchar *i,*j,*pos;
+
+ pos=(uchar*) str;
+skipp:
+ while (*pos != '\0')
+ {
+ if (toupper((uchar) *pos++) == toupper((uchar) *search))
+ {
+ i=(uchar*) pos; j=(uchar*) search+1;
+ while (*j)
+ if (toupper(*i++) != toupper(*j++)) goto skipp;
+ return ((char*) pos-1);
+ }
+ }
+ return ((my_string) 0);
+} /* strcstr */
+
+
+ /* compare strings without regarding to case */
+
+int my_strcasecmp(const char *s, const char *t)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register const char *end=s+strlen(s);
+ if (use_mb(default_charset_info))
+ {
+ while (s<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, s,end)))
+ {
+ while (l--)
+ if (*s++ != *t++) return 1;
+ }
+ else if (my_ismbhead(default_charset_info, *t)) return 1;
+ else if (toupper((uchar) *s++) != toupper((uchar) *t++)) return 1;
+ }
+ return *t;
+ }
+ else
+#endif
+ {
+ while (toupper((uchar) *s) == toupper((uchar) *t++))
+ if (!*s++) return 0;
+ return ((int) toupper((uchar) s[0]) - (int) toupper((uchar) t[-1]));
+ }
+}
+
+
+int my_casecmp(const char *s, const char *t, uint len)
+{
+#ifdef USE_MB
+ register uint32 l;
+ register const char *end=s+len;
+ if (use_mb(default_charset_info))
+ {
+ while (s<end)
+ {
+ if ((l=my_ismbchar(default_charset_info, s,end)))
+ {
+ while (l--)
+ if (*s++ != *t++) return 1;
+ }
+ else if (my_ismbhead(default_charset_info, *t)) return 1;
+ else if (toupper((uchar) *s++) != toupper((uchar) *t++)) return 1;
+ }
+ return 0;
+ }
+ else
+#endif
+ {
+ while (len-- != 0 && toupper(*s++) == toupper(*t++)) ;
+ return (int) len+1;
+ }
+}
+
+
+int my_strsortcmp(const char *s, const char *t)
+{
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ return my_strcoll(default_charset_info, (uchar *)s, (uchar *)t);
+ else
+#endif
+ {
+ while (my_sort_order[(uchar) *s] == my_sort_order[(uchar) *t++])
+ if (!*s++) return 0;
+ return ((int) my_sort_order[(uchar) s[0]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+}
+
+int my_sortcmp(const char *s, const char *t, uint len)
+{
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ return my_strnncoll(default_charset_info,
+ (uchar *)s, len, (uchar *)t, len);
+ else
+#endif
+ {
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+ return 0;
+ }
+}
+
+int my_sortncmp(const char *s, uint s_len, const char *t, uint t_len)
+{
+#ifdef USE_STRCOLL
+ if (use_strcoll(default_charset_info))
+ return my_strnncoll(default_charset_info,
+ (uchar *)s, s_len, (uchar *)t, t_len);
+ else
+#endif
+ {
+ uint len= min(s_len,t_len);
+ while (len--)
+ {
+ if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
+ return ((int) my_sort_order[(uchar) s[-1]] -
+ (int) my_sort_order[(uchar) t[-1]]);
+ }
+ return (int) (s_len - t_len);
+ }
+}
diff --git a/mysys/mf_dirname.c b/mysys/mf_dirname.c
new file mode 100644
index 00000000000..1bd6d256cfe
--- /dev/null
+++ b/mysys/mf_dirname.c
@@ -0,0 +1,106 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Functions definied in this file */
+
+uint dirname_length(const char *name)
+{
+ register my_string pos,gpos;
+#ifdef FN_DEVCHAR
+ if ((pos=strrchr(name,FN_DEVCHAR)) == 0)
+#endif
+ pos=(char*) name-1;
+
+ gpos= pos++;
+ for ( ; *pos ; pos++) /* Find last FN_LIBCHAR */
+ if (*pos == FN_LIBCHAR || *pos == '/'
+#ifdef FN_C_AFTER_DIR
+ || *pos == FN_C_AFTER_DIR || *pos == FN_C_AFTER_DIR_2
+#endif
+ )
+ gpos=pos;
+ return ((uint) (uint) (gpos+1-(char*) name));
+}
+
+
+ /* Gives directory part of filename. Directory ends with '/' */
+ /* Returns length of directory part */
+
+uint dirname_part(my_string to, const char *name)
+{
+ uint length;
+ DBUG_ENTER("dirname_part");
+ DBUG_PRINT("enter",("'%s'",name));
+
+ length=dirname_length(name);
+ (void) strmake(to,(char*) name,min(length,FN_REFLEN-2));
+ convert_dirname(to); /* Convert chars */
+ DBUG_RETURN(length);
+} /* dirname */
+
+
+ /* convert dirname to use under this system */
+ /* If MSDOS converts '/' to '\' */
+ /* If VMS converts '<' to '[' and '>' to ']' */
+ /* Adds a '/' to end if there isn't one and the last isn't a dev_char */
+ /* ARGSUSED */
+
+#ifndef FN_DEVCHAR
+#define FN_DEVCHAR '\0' /* For easier code */
+#endif
+
+void convert_dirname(my_string to)
+{
+#ifdef FN_UPPER_CASE
+ caseup_str(to);
+#endif
+#ifdef FN_LOWER_CASE
+ casedn_str(to);
+#endif
+#if FN_LIBCHAR != '/'
+ {
+ reg1 my_string pos;
+ pos=to-1; /* Change from '/' */
+ while ((pos=strchr(pos+1,'/')) != 0)
+ *pos=FN_LIBCHAR;
+ }
+#endif
+#ifdef FN_C_BEFORE_DIR_2
+ {
+ reg1 my_string pos;
+ for (pos=to ; *pos ; pos++)
+ {
+ if (*pos == FN_C_BEFORE_DIR_2)
+ *pos=FN_C_BEFORE_DIR;
+ if (*pos == FN_C_AFTER_DIR_2)
+ *pos=FN_C_AFTER_DIR;
+ }
+ }
+#else
+ { /* Append FN_LIBCHAR if not there */
+ char *end=strend(to);
+ if (end != to && (end[-1] != FN_LIBCHAR && end[-1] != FN_DEVCHAR))
+ {
+ end[0]=FN_LIBCHAR;
+ end[1]=0;
+ }
+ }
+#endif
+} /* convert_dirname */
diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c
new file mode 100644
index 00000000000..6a9b9d18341
--- /dev/null
+++ b/mysys/mf_fn_ext.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Returnerar en pekare till filnamnets extension. */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Return a pointerto the extension of the filename
+ The pointer points at the extension character (normally '.'))
+ If there isn't any extension, the pointer points at the end
+ NULL of the filename
+ */
+
+my_string fn_ext(const char *name)
+{
+ register my_string pos,gpos;
+ DBUG_ENTER("fn_ext");
+ DBUG_PRINT("mfunkt",("name: '%s'",name));
+
+#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR)
+ {
+ char buff[FN_REFLEN];
+ gpos=(my_string) name+dirname_part(buff,(char*) name);
+ }
+#else
+ if (!(gpos=strrchr(name,FNLIBCHAR)))
+ gpos=name;
+#endif
+ pos=strrchr(gpos,FN_EXTCHAR);
+ DBUG_RETURN (pos ? pos : strend(gpos));
+} /* fn_ext */
diff --git a/mysys/mf_format.c b/mysys/mf_format.c
new file mode 100644
index 00000000000..623f1dbd19e
--- /dev/null
+++ b/mysys/mf_format.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#ifdef HAVE_REALPATH
+#include <sys/param.h>
+#include <sys/stat.h>
+#endif
+
+ /* format a filename with replace of library and extension */
+ /* params to and name may be identicall */
+ /* function doesn't change name if name != to */
+ /* Flag may be: 1 replace filenames library with 'dsk' */
+ /* 2 replace extension with 'form' */
+ /* 4 Unpack filename (replace ~ with home) */
+ /* 8 Pack filename as short as possibly */
+ /* 16 Resolve symbolic links for filename */
+ /* 32 Resolve filename to full path */
+
+#ifdef MAXPATHLEN
+#define BUFF_LEN MAXPATHLEN
+#else
+#define BUFF_LEN FN_LEN
+#endif
+
+my_string fn_format(my_string to, const char *name, const char *dsk,
+ const char *form, int flag)
+{
+ reg1 uint length;
+ char dev[FN_REFLEN], buff[BUFF_LEN], *pos, *startpos;
+ const char *ext;
+ DBUG_ENTER("fn_format");
+ DBUG_PRINT("enter",("name: %s dsk: %s form: %s flag: %d",
+ name,dsk,form,flag));
+
+ /* Kopiera & skippa enheten */
+ name+=(length=dirname_part(dev,(startpos=(my_string) name)));
+ if (length == 0 || flag & 1)
+ {
+ (void) strmov(dev,dsk); /* Use given directory */
+ convert_dirname(dev); /* Fix to this OS */
+ }
+ if (flag & 8)
+ pack_dirname(dev,dev); /* Put in ./.. and ~/.. */
+ if (flag & 4)
+ (void) unpack_dirname(dev,dev); /* Replace ~/.. with dir */
+ if ((pos=strchr(name,FN_EXTCHAR)) != NullS)
+ {
+ if ((flag & 2) == 0) /* Skall vi byta extension ? */
+ {
+ length=strlength(name); /* Old extension */
+ ext = "";
+ }
+ else
+ {
+ length=(uint) (pos-(char*) name); /* Change extension */
+ ext= form;
+ }
+ }
+ else
+ {
+ length=strlength(name); /* Har ingen ext- tag nya */
+ ext=form;
+ }
+
+ if (strlen(dev)+length+strlen(ext) >= FN_REFLEN || length >= FN_LEN )
+ { /* To long path, return original */
+ uint tmp_length=strlength(startpos);
+ DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %d",dev,ext,length));
+ (void) strmake(to,startpos,min(tmp_length,FN_REFLEN-1));
+ }
+ else
+ {
+ if (to == startpos)
+ {
+ bmove(buff,(char*) name,length); /* Save name for last copy */
+ name=buff;
+ }
+ (void) strmov(strnmov(strmov(to,dev),name,length),ext);
+#ifdef FN_UPPER_CASE
+ caseup_str(to);
+#endif
+#ifdef FN_LOWER_CASE
+ casedn_str(to);
+#endif
+ }
+ /* Purify gives a lot of UMR errors when using realpath */
+#if defined(HAVE_REALPATH) && !defined(HAVE_purify)
+ if (flag & 16)
+ {
+ struct stat stat_buff;
+ if (flag & 32 || (!lstat(to,&stat_buff) && S_ISLNK(stat_buff.st_mode)))
+ {
+ if (realpath(to,buff))
+ strmov(to,buff);
+ }
+ }
+#endif
+ DBUG_RETURN (to);
+} /* fn_format */
+
+
+ /*
+ strlength(const string str)
+ Return length of string with end-space:s not counted.
+ */
+
+size_s strlength(const char *str)
+{
+ reg1 my_string pos;
+ reg2 my_string found;
+ DBUG_ENTER("strlength");
+
+ pos=found=(char*) str;
+
+ while (*pos)
+ {
+ if (*pos != ' ')
+ {
+ while (*++pos && *pos != ' ') {};
+ if (!*pos)
+ {
+ found=pos; /* String ends here */
+ break;
+ }
+ }
+ found=pos;
+ while (*++pos == ' ') {};
+ }
+ DBUG_RETURN((size_s) (found-(char*) str));
+} /* strlength */
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
new file mode 100644
index 00000000000..627789dc802
--- /dev/null
+++ b/mysys/mf_getdate.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Get date in a printable form: yyyy-mm-dd hh:mm:ss */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /*
+ If flag & 1 Return date and time
+ If flag & 2 Return short date format YYMMDD
+ */
+
+
+void get_date(register my_string to, int flag, time_t date)
+{
+ reg2 struct tm *start_time;
+ time_t skr;
+#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
+ struct tm tm_tmp;
+#endif
+
+ skr=date ? (time_t) date : time((time_t*) 0);
+#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
+ localtime_r(&skr,&tm_tmp);
+ start_time= &tm_tmp;
+#else
+ start_time=localtime(&skr);
+#endif
+ if (flag & 2)
+ sprintf(to,"%02d%02d%02d",
+ start_time->tm_year % 100,
+ start_time->tm_mon+1,
+ start_time->tm_mday);
+ else
+ sprintf(to,"%d-%02d-%02d",
+ start_time->tm_year+1900,
+ start_time->tm_mon+1,
+ start_time->tm_mday);
+ if (flag & 1)
+ sprintf(strend(to)," %2d:%02d:%02d",
+ start_time->tm_hour,
+ start_time->tm_min,
+ start_time->tm_sec);
+} /* get_date */
diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c
new file mode 100644
index 00000000000..86cf5fc65e2
--- /dev/null
+++ b/mysys/mf_iocache.c
@@ -0,0 +1,603 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Cashing of files with only does (sequential) read or writes of fixed-
+ length records. A read isn't allowed to go over file-length. A read is ok
+ if it ends at file-length and next read can try to read after file-length
+ (and get a EOF-error).
+ Possibly use of asyncronic io.
+ macros for read and writes for faster io.
+ Used instead of FILE when reading or writing hole files.
+ This shall make mf_rec_cache obsolite.
+ One can change info->pos_in_file to a higer value to skipp bytes in file if
+ also info->rc_pos is set to info->rc_end.
+*/
+
+#define MAP_TO_USE_RAID
+#include "mysys_priv.h"
+#include <m_string.h>
+#ifdef HAVE_AIOWAIT
+#include "mysys_err.h"
+#include <errno.h>
+static void my_aiowait(my_aio_result *result);
+#endif
+
+
+ /*
+ ** if cachesize == 0 then use default cachesize (from s-file)
+ ** if file == -1 then real_open_cached_file() will be called to
+ ** returns 0 if ok
+ */
+
+int init_io_cache(IO_CACHE *info, File file, uint cachesize,
+ enum cache_type type, my_off_t seek_offset,
+ pbool use_async_io, myf cache_myflags)
+{
+ uint min_cache;
+ DBUG_ENTER("init_io_cache");
+ DBUG_PRINT("enter",("type: %d pos: %ld",(int) type, (ulong) seek_offset));
+
+ info->file=file;
+ if (!cachesize)
+ if (! (cachesize= my_default_record_cache_size))
+ DBUG_RETURN(1); /* No cache requested */
+ min_cache=use_async_io ? IO_SIZE*4 : IO_SIZE*2;
+ if (type == READ_CACHE)
+ { /* Assume file isn't growing */
+ my_off_t file_pos,end_of_file;
+ if ((file_pos=my_tell(file,MYF(0)) == MY_FILEPOS_ERROR))
+ DBUG_RETURN(1);
+ end_of_file=my_seek(file,0L,MY_SEEK_END,MYF(0));
+ if (end_of_file < seek_offset)
+ end_of_file=seek_offset;
+ VOID(my_seek(file,file_pos,MY_SEEK_SET,MYF(0)));
+ if ((my_off_t) cachesize > end_of_file-seek_offset+IO_SIZE*2-1)
+ {
+ cachesize=(uint) (end_of_file-seek_offset)+IO_SIZE*2-1;
+ use_async_io=0; /* No nead to use async */
+ }
+ }
+
+ for (;;)
+ {
+ cachesize=(uint) ((ulong) (cachesize + min_cache-1) &
+ (ulong) ~(min_cache-1));
+ if (cachesize < min_cache)
+ cachesize = min_cache;
+ if ((info->buffer=
+ (byte*) my_malloc(cachesize,
+ MYF((cache_myflags & ~ MY_WME) |
+ (cachesize == min_cache ? MY_WME : 0)))) != 0)
+ break; /* Enough memory found */
+ if (cachesize == min_cache)
+ DBUG_RETURN(2); /* Can't alloc cache */
+ cachesize= (uint) ((long) cachesize*3/4); /* Try with less memory */
+ }
+ info->pos_in_file=seek_offset;
+ info->read_length=info->buffer_length=cachesize;
+ info->seek_not_done= test(file >= 0); /* Seek not done */
+ info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
+ info->rc_request_pos=info->rc_pos=info->buffer;
+
+ if (type == READ_CACHE)
+ {
+ info->rc_end=info->buffer; /* Nothing in cache */
+ }
+ else /* type == WRITE_CACHE */
+ {
+ info->rc_end=info->buffer+info->buffer_length- (seek_offset & (IO_SIZE-1));
+ }
+ info->end_of_file=MY_FILEPOS_ERROR; /* May be changed by user */
+ info->type=type;
+ info->error=0;
+ info->read_function=_my_b_read;
+#ifdef HAVE_AIOWAIT
+ if (use_async_io && ! my_disable_async_io)
+ {
+ DBUG_PRINT("info",("Using async io"));
+ info->read_length/=2;
+ info->read_function=_my_b_async_read;
+ }
+ info->inited=info->aio_result.pending=0;
+#endif
+ DBUG_RETURN(0);
+} /* init_io_cache */
+
+
+ /* Wait until current request is ready */
+
+#ifdef HAVE_AIOWAIT
+static void my_aiowait(my_aio_result *result)
+{
+ if (result->pending)
+ {
+ struct aio_result_t *tmp;
+ for (;;)
+ {
+ if ((int) (tmp=aiowait((struct timeval *) 0)) == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ DBUG_PRINT("error",("No aio request, error: %d",errno));
+ result->pending=0; /* Assume everythings is ok */
+ break;
+ }
+ ((my_aio_result*) tmp)->pending=0;
+ if ((my_aio_result*) tmp == result)
+ break;
+ }
+ }
+ return;
+}
+#endif
+
+ /* Use this to reset cache to start or other type */
+ /* Some simple optimizing is done when reinit in current buffer */
+
+my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
+ my_off_t seek_offset,
+ pbool use_async_io __attribute__((unused)),
+ pbool clear_cache)
+{
+ DBUG_ENTER("reinit_io_cache");
+
+ info->seek_not_done= test(info->file >= 0); /* Seek not done */
+ if (! clear_cache &&
+ seek_offset >= info->pos_in_file &&
+ seek_offset <= info->pos_in_file +
+ (uint) (info->rc_end - info->rc_request_pos))
+ { /* use current buffer */
+ if (info->type == WRITE_CACHE && type == READ_CACHE)
+ {
+ info->rc_end=info->rc_pos;
+ info->end_of_file=my_b_tell(info);
+ }
+ else if (info->type == READ_CACHE && type == WRITE_CACHE)
+ info->rc_end=info->buffer+info->buffer_length;
+ info->rc_pos=info->rc_request_pos+(seek_offset-info->pos_in_file);
+#ifdef HAVE_AIOWAIT
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
+#endif
+ }
+ else
+ {
+ if (info->type == WRITE_CACHE && type == READ_CACHE)
+ info->end_of_file=my_b_tell(info);
+ if (flush_io_cache(info))
+ DBUG_RETURN(1);
+ info->pos_in_file=seek_offset;
+ info->rc_request_pos=info->rc_pos=info->buffer;
+ if (type == READ_CACHE)
+ {
+ info->rc_end=info->buffer; /* Nothing in cache */
+ }
+ else
+ {
+ info->rc_end=info->buffer+info->buffer_length-
+ (seek_offset & (IO_SIZE-1));
+ info->end_of_file=MY_FILEPOS_ERROR; /* May be changed by user */
+ }
+ }
+ info->type=type;
+ info->error=0;
+ info->read_function=_my_b_read;
+#ifdef HAVE_AIOWAIT
+ if (use_async_io && ! my_disable_async_io &&
+ ((ulong) info->buffer_length <
+ (ulong) (info->end_of_file - seek_offset)))
+ {
+ info->read_length=info->buffer_length/2;
+ info->read_function=_my_b_async_read;
+ }
+ info->inited=0;
+#endif
+ DBUG_RETURN(0);
+} /* init_io_cache */
+
+
+
+ /* Read buffered. Returns 1 if can't read requested characters */
+ /* Returns 0 if record read */
+
+int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count)
+{
+ uint length,diff_length,left_length;
+ my_off_t max_length, pos_in_file;
+
+ memcpy(Buffer,info->rc_pos,
+ (size_t) (left_length=(uint) (info->rc_end-info->rc_pos)));
+ Buffer+=left_length;
+ Count-=left_length;
+ pos_in_file=info->pos_in_file+(uint) (info->rc_end - info->buffer);
+ if (info->seek_not_done)
+ { /* File touched, do seek */
+ VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)));
+ info->seek_not_done=0;
+ }
+ diff_length=(uint) (pos_in_file & (IO_SIZE-1));
+ if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length)))
+ { /* Fill first intern buffer */
+ uint read_length;
+ if (info->end_of_file == pos_in_file)
+ { /* End of file */
+ info->error=(int) left_length;
+ return 1;
+ }
+ length=(Count & (uint) ~(IO_SIZE-1))-diff_length;
+ if ((read_length=my_read(info->file,Buffer,(uint) length,info->myflags))
+ != (uint) length)
+ {
+ info->error= read_length == (uint) -1 ? -1 :
+ (int) (read_length+left_length);
+ return 1;
+ }
+ Count-=length;
+ Buffer+=length;
+ pos_in_file+=length;
+ left_length+=length;
+ diff_length=0;
+ }
+ max_length=info->end_of_file - pos_in_file;
+ if (max_length > info->read_length-diff_length)
+ max_length=info->read_length-diff_length;
+
+ if (!max_length)
+ {
+ if (Count)
+ {
+ info->error= left_length; /* We only got this many char */
+ return 1;
+ }
+ length=0; /* Didn't read any chars */
+ }
+ else if ((length=my_read(info->file,info->buffer,(uint) max_length,
+ info->myflags)) < Count ||
+ length == (uint) -1)
+ {
+ if (length != (uint) -1)
+ memcpy(Buffer,info->buffer,(size_t) length);
+ info->error= length == (uint) -1 ? -1 : (int) (length+left_length);
+ return 1;
+ }
+ info->rc_pos=info->buffer+Count;
+ info->rc_end=info->buffer+length;
+ info->pos_in_file=pos_in_file;
+ memcpy(Buffer,info->buffer,(size_t) Count);
+ return 0;
+}
+
+
+#ifdef HAVE_AIOWAIT
+
+int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count)
+{
+ uint length,read_length,diff_length,left_length,use_length,org_Count;
+ my_off_t max_length;
+ my_off_t next_pos_in_file;
+ byte *read_buffer;
+
+ memcpy(Buffer,info->rc_pos,
+ (size_t) (left_length=(uint) (info->rc_end-info->rc_pos)));
+ Buffer+=left_length;
+ org_Count=Count;
+ Count-=left_length;
+
+ if (info->inited)
+ { /* wait for read block */
+ info->inited=0; /* No more block to read */
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
+ if (info->aio_result.result.aio_errno)
+ {
+ if (info->myflags & MY_WME)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(info->file),
+ info->aio_result.result.aio_errno);
+ my_errno=info->aio_result.result.aio_errno;
+ info->error= -1;
+ return(1);
+ }
+ if (! (read_length = (uint) info->aio_result.result.aio_return) ||
+ read_length == (uint) -1)
+ {
+ my_errno=0; /* For testing */
+ info->error= (read_length == (uint) -1 ? -1 :
+ (int) (read_length+left_length));
+ return(1);
+ }
+ info->pos_in_file+=(uint) (info->rc_end - info->rc_request_pos);
+
+ if (info->rc_request_pos != info->buffer)
+ info->rc_request_pos=info->buffer;
+ else
+ info->rc_request_pos=info->buffer+info->read_length;
+ info->rc_pos=info->rc_request_pos;
+ next_pos_in_file=info->aio_read_pos+read_length;
+
+ /* Check if pos_in_file is changed
+ (_ni_read_cache may have skipped some bytes) */
+
+ if (info->aio_read_pos < info->pos_in_file)
+ { /* Fix if skipped bytes */
+ if (info->aio_read_pos + read_length < info->pos_in_file)
+ {
+ read_length=0; /* Skipp block */
+ next_pos_in_file=info->pos_in_file;
+ }
+ else
+ {
+ my_off_t offset= (info->pos_in_file - info->aio_read_pos);
+ info->pos_in_file=info->aio_read_pos; /* Whe are here */
+ info->rc_pos=info->rc_request_pos+offset;
+ read_length-=offset; /* Bytes left from rc_pos */
+ }
+ }
+#ifndef DBUG_OFF
+ if (info->aio_read_pos > info->pos_in_file)
+ {
+ my_errno=EINVAL;
+ return(info->read_length= -1);
+ }
+#endif
+ /* Copy found bytes to buffer */
+ length=min(Count,read_length);
+ memcpy(Buffer,info->rc_pos,(size_t) length);
+ Buffer+=length;
+ Count-=length;
+ left_length+=length;
+ info->rc_end=info->rc_pos+read_length;
+ info->rc_pos+=length;
+ }
+ else
+ next_pos_in_file=(info->pos_in_file+ (uint)
+ (info->rc_end - info->rc_request_pos));
+
+ /* If reading large blocks, or first read or read with skipp */
+ if (Count)
+ {
+ if (next_pos_in_file == info->end_of_file)
+ {
+ info->error=(int) (read_length+left_length);
+ return 1;
+ }
+ VOID(my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0)));
+ read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1));
+ if (Count < read_length)
+ { /* Small block, read to cache */
+ if ((read_length=my_read(info->file,info->rc_request_pos,
+ read_length, info->myflags)) == (uint) -1)
+ return info->error= -1;
+ use_length=min(Count,read_length);
+ memcpy(Buffer,info->rc_request_pos,(size_t) use_length);
+ info->rc_pos=info->rc_request_pos+Count;
+ info->rc_end=info->rc_request_pos+read_length;
+ info->pos_in_file=next_pos_in_file; /* Start of block in cache */
+ next_pos_in_file+=read_length;
+
+ if (Count != use_length)
+ { /* Didn't find hole block */
+ if (info->myflags & (MY_WME | MY_FAE | MY_FNABP) && Count != org_Count)
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(info->file),my_errno);
+ info->error=(int) (read_length+left_length);
+ return 1;
+ }
+ }
+ else
+ { /* Big block, don't cache it */
+ if ((read_length=my_read(info->file,Buffer,(uint) Count,info->myflags))
+ != Count)
+ {
+ info->error= read_length == (uint) -1 ? -1 : read_length+left_length;
+ return 1;
+ }
+ info->rc_pos=info->rc_end=info->rc_request_pos;
+ info->pos_in_file=(next_pos_in_file+=Count);
+ }
+ }
+
+ /* Read next block with asyncronic io */
+ max_length=info->end_of_file - next_pos_in_file;
+ diff_length=(next_pos_in_file & (IO_SIZE-1));
+
+ if (max_length > (my_off_t) info->read_length - diff_length)
+ max_length= (my_off_t) info->read_length - diff_length;
+ if (info->rc_request_pos != info->buffer)
+ read_buffer=info->buffer;
+ else
+ read_buffer=info->buffer+info->read_length;
+ info->aio_read_pos=next_pos_in_file;
+ if (max_length)
+ {
+ info->aio_result.result.aio_errno=AIO_INPROGRESS; /* Marker for test */
+ DBUG_PRINT("aioread",("filepos: %ld length: %ld",
+ (ulong) next_pos_in_file,(ulong) max_length));
+ if (aioread(info->file,read_buffer,(int) max_length,
+ (my_off_t) next_pos_in_file,MY_SEEK_SET,
+ &info->aio_result.result))
+ { /* Skipp async io */
+ my_errno=errno;
+ DBUG_PRINT("error",("got error: %d, aio_result: %d from aioread, async skipped",
+ errno, info->aio_result.result.aio_errno));
+ if (info->rc_request_pos != info->buffer)
+ {
+ bmove(info->buffer,info->rc_request_pos,
+ (uint) (info->rc_end - info->rc_pos));
+ info->rc_request_pos=info->buffer;
+ info->rc_pos-=info->read_length;
+ info->rc_end-=info->read_length;
+ }
+ info->read_length=info->buffer_length; /* Use hole buffer */
+ info->read_function=_my_b_read; /* Use normal IO_READ next */
+ }
+ else
+ info->inited=info->aio_result.pending=1;
+ }
+ return 0; /* Block read, async in use */
+} /* _my_b_async_read */
+#endif
+
+
+/* Read one byte when buffer is empty */
+
+int _my_b_get(IO_CACHE *info)
+{
+ byte buff;
+ if ((*(info)->read_function)(info,&buff,1))
+ return my_b_EOF;
+ return (int) (uchar) buff;
+}
+
+ /* Returns != 0 if error on write */
+
+int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count)
+{
+ uint rest_length,length;
+
+ rest_length=(uint) (info->rc_end - info->rc_pos);
+ memcpy(info->rc_pos,Buffer,(size_t) rest_length);
+ Buffer+=rest_length;
+ Count-=rest_length;
+ info->rc_pos+=rest_length;
+ if (flush_io_cache(info))
+ return 1;
+ if (Count >= IO_SIZE)
+ { /* Fill first intern buffer */
+ length=Count & (uint) ~(IO_SIZE-1);
+ if (info->seek_not_done)
+ { /* File touched, do seek */
+ VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)));
+ info->seek_not_done=0;
+ }
+ if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP))
+ return info->error= -1;
+ Count-=length;
+ Buffer+=length;
+ info->pos_in_file+=length;
+ }
+ memcpy(info->rc_pos,Buffer,(size_t) Count);
+ info->rc_pos+=Count;
+ return 0;
+}
+
+
+/*
+ Write a block to disk where part of the data may be inside the record
+ buffer. As all write calls to the data goes through the cache,
+ we will never get a seek over the end of the buffer
+*/
+
+int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
+ my_off_t pos)
+{
+ uint length;
+ int error=0;
+
+ if (pos < info->pos_in_file)
+ {
+ /* Of no overlap, write everything without buffering */
+ if (pos + Count <= info->pos_in_file)
+ return my_pwrite(info->file, Buffer, Count, pos,
+ info->myflags | MY_NABP);
+ /* Write the part of the block that is before buffer */
+ length= (uint) (info->pos_in_file - pos);
+ if (my_pwrite(info->file, Buffer, length, pos, info->myflags | MY_NABP))
+ info->error=error=-1;
+ Buffer+=length;
+ pos+= length;
+ Count-= length;
+ }
+
+ /* Check if we want to write inside the used part of the buffer.*/
+ length= (uint) (info->rc_end - info->buffer);
+ if (pos < info->pos_in_file + length)
+ {
+ uint offset= (uint) (pos - info->pos_in_file);
+ length-=offset;
+ if (length > Count)
+ length=Count;
+ memcpy(info->buffer+offset, Buffer, length);
+ Buffer+=length;
+ Count-= length;
+ /* Fix length of buffer if the new data was larger */
+ if (info->buffer+length > info->rc_pos)
+ info->rc_pos=info->buffer+length;
+ if (!Count)
+ return (error);
+ }
+ /* Write at the end of the current buffer; This is the normal case */
+ if (_my_b_write(info, Buffer, Count))
+ error= -1;
+ return error;
+}
+
+
+ /* Flush write cache */
+
+int flush_io_cache(IO_CACHE *info)
+{
+ uint length;
+ DBUG_ENTER("flush_io_cache");
+
+ if (info->type == WRITE_CACHE)
+ {
+ if (info->file == -1)
+ {
+ if (real_open_cached_file(info))
+ DBUG_RETURN((info->error= -1));
+ }
+ if (info->rc_pos != info->buffer)
+ {
+ length=(uint) (info->rc_pos - info->buffer);
+ if (info->seek_not_done)
+ { /* File touched, do seek */
+ VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0)));
+ info->seek_not_done=0;
+ }
+ info->rc_pos=info->buffer;
+ info->pos_in_file+=length;
+ info->rc_end=(info->buffer+info->buffer_length-
+ (info->pos_in_file & (IO_SIZE-1)));
+ if (my_write(info->file,info->buffer,length,info->myflags | MY_NABP))
+ DBUG_RETURN((info->error= -1));
+ DBUG_RETURN(0);
+ }
+ }
+#ifdef HAVE_AIOWAIT
+ else
+ {
+ my_aiowait(&info->aio_result); /* Wait for outstanding req */
+ info->inited=0;
+ }
+#endif
+ DBUG_RETURN(0);
+}
+
+
+int end_io_cache(IO_CACHE *info)
+{
+ int error=0;
+ DBUG_ENTER("end_io_cache");
+ if (info->buffer)
+ {
+ if (info->file != -1) /* File doesn't exist */
+ error=flush_io_cache(info);
+ my_free((gptr) info->buffer,MYF(MY_WME));
+ info->buffer=info->rc_pos=(byte*) 0;
+ }
+ DBUG_RETURN(error);
+} /* end_io_cache */
diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c
new file mode 100644
index 00000000000..eca22039444
--- /dev/null
+++ b/mysys/mf_keycache.c
@@ -0,0 +1,753 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ This functions is handle keyblock cacheing for NISAM, MISAM and PISAM
+ databases.
+ One cache can handle many files. Every different blocksize has it owns
+ set of buffers that are allocated from block_mem.
+ init_key_cache() should be used to init cache handler.
+ */
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include <m_string.h>
+#include <errno.h>
+
+#if defined(MSDOS) && !defined(M_IC80386)
+ /* We nead much memory */
+#undef my_malloc_lock
+#undef my_free_lock
+#define my_malloc_lock(A,B) halloc((long) (A/IO_SIZE),IO_SIZE)
+#define my_free_lock(A,B) hfree(A)
+#endif
+
+/* size of map to be used to find changed files */
+
+#define CHANGED_BLOCKS_HASH 128 /* Must be power of 2 */
+#define CHANGED_BLOCKS_MASK (CHANGED_BLOCKS_HASH-1)
+#define FLUSH_CACHE 2000 /* Sort this many blocks at once */
+
+static uint find_next_bigger_power(uint value);
+static SEC_LINK *find_key_block(int file,my_off_t filepos,int *error);
+
+ /* static variables in this file */
+static SEC_LINK *_my_block_root,**_my_hash_root,
+ *_my_used_first,*_my_used_last;
+static int _my_disk_blocks;
+static uint _my_disk_blocks_used, _my_hash_blocks;
+ulong _my_blocks_used,_my_blocks_changed;
+ulong _my_cache_w_requests,_my_cache_write,_my_cache_r_requests,
+ _my_cache_read;
+static byte HUGE_PTR *_my_block_mem;
+static SEC_LINK *changed_blocks[CHANGED_BLOCKS_HASH];
+static SEC_LINK *file_blocks[CHANGED_BLOCKS_HASH];
+#ifndef DBUG_OFF
+static my_bool _my_printed;
+#endif
+
+
+ /* Init of disk_buffert */
+ /* Returns blocks in use */
+ /* ARGSUSED */
+
+int init_key_cache(ulong use_mem,
+ ulong leave_this_much_mem __attribute__((unused)))
+{
+ uint blocks,length;
+ byte *extra_mem=0;
+ DBUG_ENTER("init_key_cache");
+
+ if (key_cache_inited && _my_disk_blocks > 0)
+ {
+ DBUG_PRINT("warning",("key cache allready in use")); /* purecov: inspected */
+ DBUG_RETURN(0); /* purecov: inspected */
+ }
+ if (! key_cache_inited)
+ {
+ key_cache_inited=TRUE;
+ _my_disk_blocks= -1;
+#ifndef DBUG_OFF
+ _my_printed=0;
+#endif
+ }
+
+ blocks= (uint) (use_mem/(sizeof(SEC_LINK)+sizeof(SEC_LINK*)*5/4+KEYCACHE_BLOCK_SIZE));
+ /* No use to have very few blocks */
+ if (blocks >= 8 && _my_disk_blocks < 0)
+ {
+#if !defined(HAVE_ALLOCA) && !defined(THREAD)
+ if ((extra_mem=my_malloc((uint) leave_this_much_mem,MYF(0))) == 0)
+ goto err;
+#endif
+ for (;;)
+ {
+ if ((_my_hash_blocks=find_next_bigger_power((uint) blocks)) < blocks*5/4)
+ _my_hash_blocks<<=1;
+ while ((length=(uint) blocks*sizeof(SEC_LINK)+
+ sizeof(SEC_LINK*)*_my_hash_blocks)+(ulong) blocks*KEYCACHE_BLOCK_SIZE >
+ use_mem)
+ blocks--;
+ if ((_my_block_mem=my_malloc_lock((ulong) blocks * KEYCACHE_BLOCK_SIZE,MYF(0))))
+ {
+ if ((_my_block_root=(SEC_LINK*) my_malloc((uint) length,MYF(0))) != 0)
+ break;
+ my_free_lock(_my_block_mem,MYF(0));
+ }
+ if (blocks < 8)
+ goto err;
+ blocks=blocks/4*3;
+ }
+ _my_disk_blocks=(int) blocks;
+ _my_hash_root= (SEC_LINK**) (_my_block_root+blocks);
+ bzero((byte*) _my_hash_root,_my_hash_blocks*sizeof(SEC_LINK*));
+ _my_used_first=_my_used_last=0;
+ _my_blocks_used=_my_disk_blocks_used=_my_blocks_changed=0;
+ _my_cache_w_requests=_my_cache_r_requests=_my_cache_read=_my_cache_write=0;
+ DBUG_PRINT("exit",("disk_blocks: %d block_root: %lx _my_hash_blocks: %d hash_root: %lx",
+ _my_disk_blocks,_my_block_root,_my_hash_blocks,
+ _my_hash_root));
+#if !defined(HAVE_ALLOCA) && !defined(THREAD)
+ my_free(extra_mem,MYF(0));
+#endif
+ }
+ bzero((gptr) changed_blocks,sizeof(changed_blocks[0])*CHANGED_BLOCKS_HASH);
+ bzero((gptr) file_blocks,sizeof(file_blocks[0])*CHANGED_BLOCKS_HASH);
+ DBUG_RETURN((int) blocks);
+err:
+ if (extra_mem) /* purecov: inspected */
+ my_free(extra_mem,MYF(0));
+ my_errno=ENOMEM;
+ DBUG_RETURN(0);
+} /* init_key_cache */
+
+
+ /* Remove key_cache from memory */
+
+void end_key_cache(void)
+{
+ DBUG_ENTER("end_key_cache");
+ if (! _my_blocks_changed)
+ {
+ if (_my_disk_blocks > 0)
+ {
+ my_free_lock((gptr) _my_block_mem,MYF(0));
+ my_free((gptr) _my_block_root,MYF(0));
+ _my_disk_blocks= -1;
+ }
+ }
+ DBUG_PRINT("status",
+ ("used: %d changed: %d w_requests: %ld writes: %ld r_requests: %ld reads: %ld",
+ _my_blocks_used,_my_blocks_changed,_my_cache_w_requests,
+ _my_cache_write,_my_cache_r_requests,_my_cache_read));
+ DBUG_VOID_RETURN;
+} /* end_key_cache */
+
+
+static uint find_next_bigger_power(uint value)
+{
+ uint old_value=1;
+ while (value)
+ {
+ old_value=value;
+ value&= value-1;
+ }
+ return (old_value << 1);
+}
+
+static inline void link_into_file_blocks(SEC_LINK *next, int file)
+{
+ reg1 SEC_LINK **ptr= &file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+}
+
+
+static inline void relink_into_file_blocks(SEC_LINK *next, int file)
+{
+ reg1 SEC_LINK **ptr= &file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ if (next->next_changed)
+ next->next_changed->prev_changed=next->prev_changed;
+ *next->prev_changed=next->next_changed;
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+}
+
+static inline void link_changed_to_file(SEC_LINK *next,int file)
+{
+ reg1 SEC_LINK **ptr= &file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ if (next->next_changed)
+ next->next_changed->prev_changed=next->prev_changed;
+ *next->prev_changed=next->next_changed;
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+ next->changed=0;
+ _my_blocks_changed--;
+}
+
+static inline void link_file_to_changed(SEC_LINK *next)
+{
+ reg1 SEC_LINK **ptr= &changed_blocks[(uint) next->file & CHANGED_BLOCKS_MASK];
+ if (next->next_changed)
+ next->next_changed->prev_changed=next->prev_changed;
+ *next->prev_changed=next->next_changed;
+ next->prev_changed= ptr;
+ if ((next->next_changed= *ptr))
+ (*ptr)->prev_changed= &next->next_changed;
+ *ptr=next;
+ next->changed=1;
+ _my_blocks_changed++;
+}
+
+
+#ifndef DBUG_OFF
+#define DBUG_OFF /* This should work */
+#endif
+
+#ifndef DBUG_OFF
+static void test_key_cache(char *where, my_bool lock);
+#endif
+
+
+ /*
+ ** read a key_buffer
+ ** filepos must point at a even KEYCACHE_BLOCK_SIZE block
+ ** if return_buffer is set then the intern buffer is returned if
+ ** it can be used
+ ** Returns adress to where data is read
+ */
+
+byte *key_cache_read(File file, my_off_t filepos, byte *buff, uint length,
+ uint block_length __attribute__((unused)),
+ int return_buffer __attribute__((unused)))
+{
+ reg1 SEC_LINK *next;
+ int error=0;
+
+#ifndef THREAD
+ if (block_length > KEYCACHE_BLOCK_SIZE)
+ return_buffer=0;
+#endif
+ if (_my_disk_blocks > 0)
+ { /* We have key_cacheing */
+ byte *start=buff;
+ uint read_length;
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ do
+ {
+ _my_cache_r_requests++;
+ read_length= length > KEYCACHE_BLOCK_SIZE ? KEYCACHE_BLOCK_SIZE : length;
+ if (!(next=find_key_block(file,filepos,&error)))
+ {
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return (byte*) 0; /* Got a fatal error */
+ }
+ if (error)
+ { /* Didn't find it in cache */
+ if (my_pread(file,next->buffer,read_length,filepos,MYF(MY_NABP)))
+ {
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return((byte*) 0);
+ }
+ _my_cache_read++;
+ }
+#ifndef THREAD /* buffer may be used a long time */
+ if (return_buffer)
+ {
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return (next->buffer);
+ }
+#endif
+ if (! (read_length & 511))
+ bmove512(buff,next->buffer,read_length);
+ else
+ memcpy(buff,next->buffer,(size_t) read_length);
+ buff+=read_length;
+ filepos+=read_length;
+ } while ((length-= read_length));
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return(start);
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ }
+ _my_cache_r_requests++;
+ _my_cache_read++;
+ if (my_pread(file,(byte*) buff,length,filepos,MYF(MY_NABP)))
+ error=1;
+ return (error ? (byte*) 0 : buff);
+} /* key_cache_read */
+
+
+ /* write a key_buffer */
+ /* We don't have to use pwrite because of write locking */
+ /* buff must point at a even KEYCACHE_BLOCK_SIZE block */
+
+int key_cache_write(File file, my_off_t filepos, byte *buff, uint length,
+ uint block_length __attribute__((unused)),
+ int dont_write)
+{
+ reg1 SEC_LINK *next;
+ int error=0;
+
+ if (!dont_write)
+ { /* Forced write of buffer */
+ _my_cache_write++;
+ if (my_pwrite(file,buff,length,filepos,MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ return(1);
+ }
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("start of key_cache_write",1););
+#endif
+ if (_my_disk_blocks > 0)
+ { /* We have key_cacheing */
+ uint read_length;
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ _my_cache_w_requests++;
+ do
+ {
+ read_length= length > KEYCACHE_BLOCK_SIZE ? KEYCACHE_BLOCK_SIZE : length;
+ if (!(next=find_key_block(file,filepos,&error)))
+ goto end; /* Fatal error */
+ if (!dont_write) /* If we wrote buff at start */
+ {
+ if (next->changed) /* Unlink from changed list */
+ link_changed_to_file(next,next->file);
+ }
+ else if (!next->changed)
+ link_file_to_changed(next); /* Add to changed list */
+
+ if (!(read_length & 511))
+ bmove512(next->buffer,buff,read_length);
+ else
+ memcpy(next->buffer,buff,(size_t) read_length);
+ buff+=read_length;
+ filepos+=read_length;
+ } while ((length-= read_length));
+ error=0;
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ }
+ else if (dont_write)
+ { /* We must write, no cache */
+ _my_cache_w_requests++;
+ _my_cache_write++;
+ if (my_pwrite(file,(byte*) buff,length,filepos,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ error=1;
+ }
+end:
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("end of key_cache_write",1););
+#endif
+ return(error);
+} /* key_cache_write */
+
+
+ /* Find block in cache */
+ /* IF found sector and error is set then next->changed is cleared */
+
+static SEC_LINK *find_key_block(int file, my_off_t filepos, int *error)
+{
+ reg1 SEC_LINK *next,**start;
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("start of find_key_block",0););
+#endif
+
+ *error=0;
+ next= *(start= &_my_hash_root[((ulong) (filepos/KEYCACHE_BLOCK_SIZE)+(ulong) file) &
+ (_my_hash_blocks-1)]);
+ while (next && (next->diskpos != filepos || next->file != file))
+ next= next->next_hash;
+
+ if (next)
+ { /* Found block */
+ if (next != _my_used_last)
+ { /* Relink used-chain */
+ if (next == _my_used_first)
+ _my_used_first=next->next_used;
+ else
+ {
+ next->prev_used->next_used = next->next_used;
+ next->next_used->prev_used = next->prev_used;
+ }
+ next->prev_used=_my_used_last;
+ _my_used_last->next_used=next;
+ }
+ }
+ else
+ { /* New block */
+ if (_my_disk_blocks_used+1 <= (uint) _my_disk_blocks)
+ { /* There are unused blocks */
+ next= &_my_block_root[_my_blocks_used++]; /* Link in hash-chain */
+ next->buffer=ADD_TO_PTR(_my_block_mem,
+ (ulong) _my_disk_blocks_used*KEYCACHE_BLOCK_SIZE,byte*);
+ /* link first in file_blocks */
+ next->changed=0;
+ link_into_file_blocks(next,file);
+ _my_disk_blocks_used++;
+ if (!_my_used_first)
+ _my_used_first=next;
+ if (_my_used_last)
+ _my_used_last->next_used=next; /* Last in used-chain */
+ }
+ else
+ { /* Reuse old block */
+ next= _my_used_first;
+ if (next->changed)
+ {
+ if (my_pwrite(next->file,next->buffer,KEYCACHE_BLOCK_SIZE,next->diskpos,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ *error=1;
+ return((SEC_LINK*) 0);
+ }
+ _my_cache_write++;
+ link_changed_to_file(next,file);
+ }
+ else
+ {
+ if (next->file == -1)
+ link_into_file_blocks(next,file);
+ else
+ relink_into_file_blocks(next,file);
+ }
+ if (next->prev_hash) /* If in hash-link */
+ if ((*next->prev_hash=next->next_hash) != 0) /* Remove from link */
+ next->next_hash->prev_hash= next->prev_hash;
+
+ _my_used_last->next_used=next;
+ _my_used_first=next->next_used;
+ }
+ if (*start) /* Link in first in h.-chain */
+ (*start)->prev_hash= &next->next_hash;
+ next->next_hash= *start; next->prev_hash=start; *start=next;
+ next->prev_used=_my_used_last;
+ next->file=file;
+ next->diskpos=filepos;
+ *error=1; /* Block wasn't in memory */
+ }
+ _my_used_last=next;
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("end of find_key_block",0););
+#endif
+ return next;
+} /* find_key_block */
+
+
+static void free_block(SEC_LINK *used)
+{
+ used->file= -1;
+ if (used != _my_used_first) /* Relink used-chain */
+ {
+ if (used == _my_used_last)
+ _my_used_last=used->prev_used;
+ else
+ {
+ used->prev_used->next_used = used->next_used;
+ used->next_used->prev_used = used->prev_used;
+ }
+ used->next_used=_my_used_first;
+ used->next_used->prev_used=used;
+ _my_used_first=used;
+ }
+ if ((*used->prev_hash=used->next_hash)) /* Relink hash-chain */
+ used->next_hash->prev_hash= used->prev_hash;
+ if (used->next_changed) /* Relink changed/file list */
+ used->next_changed->prev_changed=used->prev_changed;
+ *used->prev_changed=used->next_changed;
+ used->prev_hash=0; used->next_hash=0; /* Safety */
+}
+
+
+ /* Flush all changed blocks to disk. Free used blocks if requested */
+
+static int cmp_sec_link(SEC_LINK **a, SEC_LINK **b)
+{
+ return (((*a)->diskpos < (*b)->diskpos) ? -1 :
+ ((*a)->diskpos > (*b)->diskpos) ? 1 : 0);
+}
+
+static int flush_cached_blocks(File file, SEC_LINK **cache, uint count)
+{
+ uint last_errno=0;
+ qsort((byte*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
+ for ( ; count-- ; cache++)
+ {
+ if (my_pwrite(file,(*cache)->buffer,KEYCACHE_BLOCK_SIZE,(*cache)->diskpos,
+ MYF(MY_NABP | MY_WAIT_IF_FULL)))
+ {
+ if (!last_errno)
+ last_errno=errno ? errno : -1;
+ }
+ }
+ return last_errno;
+}
+
+
+int flush_key_blocks(File file, enum flush_type type)
+{
+ int error=0,last_errno=0;
+ uint count=0;
+ SEC_LINK *cache_buff[FLUSH_CACHE],**cache,**pos,**end;
+ SEC_LINK *used,*next;
+ DBUG_ENTER("flush_key_blocks");
+ DBUG_PRINT("enter",("file: %d blocks_used: %d blocks_changed: %d",
+ file,_my_blocks_used,_my_blocks_changed));
+
+ pthread_mutex_lock(&THR_LOCK_keycache);
+
+#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
+ DBUG_EXECUTE("exec",test_key_cache("start of flush_key_blocks",0););
+#endif
+ cache=cache_buff; /* If no key cache */
+ if (_my_disk_blocks > 0 &&
+ (!my_disable_flush_key_blocks || type != FLUSH_KEEP))
+ {
+ if (type != FLUSH_IGNORE_CHANGED)
+ {
+ /* Count how many key blocks we have to cache to be able to
+ write everything with so few seeks as possible */
+
+ for (used=changed_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ used ;
+ used=used->next_changed)
+ {
+ if (used->file == file)
+ count++;
+ }
+ /* Only allocate a new buffer if its bigger than the one we have */
+ if (count <= FLUSH_CACHE ||
+ !(cache=(SEC_LINK**) my_malloc(sizeof(SEC_LINK*)*count,MYF(0))))
+ {
+ cache=cache_buff; /* Fall back to safe buffer */
+ count=FLUSH_CACHE;
+ }
+ end=cache+count;
+ }
+
+ /* Go through the keys and write them to buffer to be flushed */
+ end=(pos=cache)+count;
+ for (used=changed_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ used ;
+ used=next)
+ {
+ next=used->next_changed;
+ if (used->file == file)
+ {
+ if (type != FLUSH_IGNORE_CHANGED)
+ {
+ if (pos == end)
+ {
+ if ((error=flush_cached_blocks(file, cache, count)))
+ last_errno=error;
+ pos=cache;
+ }
+ *pos++=used;
+ _my_cache_write++;
+ }
+ if (type != FLUSH_KEEP && type != FLUSH_FORCE_WRITE)
+ {
+ /* This will not destroy position or data */
+ used->changed=0;
+ _my_blocks_changed--;
+ free_block(used);
+ }
+ else
+ link_changed_to_file(used,file);
+ }
+ }
+ if (pos != cache)
+ {
+ if ((error=flush_cached_blocks(file, cache, (uint) (pos-cache))))
+ last_errno=error;
+ }
+ /* The following happens very seldom */
+ if (type != FLUSH_KEEP && type != FLUSH_FORCE_WRITE)
+ {
+ for (used=file_blocks[(uint) file & CHANGED_BLOCKS_MASK];
+ used ;
+ used=next)
+ {
+ next=used->next_changed;
+ if (used->file == file && (!used->changed ||
+ type == FLUSH_IGNORE_CHANGED))
+ free_block(used);
+ }
+ }
+ }
+#ifndef DBUG_OFF
+ DBUG_EXECUTE("exec",test_key_cache("end of flush_key_blocks",0););
+#endif
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ if (cache != cache_buff)
+ my_free((gptr) cache,MYF(0));
+ if (last_errno)
+ errno=last_errno; /* Return first error */
+ DBUG_RETURN(last_errno != 0);
+} /* flush_key_blocks */
+
+
+#ifndef DBUG_OFF
+
+ /* Test if disk-cachee is ok */
+
+static void test_key_cache(char *where, my_bool lock)
+{
+ reg1 uint i,found,error,changed;
+ SEC_LINK *pos,**prev;
+
+ if (lock)
+ pthread_mutex_lock(&THR_LOCK_keycache);
+ found=error=0;
+ for (i= 0 ; i < _my_hash_blocks ; i++)
+ {
+
+ for (pos= *(prev= &_my_hash_root[i]) ;
+ pos && found < _my_blocks_used+2 ;
+ found++, pos= *(prev= &pos->next_hash))
+ {
+ if (prev != pos->prev_hash)
+ {
+ error=1;
+ DBUG_PRINT("error",
+ ("hash: %d pos: %lx : prev: %lx != pos->prev: %lx",
+ i,pos,prev,pos->prev_hash));
+ }
+
+ if (((pos->diskpos/KEYCACHE_BLOCK_SIZE)+pos->file) % _my_hash_blocks != i)
+ {
+ DBUG_PRINT("error",("hash: %d pos: %lx : Wrong disk_buffer %ld",
+ i,pos,pos->diskpos));
+ error=1;
+ }
+ }
+ }
+ if (found > _my_blocks_used)
+ {
+ DBUG_PRINT("error",("Found too many hash_pointers"));
+ error=1;
+ }
+ if (error && !_my_printed)
+ { /* Write all hash-pointers */
+ _my_printed=1;
+ for (i=0 ; i < _my_hash_blocks ; i++)
+ {
+ DBUG_PRINT("loop",("hash: %d _my_hash_root: %lx",i,&_my_hash_root[i]));
+ pos= _my_hash_root[i]; found=0;
+ while (pos && found < 10)
+ {
+ DBUG_PRINT("loop",("pos: %lx prev: %lx next: %lx file: %d disk_buffer: %ld", pos,pos->prev_hash,pos->next_hash,pos->file,pos->diskpos));
+ found++; pos= pos->next_hash;
+ }
+ }
+ }
+
+ found=changed=0;
+
+ if ((pos=_my_used_first))
+ {
+ while (pos != _my_used_last && found < _my_blocks_used+2)
+ {
+ found++;
+ if (pos->changed)
+ changed++;
+ if (pos->next_used->prev_used != pos)
+ {
+ DBUG_PRINT("error",("pos: %lx next_used: %lx next_used->prev: %lx",
+ pos,pos->next_used,pos->next_used->prev_hash));
+ error=1;
+ }
+ pos=pos->next_used;
+ }
+ found++;
+ if (pos->changed)
+ changed++;
+ }
+ if (found != _my_blocks_used)
+ {
+ DBUG_PRINT("error",("Found %d of %d keyblocks",found,_my_blocks_used));
+ error=1;
+ }
+
+ for (i= 0 ; i < CHANGED_BLOCKS_HASH ; i++)
+ {
+ found=0;
+ prev= &changed_blocks[i];
+ for (pos= *prev ; pos && found < _my_blocks_used+2; pos=pos->next_changed)
+ {
+ found++;
+ if (pos->prev_changed != prev)
+ {
+ DBUG_PRINT("error",("changed_block list %d doesn't point backwards properly",i));
+ error=1;
+ }
+ prev= &pos->next_changed;
+ if (((uint) pos->file & CHANGED_BLOCKS_MASK) != i)
+ {
+ DBUG_PRINT("error",("Wrong file %d in changed blocks: %d",pos->file,i));
+ error=1;
+ }
+ changed--;
+ }
+ if (pos)
+ {
+ DBUG_PRINT("error",("changed_blocks %d has recursive link",i));
+ error=1;
+ }
+
+ found=0;
+ prev= &file_blocks[i];
+ for (pos= *prev ; pos && found < _my_blocks_used+2; pos=pos->next_changed)
+ {
+ found++;
+ if (pos->prev_changed != prev)
+ {
+ DBUG_PRINT("error",("file_block list %d doesn't point backwards properly",i));
+ error=1;
+ }
+ prev= &pos->next_changed;
+ if (((uint) pos->file & CHANGED_BLOCKS_MASK) != i)
+ {
+ DBUG_PRINT("error",("Wrong file %d in file_blocks: %d",pos->file,i));
+ error=1;
+ }
+ }
+ if (pos)
+ {
+ DBUG_PRINT("error",("File_blocks %d has recursive link",i));
+ error=1;
+ }
+ }
+ if (changed != 0)
+ {
+ DBUG_PRINT("error",("Found %d blocks that wasn't in changed blocks",
+ changed));
+ error=1;
+ }
+ if (error)
+ DBUG_PRINT("error",("Found error at %s",where));
+ if (lock)
+ pthread_mutex_unlock(&THR_LOCK_keycache);
+ return;
+} /* test_key_cache */
+#endif
diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c
new file mode 100644
index 00000000000..641528b8b5d
--- /dev/null
+++ b/mysys/mf_loadpath.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Returns full load-path for a file. to may be = path */
+ /* if path is a hard-path return path */
+ /* if path starts with home-dir return path */
+ /* if path starts with current dir or parent-dir unpack path */
+ /* if there is no path, prepend with own_path_prefix if given */
+ /* else unpack path according to current dir */
+
+my_string my_load_path(my_string to, const char *path,
+ const char *own_path_prefix)
+{
+ char buff[FN_REFLEN];
+ DBUG_ENTER("my_load_path");
+ DBUG_PRINT("enter",("path: %s prefix: %s",path,
+ own_path_prefix ? own_path_prefix : ""));
+
+ if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) ||
+ test_if_hard_path(path))
+ VOID(strmov(buff,path));
+ else if ((path[0] == FN_CURLIB && path[1] == FN_LIBCHAR) ||
+ (is_prefix((gptr) path,FN_PARENTDIR) &&
+ path[strlen(FN_PARENTDIR)] == FN_LIBCHAR) ||
+ ! own_path_prefix)
+ {
+ if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0)))
+ VOID(strcat(buff,path));
+ else
+ VOID(strmov(buff,path));
+ }
+ else
+ VOID(strxmov(buff,own_path_prefix,path,NullS));
+ strmov(to,buff);
+ DBUG_PRINT("exit",("to: %s",to));
+ DBUG_RETURN(to);
+} /* my_load_path */
diff --git a/mysys/mf_pack.c b/mysys/mf_pack.c
new file mode 100644
index 00000000000..8aff6a3484a
--- /dev/null
+++ b/mysys/mf_pack.c
@@ -0,0 +1,528 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef VMS
+#include <rms.h>
+#include <iodef.h>
+#include <descrip.h>
+#endif /* VMS */
+
+static my_string NEAR_F expand_tilde(my_string *path);
+
+ /* Pack a dirname ; Changes HOME to ~/ and current dev to ./ */
+ /* from is a dirname (from dirname() ?) ending with FN_LIBCHAR */
+
+void pack_dirname(my_string to, const char *from)
+
+ /* to may be == from */
+{
+ int cwd_err;
+ uint d_length,length,buff_length;
+ my_string start;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("pack_dirname");
+
+ (void) intern_filename(to,from); /* Change to intern name */
+
+#ifdef FN_DEVCHAR
+ if ((start=strrchr(to,FN_DEVCHAR)) != 0) /* Skipp device part */
+ start++;
+ else
+#endif
+ start=to;
+
+ LINT_INIT(buff_length);
+ if (!(cwd_err= my_getwd(buff,FN_REFLEN,MYF(0))))
+ {
+ buff_length=strlen(buff);
+ d_length=(uint) (start-to);
+ if ((start == to ||
+ (buff_length == d_length && !bcmp(buff,start,d_length))) &&
+ *start != FN_LIBCHAR && *start)
+ { /* Put current dir before */
+ bchange(to,d_length,buff,buff_length,strlen(to)+1);
+ }
+ }
+
+ if ((d_length= cleanup_dirname(to,to)) != 0)
+ {
+ length=0;
+ if (home_dir)
+ {
+ length=strlen(home_dir);
+ if (home_dir[length-1] == FN_LIBCHAR)
+ length--; /* Don't test last '/' */
+ }
+ if (length > 1 && length < d_length)
+ { /* test if /xx/yy -> ~/yy */
+ if (bcmp(to,home_dir,length) == 0 && to[length] == FN_LIBCHAR)
+ {
+ to[0]=FN_HOMELIB; /* Filename begins with ~ */
+ (void) strmov_overlapp(to+1,to+length);
+ }
+ }
+ if (! cwd_err)
+ { /* Test if cwd is ~/... */
+ if (length > 1 && length < buff_length)
+ {
+ if (bcmp(buff,home_dir,length) == 0 && buff[length] == FN_LIBCHAR)
+ {
+ buff[0]=FN_HOMELIB;
+ (void) strmov_overlapp(buff+1,buff+length);
+ }
+ }
+ if (is_prefix(to,buff))
+ {
+ length=strlen(buff);
+ if (to[length])
+ (void) strmov_overlapp(to,to+length); /* Remove everything before */
+ else
+ {
+ to[0]= FN_CURLIB; /* Put ./ instead of cwd */
+ to[1]= FN_LIBCHAR;
+ to[2]= '\0';
+ }
+ }
+ }
+ }
+ DBUG_PRINT("exit",("to: '%s'",to));
+ DBUG_VOID_RETURN;
+} /* pack_dirname */
+
+
+ /* remove unwanted chars from dirname */
+ /* if "/../" removes prev dir; "/~/" removes all before ~ */
+ /* "//" is same as "/", except on Win32 at start of a file */
+ /* "/./" is removed */
+ /* Unpacks home_dir if "~/.." used */
+ /* Unpacks current dir if if "./.." used */
+
+uint cleanup_dirname(register my_string to, const char *from)
+ /* to may be == from */
+
+{
+ reg5 uint length;
+ reg2 my_string pos;
+ reg3 my_string from_ptr;
+ reg4 my_string start;
+ char parent[5], /* for "FN_PARENTDIR" */
+ buff[FN_REFLEN+1],*end_parentdir;
+ DBUG_ENTER("cleanup_dirname");
+ DBUG_PRINT("enter",("from: '%s'",from));
+
+ start=buff;
+ from_ptr=(my_string) from;
+#ifdef FN_DEVCHAR
+ if ((pos=strrchr(from_ptr,FN_DEVCHAR)) != 0)
+ { /* Skipp device part */
+ length=(uint) (pos-from_ptr)+1;
+ start=strnmov(buff,from_ptr,length); from_ptr+=length;
+ }
+#endif
+
+ parent[0]=FN_LIBCHAR;
+ length=(uint) (strmov(parent+1,FN_PARENTDIR)-parent);
+ for (pos=start ; (*pos= *from_ptr++) != 0 ; pos++)
+ {
+ if (*pos == '/')
+ *pos = FN_LIBCHAR;
+ if (*pos == FN_LIBCHAR)
+ {
+ if ((uint) (pos-start) > length && bcmp(pos-length,parent,length) == 0)
+ { /* If .../../; skipp prev */
+ pos-=length;
+ if (pos != start)
+ { /* not /../ */
+ pos--;
+ if (*pos == FN_HOMELIB && (pos == start || pos[-1] == FN_LIBCHAR))
+ {
+ if (!home_dir)
+ {
+ pos+=length+1; /* Don't unpack ~/.. */
+ continue;
+ }
+ pos=strmov(buff,home_dir)-1; /* Unpacks ~/.. */
+ if (*pos == FN_LIBCHAR)
+ pos--; /* home ended with '/' */
+ }
+ if (*pos == FN_CURLIB && (pos == start || pos[-1] == FN_LIBCHAR))
+ {
+ if (my_getwd(curr_dir,FN_REFLEN,MYF(0)))
+ {
+ pos+=length+1; /* Don't unpack ./.. */
+ continue;
+ }
+ pos=strmov(buff,curr_dir)-1; /* Unpacks ./.. */
+ if (*pos == FN_LIBCHAR)
+ pos--; /* home ended with '/' */
+ }
+ end_parentdir=pos;
+ while (pos >= start && *pos != FN_LIBCHAR) /* remove prev dir */
+ pos--;
+ if (pos[1] == FN_HOMELIB || bcmp(pos,parent,length) == 0)
+ { /* Don't remove ~user/ */
+ pos=strmov(end_parentdir+1,parent);
+ *pos=FN_LIBCHAR;
+ continue;
+ }
+ }
+ }
+ else if ((uint) (pos-start) == length-1 &&
+ !bcmp(start,parent+1,length-1))
+ start=pos; /* Starts with "../" */
+ else if (pos-start > 0 && pos[-1] == FN_LIBCHAR)
+ {
+#ifdef FN_NETWORK_DRIVES
+ if (pos-start != 1)
+#endif
+ pos--; /* Remove dupplicate '/' */
+ }
+ else if (pos-start > 1 && pos[-1] == FN_CURLIB && pos[-2] == FN_LIBCHAR)
+ pos-=2; /* Skipp /./ */
+ else if (pos > buff+1 && pos[-1] == FN_HOMELIB && pos[-2] == FN_LIBCHAR)
+ { /* Found ..../~/ */
+ buff[0]=FN_HOMELIB;
+ buff[1]=FN_LIBCHAR;
+ start=buff; pos=buff+1;
+ }
+ }
+ }
+ (void) strmov(to,buff);
+ DBUG_PRINT("exit",("to: '%s'",to));
+ DBUG_RETURN((uint) (pos-buff));
+} /* cleanup_dirname */
+
+
+ /*
+ On system where you don't have symbolic links, the following
+ code will allow you to create a file:
+ directory-name.lnk that should contain the real path
+ to the directory. This will be used if the directory name
+ doesn't exists
+ */
+
+
+my_bool my_use_symdir=0; /* Set this if you want to use symdirs */
+
+#ifdef USE_SYMDIR
+void symdirget(char *dir)
+{
+ char buff[FN_REFLEN];
+ char *pos=strend(dir);
+ if (dir[0] && pos[-1] != FN_DEVCHAR && access(dir, F_OK))
+ {
+ FILE *fp;
+ char temp= *(--pos); /* May be "/" or "\" */
+ strmov(pos,".sym");
+ fp = my_fopen(dir, O_RDONLY,MYF(0));
+ *pos++=temp; *pos=0; /* Restore old filename */
+ if (fp)
+ {
+ if (fgets(buff, sizeof(buff), fp))
+ {
+ for (pos=strend(buff);
+ pos > buff && (iscntrl(pos[-1]) || isspace(pos[-1])) ;
+ pos --);
+ strmake(dir,buff, (uint) (pos-buff));
+ }
+ my_fclose(fp,MYF(0));
+ }
+ }
+}
+#endif /* USE_SYMDIR */
+
+ /* Unpacks dirname to name that can be used by open... */
+ /* Make that last char of to is '/' if from not empty and
+ from doesn't end in FN_DEVCHAR */
+ /* Uses cleanup_dirname and changes ~/.. to home_dir/.. */
+ /* Returns length of new directory */
+
+uint unpack_dirname(my_string to, const char *from)
+
+ /* to may be == from */
+{
+ uint length,h_length;
+ char buff[FN_REFLEN+1+4],*suffix,*tilde_expansion;
+ DBUG_ENTER("unpack_dirname");
+
+ (void) intern_filename(buff,from); /* Change to intern name */
+ length=strlen(buff); /* Fix that '/' is last */
+ if (length &&
+#ifdef FN_DEVCHAR
+ buff[length-1] != FN_DEVCHAR &&
+#endif
+ buff[length-1] != FN_LIBCHAR && buff[length-1] != '/')
+ {
+ buff[length]=FN_LIBCHAR;
+ buff[length+1]= '\0';
+ }
+
+ length=cleanup_dirname(buff,buff);
+ if (buff[0] == FN_HOMELIB)
+ {
+ suffix=buff+1; tilde_expansion=expand_tilde(&suffix);
+ if (tilde_expansion)
+ {
+ length-=(uint) (suffix-buff)-1;
+ if (length+(h_length=strlen(tilde_expansion)) <= FN_REFLEN)
+ {
+ if (tilde_expansion[h_length-1] == FN_LIBCHAR)
+ h_length--;
+ if (buff+h_length < suffix)
+ bmove(buff+h_length,suffix,length);
+ else
+ bmove_upp(buff+h_length+length,suffix+length,length);
+ bmove(buff,tilde_expansion,h_length);
+ }
+ }
+ }
+#ifdef USE_SYMDIR
+ if (my_use_symdir)
+ symdirget(buff);
+#endif
+ DBUG_RETURN(system_filename(to,buff)); /* Fix for open */
+} /* unpack_dirname */
+
+
+ /* Expand tilde to home or user-directory */
+ /* Path is reset to point at FN_LIBCHAR after ~xxx */
+
+static my_string NEAR_F expand_tilde(my_string *path)
+{
+ if (path[0][0] == FN_LIBCHAR)
+ return home_dir; /* ~/ expanded to home */
+#ifdef HAVE_GETPWNAM
+ {
+ char *str,save;
+ struct passwd *user_entry;
+
+ if (!(str=strchr(*path,FN_LIBCHAR)))
+ str=strend(*path);
+ save= *str; *str= '\0';
+ user_entry=getpwnam(*path);
+ *str=save;
+ endpwent();
+ if (user_entry)
+ {
+ *path=str;
+ return user_entry->pw_dir;
+ }
+ }
+#endif
+ return (my_string) 0;
+}
+
+ /* fix filename so it can be used by open, create .. */
+ /* to may be == from */
+ /* Returns to */
+
+my_string unpack_filename(my_string to, const char *from)
+{
+ uint length,n_length;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("unpack_filename");
+
+ length=dirname_part(buff,from); /* copy & convert dirname */
+ n_length=unpack_dirname(buff,buff);
+ if (n_length+strlen(from+length) < FN_REFLEN)
+ {
+ (void) strmov(buff+n_length,from+length);
+ (void) system_filename(to,buff); /* Fix to usably filename */
+ }
+ else
+ (void) system_filename(to,from); /* Fix to usably filename */
+ DBUG_RETURN(to);
+} /* unpack_filename */
+
+
+ /* Convert filename (unix standard) to system standard */
+ /* Used before system command's like open(), create() .. */
+ /* Returns to */
+
+uint system_filename(my_string to, const char *from)
+{
+#ifndef FN_C_BEFORE_DIR
+ return (uint) (strmake(to,from,FN_REFLEN-1)-to);
+#else /* VMS */
+
+ /* change 'dev:lib/xxx' to 'dev:[lib]xxx' */
+ /* change 'dev:xxx' to 'dev:xxx' */
+ /* change './xxx' to 'xxx' */
+ /* change './lib/' or lib/ to '[.lib]' */
+ /* change '/x/y/z to '[x.y]x' */
+ /* change 'dev:/x' to 'dev:[000000]x' */
+
+ int libchar_found,length;
+ my_string to_pos,from_pos,pos;
+ char buff[FN_REFLEN];
+ DBUG_ENTER("system_filename");
+
+ libchar_found=0;
+ (void) strmov(buff,from); /* If to == from */
+ from_pos= buff;
+ if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
+ {
+ pos++;
+ to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+ from_pos=pos;
+ }
+ else
+ to_pos=to;
+
+ if (from_pos[0] == FN_CURLIB && from_pos[1] == FN_LIBCHAR)
+ from_pos+=2; /* Skipp './' */
+ if (strchr(from_pos,FN_LIBCHAR))
+ {
+ *(to_pos++) = FN_C_BEFORE_DIR;
+ if (strinstr(from_pos,FN_ROOTDIR) == 1)
+ {
+ from_pos+=strlen(FN_ROOTDIR); /* Actually +1 but... */
+ if (! strchr(from_pos,FN_LIBCHAR))
+ { /* No dir, use [000000] */
+ to_pos=strmov(to_pos,FN_C_ROOT_DIR);
+ libchar_found++;
+ }
+ }
+ else
+ *(to_pos++)=FN_C_DIR_SEP; /* '.' gives current dir */
+
+ while ((pos=strchr(from_pos,FN_LIBCHAR)))
+ {
+ if (libchar_found++)
+ *(to_pos++)=FN_C_DIR_SEP; /* Add '.' between dirs */
+ if (strinstr(from_pos,FN_PARENTDIR) == 1 &&
+ from_pos+strlen(FN_PARENTDIR) == pos)
+ to_pos=strmov(to_pos,FN_C_PARENT_DIR); /* Found '../' */
+ else
+ to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
+ from_pos=pos+1;
+ }
+ *(to_pos++)=FN_C_AFTER_DIR;
+ }
+ length=(int) (strmov(to_pos,from_pos)-to);
+ DBUG_PRINT("exit",("name: '%s'",to));
+ DBUG_RETURN((uint) length);
+#endif
+} /* system_filename */
+
+
+ /* Fix a filename to intern (UNIX format) */
+
+my_string intern_filename(my_string to, const char *from)
+{
+#ifndef VMS
+ {
+ uint length;
+ char buff[FN_REFLEN];
+ if (from == to)
+ { /* Dirname may destroy from */
+ strmov(buff,from);
+ from=buff;
+ }
+ length=dirname_part(to,from); /* Copy dirname & fix chars */
+ (void) strcat(to,from+length);
+ return (to);
+ }
+#else /* VMS */
+
+ /* change 'dev:[lib]xxx' to 'dev:lib/xxx' */
+ /* change 'dev:xxx' to 'dev:xxx' */
+ /* change 'dev:x/y/[.lib]' to 'dev:x/y/lib/ */
+ /* change '[.lib]' to './lib/' */
+ /* change '[x.y]' or '[x.][y]' or '[x][.y]' to '/x/y/' */
+ /* change '[000000.x] or [x.000000]' to '/x/' */
+
+ int par_length,root_length;
+ my_string pos,from_pos,to_pos,end_pos;
+ char buff[FN_REFLEN];
+
+ (void) strmov(buff,from);
+ convert_dirname(buff); /* change '<>' to '[]' */
+ from_pos=buff;
+ if ((pos=strrchr(from_pos,FN_DEVCHAR))) /* Skipp device part */
+ {
+ pos++;
+ to_pos=strnmov(to,from_pos,(size_s) (pos-from_pos));
+ from_pos=pos;
+ }
+ else
+ to_pos=to;
+
+ root_length=strlen(FN_C_ROOT_DIR);
+ if ((pos = strchr(from_pos,FN_C_BEFORE_DIR)) &&
+ (end_pos = strrchr(pos+1,FN_C_AFTER_DIR)))
+ {
+ to_pos=strnmov(to_pos,from_pos,(size_s) (pos-from_pos));
+ /* Copy all between ':' and '[' */
+ from_pos=pos+1;
+ if (strinstr(from_pos,FN_C_ROOT_DIR) == 1 &&
+ (from_pos[root_length] == FN_C_DIR_SEP ||
+ from_pos[root_length] == FN_C_AFTER_DIR))
+ {
+ from_pos+=root_length+1;
+ }
+ else if (*from_pos == FN_C_DIR_SEP)
+ *(to_pos++) = FN_CURLIB; /* Set ./ first */
+ *(to_pos++) = FN_LIBCHAR;
+
+ par_length=strlen(FN_C_PARENT_DIR);
+ pos=to_pos;
+ for (; from_pos <= end_pos ; from_pos++)
+ {
+ switch (*from_pos) {
+ case FN_C_DIR_SEP:
+ case FN_C_AFTER_DIR:
+ if (pos != to_pos)
+ {
+ if ((int) (to_pos-pos) == root_length &&
+ is_suffix(pos,FN_C_ROOT_DIR))
+ to_pos=pos; /* remove root-pos */
+ else
+ {
+ *(to_pos++)=FN_LIBCHAR; /* Find lib */
+ pos=to_pos;
+ }
+ }
+ break;
+ case FN_C_BEFORE_DIR:
+ break;
+ case '-': /* *(FN_C_PARENT_DIR): */
+ if (to_pos[-1] == FN_LIBCHAR &&
+ strncmp(from_pos,FN_C_PARENT_DIR,par_length) == 0)
+ { /* Change '-' to '..' */
+ to_pos=strmov(to_pos,FN_PARENTDIR);
+ *(to_pos++)=FN_LIBCHAR;
+ pos=to_pos;
+ from_pos+=par_length-1;
+ break;
+ }
+ /* Fall through */
+ default:
+ *(to_pos++)= *from_pos;
+ break;
+ }
+ }
+ }
+ (void) strmov(to_pos,from_pos);
+ return (to);
+#endif /* VMS */
+} /* intern_filename */
diff --git a/mysys/mf_pack2.c b/mysys/mf_pack2.c
new file mode 100644
index 00000000000..1cda7797457
--- /dev/null
+++ b/mysys/mf_pack2.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Pack a filename for output on screen */
+ /* Changes long paths to .../ */
+ /* Removes pathname and extension */
+ /* If not possibly to pack returns '?' in to and returns 1*/
+
+int pack_filename(my_string to, const char *name, size_s max_length)
+ /* to may be name */
+
+{
+ int i;
+ char buff[FN_REFLEN];
+
+ if (strlen(fn_format(to,name,"","",0)) <= max_length)
+ return 0;
+ if (strlen(fn_format(to,name,"","",8)) <= max_length)
+ return 0;
+ if (strlen(fn_format(buff,name,".../","",1)) <= max_length)
+ {
+ VOID(strmov(to,buff));
+ return 0;
+ }
+ for (i= 0 ; i < 3 ; i++)
+ {
+ if (strlen(fn_format(buff,to,"","", i == 0 ? 2 : i == 1 ? 1 : 3 ))
+ <= max_length)
+ {
+ VOID(strmov(to,buff));
+ return 0;
+ }
+ }
+ to[0]='?'; to[1]=0; /* Can't pack filename */
+ return 1;
+} /* pack_filename */
diff --git a/mysys/mf_path.c b/mysys/mf_path.c
new file mode 100644
index 00000000000..0a0a760cea1
--- /dev/null
+++ b/mysys/mf_path.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+static char *find_file_in_path(char *to,const char *name);
+
+ /* Finds where program can find it's files.
+ pre_pathname is found by first locking at progname (argv[0]).
+ if progname contains path the path is returned.
+ else if progname is found in path, return it
+ else if progname is given and POSIX environment variable "_" is set
+ then path is taken from "_".
+ If filename doesn't contain a path append MY_BASEDIR_VERSION or
+ MY_BASEDIR if defined, else append "/my/running".
+ own_path_name_part is concatinated to result.
+ my_path puts result in to and returns to */
+
+my_string my_path(my_string to, const char *progname,
+ const char *own_pathname_part)
+{
+ my_string start,end,prog;
+ DBUG_ENTER("my_path");
+
+ start=to; /* Return this */
+ if (progname && (dirname_part(to, progname) ||
+ find_file_in_path(to,progname) ||
+ ((prog=getenv("_")) != 0 && dirname_part(to,prog))))
+ {
+ VOID(intern_filename(to,to));
+ if (!test_if_hard_path(to))
+ {
+ if (!my_getwd(curr_dir,FN_REFLEN,MYF(0)))
+ bchange(to,0,curr_dir,strlen(curr_dir),strlen(to)+1);
+ }
+ }
+ else
+ {
+ if ((end = getenv("MY_BASEDIR_VERSION")) == 0 &&
+ (end = getenv("MY_BASEDIR")) == 0)
+ {
+#ifdef DEFAULT_BASEDIR
+ end= (char*) DEFAULT_BASEDIR;
+#else
+ end= (char*) "/my/";
+#endif
+ }
+ VOID(intern_filename(to,end));
+ to=strend(to);
+ if (to != start && to[-1] != FN_LIBCHAR)
+ *to++ = FN_LIBCHAR;
+ VOID(strmov(to,own_pathname_part));
+ }
+ DBUG_PRINT("exit",("to: '%s'",start));
+ DBUG_RETURN(start);
+} /* my_path */
+
+
+ /* test if file without filename is found in path */
+ /* Returns to if found and to has dirpart if found, else NullS */
+
+#if defined(MSDOS) || defined(__WIN__)
+#define F_OK 0
+#define PATH_SEP ';'
+#define PROGRAM_EXTENSION ".exe"
+#else
+#define PATH_SEP ':'
+#endif
+
+static char *find_file_in_path(char *to, const char *name)
+{
+ char *path,*pos,dir[2];
+ const char *ext="";
+
+ if (!(path=getenv("PATH")))
+ return NullS;
+ dir[0]=FN_LIBCHAR; dir[1]=0;
+#ifdef PROGRAM_EXTENSION
+ if (!fn_ext(name)[0])
+ ext=PROGRAM_EXTENSION;
+#endif
+
+ for (pos=path ; (pos=strchr(pos,PATH_SEP)) ; path= ++pos)
+ {
+ if (path != pos)
+ {
+ strxmov(strnmov(to,path,(uint) (pos-path)),dir,name,ext,NullS);
+ if (!access(to,F_OK))
+ {
+ to[(uint) (pos-path)+1]=0; /* Return path only */
+ return to;
+ }
+ }
+ }
+#ifdef __WIN__
+ to[0]=FN_CURLIB;
+ strxmov(to+1,dir,name,ext,NullS);
+ if (!access(to,F_OK)) /* Test in current dir */
+ {
+ to[2]=0; /* Leave ".\" */
+ return to;
+ }
+#endif
+ return NullS; /* File not found */
+}
diff --git a/mysys/mf_qsort.c b/mysys/mf_qsort.c
new file mode 100644
index 00000000000..15fa5638639
--- /dev/null
+++ b/mysys/mf_qsort.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Plug-compatible replacement for UNIX qsort.
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu)
+ Optimized and modyfied for mysys by monty.
+
+This file is part of GNU CC.
+
+GNU QSORT is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU QSORT is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU QSORT; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "mysys_priv.h"
+#if !defined(HAVE_purify) || defined(QSORT_EXTRA_CMP_ARGUMENT)
+
+/* Envoke the comparison function, returns either 0, < 0, or > 0. */
+#ifdef QSORT_EXTRA_CMP_ARGUMENT
+#define CMP(A,B) ((*cmp)(cmp_argument,(A),(B)))
+#else
+#define CMP(A,B) ((*cmp)((A),(B)))
+#endif
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(A,B,SIZE) do {int sz=(int)(SIZE); char *a = (A); char *b = (B); \
+ do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0)
+
+/* Copy SIZE bytes from item B to item A. */
+#define COPY(A,B,SIZE) {int sz = (int) (SIZE); do { *(A)++ = *(B)++; } while (--sz); }
+
+/* This should be replaced by a standard ANSI macro. */
+#define BYTES_PER_WORD 8
+
+/* The next 4 #defines implement a very fast in-line stack abstraction. */
+#define STACK_SIZE (BYTES_PER_WORD * sizeof (long))
+#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
+#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
+#define STACK_NOT_EMPTY (stack < top)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sparc SLC. */
+#define MAX_THRESH 12
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+{
+ char *lo;
+ char *hi;
+} stack_node;
+
+/* Order size using quicksort. This implementation incorporates
+ four optimizations discussed in Sedgewick:
+
+ 1. Non-recursive, using an explicit stack of pointer that store the
+ next array partition to sort. To save time, this maximum amount
+ of space required to store an array of MAX_INT is allocated on the
+ stack. Assuming a 32-bit integer, this needs only 32 *
+ sizeof (stack_node) == 136 bits. Pretty cheap, actually.
+
+ 2. Chose the pivot element using a median-of-three decision tree.
+ This reduces the probability of selecting a bad pivot value and
+ eliminates certain extraneous comparisons.
+
+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+ insertion sort to order the MAX_THRESH items within each partition.
+ This is a big win, since insertion sort is faster for small, mostly
+ sorted array segements.
+
+ 4. The larger of the two sub-partitions is always pushed onto the
+ stack first, with the algorithm then concentrating on the
+ smaller partition. This *guarantees* no more than log (n)
+ stack size is needed (actually O(1) in this case)! */
+
+#if defined(QSORT_TYPE_IS_VOID)
+#define SORT_RETURN return
+#else
+#define SORT_RETURN return 0
+#endif
+
+#ifdef QSORT_EXTRA_CMP_ARGUMENT
+qsort_t qsort2(void *base_ptr, size_t total_elems, size_t size, qsort2_cmp cmp,
+ void *cmp_argument)
+#else
+qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
+#endif
+{
+ /* Allocating SIZE bytes for a pivot buffer facilitates a better
+ algorithm below since we can do comparisons directly on the pivot.
+ */
+ int max_thresh = (int) (MAX_THRESH * size);
+ if (total_elems <= 1)
+ SORT_RETURN; /* Crashes on MSDOS if continues */
+
+ if (total_elems > MAX_THRESH)
+ {
+ char *lo = base_ptr;
+ char *hi = lo + size * (total_elems - 1);
+ stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
+ stack_node *top = stack + 1;
+ char *pivot_buffer = (char *) my_alloca ((int) size);
+
+ while (STACK_NOT_EMPTY)
+ {
+ char *left_ptr;
+ char *right_ptr;
+ {
+ char *pivot = pivot_buffer;
+ {
+ /* Select median value from among LO, MID, and HI. Rearrange
+ LO and HI so the three values are sorted. This lowers the
+ probability of picking a pathological pivot value and
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
+
+ char *mid = lo + size * (((uint) (hi - lo) / (uint) size) >> 1);
+
+ if (CMP(hi,lo) < 0)
+ SWAP (hi, lo, size);
+ if (CMP (mid, lo) < 0)
+ SWAP (mid, lo, size);
+ else if (CMP (hi, mid) < 0)
+ SWAP (mid, hi, size);
+ COPY (pivot, mid, size);
+ pivot = pivot_buffer;
+ }
+ left_ptr = lo + size;
+ right_ptr = hi - size;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do
+ {
+ while (CMP (left_ptr, pivot) < 0)
+ left_ptr += size;
+
+ while (CMP (pivot, right_ptr) < 0)
+ right_ptr -= size;
+
+ if (left_ptr < right_ptr)
+ {
+ SWAP (left_ptr, right_ptr, size);
+ left_ptr += size;
+ right_ptr -= size;
+ }
+ else if (left_ptr == right_ptr)
+ {
+ left_ptr += size;
+ right_ptr -= size;
+ break;
+ }
+ }
+ while (left_ptr <= right_ptr);
+ }
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((right_ptr - lo) <= max_thresh)
+ {
+ if ((hi - left_ptr) <= max_thresh) /* Ignore both small parts. */
+ POP (lo, hi);
+ else /* Ignore small left part. */
+ lo = left_ptr;
+ }
+ else if ((hi - left_ptr) <= max_thresh) /* Ignore small right part. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left part */
+ {
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else /* Push larger right part */
+ {
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ my_afree(pivot_buffer);
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ char *end_ptr = (char*) base_ptr + size * (total_elems - 1);
+ char *run_ptr;
+ char *tmp_ptr = (char*) base_ptr;
+ char *thresh = min (end_ptr, (char*) base_ptr + max_thresh);
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+ if (CMP (run_ptr, tmp_ptr) < 0)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != (char*) base_ptr)
+ SWAP (tmp_ptr, (char*) base_ptr, size);
+
+ /* Insertion sort, running from left-hand-side up to `right-hand-side.'
+ Pretty much straight out of the original GNU qsort routine. */
+
+ for (run_ptr = (char*) base_ptr + size;
+ (tmp_ptr = run_ptr += size) <= end_ptr; )
+ {
+ while (CMP (run_ptr, tmp_ptr -= size) < 0) ;
+
+ if ((tmp_ptr += size) != run_ptr)
+ {
+ char *trav;
+
+ for (trav = run_ptr + size; --trav >= run_ptr;)
+ {
+ char c = *trav;
+ char *hi, *lo;
+
+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+ *hi = *lo;
+ *hi = c;
+ }
+ }
+
+ }
+ }
+ SORT_RETURN;
+}
+#endif /* HAVE_purify */
diff --git a/mysys/mf_qsort2.c b/mysys/mf_qsort2.c
new file mode 100644
index 00000000000..7b1ca4e39ab
--- /dev/null
+++ b/mysys/mf_qsort2.c
@@ -0,0 +1,21 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* qsort that sends one extra argument to the compare subrutine */
+
+#define QSORT_EXTRA_CMP_ARGUMENT
+#include "mf_qsort.c"
diff --git a/mysys/mf_radix.c b/mysys/mf_radix.c
new file mode 100644
index 00000000000..99aa4d0b073
--- /dev/null
+++ b/mysys/mf_radix.c
@@ -0,0 +1,56 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Radixsort for pointers to fixed length strings.
+ A very quick sort for not to long (< 20 char) strings.
+ Neads a extra buffers of number_of_elements pointers but is
+ 2-3 times faster than quicksort
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Radixsort */
+
+void radixsort_for_str_ptr(uchar **base, uint number_of_elements, size_s size_of_element, uchar **buffer)
+{
+ uchar **end,**ptr,**buffer_ptr;
+ uint32 *count_ptr,*count_end,count[256];
+ int pass;
+
+ end=base+number_of_elements; count_end=count+256;
+ for (pass=(int) size_of_element-1 ; pass >= 0 ; pass--)
+ {
+ bzero((gptr) count,sizeof(uint32)*256);
+ for (ptr= base ; ptr < end ; ptr++)
+ count[ptr[0][pass]]++;
+ if (count[0] == number_of_elements)
+ goto next;
+ for (count_ptr=count+1 ; count_ptr < count_end ; count_ptr++)
+ {
+ if (*count_ptr == number_of_elements)
+ goto next;
+ (*count_ptr)+= *(count_ptr-1);
+ }
+ for (ptr= end ; ptr-- != base ;)
+ buffer[--count[ptr[0][pass]]]= *ptr;
+ for (ptr=base, buffer_ptr=buffer ; ptr < end ;)
+ (*ptr++) = *buffer_ptr++;
+ next:;
+ }
+}
diff --git a/mysys/mf_same.c b/mysys/mf_same.c
new file mode 100644
index 00000000000..5b8c5ecf970
--- /dev/null
+++ b/mysys/mf_same.c
@@ -0,0 +1,38 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Kopierar biblioteksstrukturen och extensionen fr}n ett filnamn */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Formaterar ett filnamn i avsende p} ett annat namn */
+ /* Klarar {ven to = name */
+ /* Denna funktion r|r inte p} utg}ngsnamnet */
+
+my_string fn_same(my_string toname, const char *name, int flag)
+{
+ char dev[FN_REFLEN];
+ const char *ext;
+ DBUG_ENTER("fn_same");
+ DBUG_PRINT("mfunkt",("to: %s name: %s flag: %d",toname,name,flag));
+
+ if ((ext=strrchr(name+dirname_part(dev,name),FN_EXTCHAR)) == 0)
+ ext="";
+
+ DBUG_RETURN(fn_format(toname,toname,dev,ext,flag));
+} /* fn_same */
diff --git a/mysys/mf_sleep.c b/mysys/mf_sleep.c
new file mode 100644
index 00000000000..f33a904cf5a
--- /dev/null
+++ b/mysys/mf_sleep.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Wait a given time (On systems that dont have sleep !!; MSDOS) */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+#ifdef _MSC_VER
+
+void sleep(sec)
+int sec;
+{
+ ulong start;
+ DBUG_ENTER("sleep");
+
+ start=(ulong) time((time_t*) 0);
+ while ((ulong) time((time_t*) 0) < start+sec);
+ DBUG_VOID_RETURN;
+} /* sleep */
+
+#endif /* MSDOS */
diff --git a/mysys/mf_sort.c b/mysys/mf_sort.c
new file mode 100644
index 00000000000..754a1deb1a7
--- /dev/null
+++ b/mysys/mf_sort.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Sort of string pointers in string-order with radix or qsort */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+void my_string_ptr_sort(void *base, uint items, size_s size)
+{
+#if INT_MAX > 65536L
+ uchar **ptr=0;
+
+ if (size <= 20 && items >= 1000 &&
+ (ptr= (uchar**) my_malloc(items*sizeof(char*),MYF(0))))
+ {
+ radixsort_for_str_ptr((uchar**) base,items,size,ptr);
+ my_free((gptr) ptr,MYF(0));
+ }
+ else
+#endif
+ {
+ if (size && items)
+ {
+ uint size_arg=size;
+ qsort2(base,items,sizeof(byte*),get_ptr_compare(size),(void*) &size_arg);
+ }
+ }
+}
diff --git a/mysys/mf_soundex.c b/mysys/mf_soundex.c
new file mode 100644
index 00000000000..827385a1466
--- /dev/null
+++ b/mysys/mf_soundex.c
@@ -0,0 +1,102 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/****************************************************************
+* SOUNDEX ALGORITHM in C *
+* *
+* The basic Algorithm source is taken from EDN Nov. *
+* 14, 1985 pg. 36. *
+* *
+* As a test Those in Illinois will find that the *
+* first group of numbers in their drivers license *
+* number is the soundex number for their last name. *
+* *
+* RHW PC-IBBS ID. #1230 *
+* *
+* As an extension if remove_garbage is set then all non- *
+* alpha characters are skipped *
+****************************************************************/
+
+#include "mysys_priv.h"
+#include <m_ctype.h>
+#include "my_static.h"
+
+static char get_scode(char **ptr,pbool remove_garbage);
+
+ /* outputed string is 4 byte long */
+ /* out_pntr can be == in_pntr */
+
+void soundex(register my_string out_pntr, my_string in_pntr,
+ pbool remove_garbage)
+{
+ char ch,last_ch;
+ reg3 my_string end;
+
+ if (remove_garbage)
+ {
+ while (*in_pntr && isspace(*in_pntr)) /* Skipp pre-space */
+ in_pntr++;
+ }
+ *out_pntr++ = toupper(*in_pntr); /* Copy first letter */
+ last_ch = get_scode(&in_pntr,0); /* code of the first letter */
+ /* for the first 'double-letter */
+ /* check. */
+ end=out_pntr+3; /* Loop on input letters until */
+ /* end of input (null) or output */
+ /* letter code count = 3 */
+
+ in_pntr++;
+ while (out_pntr < end && (ch = get_scode(&in_pntr,remove_garbage)) != 0)
+ {
+ in_pntr++;
+ if ((ch != '0') && (ch != last_ch)) /* if not skipped or double */
+ {
+ *out_pntr++ = ch; /* letter, copy to output */
+ } /* for next double-letter check */
+ last_ch = ch; /* save code of last input letter */
+ }
+ while (out_pntr < end)
+ *out_pntr++ = '0';
+ *out_pntr=0; /* end string */
+ return;
+} /* soundex */
+
+
+ /*
+ If alpha, map input letter to soundex code.
+ If not alpha and remove_garbage is set then skipp to next char
+ else return 0
+ */
+
+static char get_scode(char **ptr, pbool remove_garbage)
+{
+ uchar ch;
+
+ if (remove_garbage)
+ {
+ while (**ptr && !isalpha(**ptr))
+ (*ptr)++;
+ }
+ ch=toupper(**ptr);
+ if (ch < 'A' || ch > 'Z')
+ {
+ if (isalpha(ch)) /* If exetended alfa (country spec) */
+ return '0'; /* threat as vokal */
+ return 0; /* Can't map */
+ }
+ return(soundex_map[ch-'A']);
+} /* get_scode */
diff --git a/mysys/mf_stripp.c b/mysys/mf_stripp.c
new file mode 100644
index 00000000000..6ebdce4cff6
--- /dev/null
+++ b/mysys/mf_stripp.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* T|mmer en str{ng p{ slut_space */
+
+#include "mysys_priv.h"
+
+/*
+ stripp_sp(my_string str)
+ Strips end-space from string and returns new length.
+*/
+
+size_s stripp_sp(register my_string str)
+{
+ reg2 my_string found;
+ reg3 my_string start;
+
+ start=found=str;
+
+ while (*str)
+ {
+ if (*str != ' ')
+ {
+ while (*++str && *str != ' ') {};
+ if (!*str)
+ return (size_s) (str-start); /* Return stringlength */
+ }
+ found=str;
+ while (*++str == ' ') {};
+ }
+ *found= '\0'; /* Stripp at first space */
+ return (size_s) (found-start);
+} /* stripp_sp */
diff --git a/mysys/mf_unixpath.c b/mysys/mf_unixpath.c
new file mode 100644
index 00000000000..6ae29f99136
--- /dev/null
+++ b/mysys/mf_unixpath.c
@@ -0,0 +1,33 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* convert filename to unix style filename */
+ /* If MSDOS converts '\' to '/' */
+
+void to_unix_path(my_string to __attribute__((unused)))
+{
+#if FN_LIBCHAR != '/'
+ {
+ to--;
+ while ((to=strchr(to+1,FN_LIBCHAR)) != 0)
+ *to='/';
+ }
+#endif
+}
diff --git a/mysys/mf_util.c b/mysys/mf_util.c
new file mode 100644
index 00000000000..12af323680e
--- /dev/null
+++ b/mysys/mf_util.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Utilities with are missing on some systems */
+
+#include "mysys_priv.h"
+#ifdef __ZTC__
+#include <dos.h>
+#endif
+
+#ifdef __ZTC__
+
+ /* On ZORTECH C we don't have a getpid() call */
+
+int getpid(void)
+{
+ return (int) _psp;
+}
+
+#ifndef M_IC80386
+
+ /* Define halloc and hfree in as in MSC */
+
+void * __CDECL halloc(long count,size_t length)
+{
+ return (void*) MK_FP(dos_alloc((uint) ((count*length+15) >> 4)),0);
+}
+
+void __CDECL hfree(void *ptr)
+{
+ dos_free(FP_SEG(ptr));
+}
+
+#endif /* M_IC80386 */
+#endif /* __ZTC__ */
diff --git a/mysys/mf_wcomp.c b/mysys/mf_wcomp.c
new file mode 100644
index 00000000000..5f1ab9b813e
--- /dev/null
+++ b/mysys/mf_wcomp.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Funktions for comparing with wild-cards */
+
+#include "mysys_priv.h"
+
+ /* Test if a string is "comparable" to a wild-card string */
+ /* returns 0 if the strings are "comparable" */
+
+char wild_many='*';
+char wild_one='?';
+char wild_prefix=0;
+
+int wild_compare(register const char *str, register const char *wildstr)
+{
+ reg3 int flag;
+ DBUG_ENTER("wild_compare");
+
+ while (*wildstr)
+ {
+ while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == wild_prefix && wildstr[1])
+ wildstr++;
+ if (*wildstr++ != *str++) DBUG_RETURN(1);
+ }
+ if (! *wildstr ) DBUG_RETURN (*str != 0);
+ if (*wildstr++ == wild_one)
+ {
+ if (! *str++) DBUG_RETURN (1); /* One char; skipp */
+ }
+ else
+ { /* Found '*' */
+ if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
+ flag=(*wildstr != wild_many && *wildstr != wild_one);
+ do
+ {
+ if (flag)
+ {
+ char cmp;
+ if ((cmp= *wildstr) == wild_prefix && wildstr[1])
+ cmp=wildstr[1];
+ while (*str && *str != cmp)
+ str++;
+ if (!*str) DBUG_RETURN (1);
+ }
+ if (wild_compare(str,wildstr) == 0) DBUG_RETURN (0);
+ } while (*str++ && wildstr[0] != wild_many);
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN (*str != '\0');
+} /* wild_compare */
diff --git a/mysys/mf_wfile.c b/mysys/mf_wfile.c
new file mode 100644
index 00000000000..02e155d9936
--- /dev/null
+++ b/mysys/mf_wfile.c
@@ -0,0 +1,132 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Functions for finding files with wildcards */
+
+/*
+ The following file-name-test is supported:
+ - "name [[,] name...] ; Matches any of used filenames.
+ Each name can have "*" and/or "?"
+ wild-cards.
+ - [wildspec [,]] !wildspec2 ; File that matches wildspec and not
+ wildspec2.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+ /* Store wildcard-string in a easyer format */
+
+WF_PACK *wf_comp(my_string str)
+{
+ uint ant;
+ int not_pos;
+ register my_string pos;
+ my_string buffer;
+ WF_PACK *ret;
+ DBUG_ENTER("wf_comp");
+
+ not_pos= -1; /* Skipp space and '!' in front */
+ while (*str == ' ')
+ str++;
+ if (*str == '!')
+ {
+ not_pos=0;
+ while (*++str == ' ') {};
+ }
+ if (*str == 0) /* Empty == everything */
+ DBUG_RETURN((WF_PACK *) NULL);
+
+ ant=1; /* Count filespecs */
+ for (pos=str ; *pos ; pos++)
+ ant+= test(*pos == ' ' || *pos == ',');
+
+#ifdef FN_UPPER_CASE
+ caseup(str,(int) (pos-str));
+#endif
+#ifdef FN_LOWER_CASE
+ casedn(str,(int) (pos-str));
+#endif
+
+ if ((ret= (WF_PACK*) my_malloc((uint) ant*(sizeof(my_string*)+2)+
+ sizeof(WF_PACK)+strlen(str)+1,MYF(MY_WME)))
+ == 0)
+ DBUG_RETURN((WF_PACK *) NULL);
+ ret->wild= (my_string*) (ret+1);
+ buffer= (my_string) (ret->wild+ant);
+
+ ant=0;
+ for (pos=str ; *pos ; str= pos)
+ {
+ ret->wild[ant++]=buffer;
+ while (*pos != ' ' && *pos != ',' && *pos != '!' && *pos)
+ *buffer++ = *pos++;
+
+ *buffer++ = '\0';
+ while (*pos == ' ' || *pos == ',' || *pos == '!' )
+ if (*pos++ == '!' && not_pos <0)
+ not_pos=(int) ant;
+ }
+
+ ret->wilds=ant;
+ if (not_pos <0)
+ ret->not_pos=ant;
+ else
+ ret->not_pos=(uint) not_pos;
+
+ DBUG_PRINT("exit",("antal: %d not_pos: %d",ret->wilds,ret->not_pos));
+ DBUG_RETURN(ret);
+} /* wf_comp */
+
+
+ /* Test if a given filename is matched */
+
+int wf_test(register WF_PACK *wf_pack, register const char *name)
+{
+ reg2 uint i;
+ reg3 uint not_pos;
+ DBUG_ENTER("wf_test");
+
+ if (! wf_pack || wf_pack->wilds == 0)
+ DBUG_RETURN(0); /* Everything goes */
+
+ not_pos=wf_pack->not_pos;
+ for (i=0 ; i < not_pos; i++)
+ if (wild_compare(name,wf_pack->wild[i]) == 0)
+ goto found;
+ if (i)
+ DBUG_RETURN(1); /* No-match */
+
+found:
+/* Test that it isn't in not-list */
+
+ for (i=not_pos ; i < wf_pack->wilds; i++)
+ if (wild_compare(name,wf_pack->wild[i]) == 0)
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* wf_test */
+
+
+ /* We need this because program don't know with malloc we used */
+
+void wf_end(WF_PACK *buffer)
+{
+ DBUG_ENTER("wf_end");
+ if (buffer)
+ my_free((gptr) buffer,MYF(0));
+ DBUG_VOID_RETURN;
+} /* wf_end */
diff --git a/mysys/mulalloc.c b/mysys/mulalloc.c
new file mode 100644
index 00000000000..8a7ee312aa9
--- /dev/null
+++ b/mysys/mulalloc.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+ /* Malloc many pointers at the same time */
+ /* format myFlags,ptr,length,ptr,length ... until null ptr */
+
+#include "mysys_priv.h"
+#include <stdarg.h>
+
+gptr my_multi_malloc(myf myFlags, ...)
+{
+ va_list args;
+ char **ptr,*start,*res;
+ uint tot_length,length;
+ DBUG_ENTER("my_multi_malloc");
+
+ va_start(args,myFlags);
+ tot_length=0;
+ while ((ptr=va_arg(args, char **)))
+ {
+ length=va_arg(args,uint);
+ tot_length+=ALIGN_SIZE(length);
+ }
+ va_end(args);
+
+ if (!(start=(char *) my_malloc(tot_length,myFlags)))
+ DBUG_RETURN(0); /* purecov: inspected */
+
+ va_start(args,myFlags);
+ res=start;
+ while ((ptr=va_arg(args, char **)))
+ {
+ *ptr=res;
+ length=va_arg(args,uint);
+ res+=ALIGN_SIZE(length);
+ }
+ va_end(args);
+ DBUG_RETURN((gptr) start);
+}
diff --git a/mysys/my_alarm.c b/mysys/my_alarm.c
new file mode 100644
index 00000000000..aab01ad77f4
--- /dev/null
+++ b/mysys/my_alarm.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Function to set a varible when we got a alarm */
+/* Used by my_lock samt functions in m_alarm.h */
+
+
+#include "mysys_priv.h"
+#include "my_alarm.h"
+
+#ifdef HAVE_ALARM
+
+ /* ARGSUSED */
+sig_handler my_set_alarm_variable(int signo __attribute__((unused)))
+{
+ my_have_got_alarm=1; /* Tell program that time expired */
+ return;
+}
+
+#endif /* HAVE_ALARM */
diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c
new file mode 100644
index 00000000000..693ffbfab78
--- /dev/null
+++ b/mysys/my_alloc.c
@@ -0,0 +1,129 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Routines to handle mallocing of results which will be freed the same time */
+
+#include <global.h>
+#include <my_sys.h>
+#include <m_string.h>
+
+void init_alloc_root(MEM_ROOT *mem_root,uint block_size)
+{
+ mem_root->free=mem_root->used=0;
+ mem_root->min_malloc=16;
+ mem_root->block_size=block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
+ mem_root->error_handler=0;
+}
+
+gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size)
+{
+#if defined(HAVE_purify) && defined(EXTRA_DEBUG)
+ reg1 USED_MEM *next;
+ Size+=ALIGN_SIZE(sizeof(USED_MEM));
+
+ if (!(next = (USED_MEM*) my_malloc(Size,MYF(MY_WME))))
+ {
+ if (mem_root->error_handler)
+ (*mem_root->error_handler)();
+ return((gptr) 0); /* purecov: inspected */
+ }
+ next->next=mem_root->used;
+ mem_root->used=next;
+ return (gptr) (((char*) next)+ALIGN_SIZE(sizeof(USED_MEM)));
+#else
+ uint get_size,max_left;
+ gptr point;
+ reg1 USED_MEM *next;
+ reg2 USED_MEM **prev;
+
+ Size= ALIGN_SIZE(Size);
+ prev= &mem_root->free;
+ max_left=0;
+ for (next= *prev ; next && next->left < Size ; next= next->next)
+ {
+ if (next->left > max_left)
+ max_left=next->left;
+ prev= &next->next;
+ }
+ if (! next)
+ { /* Time to alloc new block */
+ get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+ if (max_left*4 < mem_root->block_size && get_size < mem_root->block_size)
+ get_size=mem_root->block_size; /* Normal alloc */
+
+ if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
+ {
+ if (mem_root->error_handler)
+ (*mem_root->error_handler)();
+ return((gptr) 0); /* purecov: inspected */
+ }
+ next->next= *prev;
+ next->size= get_size;
+ next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
+ *prev=next;
+ }
+ point= (gptr) ((char*) next+ (next->size-next->left));
+ if ((next->left-= Size) < mem_root->min_malloc)
+ { /* Full block */
+ *prev=next->next; /* Remove block from list */
+ next->next=mem_root->used;
+ mem_root->used=next;
+ }
+ return(point);
+#endif
+}
+
+ /* deallocate everything used by alloc_root */
+
+void free_root(MEM_ROOT *root)
+{
+ reg1 USED_MEM *next,*old;
+ DBUG_ENTER("free_root");
+
+ if (!root)
+ DBUG_VOID_RETURN; /* purecov: inspected */
+ for (next= root->used ; next ; )
+ {
+ old=next; next= next->next ;
+ my_free((gptr) old,MYF(0));
+ }
+ for (next= root->free ; next ; )
+ {
+ old=next; next= next->next ;
+ my_free((gptr) old,MYF(0));
+ }
+ root->used=root->free=0;
+ DBUG_VOID_RETURN;
+}
+
+char *strdup_root(MEM_ROOT *root,const char *str)
+{
+ uint len=strlen(str)+1;
+ char *pos;
+ if ((pos=alloc_root(root,len)))
+ memcpy(pos,str,len);
+ return pos;
+}
+
+
+char *memdup_root(MEM_ROOT *root,const char *str,uint len)
+{
+ char *pos;
+ if ((pos=alloc_root(root,len)))
+ memcpy(pos,str,len);
+ return pos;
+}
diff --git a/mysys/my_append.c b/mysys/my_append.c
new file mode 100644
index 00000000000..0d3296fb278
--- /dev/null
+++ b/mysys/my_append.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <sys/stat.h>
+#include <m_string.h>
+#if defined(HAVE_SYS_UTIME_H)
+#include <sys/utime.h>
+#elif defined(HAVE_UTIME_H)
+#include <utime.h>
+#elif !defined(HPUX)
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+ /* Append a file to another */
+
+int my_append(const char *from, const char *to, myf MyFlags)
+
+
+ /* Dont set MY_FNABP or MY_NABP bits on
+ when calling this funktion */
+{
+ uint Count;
+ File from_file,to_file;
+ char buff[IO_SIZE];
+ DBUG_ENTER("my_append");
+ DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
+
+ from_file=to_file= -1;
+
+ if ((from_file=my_open(from,O_RDONLY,MyFlags)) >= 0)
+ {
+ if ((to_file=my_open(to,O_APPEND | O_WRONLY,MyFlags)) >= 0)
+ {
+ while ((Count=my_read(from_file,buff,IO_SIZE,MyFlags)) != 0)
+ if (Count == (uint) -1 ||
+ my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
+ goto err;
+ if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
+ DBUG_RETURN(-1); /* Error on close */
+ DBUG_RETURN(0);
+ }
+ }
+err:
+ if (from_file >= 0) VOID(my_close(from_file,MyFlags));
+ if (to_file >= 0) VOID(my_close(to_file,MyFlags));
+ DBUG_RETURN(-1);
+}
diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c
new file mode 100644
index 00000000000..1063e9381bf
--- /dev/null
+++ b/mysys/my_chsize.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include "m_string.h"
+
+ /* Change size of file. Truncate file if shorter, */
+ /* else expand with zero. */
+
+int my_chsize(File fd, my_off_t newlength, myf MyFlags)
+{
+ DBUG_ENTER("my_chsize");
+ DBUG_PRINT("my",("fd: %d length: %lu MyFlags: %d",fd,(ulong) newlength,
+ MyFlags));
+
+#ifdef HAVE_CHSIZE
+ if (chsize(fd,(off_t) newlength))
+ {
+ DBUG_PRINT("error",("errno: %d",errno));
+ my_errno=errno;
+ if (MyFlags & MY_WME)
+ my_error(EE_CANT_CHSIZE,MYF(ME_BELL+ME_WAITTANG),errno);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+#else
+ /* if file is shorter, expand with null, else fill unused part with null */
+ {
+ my_off_t oldsize;
+ char buff[IO_SIZE];
+
+ bzero(buff,IO_SIZE);
+ oldsize = my_seek(fd, 0L, MY_SEEK_END, MYF(MY_WME+MY_FAE));
+
+#ifdef HAVE_FTRUNCATE
+ if (oldsize > newlength)
+ {
+ if (ftruncate(fd, (off_t) newlength))
+ {
+ my_errno=errno;
+ DBUG_PRINT("error",("errno: %d",errno));
+ if (MyFlags & MY_WME)
+ my_error(EE_CANT_CHSIZE, MYF(ME_BELL+ME_WAITTANG), errno);
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+#else
+ if (oldsize > newlength)
+ { /* Fill diff with null */
+ VOID(my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE)));
+ swap(long, newlength, oldsize);
+ }
+#endif
+ while (newlength-oldsize > IO_SIZE)
+ {
+ if (my_write(fd,(byte*) buff,IO_SIZE,MYF(MY_NABP)))
+ goto err;
+ oldsize+= IO_SIZE;
+ }
+ if (my_write(fd,(byte*) buff,(uint) (newlength-oldsize),MYF(MY_NABP)))
+ goto err;
+ DBUG_RETURN(0);
+ err:
+ if (MyFlags & MY_WME)
+ my_error(EE_CANT_CHSIZE,MYF(ME_BELL+ME_WAITTANG),my_errno);
+ DBUG_PRINT("error",("errno: %d",my_errno));
+ DBUG_RETURN(1);
+ }
+#endif
+} /* my_chsize */
diff --git a/mysys/my_clock.c b/mysys/my_clock.c
new file mode 100644
index 00000000000..d13d69a7b88
--- /dev/null
+++ b/mysys/my_clock.c
@@ -0,0 +1,35 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES
+#include "global.h"
+
+#if !defined(_MSC_VER) && !defined(__BORLANDC__)
+#include "mysys_priv.h"
+#include <sys/times.h>
+#endif
+
+long my_clock(void)
+{
+#if !defined(MSDOS) && !defined(__WIN__)
+ struct tms tmsbuf;
+ VOID(times(&tmsbuf));
+ return (tmsbuf.tms_utime + tmsbuf.tms_stime);
+#else
+ return clock();
+#endif
+}
diff --git a/mysys/my_compress.c b/mysys/my_compress.c
new file mode 100644
index 00000000000..d1e32234135
--- /dev/null
+++ b/mysys/my_compress.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Written by Sinisa Milivojevic <sinisa@coresinc.com> */
+
+#include <global.h>
+#ifdef HAVE_COMPRESS
+#include <my_sys.h>
+#include <zlib.h>
+
+/*
+** This replaces the packet with a compressed packet
+** Returns 1 on error
+** *complen is 0 if the packet wasn't compressed
+*/
+
+my_bool my_compress(byte *packet, ulong *len, ulong *complen)
+{
+ if (*len < MIN_COMPRESS_LENGTH)
+ *complen=0;
+ else
+ {
+ byte *compbuf=my_compress_alloc(packet,len,complen);
+ if (!compbuf)
+ return *complen ? 0 : 1;
+ memcpy(packet,compbuf,*len);
+ my_free(compbuf,MYF(MY_WME)); }
+ return 0;
+}
+
+
+byte *my_compress_alloc(const byte *packet, ulong *len, ulong *complen)
+{
+ byte *compbuf;
+ *complen = *len * 120 / 100 + 12;
+ if (!(compbuf = (byte *) my_malloc(*complen,MYF(MY_WME))))
+ return 0; /* Not enough memory */
+ if (compress((Bytef*) compbuf,(ulong *) complen, (Bytef*) packet,
+ (uLong) *len ) != Z_OK)
+ {
+ my_free(compbuf,MYF(MY_WME));
+ return 0;
+ }
+ if (*complen >= *len)
+ {
+ *complen=0;
+ my_free(compbuf,MYF(MY_WME));
+ return 0;
+ }
+ swap(ulong,*len,*complen); /* *len is now packet length */
+ return compbuf;
+}
+
+
+my_bool my_uncompress (byte *packet, ulong *len, ulong *complen)
+{
+ if (*complen) /* If compressed */
+ {
+ byte *compbuf = (byte *) my_malloc (*complen,MYF(MY_WME));
+ if (!compbuf)
+ return 1; /* Not enough memory */
+ if (uncompress((Bytef*) compbuf, complen, (Bytef*) packet, *len) != Z_OK)
+ { /* Probably wrong packet */
+ my_free (compbuf,MYF(MY_WME));
+ return 1;
+ }
+ *len = *complen;
+ memcpy(packet,compbuf,*len);
+ my_free(compbuf,MYF(MY_WME));
+ }
+ return 0;
+}
+#endif /* HAVE_COMPRESS */
diff --git a/mysys/my_copy.c b/mysys/my_copy.c
new file mode 100644
index 00000000000..bfd7e957585
--- /dev/null
+++ b/mysys/my_copy.c
@@ -0,0 +1,103 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <sys/stat.h>
+#include <m_string.h>
+#if defined(HAVE_SYS_UTIME_H)
+#include <sys/utime.h>
+#elif defined(HAVE_UTIME_H)
+#include <utime.h>
+#elif !defined(HPUX)
+#include <time.h>
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+
+ /*
+ Ordinary ownership and accesstimes are copied from 'from-file'
+ if MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
+ the modes of to-file isn't changed
+ Dont set MY_FNABP or MY_NABP bits on when calling this function !
+ */
+
+int my_copy(const char *from, const char *to, myf MyFlags)
+{
+ uint Count;
+ int new_file_stat;
+ File from_file,to_file;
+ char buff[IO_SIZE];
+ struct stat stat_buff,new_stat_buff;
+ DBUG_ENTER("my_copy");
+ DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
+
+ from_file=to_file= -1;
+ new_file_stat=0;
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES) /* Copy stat if possible */
+ new_file_stat=stat((char*) to, &new_stat_buff);
+
+ if ((from_file=my_open(from,O_RDONLY,MyFlags)) >= 0)
+ {
+ if (stat(from,&stat_buff))
+ {
+ my_errno=errno;
+ goto err;
+ }
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
+ stat_buff=new_stat_buff;
+ if ((to_file= my_create(to,(int) stat_buff.st_mode,
+ O_WRONLY | O_TRUNC | O_BINARY,
+ MyFlags)) < 0)
+ goto err;
+
+ while ((Count=my_read(from_file,buff,IO_SIZE,MyFlags)) != 0)
+ if (Count == (uint) -1 ||
+ my_write(to_file,buff,Count,MYF(MyFlags | MY_NABP)))
+ goto err;
+
+ if (my_close(from_file,MyFlags) | my_close(to_file,MyFlags))
+ DBUG_RETURN(-1); /* Error on close */
+
+ /* Copy modes if possible */
+
+ if (MyFlags & MY_HOLD_ORIGINAL_MODES && new_file_stat)
+ DBUG_RETURN(0); /* File copyed but not stat */
+ VOID(chmod(to, stat_buff.st_mode & 07777)); /* Copy modes */
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__)
+ VOID(chown(to, stat_buff.st_uid,stat_buff.st_gid)); /* Copy ownership */
+#endif
+#if !defined(VMS) && !defined(__ZTC__)
+ if (MyFlags & MY_COPYTIME)
+ {
+ struct utimbuf timep;
+ timep.actime = stat_buff.st_atime;
+ timep.modtime = stat_buff.st_mtime;
+ VOID(utime((char*) to, &timep)); /* last accessed and modified times */
+ }
+#endif
+ DBUG_RETURN(0);
+ }
+
+err:
+ if (from_file >= 0) VOID(my_close(from_file,MyFlags));
+ if (to_file >= 0) VOID(my_close(to_file,MyFlags));
+ DBUG_RETURN(-1);
+} /* my_copy */
diff --git a/mysys/my_create.c b/mysys/my_create.c
new file mode 100644
index 00000000000..866c0dfd465
--- /dev/null
+++ b/mysys/my_create.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include <my_dir.h>
+#include "mysys_err.h"
+#include <errno.h>
+#if defined(MSDOS) || defined(__WIN__)
+#include <share.h>
+#endif
+
+ /*
+ ** Create a new file
+ ** Arguments:
+ ** Path-name of file
+ ** Read | write on file (umask value)
+ ** Read & Write on open file
+ ** Special flags
+ */
+
+
+File my_create(const char *FileName, int CreateFlags, int access_flags,
+ myf MyFlags)
+{
+ int fd;
+ DBUG_ENTER("my_create");
+ DBUG_PRINT("my",("Name: '%s' CreateFlags: %d AccessFlags: %d MyFlags: %d",
+ FileName, CreateFlags, access_flags, MyFlags));
+
+#if !defined(NO_OPEN_3)
+ fd = open((my_string) FileName, access_flags | O_CREAT,
+ CreateFlags ? CreateFlags : my_umask);
+#elif defined(VMS)
+ fd = open((my_string) FileName, access_flags | O_CREAT, 0,
+ "ctx=stm","ctx=bin");
+#elif defined(MSDOS) || defined(__WIN__)
+ if (access_flags & O_SHARE)
+ fd = sopen((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+ SH_DENYNO, MY_S_IREAD | MY_S_IWRITE);
+ else
+ fd = open((my_string) FileName, access_flags | O_CREAT | O_BINARY,
+ MY_S_IREAD | MY_S_IWRITE);
+#else
+ fd = open(FileName, access_flags);
+#endif
+
+ if (fd >= 0)
+ {
+ if ((int) fd >= MY_NFILE)
+ {
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd); /* safeguard */
+ }
+ if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
+ {
+ my_file_opened++;
+ my_file_info[fd].type = FILE_BY_CREATE;
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd);
+ }
+ VOID(my_close(fd,MyFlags));
+ my_errno=ENOMEM;
+ }
+ else
+ my_errno=errno;
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error(EE_CANTCREATEFILE, MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ DBUG_RETURN(-1);
+} /* my_create */
diff --git a/mysys/my_delete.c b/mysys/my_delete.c
new file mode 100644
index 00000000000..77d5f311418
--- /dev/null
+++ b/mysys/my_delete.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+
+#include "mysys_err.h"
+
+int my_delete(const char *name, myf MyFlags)
+{
+ int err;
+ DBUG_ENTER("my_delete");
+ DBUG_PRINT("my",("name %s MyFlags %d", name, MyFlags));
+
+ if ((err = unlink(name)) == -1)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_DELETE,MYF(ME_BELL+ME_WAITTANG+(MyFlags & ME_NOINPUT)),
+ name,errno);
+ }
+ DBUG_RETURN(err);
+} /* my_delete */
diff --git a/mysys/my_div.c b/mysys/my_div.c
new file mode 100644
index 00000000000..24794679376
--- /dev/null
+++ b/mysys/my_div.c
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+
+my_string my_filename(File fd)
+{
+ DBUG_ENTER("my_filename");
+ if (fd >= MY_NFILE)
+ DBUG_RETURN((char*) "UNKNOWN");
+ if (fd >= 0 && my_file_info[fd].type != UNOPEN)
+ {
+ DBUG_RETURN(my_file_info[fd].name);
+ }
+ else
+ DBUG_RETURN((char*) "UNOPENED"); /* Debug message */
+}
diff --git a/mysys/my_error.c b/mysys/my_error.c
new file mode 100644
index 00000000000..26510f08480
--- /dev/null
+++ b/mysys/my_error.c
@@ -0,0 +1,122 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <m_string.h>
+#include <stdarg.h>
+#include <m_ctype.h>
+
+/* Define some external variables for error handling */
+
+const char ** NEAR errmsg[MAXMAPS]={0,0,0,0};
+char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
+
+/* Error message to user */
+/*VARARGS2*/
+
+int my_error(int nr,myf MyFlags, ...)
+{
+ va_list ap;
+ uint olen, plen;
+ reg1 const char *tpos;
+ reg2 char *endpos;
+ char * par;
+ char ebuff[ERRMSGSIZE+20];
+ DBUG_ENTER("my_error");
+
+ va_start(ap,MyFlags);
+ DBUG_PRINT("my", ("nr: %d MyFlags: %d errno: %d", nr, MyFlags, errno));
+
+ if (nr / ERRMOD == GLOB && errmsg[GLOB] == 0)
+ init_glob_errs();
+
+ olen=(uint) strlen(tpos=errmsg[nr / ERRMOD][nr % ERRMOD]);
+ endpos=ebuff;
+
+ while (*tpos)
+ {
+ if (tpos[0] != '%')
+ {
+ *endpos++= *tpos++; /* Copy ordinary char */
+ olen++;
+ continue;
+ }
+ if (*++tpos == '%') /* test if %% */
+ {
+ olen--;
+ }
+ else
+ {
+ /* Skipp if max size is used (to be compatible with printf) */
+ while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
+ tpos++;
+ if (*tpos == 's') /* String parameter */
+ {
+ par = va_arg(ap, char *);
+ plen = (uint) strlen(par);
+ if (olen + plen < ERRMSGSIZE+2) /* Replace if possible */
+ {
+ endpos=strmov(endpos,par);
+ tpos++;
+ olen+=plen-2;
+ continue;
+ }
+ }
+ else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
+ {
+ register int iarg;
+ iarg = va_arg(ap, int);
+ if (*tpos == 'd')
+ plen= (uint) (int2str((long) iarg,endpos, -10) - endpos);
+ else
+ plen= (uint) (int2str((long) (uint) iarg,endpos,10)- endpos);
+ if (olen + plen < ERRMSGSIZE+2) /* Replace parameter if possible */
+ {
+ endpos+=plen;
+ tpos++;
+ olen+=plen-2;
+ continue;
+ }
+ }
+ }
+ *endpos++='%'; /* % used as % or unknown code */
+ }
+ *endpos='\0'; /* End of errmessage */
+ va_end(ap);
+ DBUG_RETURN((*error_handler_hook)(nr, ebuff, MyFlags));
+}
+
+ /* Error as printf */
+
+int my_printf_error (uint error, const char *format, myf MyFlags, ...)
+{
+ va_list args;
+ char ebuff[ERRMSGSIZE+20];
+
+ va_start(args,MyFlags);
+ (void) vsprintf (ebuff,format,args);
+ va_end(args);
+ return (*error_handler_hook)(error, ebuff, MyFlags);
+}
+
+ /* Give message using error_handler_hook */
+
+int my_message(uint error, const char *str, register myf MyFlags)
+{
+ return (*error_handler_hook)(error, str, MyFlags);
+}
diff --git a/mysys/my_fopen.c b/mysys/my_fopen.c
new file mode 100644
index 00000000000..b2e99518792
--- /dev/null
+++ b/mysys/my_fopen.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include <errno.h>
+#include "mysys_err.h"
+
+static void make_ftype(my_string to,int flag);
+
+ /* Open a file as stream */
+
+FILE *my_fopen(const char *FileName, int Flags, myf MyFlags)
+ /* Path-name of file */
+ /* Read | write .. */
+ /* Special flags */
+{
+ FILE *fd;
+ char type[5];
+ DBUG_ENTER("my_fopen");
+ DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+
+ make_ftype(type,Flags);
+ if ((fd = fopen(FileName, type)) != 0)
+ {
+ /*
+ The test works if MY_NFILE < 128. The problem is that fileno() is char
+ on some OS (SUNOS). Actually the filename save isn't that important
+ so we can ignore if this doesn't work.
+ */
+ if ((uint) fileno(fd) >= MY_NFILE)
+ DBUG_RETURN(fd); /* safeguard */
+ pthread_mutex_lock(&THR_LOCK_open);
+ if ((my_file_info[fileno(fd)].name = (char*)
+ my_strdup(FileName,MyFlags)))
+ {
+ my_stream_opened++;
+ my_file_info[fileno(fd)].type = STREAM_BY_FOPEN;
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_PRINT("exit",("stream: %lx",fd));
+ DBUG_RETURN(fd);
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ (void) my_fclose(fd,MyFlags);
+ my_errno=ENOMEM;
+ }
+ else
+ my_errno=errno;
+ DBUG_PRINT("error",("Got error %d on open",my_errno));
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error((Flags & O_RDONLY) || (Flags == O_RDONLY ) ? EE_FILENOTFOUND :
+ EE_CANTCREATEFILE,
+ MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ DBUG_RETURN((FILE*) 0);
+} /* my_fopen */
+
+
+ /* Close a stream */
+
+int my_fclose(FILE *fd, myf MyFlags)
+{
+ int err,file;
+ DBUG_ENTER("my_fclose");
+ DBUG_PRINT("my",("stream: %lx MyFlags: %d",fd, MyFlags));
+
+ pthread_mutex_lock(&THR_LOCK_open);
+ file=fileno(fd);
+ if ((err = fclose(fd)) < 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE | MY_WME))
+ my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(file),errno);
+ }
+ if ((uint) file < MY_NFILE && my_file_info[file].type != UNOPEN)
+ {
+ my_file_info[file].type = UNOPEN;
+ my_free(my_file_info[file].name, MYF(0));
+ my_stream_opened--;
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(err);
+} /* my_fclose */
+
+
+ /* Make a stream out of a file handle */
+
+FILE *my_fdopen(File Filedes, int Flags, myf MyFlags)
+
+ /* Read | write .. */
+ /* Special flags */
+{
+ FILE *fd;
+ char type[5];
+ DBUG_ENTER("my_fdopen");
+ DBUG_PRINT("my",("Fd: %d Flags: %d MyFlags: %d",
+ Filedes, Flags, MyFlags));
+
+ make_ftype(type,Flags);
+ if ((fd = fdopen(Filedes, type)) == 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE | MY_WME))
+ my_error(EE_CANT_OPEN_STREAM, MYF(ME_BELL+ME_WAITTANG),errno);
+ }
+ else
+ {
+ pthread_mutex_lock(&THR_LOCK_open);
+ if (my_file_info[Filedes].type != UNOPEN)
+ {
+ my_file_info[Filedes].type = STREAM_BY_FDOPEN;
+ my_file_opened--; /* File is opened with my_open ! */
+ my_stream_opened++;
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ }
+
+ DBUG_PRINT("exit",("stream: %lx",fd));
+ DBUG_RETURN(fd);
+} /* my_fdopen */
+
+
+ /* Make a filehandler-open-typestring from ordinary inputflags */
+
+static void make_ftype(register my_string to, register int flag)
+{
+#if FILE_BINARY /* If we have binary-files */
+ reg3 int org_flag=flag;
+#endif
+ flag&= ~FILE_BINARY; /* remove binary bit */
+ if (flag == O_RDONLY)
+ *to++= 'r';
+ else if (flag == O_WRONLY)
+ *to++= 'w';
+ else
+ { /* Add '+' after theese */
+ if (flag == O_RDWR)
+ *to++= 'r';
+ else if (flag & O_APPEND)
+ *to++= 'a';
+ else
+ *to++= 'w'; /* Create file */
+ *to++= '+';
+ }
+#if FILE_BINARY /* If we have binary-files */
+ if (org_flag & FILE_BINARY)
+ *to++='b';
+#endif
+ *to='\0';
+} /* make_ftype */
diff --git a/mysys/my_fstream.c b/mysys/my_fstream.c
new file mode 100644
index 00000000000..76bd12abe32
--- /dev/null
+++ b/mysys/my_fstream.c
@@ -0,0 +1,170 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* USE_MY_STREAM isn't set because we can't thrust my_fclose! */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+
+#ifdef HAVE_FSEEKO
+#undef ftell
+#undef fseek
+#define ftell(A) ftello(A)
+#define fseek(A,B,C) fseeko((A),(B),(C))
+#endif
+
+ /* Read a chunk of bytes from a file */
+ /* Returns (uint) -1 if error as my_read() */
+
+uint my_fread(FILE *stream, byte *Buffer, uint Count, myf MyFlags)
+ /* File descriptor */
+ /* Buffer must be at least count bytes */
+ /* Max number of bytes returnd */
+ /* Flags on what to do on error */
+{
+ uint readbytes;
+ DBUG_ENTER("my_fread");
+ DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
+ stream, Buffer, Count, MyFlags));
+
+ if ((readbytes = (uint) fread(Buffer,sizeof(char),(size_t) Count,stream))
+ != Count)
+ {
+ DBUG_PRINT("error",("Read only %d bytes",readbytes));
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if (ferror(stream))
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(fileno(stream)),errno);
+ else
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(fileno(stream)),errno);
+ }
+ my_errno=errno ? errno : -1;
+ if (ferror(stream) || MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN((uint) -1); /* Return with error */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Read ok */
+ DBUG_RETURN(readbytes);
+} /* my_fread */
+
+
+/*
+** Write a chunk of bytes to a stream
+** Returns (uint) -1 if error as my_write()
+** Does retries if interrupted
+*/
+
+uint my_fwrite(FILE *stream, const byte *Buffer, uint Count, myf MyFlags)
+{
+ uint writenbytes=0;
+ off_t seekptr;
+#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+ uint errors;
+#endif
+ DBUG_ENTER("my_fwrite");
+ DBUG_PRINT("my",("stream: %lx Buffer: %lx Count: %u MyFlags: %d",
+ stream, Buffer, Count, MyFlags));
+
+#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+ errors=0;
+#endif
+ seekptr=ftell(stream);
+ for (;;)
+ {
+ uint writen;
+ if ((writen = (uint) fwrite((char*) Buffer,sizeof(char),
+ (size_t) Count, stream)) != Count)
+ {
+ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+ my_errno=errno;
+ if (writen != (uint) -1)
+ {
+ seekptr+=writen;
+ Buffer+=writen;
+ writenbytes+=writen;
+ Count-=writen;
+ }
+#ifdef EINTR
+ if (errno == EINTR)
+ {
+ VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
+ continue;
+ }
+#endif
+#if !defined(NO_BACKGROUND) && defined(USE_MY_STREAM)
+#ifdef THREAD
+ if (my_thread_var->abort)
+ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+#endif
+ if (errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+ {
+ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH));
+ sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC);
+ VOID(my_fseek(stream,seekptr,MY_SEEK_SET,MYF(0)));
+ continue;
+ }
+#endif
+ if (ferror(stream) || (MyFlags & (MY_NABP | MY_FNABP)))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(fileno(stream)),errno);
+ }
+ writenbytes=(uint) -1; /* Return that we got error */
+ break;
+ }
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ writenbytes=0; /* Everything OK */
+ else
+ writenbytes+=writen;
+ break;
+ }
+ DBUG_RETURN(writenbytes);
+} /* my_fwrite */
+
+ /* Seek to position in file */
+ /* ARGSUSED */
+
+my_off_t my_fseek(FILE *stream, my_off_t pos, int whence, myf MyFlags)
+{
+ DBUG_ENTER("my_fseek");
+ DBUG_PRINT("my",("stream: %lx pos: %lu whence: %d MyFlags: %d",
+ stream, pos, whence, MyFlags));
+ DBUG_RETURN(fseek(stream, (off_t) pos, whence) ?
+ MY_FILEPOS_ERROR : (my_off_t) ftell(stream));
+} /* my_seek */
+
+
+ /* Tell current position of file */
+ /* ARGSUSED */
+
+my_off_t my_ftell(FILE *stream, myf MyFlags)
+{
+ off_t pos;
+ DBUG_ENTER("my_ftell");
+ DBUG_PRINT("my",("stream: %lx MyFlags: %d",stream, MyFlags));
+ pos=ftell(stream);
+ DBUG_PRINT("exit",("ftell: %lu",(ulong) pos));
+ DBUG_RETURN((my_off_t) pos);
+} /* my_ftell */
diff --git a/mysys/my_getwd.c b/mysys/my_getwd.c
new file mode 100644
index 00000000000..3d674276731
--- /dev/null
+++ b/mysys/my_getwd.c
@@ -0,0 +1,182 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* my_setwd() and my_getwd() works with intern_filenames !! */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "mysys_err.h"
+#ifdef HAVE_GETWD
+#include <sys/param.h>
+#endif
+#if defined(MSDOS) || defined(__WIN__)
+#include <m_ctype.h>
+#include <dos.h>
+#include <direct.h>
+#endif
+
+
+ /* Gets current working directory in buff. Directory is allways ended
+ with FN_LIBCHAR */
+ /* One must pass a buffer to my_getwd. One can allways use
+ curr_dir[] */
+
+int my_getwd(my_string buf, uint size, myf MyFlags)
+{
+ my_string pos;
+ DBUG_ENTER("my_getwd");
+ DBUG_PRINT("my",("buf: %lx size: %d MyFlags %d", buf,size,MyFlags));
+
+#if ! defined(MSDOS)
+ if (curr_dir[0]) /* Current pos is saved here */
+ VOID(strmake(buf,&curr_dir[0],size-1));
+ else
+#endif
+ {
+#if defined(HAVE_GETCWD)
+ if (!getcwd(buf,size-2) && MyFlags & MY_WME)
+ {
+ my_errno=errno;
+ my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
+ return(-1);
+ }
+#elif defined(HAVE_GETWD)
+ {
+ char pathname[MAXPATHLEN];
+ getwd(pathname);
+ strmake(buf,pathname,size-1);
+ }
+#elif defined(VMS)
+ if (!getcwd(buf,size-2,1) && MyFlags & MY_WME)
+ {
+ my_errno=errno;
+ my_error(EE_GETWD,MYF(ME_BELL+ME_WAITTANG),errno);
+ return(-1);
+ }
+ intern_filename(buf,buf);
+#else
+#error "No way to get current directory"
+#endif
+ if (*((pos=strend(buf))-1) != FN_LIBCHAR) /* End with FN_LIBCHAR */
+ {
+ pos[0]= FN_LIBCHAR;
+ pos[1]=0;
+ }
+ (void) strmake(&curr_dir[0],buf,(size_s) (FN_REFLEN-1));
+ }
+ DBUG_RETURN(0);
+} /* my_getwd */
+
+
+ /* Set new working directory */
+
+int my_setwd(const char *dir, myf MyFlags)
+{
+ int res;
+ size_s length;
+ my_string start,pos;
+#if defined(VMS) || defined(MSDOS)
+ char buff[FN_REFLEN];
+#endif
+ DBUG_ENTER("my_setwd");
+ DBUG_PRINT("my",("dir: '%s' MyFlags %d", dir, MyFlags));
+
+ start=(my_string) dir;
+#if defined(MSDOS) /* MSDOS chdir can't change drive */
+#if !defined(_DDL) && !defined(WIN32)
+ if ((pos=strchr(dir,FN_DEVCHAR)) != 0)
+ {
+ uint drive,drives;
+
+ pos++; /* Skipp FN_DEVCHAR */
+ drive=(uint) (toupper(dir[0])-'A'+1); drives= (uint) -1;
+ if ((pos-(byte*) dir) == 2 && drive > 0 && drive < 32)
+ {
+ _dos_setdrive(drive,&drives);
+ _dos_getdrive(&drives);
+ }
+ if (drive != drives)
+ {
+ *pos='\0'; /* Dir is now only drive */
+ my_errno=errno;
+ my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),dir,ENOENT);
+ DBUG_RETURN(-1);
+ }
+ dir=pos; /* drive changed, change now path */
+ }
+#endif
+ if (*((pos=strend(dir)-1)) == FN_LIBCHAR && pos != dir)
+ {
+ strmov(buff,dir)[-1]=0; /* Remove last '/' */
+ dir=buff;
+ }
+#endif /* MSDOS*/
+ if (! dir[0] || (dir[0] == FN_LIBCHAR && dir[1] == 0))
+ dir=FN_ROOTDIR;
+#ifdef VMS
+ {
+ pos=strmov(buff,dir);
+ if (pos[-1] != FN_LIBCHAR)
+ {
+ pos[0]=FN_LIBCHAR; /* Mark as directory */
+ pos[1]=0;
+ }
+ system_filename(buff,buff); /* Change to VMS format */
+ dir=buff;
+ }
+#endif /* VMS */
+ if ((res=chdir((char*) dir)) != 0)
+ {
+ my_errno=errno;
+ if (MyFlags & MY_WME)
+ my_error(EE_SETWD,MYF(ME_BELL+ME_WAITTANG),start,errno);
+ }
+ else
+ {
+ if (test_if_hard_path(start))
+ { /* Hard pathname */
+ pos=strmake(&curr_dir[0],start,(size_s) FN_REFLEN-1);
+ if (pos[-1] != FN_LIBCHAR)
+ {
+ length=(uint) (pos-(char*) curr_dir);
+ curr_dir[length]=FN_LIBCHAR; /* must end with '/' */
+ curr_dir[length+1]='\0';
+ }
+ }
+ else
+ curr_dir[0]='\0'; /* Don't save name */
+ }
+ DBUG_RETURN(res);
+} /* my_setwd */
+
+
+
+ /* Test if hard pathname */
+ /* Returns 1 if dirname is a hard path */
+
+int test_if_hard_path(register const char *dir_name)
+{
+ if (dir_name[0] == FN_HOMELIB && dir_name[1] == FN_LIBCHAR)
+ return (home_dir != NullS && test_if_hard_path(home_dir));
+ if (dir_name[0] == FN_LIBCHAR)
+ return (TRUE);
+#ifdef FN_DEVCHAR
+ return (strchr(dir_name,FN_DEVCHAR) != 0);
+#else
+ return FALSE;
+#endif
+} /* test_if_hard_path */
diff --git a/mysys/my_init.c b/mysys/my_init.c
new file mode 100644
index 00000000000..912e80d9ebd
--- /dev/null
+++ b/mysys/my_init.c
@@ -0,0 +1,301 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include "mysys_err.h"
+#include "m_ctype.h"
+#include <m_string.h>
+#include <m_ctype.h>
+#ifdef THREAD
+#include <my_pthread.h>
+#endif
+#ifdef HAVE_GETRUSAGE
+#include <sys/resource.h>
+/* extern int getrusage(int, struct rusage *); */
+#endif
+#include <signal.h>
+#ifdef VMS
+#include <my_static.c>
+#include <m_ctype.h>
+#endif
+#ifdef __WIN__
+#ifdef _MSC_VER
+#include <locale.h>
+#include <crtdbg.h>
+#endif
+my_bool have_tcpip=0;
+static void my_win_init(void);
+static my_bool win32_have_tcpip(void);
+static my_bool win32_init_tcp_ip();
+#else
+#define my_win_init()
+#endif
+static my_bool my_init_done=0;
+
+ /* Init my_sys functions and my_sys variabels */
+
+void my_init(void)
+{
+ my_string str;
+ if (my_init_done)
+ return;
+ my_init_done=1;
+#ifdef THREAD
+#if defined(HAVE_PTHREAD_INIT)
+ pthread_init(); /* Must be called before DBUG_ENTER */
+#endif
+ my_thread_global_init();
+#ifndef __WIN__
+ sigfillset(&my_signals); /* signals blocked by mf_brkhant */
+#endif
+#endif
+ {
+ DBUG_ENTER("my_init");
+ DBUG_PROCESS(my_progname ? my_progname : (char*) "unknown");
+ if (!home_dir)
+ { /* Don't initialize twice */
+ my_win_init();
+ if ((home_dir=getenv("HOME")) != 0)
+ home_dir=intern_filename(home_dir_buff,home_dir);
+#ifndef VMS
+ if ((str=getenv("UMASK")) != 0)
+ my_umask=atoi(str) | 0600; /* Default creation of new files */
+ if ((str=getenv("UMASK_DIR")) != 0)
+ my_umask_dir=atoi(str) | 0700; /* Default creation of new dir's */
+#endif
+#ifdef VMS
+ init_ctype(); /* Stupid linker don't link _ctype.c */
+#endif
+ DBUG_PRINT("exit",("home: '%s'",home_dir));
+ }
+#ifdef __WIN__
+ win32_init_tcp_ip();
+#endif
+ DBUG_VOID_RETURN;
+ }
+} /* my_init */
+
+
+ /* End my_sys */
+
+void my_end(int infoflag)
+{
+ FILE *info_file;
+ if (!(info_file=DBUG_FILE))
+ info_file=stderr;
+ if (infoflag & MY_CHECK_ERROR || info_file != stderr)
+ { /* Test if some file is left open */
+ if (my_file_opened | my_stream_opened)
+ {
+ sprintf(errbuff[0],EE(EE_OPEN_WARNING),my_file_opened,my_stream_opened);
+ (void) my_message_no_curses(EE_OPEN_WARNING,errbuff[0],ME_BELL);
+ DBUG_PRINT("error",("%s",errbuff[0]));
+ }
+ }
+ if (infoflag & MY_GIVE_INFO || info_file != stderr)
+ {
+#ifdef HAVE_GETRUSAGE
+ struct rusage rus;
+ if (!getrusage(RUSAGE_SELF, &rus))
+ fprintf(info_file,"\nUser time %.2f, System time %.2f\nMaximum resident set size %ld, Integral resident set size %ld\nNon physical pagefaults %ld, Physical pagefaults %ld, Swaps %ld\nBlocks in %ld out %ld, Messages in %ld out %ld, Signals %ld\nVouluntary context switches %ld, Invouluntary context switches %ld\n",
+ (rus.ru_utime.tv_sec * SCALE_SEC +
+ rus.ru_utime.tv_usec / SCALE_USEC) / 100.0,
+ (rus.ru_stime.tv_sec * SCALE_SEC +
+ rus.ru_stime.tv_usec / SCALE_USEC) / 100.0,
+ rus.ru_maxrss, rus.ru_idrss,
+ rus.ru_minflt, rus.ru_majflt,
+ rus.ru_nswap, rus.ru_inblock, rus.ru_oublock,
+ rus.ru_msgsnd, rus.ru_msgrcv, rus.ru_nsignals,
+ rus.ru_nvcsw, rus.ru_nivcsw);
+#endif
+#if defined(MSDOS) && !defined(__WIN__)
+ fprintf(info_file,"\nRun time: %.1f\n",(double) clock()/CLOCKS_PER_SEC);
+#endif
+ free_charsets();
+#if defined(SAFEMALLOC)
+ TERMINATE(stderr); /* Give statistic on screen */
+#elif defined(__WIN__) && defined(_MSC_VER)
+ _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
+ _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
+ _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
+ _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
+ _CrtCheckMemory();
+ _CrtDumpMemoryLeaks();
+#endif
+ }
+#ifdef THREAD
+ pthread_mutex_destroy(&THR_LOCK_keycache);
+ pthread_mutex_destroy(&THR_LOCK_malloc);
+ pthread_mutex_destroy(&THR_LOCK_open);
+ DBUG_POP(); /* Must be done before my_thread_end */
+ my_thread_end();
+ my_thread_global_end();
+#endif
+#ifdef __WIN__
+ if (have_tcpip);
+ WSACleanup( );
+#endif /* __WIN__ */
+} /* my_end */
+
+#ifdef __WIN__
+
+/*
+ This code is specially for running MySQL, but it should work in
+ other cases too.
+
+ Inizializzazione delle variabili d'ambiente per Win a 32 bit.
+
+ Vengono inserite nelle variabili d'ambiente (utilizzando cosi'
+ le funzioni getenv e putenv) i valori presenti nelle chiavi
+ del file di registro:
+
+ HKEY_LOCAL_MACHINE\software\MySQL
+
+ Se la kiave non esiste nonn inserisce nessun valore
+*/
+
+/* Crea la stringa d'ambiente */
+
+void setEnvString(char *ret, const char *name, const char *value)
+{
+ DBUG_ENTER("setEnvString");
+ strxmov(ret, name,"=",value,NullS);
+ DBUG_VOID_RETURN ;
+}
+
+static void my_win_init(void)
+{
+ HKEY hSoftMysql ;
+ DWORD dimName = 256 ;
+ DWORD dimData = 1024 ;
+ DWORD dimNameValueBuffer = 256 ;
+ DWORD dimDataValueBuffer = 1024 ;
+ DWORD indexValue = 0 ;
+ long retCodeEnumValue ;
+ char NameValueBuffer[256] ;
+ char DataValueBuffer[1024] ;
+ char EnvString[1271] ;
+ const char *targetKey = "Software\\MySQL" ;
+ DBUG_ENTER("my_win_init");
+
+ setlocale(LC_CTYPE, ""); /* To get right sortorder */
+
+ /* apre la chiave HKEY_LOCAL_MACHINES\software\MySQL */
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,(LPCTSTR)targetKey,0,
+ KEY_READ,&hSoftMysql) != ERROR_SUCCESS)
+ DBUG_VOID_RETURN;
+
+ /*
+ ** Ne legge i valori e li inserisce nell'ambiente
+ ** suppone che tutti i valori letti siano di tipo stringa + '\0'
+ ** Legge il valore con indice 0 e lo scarta
+ */
+ retCodeEnumValue = RegEnumValue(hSoftMysql, indexValue++,
+ (LPTSTR)NameValueBuffer, &dimNameValueBuffer,
+ NULL, NULL, (LPBYTE)DataValueBuffer,
+ &dimDataValueBuffer) ;
+
+ while (retCodeEnumValue != ERROR_NO_MORE_ITEMS)
+ {
+ char *my_env;
+ /* Crea la stringa d'ambiente */
+ setEnvString(EnvString, NameValueBuffer, DataValueBuffer) ;
+
+ /* Inserisce i dati come variabili d'ambiente */
+ my_env=strdup(EnvString); /* variable for putenv must be allocated ! */
+ putenv(EnvString) ;
+
+ dimNameValueBuffer = dimName ;
+ dimDataValueBuffer = dimData ;
+
+ retCodeEnumValue = RegEnumValue(hSoftMysql, indexValue++,
+ NameValueBuffer, &dimNameValueBuffer,
+ NULL, NULL, (LPBYTE)DataValueBuffer,
+ &dimDataValueBuffer) ;
+ }
+
+ /* chiude la chiave */
+ RegCloseKey(hSoftMysql) ;
+ DBUG_VOID_RETURN ;
+}
+
+
+/*------------------------------------------------------------------
+** Name: CheckForTcpip| Desc: checks if tcpip has been installed on system
+** According to Microsoft Developers documentation the first registry
+** entry should be enough to check if TCP/IP is installed, but as expected
+** this doesn't work on all Win32 machines :(
+------------------------------------------------------------------*/
+
+#define TCPIPKEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+#define WINSOCK2KEY "SYSTEM\\CurrentControlSet\\Services\\Winsock2\\Parameters"
+#define WINSOCKKEY "SYSTEM\\CurrentControlSet\\Services\\Winsock\\Parameters"
+
+static my_bool win32_have_tcpip(void)
+{
+ HKEY hTcpipRegKey;
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, TCPIPKEY, 0, KEY_READ,
+ &hTcpipRegKey) != ERROR_SUCCESS)
+ {
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCK2KEY, 0, KEY_READ,
+ &hTcpipRegKey) != ERROR_SUCCESS)
+ {
+ if (RegOpenKeyEx ( HKEY_LOCAL_MACHINE, WINSOCKKEY, 0, KEY_READ,
+ &hTcpipRegKey) != ERROR_SUCCESS)
+ if (!getenv("HAVE_TCPIP") || have_tcpip) /* Provide a workaround */
+ return (FALSE);
+ }
+ }
+ RegCloseKey ( hTcpipRegKey);
+ return (TRUE);
+}
+
+static my_bool win32_init_tcp_ip()
+{
+ if (win32_have_tcpip())
+ {
+ WORD wVersionRequested = MAKEWORD( 2, 0 );
+ WSADATA wsaData;
+ /* Be a good citizen: maybe another lib has already initialised
+ sockets, so dont clobber them unless necessary */
+ if (WSAStartup( wVersionRequested, &wsaData ))
+ {
+ /* Load failed, maybe because of previously loaded
+ incompatible version; try again */
+ WSACleanup( );
+ if (!WSAStartup( wVersionRequested, &wsaData ))
+ have_tcpip=1;
+ }
+ else
+ {
+ if (wsaData.wVersion != wVersionRequested)
+ {
+ /* Version is no good, try again */
+ WSACleanup( );
+ if (!WSAStartup( wVersionRequested, &wsaData ))
+ have_tcpip=1;
+ }
+ else
+ have_tcpip=1;
+ }
+ }
+ return(0);
+}
+#endif
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
new file mode 100644
index 00000000000..b8554b08d28
--- /dev/null
+++ b/mysys/my_lib.c
@@ -0,0 +1,607 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* TODO: check for overun of memory for names. */
+/* Convert MSDOS-TIME to standar time_t */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <my_dir.h> /* Structs used by my_dir,includes sys/types */
+#include "mysys_err.h"
+#if defined(HAVE_DIRENT_H)
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if defined(HAVE_SYS_NDIR_H)
+# include <sys/ndir.h>
+# endif
+# if defined(HAVE_SYS_DIR_H)
+# include <sys/dir.h>
+# endif
+# if defined(HAVE_NDIR_H)
+# include <ndir.h>
+# endif
+# if defined(MSDOS) || defined(__WIN__)
+# include <dos.h>
+# ifdef __BORLANDC__
+# include <dir.h>
+# endif
+# endif
+#endif
+#ifdef VMS
+#include <rms.h>
+#include <iodef.h>
+#include <descrip.h>
+#endif
+#if defined(THREAD) && defined(HAVE_READDIR_R)
+#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
+#else
+#define READDIR(A,B,C) (!(C=readdir(A)))
+#endif
+
+
+#define STARTSIZE ONCE_ALLOC_INIT*8 /* some mallocmargin */
+
+static int comp_names(struct fileinfo *a,struct fileinfo *b);
+
+
+ /* We need this because program don't know with malloc we used */
+
+void my_dirend(MY_DIR *buffer)
+{
+ DBUG_ENTER("my_dirend");
+ if (buffer)
+ my_free((gptr) buffer,MYF(0));
+ DBUG_VOID_RETURN;
+} /* my_dirend */
+
+
+ /* Compare in sort of filenames */
+
+static int comp_names(struct fileinfo *a, struct fileinfo *b)
+{
+ return (strcmp(a->name,b->name));
+} /* comp_names */
+
+
+#if !defined(MSDOS) && !defined(__WIN__)
+
+MY_DIR *my_dir(const char *path, myf MyFlags)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ struct fileinfo *fnames;
+ char *buffer, *obuffer, *tempptr;
+ uint fcnt,i,size,firstfcnt, maxfcnt,length;
+ char tmp_path[FN_REFLEN+1],*tmp_file;
+ my_ptrdiff_t diff;
+ bool eof;
+#ifdef THREAD
+ char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
+#endif
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+
+#if defined(THREAD) && !defined(HAVE_READDIR_R)
+ pthread_mutex_lock(&THR_LOCK_open);
+#endif
+
+ dirp = opendir(directory_file_name(tmp_path,(my_string) path));
+ size = STARTSIZE;
+ if (dirp == NULL || ! (buffer = (char *) my_malloc(size, MyFlags)))
+ goto error;
+
+ fcnt = 0;
+ tmp_file=strend(tmp_path);
+ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+ (sizeof(struct fileinfo) + FN_LEN);
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr = (char *) (fnames + maxfcnt);
+
+#ifdef THREAD
+ dp= (struct dirent*) dirent_tmp;
+#else
+ dp=0;
+#endif
+ eof=0;
+ for (;;)
+ {
+ while (fcnt < maxfcnt &&
+ !(eof= READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
+ {
+ bzero((gptr) (fnames+fcnt),sizeof(fnames[0])); /* for purify */
+ fnames[fcnt].name = tempptr;
+ tempptr = strmov(tempptr,dp->d_name) + 1;
+ if (MyFlags & MY_WANT_STAT)
+ {
+ VOID(strmov(tmp_file,dp->d_name));
+ VOID(my_stat(tmp_path, &fnames[fcnt].mystat, MyFlags));
+ }
+ ++fcnt;
+ }
+ if (eof)
+ break;
+ size += STARTSIZE; obuffer = buffer;
+ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+ MyFlags | MY_FREE_ON_ERROR)))
+ goto error; /* No memory */
+ length= (uint) (sizeof(struct fileinfo ) * firstfcnt);
+ diff= PTR_BYTE_DIFF(buffer , obuffer) + (int) length;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr= ADD_TO_PTR(tempptr,diff,char*);
+ for (i = 0; i < maxfcnt; i++)
+ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+
+ /* move filenames upp a bit */
+ maxfcnt += firstfcnt;
+ bmove_upp(tempptr,tempptr-length,
+ (uint) (tempptr- (char*) (fnames+maxfcnt)));
+ }
+
+ (void) closedir(dirp);
+ {
+ MY_DIR * s = (MY_DIR *) buffer;
+ s->number_off_files = (uint) fcnt;
+ s->dir_entry = fnames;
+ }
+ if (!(MyFlags & MY_DONT_SORT))
+ qsort((void *) fnames, (size_s) fcnt, sizeof(struct fileinfo),
+ (qsort_cmp) comp_names);
+#if defined(THREAD) && !defined(HAVE_READDIR_R)
+ pthread_mutex_unlock(&THR_LOCK_open);
+#endif
+ DBUG_RETURN((MY_DIR *) buffer);
+
+ error:
+#if defined(THREAD) && !defined(HAVE_READDIR_R)
+ pthread_mutex_unlock(&THR_LOCK_open);
+#endif
+ my_errno=errno;
+ if (dirp)
+ (void) closedir(dirp);
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,my_errno);
+ DBUG_RETURN((MY_DIR *) NULL);
+} /* my_dir */
+
+
+/*
+ * Convert from directory name to filename.
+ * On VMS:
+ * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
+ * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
+ * On UNIX, it's simple: just make sure there is a terminating /
+
+ * Returns pointer to dst;
+ */
+
+my_string directory_file_name (my_string dst, const char *src)
+{
+#ifndef VMS
+
+ /* Process as Unix format: just remove test the final slash. */
+
+ my_string end;
+
+ if (src[0] == 0)
+ src= (char*) "."; /* Use empty as current */
+ end=strmov(dst, src);
+ if (end[-1] != FN_LIBCHAR)
+ {
+ end[0]=FN_LIBCHAR; /* Add last '/' */
+ end[1]='\0';
+ }
+ return dst;
+
+#else /* VMS */
+
+ long slen;
+ long rlen;
+ my_string ptr, rptr;
+ char bracket;
+ struct FAB fab = cc$rms_fab;
+ struct NAM nam = cc$rms_nam;
+ char esa[NAM$C_MAXRSS];
+
+ if (! src[0])
+ src="[.]"; /* Empty is == current dir */
+
+ slen = strlen (src) - 1;
+ if (src[slen] == FN_C_AFTER_DIR || src[slen] == FN_C_AFTER_DIR_2 ||
+ src[slen] == FN_DEVCHAR)
+ {
+ /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
+ fab.fab$l_fna = src;
+ fab.fab$b_fns = slen + 1;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = sizeof esa;
+ nam.nam$b_nop |= NAM$M_SYNCHK;
+
+ /* We call SYS$PARSE to handle such things as [--] for us. */
+ if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
+ {
+ slen = nam.nam$b_esl - 1;
+ if (esa[slen] == ';' && esa[slen - 1] == '.')
+ slen -= 2;
+ esa[slen + 1] = '\0';
+ src = esa;
+ }
+ if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
+ {
+ /* what about when we have logical_name:???? */
+ if (src[slen] == FN_DEVCHAR)
+ { /* Xlate logical name and see what we get */
+ VOID(strmov(dst,src));
+ dst[slen] = 0; /* remove colon */
+ if (!(src = getenv (dst)))
+ return dst; /* Can't translate */
+
+ /* should we jump to the beginning of this procedure?
+ Good points: allows us to use logical names that xlate
+ to Unix names,
+ Bad points: can be a problem if we just translated to a device
+ name...
+ For now, I'll punt and always expect VMS names, and hope for
+ the best! */
+
+ slen = strlen (src) - 1;
+ if (src[slen] != FN_C_AFTER_DIR && src[slen] != FN_C_AFTER_DIR_2)
+ { /* no recursion here! */
+ VOID(strmov(dst, src));
+ return(dst);
+ }
+ }
+ else
+ { /* not a directory spec */
+ VOID(strmov(dst, src));
+ return(dst);
+ }
+ }
+
+ bracket = src[slen]; /* End char */
+ if (!(ptr = strchr (src, bracket - 2)))
+ { /* no opening bracket */
+ VOID(strmov (dst, src));
+ return dst;
+ }
+ if (!(rptr = strrchr (src, '.')))
+ rptr = ptr;
+ slen = rptr - src;
+ VOID(strmake (dst, src, slen));
+
+ if (*rptr == '.')
+ { /* Put bracket and add */
+ dst[slen++] = bracket; /* (rptr+1) after this */
+ }
+ else
+ {
+ /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
+ then translate the device and recurse. */
+
+ if (dst[slen - 1] == ':'
+ && dst[slen - 2] != ':' /* skip decnet nodes */
+ && strcmp(src + slen, "[000000]") == 0)
+ {
+ dst[slen - 1] = '\0';
+ if ((ptr = getenv (dst))
+ && (rlen = strlen (ptr) - 1) > 0
+ && (ptr[rlen] == FN_C_AFTER_DIR || ptr[rlen] == FN_C_AFTER_DIR_2)
+ && ptr[rlen - 1] == '.')
+ {
+ VOID(strmov(esa,ptr));
+ esa[rlen - 1] = FN_C_AFTER_DIR;
+ esa[rlen] = '\0';
+ return (directory_file_name (dst, esa));
+ }
+ else
+ dst[slen - 1] = ':';
+ }
+ VOID(strmov(dst+slen,"[000000]"));
+ slen += 8;
+ }
+ VOID(strmov(strmov(dst+slen,rptr+1)-1,".DIR.1"));
+ return dst;
+ }
+ VOID(strmov(dst, src));
+ if (dst[slen] == '/' && slen > 1)
+ dst[slen] = 0;
+ return dst;
+#endif /* VMS */
+} /* directory_file_name */
+
+#elif defined(WIN32)
+
+/*
+*****************************************************************************
+** Read long filename using windows rutines
+*****************************************************************************
+*/
+
+MY_DIR *my_dir(path, MyFlags)
+const char *path;
+myf MyFlags;
+{
+ struct fileinfo *fnames;
+ char *buffer, *obuffer, *tempptr;
+ int eof,i,fcnt,firstfcnt,length,maxfcnt;
+ uint size;
+#ifdef __BORLANDC__
+ struct ffblk find;
+#else
+ struct _finddata_t find;
+#endif
+ ushort mode;
+ char tmp_path[FN_REFLEN],*tmp_file,attrib;
+ my_ptrdiff_t diff;
+ long handle;
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+
+ /* Put LIB-CHAR as last path-character if not there */
+
+ tmp_file=tmp_path;
+ if (!*path)
+ *tmp_file++ ='.'; /* From current dir */
+ tmp_file= strmov(tmp_file,path);
+ if (tmp_file[-1] == FN_DEVCHAR)
+ *tmp_file++= '.'; /* From current dev-dir */
+ if (tmp_file[-1] != FN_LIBCHAR)
+ *tmp_file++ =FN_LIBCHAR;
+ tmp_file[0]='*'; /* MSDOS needs this !??? */
+ tmp_file[1]='.';
+ tmp_file[2]='*';
+ tmp_file[3]='\0';
+
+#ifdef __BORLANDC__
+ if ((handle= findfirst(tmp_path,&find,0)) == -1L)
+ goto error;
+#else
+ if ((handle=_findfirst(tmp_path,&find)) == -1L)
+ goto error;
+#endif
+
+ size = STARTSIZE;
+ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+ (sizeof(struct fileinfo) + FN_LEN);
+ if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
+ goto error;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr = (char *) (fnames + maxfcnt);
+
+ fcnt = 0;
+ for (;;)
+ {
+ do
+ {
+ fnames[fcnt].name = tempptr;
+#ifdef __BORLANDC__
+ tempptr = strmov(tempptr,find.ff_name) + 1;
+ fnames[fcnt].mystat.st_size=find.ff_fsize;
+ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+ mode=MY_S_IREAD; attrib=find.ff_attrib;
+#else
+ tempptr = strmov(tempptr,find.name) + 1;
+ fnames[fcnt].mystat.st_size=find.size;
+ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+ mode=MY_S_IREAD; attrib=find.attrib;
+#endif
+ if (!(attrib & _A_RDONLY))
+ mode|=MY_S_IWRITE;
+ if (attrib & _A_SUBDIR)
+ mode|=MY_S_IFDIR;
+ fnames[fcnt].mystat.st_mode=mode;
+#ifdef __BORLANDC__
+ fnames[fcnt].mystat.st_mtime=((uint32) find.ff_ftime);
+#else
+ fnames[fcnt].mystat.st_mtime=((uint32) find.time_write);
+#endif
+ ++fcnt;
+#ifdef __BORLANDC__
+ } while ((eof= findnext(&find)) == 0 && fcnt < maxfcnt);
+#else
+ } while ((eof= _findnext(handle,&find)) == 0 && fcnt < maxfcnt);
+#endif
+
+ DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
+ if (eof)
+ break;
+ size += STARTSIZE; obuffer = buffer;
+ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+ MyFlags | MY_FREE_ON_ERROR)))
+ goto error;
+ length= sizeof(struct fileinfo ) * firstfcnt;
+ diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr= ADD_TO_PTR(tempptr,diff,char*);
+ for (i = 0; i < maxfcnt; i++)
+ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+
+ /* move filenames upp a bit */
+ maxfcnt += firstfcnt;
+ bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
+ (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
+ }
+ {
+ MY_DIR * s = (MY_DIR *) buffer;
+ s->number_off_files = (uint) fcnt;
+ s->dir_entry = fnames;
+ }
+ if (!(MyFlags & MY_DONT_SORT))
+ qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
+#ifndef __BORLANDC__
+ _findclose(handle);
+#endif
+ DBUG_RETURN((MY_DIR *) buffer);
+
+error:
+ my_errno=errno;
+#ifndef __BORLANDC__
+ if (handle != -1)
+ _findclose(handle);
+#endif
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
+ DBUG_RETURN((MY_DIR *) NULL);
+} /* my_dir */
+
+#else /* MSDOS and not WIN32 */
+
+
+/******************************************************************************
+** At MSDOS you always get stat of files, but time is in packed MSDOS-format
+******************************************************************************/
+
+MY_DIR *my_dir(path, MyFlags)
+const char *path;
+myf MyFlags;
+{
+ struct fileinfo *fnames;
+ char *buffer, *obuffer, *tempptr;
+ int eof,i,fcnt,firstfcnt,length,maxfcnt;
+ uint size;
+ struct find_t find;
+ ushort mode;
+ char tmp_path[FN_REFLEN],*tmp_file,attrib;
+ my_ptrdiff_t diff;
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("my",("path: '%s' stat: %d MyFlags: %d",path,MyFlags));
+
+ /* Put LIB-CHAR as last path-character if not there */
+
+ tmp_file=tmp_path;
+ if (!*path)
+ *tmp_file++ ='.'; /* From current dir */
+ tmp_file= strmov(tmp_file,path);
+ if (tmp_file[-1] == FN_DEVCHAR)
+ *tmp_file++= '.'; /* From current dev-dir */
+ if (tmp_file[-1] != FN_LIBCHAR)
+ *tmp_file++ =FN_LIBCHAR;
+ tmp_file[0]='*'; /* MSDOS needs this !??? */
+ tmp_file[1]='.';
+ tmp_file[2]='*';
+ tmp_file[3]='\0';
+
+ if (_dos_findfirst(tmp_path,_A_NORMAL | _A_SUBDIR, &find))
+ goto error;
+
+ size = STARTSIZE;
+ firstfcnt = maxfcnt = (size - sizeof(MY_DIR)) /
+ (sizeof(struct fileinfo) + FN_LEN);
+ if ((buffer = (char *) my_malloc(size, MyFlags)) == 0)
+ goto error;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr = (char *) (fnames + maxfcnt);
+
+ fcnt = 0;
+ for (;;)
+ {
+ do
+ {
+ fnames[fcnt].name = tempptr;
+ tempptr = strmov(tempptr,find.name) + 1;
+ fnames[fcnt].mystat.st_size=find.size;
+ fnames[fcnt].mystat.st_uid=fnames[fcnt].mystat.st_gid=0;
+ mode=MY_S_IREAD; attrib=find.attrib;
+ if (!(attrib & _A_RDONLY))
+ mode|=MY_S_IWRITE;
+ if (attrib & _A_SUBDIR)
+ mode|=MY_S_IFDIR;
+ fnames[fcnt].mystat.st_mode=mode;
+ fnames[fcnt].mystat.st_mtime=((uint32) find.wr_date << 16) +
+ find.wr_time;
+ ++fcnt;
+ } while ((eof= _dos_findnext(&find)) == 0 && fcnt < maxfcnt);
+
+ DBUG_PRINT("test",("eof: %d errno: %d",eof,errno));
+ if (eof)
+ break;
+ size += STARTSIZE; obuffer = buffer;
+ if (!(buffer = (char *) my_realloc((gptr) buffer, size,
+ MyFlags | MY_FREE_ON_ERROR)))
+ goto error;
+ length= sizeof(struct fileinfo ) * firstfcnt;
+ diff= PTR_BYTE_DIFF(buffer , obuffer) +length;
+ fnames= (struct fileinfo *) (buffer + sizeof(MY_DIR));
+ tempptr= ADD_TO_PTR(tempptr,diff,char*);
+ for (i = 0; i < maxfcnt; i++)
+ fnames[i].name = ADD_TO_PTR(fnames[i].name,diff,char*);
+
+ /* move filenames upp a bit */
+ maxfcnt += firstfcnt;
+ bmove_upp(tempptr,ADD_TO_PTR(tempptr,-length,char*),
+ (int) PTR_BYTE_DIFF(tempptr,fnames+maxfcnt));
+ }
+ {
+ MY_DIR * s = (MY_DIR *) buffer;
+ s->number_off_files = (uint) fcnt;
+ s->dir_entry = fnames;
+ }
+ if (!(MyFlags & MY_DONT_SORT))
+ qsort(fnames,fcnt,sizeof(struct fileinfo),(qsort_cmp) comp_names);
+ DBUG_RETURN((MY_DIR *) buffer);
+
+error:
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_DIR,MYF(ME_BELL+ME_WAITTANG),path,errno);
+ DBUG_RETURN((MY_DIR *) NULL);
+} /* my_dir */
+
+#endif /* WIN32 && MSDOS */
+
+/****************************************************************************
+** File status
+** Note that MY_STAT is assumed to be same as struct stat
+****************************************************************************/
+
+int my_fstat(int Filedes, MY_STAT *stat_area, myf MyFlags )
+{
+ DBUG_ENTER("my_fstat");
+ DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags));
+ DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
+}
+
+MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
+{
+ int m_used;
+ DBUG_ENTER("my_stat");
+ DBUG_PRINT("my", ("path: '%s', stat_area: %lx, MyFlags: %d", path,
+ (byte *) stat_area, my_flags));
+
+ if ((m_used= (stat_area == NULL)))
+ if (!(stat_area = (MY_STAT *) my_malloc(sizeof(MY_STAT), my_flags)))
+ goto error;
+ if ( ! stat((my_string) path, (struct stat *) stat_area) )
+ DBUG_RETURN(stat_area);
+ my_errno=errno;
+ if (m_used) /* Free if new area */
+ my_free((gptr) stat_area,MYF(0));
+
+error:
+ if (my_flags & (MY_FAE+MY_WME))
+ {
+ my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),path,my_errno);
+ DBUG_RETURN((MY_STAT *) NULL);
+ }
+ DBUG_RETURN((MY_STAT *) NULL);
+} /* my_stat */
+
diff --git a/mysys/my_lock.c b/mysys/my_lock.c
new file mode 100644
index 00000000000..4f1506f20cf
--- /dev/null
+++ b/mysys/my_lock.c
@@ -0,0 +1,161 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+#undef MY_HOW_OFTEN_TO_ALARM
+#define MY_HOW_OFTEN_TO_ALARM ((int) my_time_to_wait_for_lock)
+#ifdef NO_ALARM_LOOP
+#undef NO_ALARM_LOOP
+#endif
+#include <my_alarm.h>
+#ifdef __WIN__
+#include <sys/locking.h>
+#endif
+#ifdef __EMX__
+#define INCL_BASE
+#define INCL_NOPMAPI
+#include <os2emx.h>
+#endif
+
+#ifdef HAVE_FCNTL
+static struct flock lock; /* Must be static for sun-sparc */
+#endif
+
+ /* Lock a part of a file */
+
+int my_lock(File fd, int locktype, my_off_t start, my_off_t length,
+ myf MyFlags)
+{
+#ifdef __EMX__
+ FILELOCK LockArea = {0,0}, UnlockArea = {0,0};
+ APIRET rc = 0;
+ fpos_t oldpos;
+ int lockflags = 0;
+#endif
+#ifdef HAVE_FCNTL
+ int value;
+ ALARM_VARIABLES;
+#endif
+ DBUG_ENTER("my_lock");
+ DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d",
+ fd,locktype,(long) start,(long) length,MyFlags));
+#ifdef VMS
+ DBUG_RETURN(0);
+#else
+ if (my_disable_locking)
+ DBUG_RETURN(0);
+#if defined(__EMX__)
+ if (locktype == F_UNLCK) {
+ UnlockArea.lOffset = start;
+ if (length)
+ UnlockArea.lRange = length;
+ else
+ UnlockArea.lRange = 0x7FFFFFFFL;
+ } else
+ if (locktype == F_RDLCK || locktype == F_WRLCK) {
+ if (locktype == F_RDLCK) lockflags |= 1;
+ LockArea.lOffset = start;
+ if (length)
+ LockArea.lRange = length;
+ else
+ LockArea.lRange = 0x7FFFFFFFL;
+ } else {
+ my_errno = EINVAL;
+ DBUG_RETURN(-1);
+ }
+ if (!LockArea.lRange && !UnlockArea.lRange)
+ DBUG_RETURN(0);
+ if (MyFlags & MY_DONT_WAIT) {
+ if (!(rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,0,lockflags)))
+ DBUG_RETURN(0); /* Lock was OK */
+ if (rc == 175 && locktype == F_RDLCK) {
+ lockflags &= ~1;
+ rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,0,lockflags);
+ }
+ if (rc == 33) { /* Lock Violation */
+ DBUG_PRINT("info",("Was locked, trying with timeout"));
+ rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,MY_HOW_OFTEN_TO_ALARM * 1000,lockflags);
+ }
+ if (!rc) DBUG_RETURN(0);
+ if (rc == 33) errno = EAGAIN;
+ else {
+ errno = EINVAL;
+ printf("Error: DosSetFileLocks() == %d\n",rc);
+ }
+ } else {
+ while (rc = DosSetFileLocks(fd,&UnlockArea,&LockArea,
+ MY_HOW_OFTEN_TO_ALARM * 1000,lockflags) && (rc == 33 || rc == 175)) {
+ printf(".");
+ if (rc == 175) lockflags &= ~1;
+ }
+ if (!rc) DBUG_RETURN(0);
+ errno = EINVAL;
+ printf("Error: DosSetFileLocks() == %d\n",rc);
+ }
+#elif defined(HAVE_LOCKING)
+ if (MyFlags & MY_SEEK_NOT_DONE)
+ VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)));
+ if (!locking(fd,locktype,(ulong) length) || errno == EINVAL)
+ DBUG_RETURN(0);
+#else
+#if defined(HAVE_FCNTL)
+ lock.l_type= (short) locktype;
+ lock.l_whence=0L;
+ lock.l_start=(long) start;
+ lock.l_len=(long) length;
+ if (MyFlags & MY_DONT_WAIT)
+ {
+ if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */
+ DBUG_RETURN(0); /* Ok, file locked */
+ DBUG_PRINT("info",("Was locked, trying with alarm"));
+ ALARM_INIT;
+ while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST &&
+ errno == EINTR)
+ { /* Setup again so we don`t miss it */
+ ALARM_REINIT;
+ }
+ ALARM_END;
+ if (value != -1)
+ DBUG_RETURN(0);
+ if (errno == EINTR)
+ errno=EAGAIN;
+ }
+ else if (fcntl(fd,F_SETLKW,&lock) != -1) /* Wait until a lock */
+ DBUG_RETURN(0);
+#else
+ if (MyFlags & MY_SEEK_NOT_DONE)
+ VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)));
+ if (lockf(fd,locktype,length) != -1)
+ DBUG_RETURN(0);
+#endif /* HAVE_FCNTL */
+#endif /* HAVE_LOCKING */
+
+ /* We got an error. We don't want EACCES errors */
+ my_errno=(errno == EACCES) ? EAGAIN : errno ? errno : -1;
+ if (MyFlags & MY_WME)
+ {
+ if (locktype == F_UNLCK)
+ my_error(EE_CANTUNLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
+ else
+ my_error(EE_CANTLOCK,MYF(ME_BELL+ME_WAITTANG),my_errno);
+ }
+ DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno));
+ DBUG_RETURN(-1);
+#endif /* ! VMS */
+} /* my_lock */
diff --git a/mysys/my_lockmem.c b/mysys/my_lockmem.c
new file mode 100644
index 00000000000..9c77c885797
--- /dev/null
+++ b/mysys/my_lockmem.c
@@ -0,0 +1,101 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Alloc a block of locked memory */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <my_list.h>
+
+#ifdef HAVE_MLOCK
+#include <sys/mman.h>
+
+struct st_mem_list
+{
+ LIST list;
+ byte *page;
+ uint size;
+};
+
+LIST *mem_list;
+
+byte *my_malloc_lock(uint size,myf MyFlags)
+{
+ int success;
+ uint pagesize=sysconf(_SC_PAGESIZE);
+ byte *ptr;
+ struct st_mem_list *element;
+ DBUG_ENTER("my_malloc_lock");
+
+ size=((size-1) & ~(pagesize-1))+pagesize;
+ if (!(ptr=memalign(pagesize,size)))
+ {
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),size);
+ DBUG_RETURN(0);
+ }
+ success = mlock((byte*) ptr,size);
+ if (success != 0 && geteuid() == 0)
+ {
+ DBUG_PRINT("warning",("Failed to lock memory. errno %d\n",
+ errno));
+ fprintf(stderr, "Warning: Failed to lock memory. errno %d\n",
+ errno);
+ }
+ else
+ {
+ /* Add block in a list for munlock */
+ if (!(element=(struct st_mem_list*) my_malloc(sizeof(*element),MyFlags)))
+ {
+ VOID(munlock((byte*) ptr,size));
+ free(ptr);
+ DBUG_RETURN(0);
+ }
+ element->list.data=(byte*) element;
+ element->page=ptr;
+ element->size=size;
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ mem_list=list_add(mem_list,&element->list);
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ }
+ DBUG_RETURN(ptr);
+}
+
+
+void my_free_lock(byte *ptr,myf Myflags __attribute__((unused)))
+{
+ LIST *list;
+ struct st_mem_list *element=0;
+
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ for (list=mem_list ; list ; list=list->next)
+ {
+ element=(struct st_mem_list*) list->data;
+ if (ptr == element->page)
+ { /* Found locked mem */
+ VOID(munlock((byte*) ptr,element->size));
+ mem_list=list_delete(mem_list,list);
+ break;
+ }
+ }
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ if (element)
+ my_free((gptr) element,MYF(0));
+ free(ptr); /* Free even if not locked */
+}
+
+#endif /* HAVE_MLOCK */
diff --git a/mysys/my_lread.c b/mysys/my_lread.c
new file mode 100644
index 00000000000..c3b8a6704c3
--- /dev/null
+++ b/mysys/my_lread.c
@@ -0,0 +1,54 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+
+ /* Read a chunk of bytes from a file */
+
+uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags)
+ /* File descriptor */
+ /* Buffer must be at least count bytes */
+ /* Max number of bytes returnd */
+ /* Flags on what to do on error */
+{
+ uint32 readbytes;
+ DBUG_ENTER("my_lread");
+ DBUG_PRINT("my",("Fd: %d Buffer: %ld Count: %ld MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+
+ /* Temp hack to get count to int32 while read wants int */
+ if ((readbytes = (uint32) read(Filedes, Buffer, (size_t) Count)) != Count)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if (readbytes == MY_FILE_ERROR)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),errno);
+ else
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),errno);
+ }
+ if (readbytes == MY_FILE_ERROR || MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN((uint32) -1); /* Return med felkod */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Ok vid l{sning */
+ DBUG_RETURN(readbytes);
+} /* my_lread */
diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c
new file mode 100644
index 00000000000..201c36f619c
--- /dev/null
+++ b/mysys/my_lwrite.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+
+ /* Write a chunk of bytes to a file */
+
+uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags)
+{
+ uint32 writenbytes;
+ DBUG_ENTER("my_lwrite");
+ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %ld MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+
+ /* Temp hack to get count to int32 while write wants int */
+ if ((writenbytes = (uint32) write(Filedes, Buffer, (size_t) Count)) != Count)
+ {
+ my_errno=errno;
+ if (writenbytes == (uint32) -1 || MyFlags & (MY_NABP | MY_FNABP))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),errno);
+ }
+ DBUG_RETURN((uint32) -1); /* Return med felkod */
+ }
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Ok vid l{sning */
+ DBUG_RETURN(writenbytes);
+} /* my_lwrite */
diff --git a/mysys/my_malloc.c b/mysys/my_malloc.c
new file mode 100644
index 00000000000..6cae6fe3a4d
--- /dev/null
+++ b/mysys/my_malloc.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+#undef SAFEMALLOC
+#endif
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <m_string.h>
+
+ /* My memory allocator */
+
+gptr my_malloc(unsigned int Size, myf MyFlags)
+{
+ gptr point;
+ DBUG_ENTER("my_malloc");
+ DBUG_PRINT("my",("Size: %u MyFlags: %d",Size, MyFlags));
+
+ if (!Size)
+ Size=1; /* Safety */
+ if ((point = malloc(Size)) == NULL)
+ {
+ my_errno=errno;
+ if (MyFlags & MY_FAE)
+ error_handler_hook=fatal_error_handler_hook;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
+ if (MyFlags & MY_FAE)
+ exit(1);
+ }
+ else if (MyFlags & MY_ZEROFILL)
+ bzero(point,Size);
+ DBUG_PRINT("exit",("ptr: %lx",point));
+ DBUG_RETURN(point);
+} /* my_malloc */
+
+
+ /* Free memory allocated with my_malloc */
+ /*ARGSUSED*/
+
+void my_no_flags_free(gptr ptr)
+{
+ DBUG_ENTER("my_free");
+ DBUG_PRINT("my",("ptr: %lx",ptr));
+ if (ptr)
+ free(ptr);
+ DBUG_VOID_RETURN;
+} /* my_free */
+
+
+ /* malloc and copy */
+
+gptr my_memdup(const byte *from, uint length, myf MyFlags)
+{
+ gptr ptr;
+ if ((ptr=my_malloc(length,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return(ptr);
+}
+
+
+my_string my_strdup(const char *from, myf MyFlags)
+{
+ gptr ptr;
+ uint length=(uint) strlen(from)+1;
+ if ((ptr=my_malloc(length,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return((my_string) ptr);
+}
diff --git a/mysys/my_messnc.c b/mysys/my_messnc.c
new file mode 100644
index 00000000000..0dd3be5ba98
--- /dev/null
+++ b/mysys/my_messnc.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+
+int my_message_no_curses(uint error __attribute__((unused)),
+ const char *str, myf MyFlags)
+{
+ DBUG_ENTER("my_message_no_curses");
+ DBUG_PRINT("enter",("message: %s",str));
+ (void) fflush(stdout);
+ if (MyFlags & ME_BELL)
+ (void) fputc('\007',stderr); /* Bell */
+ if (my_progname)
+ {
+ (void)fputs(my_progname,stderr); (void)fputs(": ",stderr);
+ }
+ (void)fputs(str,stderr);
+ (void)fputc('\n',stderr);
+ (void)fflush(stderr);
+ DBUG_RETURN(0);
+}
diff --git a/mysys/my_mkdir.c b/mysys/my_mkdir.c
new file mode 100644
index 00000000000..773cd26cb03
--- /dev/null
+++ b/mysys/my_mkdir.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __WIN__
+#include <direct.h>
+#endif
+
+int my_mkdir(const char *dir, int Flags, myf MyFlags)
+{
+ DBUG_ENTER("my_dir");
+ DBUG_PRINT("enter",("dir: %s",dir));
+
+#ifdef __WIN__
+ if (mkdir(dir))
+#else
+ if (mkdir((char*) dir, Flags & my_umask_dir))
+#endif
+ {
+ my_errno=errno;
+ DBUG_PRINT("error",("error %d when creating direcory %s",my_errno,dir));
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error(EE_CANT_MKDIR, MYF(ME_BELL+ME_WAITTANG), dir, my_errno);
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/mysys/my_net.c b/mysys/my_net.c
new file mode 100644
index 00000000000..1c91f7ff802
--- /dev/null
+++ b/mysys/my_net.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* thread safe version of some common functions */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+/* for thread safe my_inet_ntoa */
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <netdb.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#endif /* !defined(MSDOS) && !defined(__WIN__) */
+
+#ifndef THREAD
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+#endif
+
+void my_inet_ntoa(struct in_addr in, char *buf)
+{
+ char *ptr;
+ pthread_mutex_lock(&THR_LOCK_net);
+ ptr=inet_ntoa(in);
+ strmov(buf,ptr);
+ pthread_mutex_unlock(&THR_LOCK_net);
+}
diff --git a/mysys/my_once.c b/mysys/my_once.c
new file mode 100644
index 00000000000..0b8b5addc16
--- /dev/null
+++ b/mysys/my_once.c
@@ -0,0 +1,88 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Not MT-SAFE */
+
+#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+#undef SAFEMALLOC
+#endif
+
+#include "mysys_priv.h"
+#include "my_static.h"
+#include "mysys_err.h"
+
+ /* alloc for things we don't nead to free */
+ /* No DBUG_ENTER... here to get smaller dbug-startup */
+
+gptr my_once_alloc(unsigned int Size, myf MyFlags)
+{
+ uint get_size,max_left;
+ gptr point;
+ reg1 USED_MEM *next;
+ reg2 USED_MEM **prev;
+
+ Size= ALIGN_SIZE(Size);
+ prev= &my_once_root_block;
+ max_left=0;
+ for (next=my_once_root_block ; next && next->left < Size ; next= next->next)
+ {
+ if (next->left > max_left)
+ max_left=next->left;
+ prev= &next->next;
+ }
+ if (! next)
+ { /* Time to alloc new block */
+ get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
+ if (max_left*4 < my_once_extra && get_size < my_once_extra)
+ get_size=my_once_extra; /* Normal alloc */
+
+ if ((next = (USED_MEM*) malloc(get_size)) == 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),get_size);
+ return((gptr) 0);
+ }
+ DBUG_PRINT("test",("my_once_malloc %u byte malloced",get_size));
+ next->next= 0;
+ next->size= get_size;
+ next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
+ *prev=next;
+ }
+ point= (gptr) ((char*) next+ (next->size-next->left));
+ next->left-= Size;
+
+ return(point);
+} /* my_once_alloc */
+
+
+ /* deallocate everything used by my_once_alloc */
+
+void my_once_free(void)
+{
+ reg1 USED_MEM *next,*old;
+ DBUG_ENTER("my_once_free");
+
+ for (next=my_once_root_block ; next ; )
+ {
+ old=next; next= next->next ;
+ free((gptr) old);
+ }
+ my_once_root_block=0;
+
+ DBUG_VOID_RETURN;
+} /* my_once_free */
diff --git a/mysys/my_open.c b/mysys/my_open.c
new file mode 100644
index 00000000000..ef1db41e3f5
--- /dev/null
+++ b/mysys/my_open.c
@@ -0,0 +1,97 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+#if defined(MSDOS) || defined(__WIN__)
+#include <share.h>
+#endif
+
+ /* Open a file */
+
+File my_open(const char *FileName, int Flags, myf MyFlags)
+ /* Path-name of file */
+ /* Read | write .. */
+ /* Special flags */
+{
+ File fd;
+ DBUG_ENTER("my_open");
+ DBUG_PRINT("my",("Name: '%s' Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+#if defined(MSDOS) || defined(__WIN__)
+ if (Flags & O_SHARE)
+ fd = sopen((my_string) FileName, (Flags & ~O_SHARE) | O_BINARY, SH_DENYNO);
+ else
+ fd = open((my_string) FileName, Flags | O_BINARY);
+#elif !defined(NO_OPEN_3)
+ fd = open(FileName, Flags, 0); /* Normal unix */
+#else
+ fd = open((my_string) FileName, Flags);
+#endif
+
+ if ((int) fd >= 0)
+ {
+ if ((int) fd >= MY_NFILE)
+ DBUG_RETURN(fd); /* safeguard */
+ pthread_mutex_lock(&THR_LOCK_open);
+ if ((my_file_info[fd].name = (char*) my_strdup(FileName,MyFlags)))
+ {
+ my_file_opened++;
+ my_file_info[fd].type = FILE_BY_OPEN;
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_PRINT("exit",("fd: %d",fd));
+ DBUG_RETURN(fd);
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ (void) my_close(fd,MyFlags);
+ my_errno=ENOMEM;
+ }
+ else
+ my_errno=errno;
+ DBUG_PRINT("error",("Got error %d on open",my_errno));
+ if (MyFlags & (MY_FFNF | MY_FAE | MY_WME))
+ my_error(EE_FILENOTFOUND, MYF(ME_BELL+ME_WAITTANG), FileName,my_errno);
+ DBUG_RETURN(fd);
+} /* my_open */
+
+
+ /* Close a file */
+
+int my_close(File fd, myf MyFlags)
+{
+ int err;
+ DBUG_ENTER("my_close");
+ DBUG_PRINT("my",("fd: %d MyFlags: %d",fd, MyFlags));
+
+ pthread_mutex_lock(&THR_LOCK_open);
+ if ((err = close(fd)) != 0)
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE | MY_WME))
+ my_error(EE_BADCLOSE, MYF(ME_BELL+ME_WAITTANG),my_filename(fd),errno);
+ }
+ if ((uint) fd < MY_NFILE && my_file_info[fd].type != UNOPEN)
+ {
+ my_file_opened--;
+ my_free(my_file_info[fd].name, MYF(0));
+ my_file_info[fd].type = UNOPEN;
+ }
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(err);
+} /* my_close */
diff --git a/mysys/my_pread.c b/mysys/my_pread.c
new file mode 100644
index 00000000000..1190f2cc81b
--- /dev/null
+++ b/mysys/my_pread.c
@@ -0,0 +1,137 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+#ifdef HAVE_PREAD
+#include <unistd.h>
+#endif
+
+ /* Read a chunk of bytes from a file */
+
+uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags)
+{
+ uint readbytes;
+ DBUG_ENTER("my_pread");
+ DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: %lx Count: %u MyFlags: %d",
+ Filedes, (ulong) offset, Buffer, Count, MyFlags));
+
+ for (;;)
+ {
+#ifndef __WIN__
+ errno=0; /* Linux doesn't reset this */
+#endif
+#ifndef HAVE_PREAD
+ readbytes= (uint) -1;
+ if (lseek(Filedes, offset, MY_SEEK_SET) == -1L ||
+ (readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+#else
+ if ((readbytes = (uint) pread(Filedes, Buffer, Count, offset)) != Count)
+#endif
+ {
+ my_errno=errno;
+ DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
+ readbytes,Count,Filedes,my_errno));
+#ifdef THREAD
+ if (readbytes == 0 && errno == EINTR)
+ continue; /* Interrupted */
+#endif
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if ((int) readbytes == -1)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ else if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Ok vid l{sning */
+ DBUG_RETURN(readbytes); /* purecov: inspected */
+ }
+} /* my_pread */
+
+
+ /* Write a chunk of bytes to a file */
+
+uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags)
+{
+ uint writenbytes,errors;
+ ulong written;
+ DBUG_ENTER("my_pwrite");
+ DBUG_PRINT("my",("Fd: %d Seek: %lu Buffer: %lx Count: %d MyFlags: %d",
+ Filedes, (ulong) offset,Buffer, Count, MyFlags));
+ errors=0; written=0L;
+
+ for (;;)
+ {
+#ifndef HAVE_PREAD
+ writenbytes= (uint) -1;
+ if (lseek(Filedes, offset, MY_SEEK_SET) != -1L &&
+ (writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
+#else
+ if ((writenbytes = (uint) pwrite(Filedes, Buffer, Count,offset)) == Count)
+#endif
+ break;
+ if ((int) writenbytes != -1)
+ { /* Safegueard */
+ written+=writenbytes;
+ Buffer+=writenbytes;
+ Count-=writenbytes;
+ offset+=writenbytes;
+ }
+ my_errno=errno;
+ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+#ifndef NO_BACKGROUND
+#ifdef THREAD
+ if (my_thread_var->abort)
+ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+#endif
+ if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+ {
+ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
+ my_filename(Filedes));
+ VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
+ continue;
+ }
+ if ((writenbytes == 0 && my_errno == EINTR) ||
+ (writenbytes > 0 && (uint) writenbytes != (uint) -1))
+ continue; /* Retry */
+#endif
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
+ }
+ else
+ break; /* Return bytes written */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Want only errors */
+ DBUG_RETURN(writenbytes+written); /* purecov: inspected */
+} /* my_write */
diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c
new file mode 100644
index 00000000000..4bf3e5e702a
--- /dev/null
+++ b/mysys/my_pthread.c
@@ -0,0 +1,476 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Functions to get threads more portable */
+
+#include "mysys_priv.h"
+#ifdef THREAD
+#include <signal.h>
+#include <m_string.h>
+#include <thr_alarm.h>
+#include <assert.h>
+#if !defined(MSDOS) && !defined(__WIN__)
+#include <netdb.h>
+#endif
+
+#if (defined(__BSD__) || defined(_BSDI_VERSION)) && !defined(HAVE_mit_thread)
+#define SCHED_POLICY SCHED_RR
+#else
+#define SCHED_POLICY SCHED_OTHER
+#endif
+
+#ifndef my_pthread_setprio
+void my_pthread_setprio(pthread_t thread_id,int prior)
+{
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+ struct sched_param tmp_sched_param;
+ bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
+ tmp_sched_param.sched_priority=prior;
+ VOID(pthread_setschedparam(thread_id,SCHED_POLICY,&tmp_sched_param));
+#endif
+}
+#endif
+
+#ifndef my_pthread_getprio
+int my_pthread_getprio(pthread_t thread_id)
+{
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+ struct sched_param tmp_sched_param;
+ int policy;
+ if (!pthread_getschedparam(thread_id,&policy,&tmp_sched_param))
+ {
+ DBUG_PRINT("thread",("policy: %d priority: %d",
+ policy,tmp_sched_param.sched_priority));
+ return tmp_sched_param.sched_priority;
+ }
+#endif
+ return -1;
+}
+#endif
+
+#ifndef my_pthread_attr_setprio
+void my_pthread_attr_setprio(pthread_attr_t *attr, int priority)
+{
+#ifdef HAVE_PTHREAD_SETSCHEDPARAM
+ struct sched_param tmp_sched_param;
+ bzero((char*) &tmp_sched_param,sizeof(tmp_sched_param));
+ tmp_sched_param.sched_priority=priority;
+ VOID(pthread_attr_setschedparam(attr,&tmp_sched_param));
+#endif
+}
+#endif
+
+
+/* To allow use of pthread_getspecific with two arguments */
+
+#ifdef HAVE_NONPOSIX_PTHREAD_GETSPECIFIC
+#undef pthread_getspecific
+#ifdef HAVE_UNIXWARE7_THREADS
+#define pthread_getspecific thr_getspecific
+#endif
+
+void *my_pthread_getspecific_imp(pthread_key_t key)
+{
+ void *value;
+ if (pthread_getspecific(key,(void *) &value))
+ return 0;
+ return value;
+}
+#endif
+
+
+/* Some functions for RTS threads, AIX, Siemens Unix and UnixWare 7
+ (and DEC OSF/1 3.2 too) */
+
+int my_pthread_create_detached=1;
+
+#if defined(HAVE_NONPOSIX_SIGWAIT) || defined(HAVE_DEC_3_2_THREADS)
+
+int my_sigwait(sigset_t *set,int *sig)
+{
+ int signal=sigwait(set);
+ if (signal < 0)
+ return errno;
+ *sig=signal;
+ return 0;
+}
+#endif
+
+/* localtime_r for SCO 3.2V4.2 */
+
+#ifndef HAVE_LOCALTIME_R
+
+extern pthread_mutex_t LOCK_localtime_r;
+
+struct tm *localtime_r(const time_t *clock, struct tm *res)
+{
+ struct tm *tmp;
+ pthread_mutex_lock(&LOCK_localtime_r);
+ tmp=localtime(clock);
+ *res= *tmp;
+ pthread_mutex_unlock(&LOCK_localtime_r);
+ return res;
+}
+#endif
+
+
+/****************************************************************************
+** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
+**
+** Note:
+** This version of sigwait() is assumed to called in a loop so the signalmask
+** is permanently modified to reflect the signal set. This is done to get
+** a much faster implementation.
+**
+** This implementation isn't thread safe: It assumes that only one
+** thread is using sigwait.
+**
+** If one later supplies a different signal mask, all old signals that
+** was used before are unblocked and set to SIGDFL.
+**
+** Author: Gary Wisniewski <garyw@spidereye.com.au>, much modified by Monty
+****************************************************************************/
+
+#if !defined(HAVE_SIGWAIT) && !defined(HAVE_mit_thread) && !defined(sigwait) && !defined(__WIN__) && !defined(HAVE_rts_threads) && !defined(HAVE_NONPOSIX_SIGWAIT) && !defined(HAVE_DEC_3_2_THREADS)
+
+#if !defined(DONT_USE_SIGSUSPEND)
+
+static sigset_t sigwait_set,rev_sigwait_set,px_recd;
+
+void px_handle_sig(int sig)
+{
+ sigaddset(&px_recd, sig);
+}
+
+
+void sigwait_setup(sigset_t *set)
+{
+ int i;
+ struct sigaction sact,sact1;
+ sigset_t unblock_mask;
+
+ sact.sa_flags = 0;
+ sact.sa_handler = px_handle_sig;
+ memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
+ sigemptyset(&unblock_mask);
+ pthread_sigmask(SIG_UNBLOCK,(sigset_t*) 0,&rev_sigwait_set);
+
+ for (i = 1; i <= sizeof(sigwait_set)*8; i++)
+ {
+ if (sigismember(set,i))
+ {
+ sigdelset(&rev_sigwait_set,i);
+ if (!sigismember(&sigwait_set,i))
+ sigaction(i, &sact, (struct sigaction*) 0);
+ }
+ else
+ {
+ sigdelset(&px_recd,i); /* Don't handle this */
+ if (sigismember(&sigwait_set,i))
+ { /* Remove the old handler */
+ sigaddset(&unblock_mask,i);
+ sigdelset(&rev_sigwait_set,i);
+ sact1.sa_flags = 0;
+ sact1.sa_handler = SIG_DFL;
+ sigemptyset(&sact1.sa_mask);
+ sigaction(i, &sact1, 0);
+ }
+ }
+ }
+ memcpy_fixed(&sigwait_set,set,sizeof(*set));
+ pthread_sigmask(SIG_BLOCK,(sigset_t*) set,(sigset_t*) 0);
+ pthread_sigmask(SIG_UNBLOCK,&unblock_mask,(sigset_t*) 0);
+}
+
+
+int sigwait(sigset_t *setp, int *sigp)
+{
+ if (memcmp(setp,&sigwait_set,sizeof(sigwait_set)))
+ sigwait_setup(setp); /* Init or change of set */
+
+ for (;;)
+ {
+ /*
+ This is a fast, not 100% portable implementation to find the signal.
+ Because the handler is blocked there should be at most 1 bit set, but
+ the specification on this is somewhat shady so we use a set instead a
+ single variable.
+ */
+
+ ulong *ptr= (ulong*) &px_recd;
+ ulong *end=ptr+sizeof(px_recd)/sizeof(ulong);
+
+ for ( ; ptr != end ; ptr++)
+ {
+ if (*ptr)
+ {
+ ulong set= *ptr;
+ int found= (int) ((char*) ptr - (char*) &px_recd)*8+1;
+ while (!(set & 1))
+ {
+ found++;
+ set>>=1;
+ }
+ *sigp=found;
+ sigdelset(&px_recd,found);
+ return 0;
+ }
+ }
+ sigsuspend(&rev_sigwait_set);
+ }
+ return 0;
+}
+#else /* !DONT_USE_SIGSUSPEND */
+
+/****************************************************************************
+** Replacement of sigwait if the system doesn't have one (like BSDI 3.0)
+**
+** Note:
+** This version of sigwait() is assumed to called in a loop so the signalmask
+** is permanently modified to reflect the signal set. This is done to get
+** a much faster implementation.
+**
+** This implementation uses a extra thread to handle the signals and one
+** must always call sigwait() with the same signal mask!
+**
+** BSDI 3.0 NOTE:
+**
+** pthread_kill() doesn't work on a thread in a select() or sleep() loop?
+** After adding the sleep to sigwait_thread, all signals are checked and
+** delivered every second. This isn't that terrible performance vice, but
+** someone should report this to BSDI and ask for a fix!
+** Another problem is that when the sleep() ends, every select() in other
+** threads are interrupted!
+****************************************************************************/
+
+static sigset_t pending_set;
+static bool inited=0;
+static pthread_cond_t COND_sigwait;
+static pthread_mutex_t LOCK_sigwait;
+
+
+void sigwait_handle_sig(int sig)
+{
+ pthread_mutex_lock(&LOCK_sigwait);
+ sigaddset(&pending_set, sig);
+ VOID(pthread_cond_signal(&COND_sigwait)); /* inform sigwait() about signal */
+ pthread_mutex_unlock(&LOCK_sigwait);
+}
+
+extern pthread_t alarm_thread;
+
+void *sigwait_thread(void *set_arg)
+{
+ sigset_t *set=(sigset_t*) set_arg;
+
+ int i;
+ struct sigaction sact;
+ sact.sa_flags = 0;
+ sact.sa_handler = sigwait_handle_sig;
+ memcpy_fixed(&sact.sa_mask,set,sizeof(*set)); /* handler isn't thread_safe */
+ sigemptyset(&pending_set);
+
+ for (i = 1; i <= sizeof(pending_set)*8; i++)
+ {
+ if (sigismember(set,i))
+ {
+ sigaction(i, &sact, (struct sigaction*) 0);
+ }
+ }
+ sigaddset(set,THR_CLIENT_ALARM);
+ pthread_sigmask(SIG_UNBLOCK,(sigset_t*) set,(sigset_t*) 0);
+ alarm_thread=pthread_self(); /* For thr_alarm */
+
+ for (;;)
+ { /* Wait for signals */
+#ifdef HAVE_NOT_BROKEN_SELECT
+ fd_set fd;
+ FD_ZERO(&fd);
+ select(0,&fd,0,0,0);
+#else
+ sleep(1); /* Because of broken BSDI */
+#endif
+ }
+}
+
+
+int sigwait(sigset_t *setp, int *sigp)
+{
+ if (!inited)
+ {
+ pthread_attr_t thr_attr;
+ pthread_t sigwait_thread_id;
+ inited=1;
+ sigemptyset(&pending_set);
+ pthread_mutex_init(&LOCK_sigwait,NULL);
+ pthread_cond_init(&COND_sigwait,NULL);
+
+ pthread_attr_init(&thr_attr);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,8196);
+ my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
+ VOID(pthread_create(&sigwait_thread_id,&thr_attr,sigwait_thread,setp));
+ VOID(pthread_attr_destroy(&thr_attr));
+ }
+
+ pthread_mutex_lock(&LOCK_sigwait);
+ for (;;)
+ {
+ ulong *ptr= (ulong*) &pending_set;
+ ulong *end=ptr+sizeof(pending_set)/sizeof(ulong);
+
+ for ( ; ptr != end ; ptr++)
+ {
+ if (*ptr)
+ {
+ ulong set= *ptr;
+ int found= (int) ((char*) ptr - (char*) &pending_set)*8+1;
+ while (!(set & 1))
+ {
+ found++;
+ set>>=1;
+ }
+ *sigp=found;
+ sigdelset(&pending_set,found);
+ pthread_mutex_unlock(&LOCK_sigwait);
+ return 0;
+ }
+ }
+ VOID(pthread_cond_wait(&COND_sigwait,&LOCK_sigwait));
+ }
+ return 0;
+}
+
+#endif /* DONT_USE_SIGSUSPEND */
+#endif /* HAVE_SIGWAIT */
+
+/*****************************************************************************
+** Implement pthread_signal for systems that can't use signal() with threads
+** Currently this is only used with BSDI 3.0
+*****************************************************************************/
+
+#ifdef USE_PTHREAD_SIGNAL
+
+int pthread_signal(int sig, void (*func)())
+{
+ struct sigaction sact;
+ sact.sa_flags= 0;
+ sact.sa_handler= func;
+ sigemptyset(&sact.sa_mask);
+ sigaction(sig, &sact, (struct sigaction*) 0);
+ return 0;
+}
+
+#endif
+
+/*****************************************************************************
+** Patches for AIX and DEC OSF/1 3.2
+*****************************************************************************/
+
+#if (defined(HAVE_NONPOSIX_PTHREAD_MUTEX_INIT) && !defined(HAVE_UNIXWARE7_THREADS)) || defined(HAVE_DEC_3_2_THREADS)
+#undef pthread_mutex_init
+#undef pthread_cond_init
+
+#include <netdb.h>
+
+int my_pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *attr)
+{
+ int error;
+ if (!attr)
+ error=pthread_mutex_init(mp,pthread_mutexattr_default);
+ else
+ error=pthread_mutex_init(mp,*attr);
+ return error;
+}
+
+int my_pthread_cond_init(pthread_cond_t *mp, const pthread_condattr_t *attr)
+{
+ int error;
+ if (!attr)
+ error=pthread_cond_init(mp,pthread_condattr_default);
+ else
+ error=pthread_cond_init(mp,*attr);
+ return error;
+}
+
+#endif
+
+/*
+** Emulate SOLARIS style calls, not because it's better, but just to make the
+** usage of getbostbyname_r simpler.
+*/
+
+#if !defined(my_gethostbyname_r) && defined(HAVE_GETHOSTBYNAME_R)
+
+#if defined(HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R)
+
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop)
+{
+ struct hostent *hp;
+ assert((size_t) buflen >= sizeof(*result));
+ if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
+ return 0;
+ return hp;
+}
+
+#elif defined(_HPUX_SOURCE) || (defined(_AIX) && !defined(_AIX32_THREADS))
+
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop)
+{
+ assert(buflen >= sizeof(struct hostent_data));
+ if (gethostbyname_r(name,result,(struct hostent_data *) buffer) == -1)
+ {
+ *h_errnop= errno;
+ return 0;
+ }
+ return result;
+}
+
+#else
+
+struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *result, char *buffer,
+ int buflen, int *h_errnop)
+{
+ struct hostent *hp;
+ assert(buflen >= sizeof(struct hostent_data));
+ hp= gethostbyname_r(name,result,(struct hostent_data *) buffer);
+ *h_errnop= errno;
+ return hp;
+}
+
+#endif /* GLIBC2_STYLE_GETHOSTBYNAME_R */
+#endif
+
+
+/* Some help functions */
+
+int pthread_no_free(void *not_used __attribute__((unused)))
+{
+ return 0;
+}
+
+int pthread_dummy(int ret)
+{
+ return ret;
+}
+#endif /* THREAD */
diff --git a/mysys/my_quick.c b/mysys/my_quick.c
new file mode 100644
index 00000000000..6151d5037ae
--- /dev/null
+++ b/mysys/my_quick.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Quicker interface to read & write. Used with my_nosys.h */
+
+#include "mysys_priv.h"
+#include "my_nosys.h"
+
+
+uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags)
+{
+ uint readbytes;
+
+ if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+ {
+ my_errno=errno;
+ return readbytes;
+ }
+ return (MyFlags & (MY_NABP | MY_FNABP)) ? 0 : readbytes;
+}
+
+
+uint my_quick_write(File Filedes,const byte *Buffer,uint Count)
+{
+ if ((uint) write(Filedes,Buffer,Count) != Count)
+ {
+ my_errno=errno;
+ return (uint) -1;
+ }
+ return 0;
+}
diff --git a/mysys/my_read.c b/mysys/my_read.c
new file mode 100644
index 00000000000..b317630f4bd
--- /dev/null
+++ b/mysys/my_read.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+
+
+ /* Read a chunk of bytes from a file */
+
+uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags)
+ /* File descriptor */
+ /* Buffer must be at least count bytes */
+ /* Max number of bytes returnd */
+ /* Flags on what to do on error */
+{
+ uint readbytes;
+ DBUG_ENTER("my_read");
+ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+
+ for (;;)
+ {
+ errno=0; /* Linux doesn't reset this */
+ if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count)
+ {
+ my_errno=errno ? errno : -1;
+ DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d",
+ readbytes,Count,Filedes,my_errno));
+#ifdef THREAD
+ if (readbytes == 0 && errno == EINTR)
+ continue; /* Interrupted */
+#endif
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ if ((int) readbytes == -1)
+ my_error(EE_READ, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ else if (MyFlags & (MY_NABP | MY_FNABP))
+ my_error(EE_EOFERR, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ if ((int) readbytes == -1 || (MyFlags & (MY_FNABP | MY_NABP)))
+ DBUG_RETURN(MY_FILE_ERROR); /* Return with error */
+ }
+
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ readbytes=0; /* Ok on read */
+ break;
+ }
+ DBUG_RETURN(readbytes);
+} /* my_read */
diff --git a/mysys/my_realloc.c b/mysys/my_realloc.c
new file mode 100644
index 00000000000..c9d8edd6ddf
--- /dev/null
+++ b/mysys/my_realloc.c
@@ -0,0 +1,65 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#ifdef SAFEMALLOC /* We don't need SAFEMALLOC here */
+#undef SAFEMALLOC
+#endif
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+
+ /* My memory re allocator */
+
+gptr my_realloc(gptr oldpoint, uint Size, myf MyFlags)
+{
+ gptr point;
+ DBUG_ENTER("my_realloc");
+ DBUG_PRINT("my",("ptr: %lx Size: %u MyFlags: %d",oldpoint, Size, MyFlags));
+
+ if (!oldpoint && (MyFlags & MY_ALLOW_ZERO_PTR))
+ DBUG_RETURN(my_malloc(Size,MyFlags));
+#ifdef USE_HALLOC
+ if (!(point = malloc(Size)))
+ {
+ if (MyFlags & MY_FREE_ON_ERROR)
+ my_free(oldpoint,MyFlags);
+ if (MyFlags & MY_HOLD_ON_ERROR)
+ DBUG_RETURN(oldpoint);
+ my_errno=errno;
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),Size);
+ }
+ else
+ {
+ memcpy(point,oldpoint,Size);
+ free(oldpoint);
+ }
+#else
+ if ((point = realloc(oldpoint,Size)) == NULL)
+ {
+ if (MyFlags & MY_FREE_ON_ERROR)
+ my_free(oldpoint,MyFLAGS);
+ if (MyFlags & MY_HOLD_ON_ERROR)
+ DBUG_RETURN(oldpoint);
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG), Size);
+ }
+#endif
+ DBUG_PRINT("exit",("ptr: %lx",point));
+ DBUG_RETURN(point);
+} /* my_realloc */
diff --git a/mysys/my_redel.c b/mysys/my_redel.c
new file mode 100644
index 00000000000..da03b026c9f
--- /dev/null
+++ b/mysys/my_redel.c
@@ -0,0 +1,98 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES /* sys/types is included */
+#include "mysys_priv.h"
+#include <my_dir.h>
+#include "mysys_err.h"
+#if defined(HAVE_SYS_UTIME_H)
+#include <sys/utime.h>
+#elif defined(HAVE_UTIME_H)
+#include <utime.h>
+#elif !defined(HPUX)
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+ /* Rename with copy stat form old file */
+ /* Copy stats from old file to new file, deletes orginal and */
+ /* changes new file name to old file name */
+
+int my_redel(const char *org_name, const char *tmp_name, myf MyFlags)
+{
+ DBUG_ENTER("my_redel");
+ DBUG_PRINT("my",("org_name: '%s' tmp_name: '%s' MyFlags: %d",
+ org_name,tmp_name,MyFlags));
+
+ if (my_copystat(org_name,tmp_name,MyFlags) < 0 ||
+ my_delete(org_name,MyFlags) ||
+ my_rename(tmp_name,org_name,MyFlags))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+} /* my_redel */
+
+
+ /* Copy stat from one file to another */
+ /* Return -1 if can't get stat, 1 if wrong type of file */
+
+int my_copystat(const char *from, const char *to, int MyFlags)
+{
+ struct stat statbuf;
+
+ if (stat((char*) from, &statbuf))
+ {
+ my_errno=errno;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_STAT, MYF(ME_BELL+ME_WAITTANG),from,errno);
+ return -1; /* Can't get stat on input file */
+ }
+ if ((statbuf.st_mode & S_IFMT) != S_IFREG)
+ return 1;
+ VOID(chmod(to, statbuf.st_mode & 07777)); /* Copy modes */
+
+#if !defined(MSDOS) && !defined(__WIN__) && !defined(__EMX__)
+ if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING)
+ {
+ if (MyFlags & MY_LINK_WARNING)
+ my_error(EE_LINK_WARNING,MYF(ME_BELL+ME_WAITTANG),from,statbuf.st_nlink);
+ }
+ VOID(chown(to, statbuf.st_uid, statbuf.st_gid)); /* Copy ownership */
+#endif /* MSDOS */
+
+#ifndef VMS
+#ifndef __ZTC__
+ if (MyFlags & MY_COPYTIME)
+ {
+ struct utimbuf timep;
+ timep.actime = statbuf.st_atime;
+ timep.modtime = statbuf.st_mtime;
+ VOID(utime((char*) to, &timep));/* Update last accessed and modified times */
+ }
+#else
+ if (MyFlags & MY_COPYTIME)
+ {
+ time_t time[2];
+ time[0]= statbuf.st_atime;
+ time[1]= statbuf.st_mtime;
+ VOID(utime((char*) to, time));/* Update last accessed and modified times */
+ }
+#endif
+#endif
+ return 0;
+} /* my_copystat */
diff --git a/mysys/my_rename.c b/mysys/my_rename.c
new file mode 100644
index 00000000000..ea895ffcf76
--- /dev/null
+++ b/mysys/my_rename.c
@@ -0,0 +1,60 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include <my_dir.h>
+#include "mysys_err.h"
+
+#undef my_rename
+ /* On unix rename deletes to file if it exists */
+
+int my_rename(const char *from, const char *to, myf MyFlags)
+{
+ int error = 0;
+ DBUG_ENTER("my_rename");
+ DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags));
+
+#if defined(HAVE_FILE_VERSIONS)
+ { /* Check that there isn't a old file */
+ int save_errno;
+ MY_STAT my_stat_result;
+ save_errno=my_errno;
+ if (my_stat(to,&my_stat_result,MYF(0)))
+ {
+ my_errno=EEXIST;
+ error= -1;
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
+ DBUG_RETURN(error);
+ }
+ my_errno=save_errno;
+ }
+#endif
+#if defined(HAVE_RENAME)
+ if (rename(from,to))
+#else
+ if (link(from, to) || unlink(from))
+#endif
+ {
+ my_errno=errno;
+ error = -1;
+ if (MyFlags & (MY_FAE+MY_WME))
+ my_error(EE_LINK, MYF(ME_BELL+ME_WAITTANG),from,to,my_errno);
+ }
+ DBUG_RETURN(error);
+} /* my_rename */
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
new file mode 100644
index 00000000000..12f8ced0642
--- /dev/null
+++ b/mysys/my_seek.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+
+ /* Seek to position in file */
+ /*ARGSUSED*/
+
+my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags)
+{
+ reg1 os_off_t newpos;
+ DBUG_ENTER("my_seek");
+ DBUG_PRINT("my",("Fd: %d Pos: %lu Whence: %d MyFlags: %d",
+ fd, (ulong) pos, whence, MyFlags));
+ newpos=lseek(fd, pos, whence);
+ if (newpos == (os_off_t) -1)
+ {
+ my_errno=errno;
+ DBUG_PRINT("error",("lseek: %lu, errno: %d",newpos,errno));
+ DBUG_RETURN(MY_FILEPOS_ERROR);
+ }
+ DBUG_RETURN((my_off_t) newpos);
+} /* my_seek */
+
+
+ /* Tell current position of file */
+ /* ARGSUSED */
+
+my_off_t my_tell(File fd, myf MyFlags)
+{
+ os_off_t pos;
+ DBUG_ENTER("my_tell");
+ DBUG_PRINT("my",("Fd: %d MyFlags: %d",fd, MyFlags));
+#ifdef HAVE_TELL
+ pos=tell(fd);
+#else
+ pos=lseek(fd, 0L, MY_SEEK_CUR);
+#endif
+ if (pos == (os_off_t) -1)
+ my_errno=errno;
+ DBUG_PRINT("exit",("pos: %lu",pos));
+ DBUG_RETURN((my_off_t) pos);
+} /* my_tell */
diff --git a/mysys/my_static.c b/mysys/my_static.c
new file mode 100644
index 00000000000..db942d96db9
--- /dev/null
+++ b/mysys/my_static.c
@@ -0,0 +1,100 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Static variables for mysys library. All definied here for easy making of
+ a shared library
+*/
+
+#ifndef stdin
+#include "mysys_priv.h"
+#include "my_static.h"
+#include "my_alarm.h"
+#endif
+
+ /* from my_init */
+my_string home_dir=0,my_progname=0;
+char NEAR curr_dir[FN_REFLEN]= {0},
+ NEAR home_dir_buff[FN_REFLEN]= {0};
+uint my_stream_opened=0,my_file_opened=0;
+int NEAR my_umask=0664, NEAR my_umask_dir=0777;
+#ifndef THREAD
+int NEAR my_errno=0;
+#endif
+struct my_file_info my_file_info[MY_NFILE]= {{0,UNOPEN}};
+
+ /* From mf_brkhant */
+int NEAR my_dont_interrupt=0;
+volatile int _my_signals=0;
+struct st_remember _my_sig_remember[MAX_SIGNALS]={{0,0}};
+#ifdef THREAD
+sigset_t my_signals; /* signals blocked by mf_brkhant */
+#endif
+
+ /* from mf_keycache.c */
+my_bool key_cache_inited=0;
+
+ /* from mf_reccache.c */
+ulong my_default_record_cache_size=RECORD_CACHE_SIZE;
+
+ /* from soundex.c */
+ /* ABCDEFGHIJKLMNOPQRSTUVWXYZ */
+ /* :::::::::::::::::::::::::: */
+const char *soundex_map= "01230120022455012623010202";
+
+ /* from my_malloc */
+USED_MEM* my_once_root_block=0; /* pointer to first block */
+uint my_once_extra=ONCE_ALLOC_INIT; /* Memory to alloc / block */
+
+ /* from my_tempnam */
+#ifndef HAVE_TEMPNAM
+int _my_tempnam_used=0;
+#endif
+
+ /* from safe_malloc */
+uint sf_malloc_prehunc=0, /* If you have problem with core- */
+ sf_malloc_endhunc=0, /* dump when malloc-message.... */
+ /* set theese to 64 or 128 */
+ sf_malloc_quick=0; /* set if no calls to sanity */
+long lCurMemory = 0L; /* Current memory usage */
+long lMaxMemory = 0L; /* Maximum memory usage */
+uint cNewCount = 0; /* Number of times NEW() was called */
+byte *sf_min_adress= (byte*) ~(unsigned long) 0L,
+ *sf_max_adress= (byte*) 0L;
+
+/* Root of the linked list of remembers */
+struct remember *pRememberRoot = NULL;
+
+ /* from my_alarm */
+int volatile my_have_got_alarm=0; /* declare variable to reset */
+ulong my_time_to_wait_for_lock=2; /* In seconds */
+
+ /* from errors.c */
+#ifdef SHARED_LIBRARY
+char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */
+#endif
+void (*my_abort_hook)(int) = (void(*)(int)) exit;
+int (*error_handler_hook)(uint error,const char *str,myf MyFlags)=
+ my_message_no_curses;
+int (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)=
+ my_message_no_curses;
+
+ /* How to disable options */
+my_bool NEAR my_disable_locking=0;
+my_bool NEAR my_disable_async_io=0;
+my_bool NEAR my_disable_flush_key_blocks=0;
+my_bool NEAR mysys_uses_curses=0;
diff --git a/mysys/my_static.h b/mysys/my_static.h
new file mode 100644
index 00000000000..dd80a8da1f9
--- /dev/null
+++ b/mysys/my_static.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Static variables for mysys library. All definied here for easy making of
+ a shared library
+*/
+
+#include "mysys_priv.h"
+#include <signal.h>
+
+#define MAX_SIGNALS 10 /* Max signals under a dont-allow */
+#define MIN_KEYBLOCK (min(IO_SIZE,1024))
+#define MAX_KEYBLOCK 8192 /* Max keyblocklength == 8*IO_SIZE */
+#define MAX_BLOCK_TYPES MAX_KEYBLOCK/MIN_KEYBLOCK
+
+struct st_remember {
+ int number;
+ sig_handler (*func)(int number);
+};
+
+typedef struct sec_link {
+ struct sec_link *next_hash,**prev_hash;/* Blocks linked acc. to hash-value */
+ struct sec_link *next_used,*prev_used;
+ struct sec_link *next_changed,**prev_changed;
+ File file;
+ my_off_t diskpos;
+ byte *buffer;
+ my_bool changed;
+} SEC_LINK;
+
+struct irem {
+ struct remember *_pNext; /* Linked list of structures */
+ struct remember *_pPrev; /* Other link */
+ my_string _sFileName; /* File in which memory was new'ed */
+ uint _uLineNum; /* Line number in above file */
+ uint _uDataSize; /* Size requested */
+ long _lSpecialValue; /* Underrun marker value */
+};
+
+struct remember {
+ struct irem tInt;
+ char aData[1];
+};
+
+extern char NEAR curr_dir[FN_REFLEN],NEAR home_dir_buff[FN_REFLEN];
+
+extern volatile int _my_signals;
+extern struct st_remember _my_sig_remember[MAX_SIGNALS];
+
+extern my_bool key_cache_inited;
+
+extern const char *soundex_map;
+
+extern USED_MEM* my_once_root_block;
+extern uint my_once_extra;
+
+#ifndef HAVE_TEMPNAM
+extern int _my_tempnam_used;
+#endif
+
+extern byte *sf_min_adress,*sf_max_adress;
+extern uint cNewCount;
+extern struct remember *pRememberRoot;
+
+#if defined(THREAD) && !defined(__WIN__)
+extern sigset_t my_signals; /* signals blocked by mf_brkhant */
+#endif
diff --git a/mysys/my_tempnam.c b/mysys/my_tempnam.c
new file mode 100644
index 00000000000..7e5b953fe53
--- /dev/null
+++ b/mysys/my_tempnam.c
@@ -0,0 +1,142 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "my_static.h"
+#include "mysys_err.h"
+
+#define TMP_EXT ".tmp" /* Extension of tempfile */
+#if ! defined(P_tmpdir)
+#define P_tmpdir ""
+#endif
+
+#ifdef HAVE_TEMPNAM
+#ifndef MSDOS
+extern char **environ;
+#endif
+#endif
+
+/* Make a uniq temp file name by using dir and adding something after
+ pfx to make name uniq. Name is made by adding a uniq 8 length-string and
+ TMP_EXT after pfx.
+ Returns pointer to malloced area for filename. Should be freed by
+ free().
+ The name should be uniq, but it isn't checked if it file allready exists.
+ Uses tempnam() if function exist on system.
+ This function fixes that if dir is given it's used. For example
+ MSDOS tempnam() uses always TMP environment-variable if it exists.
+*/
+ /* ARGSUSED */
+
+my_string my_tempnam(const char *dir, const char *pfx,
+ myf MyFlags __attribute__((unused)))
+{
+#ifdef _MSC_VER
+ char temp[FN_REFLEN],*end,*res,**old_env,*temp_env[1];
+ old_env=environ;
+ if (dir)
+ {
+ end=strend(dir)-1;
+ if (!dir[0])
+ { /* Change empty string to current dir */
+ temp[0]= FN_CURLIB;
+ temp[1]= 0;
+ dir=temp;
+ }
+ else if (*end == FN_DEVCHAR)
+ { /* Get current dir for drive */
+ _fullpath(temp,dir,FN_REFLEN);
+ dir=temp;
+ }
+ else if (*end == FN_LIBCHAR && dir < end && end[-1] != FN_DEVCHAR)
+ {
+ strmake(temp,dir,(uint) (end-dir)); /* Copy and remove last '\' */
+ dir=temp;
+ }
+ environ=temp_env; /* Force use of dir (dir not checked) */
+ temp_env[0]=0;
+ }
+ res=tempnam((char*) dir,(my_string) pfx);
+ environ=old_env;
+ return res;
+#else
+#ifdef __ZTC__
+ if (!dir)
+ { /* If empty test first if TMP can be used */
+ dir=getenv("TMP");
+ }
+ return tempnam((char*) dir,(my_string) pfx); /* Use stand. dir with prefix */
+#else
+#ifdef HAVE_TEMPNAM
+ char temp[2],*res,**old_env,*temp_env[1];
+
+ if (dir && !dir[0])
+ { /* Change empty string to current dir */
+ temp[0]= FN_CURLIB;
+ temp[1]= 0;
+ dir=temp;
+ }
+ old_env=environ;
+ if (dir)
+ { /* Don't use TMPDIR if dir is given */
+ environ=temp_env;
+ temp_env[0]=0;
+ }
+ res=tempnam((char*) dir,(my_string) pfx); /* Use stand. dir with prefix */
+ environ=old_env;
+ if (!res)
+ DBUG_PRINT("error",("Got error: %d from tempnam",errno));
+ return res;
+#else
+ register long uniq;
+ register int length;
+ my_string pos,end_pos;
+ DBUG_ENTER("my_tempnam");
+ /* Make a uniq nummber */
+ pthread_mutex_lock(&THR_LOCK_open);
+ uniq= ((long) getpid() << 20) + (long) _my_tempnam_used++ ;
+ pthread_mutex_unlock(&THR_LOCK_open);
+ if (!dir && !(dir=getenv("TMPDIR"))) /* Use this if possibly */
+ dir=P_tmpdir; /* Use system default */
+ length=strlen(dir)+strlen(pfx)+1;
+
+ DBUG_PRINT("test",("mallocing %d byte",length+8+sizeof(TMP_EXT)+1));
+ if (!(pos=(char*) malloc(length+8+sizeof(TMP_EXT)+1)))
+ {
+ if (MyFlags & MY_FAE+MY_WME)
+ my_error(EE_OUTOFMEMORY, MYF(ME_BELL+ME_WAITTANG),
+ length+8+sizeof(TMP_EXT)+1);
+ DBUG_RETURN(NullS);
+ }
+ end_pos=strmov(pos,dir);
+ if (end_pos != pos && end_pos[-1] != FN_LIBCHAR)
+ *end_pos++=FN_LIBCHAR;
+ end_pos=strmov(end_pos,pfx);
+
+ for (length=0 ; length < 8 && uniq ; length++)
+ {
+ *end_pos++= _dig_vec[(int) (uniq & 31)];
+ uniq >>= 5;
+ }
+ VOID(strmov(end_pos,TMP_EXT));
+ DBUG_PRINT("exit",("tempnam: '%s'",pos));
+ DBUG_RETURN(pos);
+#endif /* HAVE_TEMPNAM */
+#endif /* __ZTC__ */
+#endif /* _MSC_VER */
+} /* my_tempnam */
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
new file mode 100644
index 00000000000..d879da8e65d
--- /dev/null
+++ b/mysys/my_thr_init.c
@@ -0,0 +1,194 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+** Functions to handle initializating and allocationg of all mysys & debug
+** thread variables.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+#ifdef THREAD
+#ifdef USE_TLS
+pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
+#else
+pthread_key(struct st_my_thread_var, THR_KEY_mysys);
+#endif
+pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+ THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
+ THR_LOCK_net, THR_LOCK_charset;
+#ifndef HAVE_LOCALTIME_R
+pthread_mutex_t LOCK_localtime_r;
+#endif
+#ifdef __WIN__
+pthread_mutex_t THR_LOCK_thread;
+#endif
+
+/* FIXME Note. TlsAlloc does not set an auto destructor, so
+ the function my_thread_global_free must be called from
+ somewhere before final exit of the library */
+
+my_bool my_thread_global_init(void)
+{
+ if (pthread_key_create(&THR_KEY_mysys,free))
+ {
+ fprintf(stderr,"Can't initialize threads: error %d\n",errno);
+ exit(1);
+ }
+ pthread_mutex_init(&THR_LOCK_malloc,NULL);
+ pthread_mutex_init(&THR_LOCK_open,NULL);
+ pthread_mutex_init(&THR_LOCK_keycache,NULL);
+ pthread_mutex_init(&THR_LOCK_lock,NULL);
+ pthread_mutex_init(&THR_LOCK_isam,NULL);
+ pthread_mutex_init(&THR_LOCK_myisam,NULL);
+ pthread_mutex_init(&THR_LOCK_heap,NULL);
+ pthread_mutex_init(&THR_LOCK_net,NULL);
+ pthread_mutex_init(&THR_LOCK_charset,NULL);
+#ifdef __WIN__
+ pthread_mutex_init(&THR_LOCK_thread,NULL);
+#endif
+#ifndef HAVE_LOCALTIME_R
+ pthread_mutex_init(&LOCK_localtime_r,NULL);
+#endif
+ return my_thread_init();
+}
+
+void my_thread_global_end(void)
+{
+#if defined(USE_TLS)
+ (void) TlsFree(THR_KEY_mysys);
+#endif
+}
+
+static long thread_id=0;
+
+my_bool my_thread_init(void)
+{
+ struct st_my_thread_var *tmp;
+ pthread_mutex_lock(&THR_LOCK_lock);
+#if !defined(__WIN__) || defined(USE_TLS)
+ if (my_pthread_getspecific(struct st_my_thread_var *,THR_KEY_mysys))
+ {
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 0; /* Safequard */
+ }
+ /* We must have many calloc() here because these are freed on
+ pthread_exit */
+ if (!(tmp=(struct st_my_thread_var *)
+ calloc(1,sizeof(struct st_my_thread_var))))
+ {
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 1;
+ }
+ pthread_setspecific(THR_KEY_mysys,tmp);
+
+#else
+ if (THR_KEY_mysys.id) /* Allready initialized */
+ {
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 0;
+ }
+ tmp= &THR_KEY_mysys;
+#endif
+ tmp->id= ++thread_id;
+ pthread_mutex_init(&tmp->mutex,NULL);
+ pthread_cond_init(&tmp->suspend, NULL);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ return 0;
+}
+
+void my_thread_end(void)
+{
+ struct st_my_thread_var *tmp=my_thread_var;
+ if (tmp)
+ {
+#if !defined(DBUG_OFF)
+ if (tmp->dbug)
+ {
+ free(tmp->dbug);
+ tmp->dbug=0;
+ }
+#endif
+#if !defined(__bsdi__) || defined(HAVE_mit_thread) /* bsdi dumps core here */
+ pthread_cond_destroy(&tmp->suspend);
+#endif
+ pthread_mutex_destroy(&tmp->mutex);
+#if !defined(__WIN__) || defined(USE_TLS)
+ free(tmp);
+#endif
+ }
+#if !defined(__WIN__) || defined(USE_TLS)
+ pthread_setspecific(THR_KEY_mysys,0);
+#endif
+}
+
+struct st_my_thread_var *_my_thread_var(void)
+{
+ struct st_my_thread_var *tmp=
+ my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+#if defined(USE_TLS)
+ /* This can only happen in a .DLL */
+ if (!tmp)
+ {
+ my_thread_init();
+ tmp=my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys);
+ }
+#endif
+ return tmp;
+}
+
+/****************************************************************************
+** Get name of current thread.
+****************************************************************************/
+
+#define UNKNOWN_THREAD -1
+
+long my_thread_id()
+{
+#if defined(HAVE_PTHREAD_GETSEQUENCE_NP)
+ return pthread_getsequence_np(pthread_self());
+#elif (defined(__sun) || defined(__sgi) || defined(__linux__)) && !defined(HAVE_mit_thread)
+ return pthread_self();
+#else
+ return my_thread_var->id;
+#endif
+}
+
+#ifdef DBUG_OFF
+char *my_thread_name(void)
+{
+ return "no_name";
+}
+
+#else
+
+char *my_thread_name(void)
+{
+ char name_buff[100];
+ struct st_my_thread_var *tmp=my_thread_var;
+ if (!tmp->name[0])
+ {
+ long id=my_thread_id();
+ sprintf(name_buff,"T@%ld", id);
+ strmake(tmp->name,name_buff,THREAD_NAME_SIZE);
+ }
+ return tmp->name;
+}
+#endif /* DBUG_OFF */
+
+#endif /* THREAD */
diff --git a/mysys/my_vsnprintf.c b/mysys/my_vsnprintf.c
new file mode 100644
index 00000000000..63730926156
--- /dev/null
+++ b/mysys/my_vsnprintf.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <m_string.h>
+#include <stdarg.h>
+#include <m_ctype.h>
+
+
+
+int my_vsnprintf(char* str, size_t n, const char* fmt, va_list ap)
+{
+ uint olen = 0, plen;
+ const char *tpos;
+ reg1 char *endpos;
+ reg2 char * par;
+ char* ebuff = str;
+
+ endpos=ebuff;
+ tpos = fmt;
+
+ while (*tpos)
+ {
+ if (tpos[0] != '%')
+ {
+ if(olen + 1 >= n)
+ break;
+
+ *endpos++= *tpos++; /* Copy ordinary char */
+ olen++;
+ continue;
+ }
+ if (*++tpos == '%') /* test if %% */
+ {
+ olen--;
+ }
+ else
+ {
+ /* Skipp if max size is used (to be compatible with printf) */
+ while (isdigit(*tpos) || *tpos == '.' || *tpos == '-')
+ tpos++;
+ if (*tpos == 's') /* String parameter */
+ {
+ par = va_arg(ap, char *);
+ plen = (uint) strlen(par);
+ if (olen + plen < n) /* Replace if possible */
+ {
+ endpos=strmov(endpos,par);
+ tpos++;
+ olen+=plen;
+ continue;
+ }
+ }
+ else if (*tpos == 'd' || *tpos == 'u') /* Integer parameter */
+ {
+ register int iarg;
+ iarg = va_arg(ap, int);
+ if(olen + 16 >= n) break;
+
+ if (*tpos == 'd')
+ plen= (uint) (int2str((long) iarg,endpos, -10) - endpos);
+ else
+ plen= (uint) (int2str((long) (uint) iarg,endpos,10)- endpos);
+ if (olen + plen < n) /* Replace parameter if possible */
+ {
+ endpos+=plen;
+ tpos++;
+ olen+=plen;
+ continue;
+ }
+ }
+ }
+ *endpos++='%'; /* % used as % or unknown code */
+ }
+ *endpos='\0';
+ /* End of errmessage */
+ return olen;
+}
+
diff --git a/mysys/my_wincond.c b/mysys/my_wincond.c
new file mode 100644
index 00000000000..3643d0ec0a6
--- /dev/null
+++ b/mysys/my_wincond.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*****************************************************************************
+** The following is a simple implementation of posix conditions
+*****************************************************************************/
+
+#include "mysys_priv.h"
+#if defined(THREAD) && defined(__WIN__)
+#include <m_string.h>
+#undef getpid
+#include <process.h>
+#include <sys/timeb.h>
+
+int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
+{
+ cond->waiting=0;
+ cond->semaphore=CreateSemaphore(NULL,0,0x7FFFFFFF,NullS);
+ if (!cond->semaphore)
+ return ENOMEM;
+ return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *cond)
+{
+ return CloseHandle(cond->semaphore) ? 0 : EINVAL;
+}
+
+
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ InterlockedIncrement(&cond->waiting);
+ LeaveCriticalSection(mutex);
+ WaitForSingleObject(cond->semaphore,INFINITE);
+ InterlockedDecrement(&cond->waiting);
+ EnterCriticalSection(mutex);
+ return 0 ;
+}
+
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ struct timespec *abstime)
+{
+ struct _timeb curtime;
+ int result;
+ long timeout;
+ _ftime(&curtime);
+ timeout= ((long) (abstime->tv_sec - curtime.time)*1000L +
+ (long)((abstime->tv_nsec/1000) - curtime.millitm)/1000L);
+ if (timeout < 0) /* Some safety */
+ timeout = 0L;
+ InterlockedIncrement(&cond->waiting);
+ LeaveCriticalSection(mutex);
+ result=WaitForSingleObject(cond->semaphore,timeout);
+ InterlockedDecrement(&cond->waiting);
+ EnterCriticalSection(mutex);
+
+ return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;
+}
+
+
+int pthread_cond_signal(pthread_cond_t *cond)
+{
+ long prev_count;
+ if (cond->waiting)
+ ReleaseSemaphore(cond->semaphore,1,&prev_count);
+ return 0;
+}
+
+
+int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+ long prev_count;
+ if (cond->waiting)
+ ReleaseSemaphore(cond->semaphore,cond->waiting,&prev_count);
+ return 0 ;
+}
+
+
+int pthread_attr_init(pthread_attr_t *connect_att)
+{
+ connect_att->dwStackSize = 0;
+ connect_att->dwCreatingFlag = 0;
+ connect_att->priority = 0;
+ return 0;
+}
+
+int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack)
+{
+ connect_att->dwStackSize=stack;
+ return 0;
+}
+
+int pthread_attr_setprio(pthread_attr_t *connect_att,int priority)
+{
+ connect_att->priority=priority;
+ return 0;
+}
+
+int pthread_attr_destroy(pthread_attr_t *connect_att)
+{
+ bzero((gptr) connect_att,sizeof(*connect_att));
+ return 0;
+}
+
+/****************************************************************************
+** Fix localtime_r() to be a bit safer
+****************************************************************************/
+
+struct tm *localtime_r(const time_t *timep,struct tm *tmp)
+{
+ if (*timep == (time_t) -1) /* This will crash win32 */
+ {
+ bzero(tmp,sizeof(*tmp));
+ }
+ else
+ {
+ struct tm *res=localtime(timep);
+ if (!res) /* Wrong date */
+ {
+ bzero(tmp,sizeof(*tmp)); /* Keep things safe */
+ return 0;
+ }
+ *tmp= *res;
+ }
+ return tmp;
+}
+#endif /* __WIN__ */
diff --git a/mysys/my_winthread.c b/mysys/my_winthread.c
new file mode 100644
index 00000000000..436fc954d93
--- /dev/null
+++ b/mysys/my_winthread.c
@@ -0,0 +1,111 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*****************************************************************************
+** Simulation of posix threads calls for WIN95 and NT
+*****************************************************************************/
+
+#include "mysys_priv.h"
+#if defined(THREAD) && defined(__WIN__)
+#include <m_string.h>
+#undef getpid
+#include <process.h>
+
+extern pthread_mutex_t THR_LOCK_thread;
+
+struct pthread_map
+{
+ HANDLE pthreadself;
+ pthread_handler func;
+ void *param;
+};
+
+/*
+** We have tried to use '_beginthreadex' instead of '_beginthread' here
+** but in this case the program leaks about 512 characters for each
+** created thread !
+** As we want to save the created thread handler for other threads to
+** use and to be returned by pthread_self() (instead of the Win32 pseudo
+** handler), we have to go trough pthread_start() to catch the returned handler
+** in the new thread.
+*/
+
+static pthread_handler_decl(pthread_start,param)
+{
+ pthread_handler func=((struct pthread_map *) param)->func;
+ void *func_param=((struct pthread_map *) param)->param;
+ my_thread_init();
+ pthread_mutex_lock(&THR_LOCK_thread); /* Wait for beingthread to return */
+ win_pthread_self=((struct pthread_map *) param)->pthreadself;
+ pthread_mutex_unlock(&THR_LOCK_thread);
+ free((char*) param);
+ pthread_exit((*func)(func_param));
+ return 0;
+}
+
+
+int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,
+ pthread_handler func, void *param)
+{
+ HANDLE hThread;
+ struct pthread_map *map;
+ DBUG_ENTER("pthread_create");
+
+ if (!(map=malloc(sizeof(*map))))
+ DBUG_RETURN(-1);
+ map->func=func;
+ map->param=param;
+ pthread_mutex_lock(&THR_LOCK_thread);
+#ifdef __BORLANDC__
+ hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
+ attr->dwStackSize ? attr->dwStackSize :
+ 65535, (void*) map);
+#else
+ hThread=(HANDLE)_beginthread(pthread_start,
+ attr->dwStackSize ? attr->dwStackSize :
+ 65535, (void*) map);
+#endif
+ DBUG_PRINT("info", ("hThread=%lu",(long) hThread));
+ *thread_id=map->pthreadself=hThread;
+ pthread_mutex_unlock(&THR_LOCK_thread);
+
+ if ((long) hThread == -1L)
+ {
+ long error=errno;
+ DBUG_PRINT("error",
+ ("Can't create thread to handle request (error %ld)",error));
+ DBUG_RETURN(error ? error : -1);
+ }
+ VOID(SetThreadPriority(hThread, attr->priority)) ;
+ DBUG_RETURN(0);
+}
+
+
+void pthread_exit(unsigned A)
+{
+ _endthread();
+}
+
+/* This is neaded to get the macro pthread_setspecific to work */
+
+int win_pthread_setspecific(void *a,void *b,uint length)
+{
+ memcpy(a,b,length);
+ return 0;
+}
+
+#endif
diff --git a/mysys/my_write.c b/mysys/my_write.c
new file mode 100644
index 00000000000..0ff32094ed7
--- /dev/null
+++ b/mysys/my_write.c
@@ -0,0 +1,77 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+#include "mysys_err.h"
+#include <errno.h>
+
+ /* Write a chunk of bytes to a file */
+
+uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags)
+{
+ uint writenbytes,errors;
+ ulong written;
+ DBUG_ENTER("my_write");
+ DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %d MyFlags: %d",
+ Filedes, Buffer, Count, MyFlags));
+ errors=0; written=0L;
+
+ for (;;)
+ {
+ if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
+ break;
+ if ((int) writenbytes != -1)
+ { /* Safeguard */
+ written+=writenbytes;
+ Buffer+=writenbytes;
+ Count-=writenbytes;
+ }
+ my_errno=errno;
+ DBUG_PRINT("error",("Write only %d bytes",writenbytes));
+#ifndef NO_BACKGROUND
+#ifdef THREAD
+ if (my_thread_var->abort)
+ MyFlags&= ~ MY_WAIT_IF_FULL; /* End if aborted by user */
+#endif
+ if (my_errno == ENOSPC && (MyFlags & MY_WAIT_IF_FULL))
+ {
+ if (!(errors++ % MY_WAIT_GIVE_USER_A_MESSAGE))
+ my_error(EE_DISK_FULL,MYF(ME_BELL | ME_NOREFRESH),
+ my_filename(Filedes));
+ VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC));
+ continue;
+ }
+ if ((writenbytes == 0 && my_errno == EINTR) ||
+ (writenbytes > 0 && (uint) writenbytes != (uint) -1))
+ continue; /* Retry */
+#endif
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ {
+ if (MyFlags & (MY_WME | MY_FAE | MY_FNABP))
+ {
+ my_error(EE_WRITE, MYF(ME_BELL+ME_WAITTANG),
+ my_filename(Filedes),my_errno);
+ }
+ DBUG_RETURN(MY_FILE_ERROR); /* Error on read */
+ }
+ else
+ break; /* Return bytes written */
+ }
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ DBUG_RETURN(0); /* Want only errors */
+ DBUG_RETURN(writenbytes+written);
+} /* my_write */
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
new file mode 100644
index 00000000000..86c32202e99
--- /dev/null
+++ b/mysys/mysys_priv.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include <global.h>
+#include <my_sys.h>
+
+#ifdef USE_SYSTEM_WRAPPERS
+#include "system_wrappers.h"
+#endif
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache,
+ THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_net,THR_LOCK_charset;
+#else /* THREAD */
+#define pthread_mutex_lock(A)
+#define pthread_mutex_unlock(A)
+#endif
diff --git a/mysys/ptr_cmp.c b/mysys/ptr_cmp.c
new file mode 100644
index 00000000000..65b2c51aafd
--- /dev/null
+++ b/mysys/ptr_cmp.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ get_ptr_compare(len) returns a pointer to a optimal byte-compare function
+ for a array of stringpointer where all strings have size len.
+ The bytes are compare as unsigned chars.
+ Because the size is saved in a static variable.
+ When using threads the program must have called my_init and the thread
+ my_init_thread()
+ */
+
+#include "mysys_priv.h"
+
+static int ptr_compare(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_0(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_1(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_2(uint *compare_length, uchar **a, uchar **b);
+static int ptr_compare_3(uint *compare_length, uchar **a, uchar **b);
+
+ /* Get a pointer to a optimal byte-compare function for a given size */
+
+qsort2_cmp get_ptr_compare (uint size)
+{
+ if (size < 4)
+ return (qsort2_cmp) ptr_compare;
+ switch (size & 3) {
+ case 0: return (qsort2_cmp) ptr_compare_0;
+ case 1: return (qsort2_cmp) ptr_compare_1;
+ case 2: return (qsort2_cmp) ptr_compare_2;
+ case 3: return (qsort2_cmp) ptr_compare_3;
+ }
+ return 0; /* Impossible */
+}
+
+
+ /*
+ Compare to keys to see witch is smaller.
+ Loop unrolled to make it quick !!
+ */
+
+#define cmp(N) if (first[N] != last[N]) return (int) first[N] - (int) last[N]
+
+static int ptr_compare(uint *compare_length, uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length;
+ reg1 uchar *first,*last;
+
+ first= *a; last= *b;
+ while (--length)
+ {
+ if (*first++ != *last++)
+ return (int) first[-1] - (int) last[-1];
+ }
+ return (int) first[0] - (int) last[0];
+}
+
+
+static int ptr_compare_0(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length;
+ reg1 uchar *first,*last;
+
+ first= *a; last= *b;
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+
+static int ptr_compare_1(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length-1;
+ reg1 uchar *first,*last;
+
+ first= *a+1; last= *b+1;
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+static int ptr_compare_2(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length-2;
+ reg1 uchar *first,*last;
+
+ first= *a +2 ; last= *b +2;
+ cmp(-2);
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
+
+static int ptr_compare_3(uint *compare_length,uchar **a, uchar **b)
+{
+ reg3 int length= *compare_length-3;
+ reg1 uchar *first,*last;
+
+ first= *a +3 ; last= *b +3;
+ cmp(-3);
+ cmp(-2);
+ cmp(-1);
+ loop:
+ cmp(0);
+ cmp(1);
+ cmp(2);
+ cmp(3);
+ if ((length-=4))
+ {
+ first+=4;
+ last+=4;
+ goto loop;
+ }
+ return (0);
+}
diff --git a/mysys/queues.c b/mysys/queues.c
new file mode 100644
index 00000000000..f33856b892d
--- /dev/null
+++ b/mysys/queues.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Code for generell handling of priority Queues.
+ Implemention of queues from "Algoritms in C" by Robert Sedgewick.
+*/
+
+#include "mysys_priv.h"
+#include <queues.h>
+
+
+ /* The actuall code for handling queues */
+
+int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key,
+ pbool max_at_top, int (*compare) (void *, byte *, byte *),
+ void *first_cmp_arg)
+{
+ DBUG_ENTER("init_queue");
+ if ((queue->root= (byte **) my_malloc((max_elements+1)*sizeof(void*),
+ MYF(MY_WME))) == 0)
+ DBUG_RETURN(1);
+ queue->elements=0;
+ queue->compare=compare;
+ queue->first_cmp_arg=first_cmp_arg;
+ queue->max_elements=max_elements;
+ queue->offset_to_key=offset_to_key;
+ queue->max_at_top= max_at_top ? (-1 ^ 1) : 0;
+ DBUG_RETURN(0);
+}
+
+void delete_queue(QUEUE *queue)
+{
+ DBUG_ENTER("delete_queue");
+ if (queue->root)
+ {
+ my_free((gptr) queue->root,MYF(0));
+ queue->root=0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Code for insert, search and delete of elements */
+
+void queue_insert(register QUEUE *queue, byte *element)
+{
+ reg2 uint idx,next;
+
+#ifndef DBUG_OFF
+ if (queue->elements < queue->max_elements)
+#endif
+ {
+ queue->root[0]=element;
+ idx= ++queue->elements;
+
+ while ((queue->compare(queue->first_cmp_arg,
+ element+queue->offset_to_key,
+ queue->root[(next=idx >> 1)]+queue->offset_to_key)
+ ^ queue->max_at_top) < 0)
+ {
+ queue->root[idx]=queue->root[next];
+ idx=next;
+ }
+ queue->root[idx]=element;
+ }
+}
+
+ /* Remove item from queue */
+ /* Returns pointer to removed element */
+
+byte *queue_remove(register QUEUE *queue, uint idx)
+{
+#ifndef DBUG_OFF
+ if (idx >= queue->max_elements)
+ return 0;
+#endif
+ {
+ byte *element=queue->root[++idx]; /* Intern index starts from 1 */
+ queue->root[idx]=queue->root[queue->elements--];
+ _downheap(queue,idx);
+ return element;
+ }
+}
+
+
+ /* Fix when element on top has been replaced */
+
+#ifndef queue_replaced
+void queue_replaced(queue)
+QUEUE *queue;
+{
+ _downheap(queue,1);
+}
+#endif
+
+ /* Fix heap when index have changed */
+
+void _downheap(register QUEUE *queue, uint idx)
+{
+ byte *element;
+ uint elements,half_queue,next_index,offset_to_key;
+ int cmp;
+
+ offset_to_key=queue->offset_to_key;
+ element=queue->root[idx];
+ half_queue=(elements=queue->elements) >> 1;
+
+ while (idx <= half_queue)
+ {
+ next_index=idx+idx;
+ if (next_index < elements &&
+ (queue->compare(queue->first_cmp_arg,
+ queue->root[next_index]+offset_to_key,
+ queue->root[next_index+1]+offset_to_key) ^
+ queue->max_at_top) > 0)
+ next_index++;
+ if ((cmp=queue->compare(queue->first_cmp_arg,
+ queue->root[next_index]+offset_to_key,
+ element+offset_to_key)) == 0 ||
+ (cmp ^ queue->max_at_top) > 0)
+ break;
+ queue->root[idx]=queue->root[next_index];
+ idx=next_index;
+ }
+ queue->root[idx]=element;
+}
diff --git a/mysys/raid.cc b/mysys/raid.cc
new file mode 100644
index 00000000000..a92647d1d95
--- /dev/null
+++ b/mysys/raid.cc
@@ -0,0 +1,809 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* --------------------------------------------------------*
+*
+* RAID support for MySQL. Raid 0 (stiping) only implemented yet.
+*
+* Why RAID? Why it must be in MySQL?
+*
+* This is because then you can:
+* 1. Have bigger tables than your OS limit. In time of writing this
+* we are hitting to 2GB limit under linux/ext2
+* 2. You can get more speed from IO bottleneck by putting
+* Raid dirs on different physical disks.
+* 3. Getting more fault tolerance (not implemented yet)
+*
+* Why not to use RAID:
+*
+* 1. You are losing some processor power to calculate things,
+* do more syscalls and interrupts.
+*
+* Functionality is supplied by two classes: RaidFd and RaidName.
+* RaidFd supports funtionality over file descriptors like
+* open/create/write/seek/close. RaidName supports functionality
+* like rename/delete where we have no relations to filedescriptors.
+* RaidName can be prorably unchanged for different Raid levels. RaidFd
+* have to be virtual I think ;).
+* You can speed up some calls in MySQL code by skipping RAID code.
+* For example LOAD DATA INFILE never needs to read RAID-ed files.
+* This can be done adding proper "#undef my_read" or similar undef-s
+* in your code. Check out the raid.h!
+*
+* Some explanation about _seek_vector[]
+* This is seek cache. RAID seeks too much and we cacheing this. We
+* fool it and just storing new position in file to _seek_vector.
+* When there is no seeks to do, we are putting RAID_SEEK_DONE into it.
+* Any other value requires seeking to that position.
+*
+* TODO:
+*
+*
+* - Implement other fancy things like RAID 1 (mirroring) and RAID 5.
+* Should not to be very complex.
+*
+* - Optimize big blob writes by resorting write buffers and writing
+* big chunks at once instead of doing many syscalls. - after thinking I
+* found this is useless. This is because same thing one can do with just
+* increasing RAID_CHUNKSIZE. Monty, what do you think? tonu.
+*
+* - If needed, then implement missing syscalls. One known to miss is stat();
+*
+* - Make and use a thread safe dynamic_array buffer. The used one
+* will not work if needs to be extended at the same time someone is
+* accessing it.
+*
+*
+* tonu@mysql.com & monty@mysql.com
+* --------------------------------------------------------*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysys_priv.h"
+#include "my_dir.h"
+#include <m_string.h>
+#include <assert.h>
+
+const char *raid_type_string[]={"none","striped"};
+
+
+extern "C" {
+ const char *my_raid_type(int raid_type)
+ {
+ return raid_type_string[raid_type];
+ }
+}
+
+#if defined(USE_RAID) && !defined(MYSQL_CLIENT)
+
+#define RAID_SEEK_DONE ~(off_t) 0
+#define RAID_SIZE_UNKNOWN ~(my_off_t) 0
+
+DYNAMIC_ARRAY RaidFd::_raid_map;
+
+
+/* --------------- C compatibility ---------------*/
+
+extern "C" {
+
+ void init_raid(void)
+ {
+ /* Allocate memory for global file to raid map */
+ init_dynamic_array(&RaidFd::_raid_map, sizeof(RaidFd*), 4096, 1024);
+ }
+ void end_raid(void)
+ {
+ /* Free memory used by raid */
+ delete_dynamic(&RaidFd::_raid_map);
+ }
+
+ bool is_raid(File fd)
+ {
+ return RaidFd::IsRaid(fd);
+ }
+
+ File my_raid_create(const char *FileName, int CreateFlags, int access_flags,
+ uint raid_type, uint raid_chunks, ulong raid_chunksize,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_create");
+ DBUG_PRINT("enter",("Filename: %s CreateFlags: %d access_flags: %d MyFlags: %d",
+ FileName, CreateFlags, access_flags, MyFlags));
+ if (raid_type)
+ {
+ RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
+ File res = raid->Create(FileName,CreateFlags,access_flags,MyFlags);
+ if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
+ {
+ delete raid;
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(res);
+ }
+ else
+ DBUG_RETURN(my_create(FileName, CreateFlags, access_flags, MyFlags));
+ }
+
+ File my_raid_open(const char *FileName, int Flags,
+ uint raid_type, uint raid_chunks, ulong raid_chunksize,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_open");
+ DBUG_PRINT("enter",("Filename: %s Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+ if (raid_type)
+ {
+ RaidFd *raid = new RaidFd(raid_type, raid_chunks , raid_chunksize);
+ File res = raid->Open(FileName,Flags,MyFlags);
+ if (res < 0 || set_dynamic(&RaidFd::_raid_map,(char*) &raid,res))
+ {
+ delete raid;
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(res);
+ }
+ else
+ DBUG_RETURN(my_open(FileName, Flags, MyFlags));
+ }
+
+ my_off_t my_raid_seek(File fd, my_off_t pos,int whence,myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_seek");
+ DBUG_PRINT("enter",("Fd: %d pos: %lu whence: %d MyFlags: %d",
+ fd, (ulong) pos, whence, MyFlags));
+
+ assert(pos != MY_FILEPOS_ERROR);
+
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Seek(pos,whence,MyFlags));
+ }
+ else
+ DBUG_RETURN(my_seek(fd, pos, whence, MyFlags));
+ }
+
+ my_off_t my_raid_tell(File fd,myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_tell");
+ DBUG_PRINT("enter",("Fd: %d MyFlags: %d",
+ fd, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Tell(MyFlags));
+ }
+ else
+ DBUG_RETURN(my_tell(fd, MyFlags));
+ }
+
+ uint my_raid_write(File fd,const byte *Buffer, uint Count, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_write");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ fd, Buffer, Count, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
+ } else
+ DBUG_RETURN(my_write(fd,Buffer,Count,MyFlags));
+ }
+
+ uint my_raid_read(File fd, byte *Buffer, uint Count, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_read");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u MyFlags: %d",
+ fd, Buffer, Count, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
+ } else
+ DBUG_RETURN(my_read(fd,Buffer,Count,MyFlags));
+ }
+
+ uint my_raid_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_pread");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u offset: %u MyFlags: %d",
+ Filedes, Buffer, Count, offset, MyFlags));
+ if (is_raid(Filedes))
+ {
+ assert(offset != MY_FILEPOS_ERROR);
+
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
+ /* Returning value isn't important because real seek is done later. */
+ raid->Seek(offset,MY_SEEK_SET,MyFlags);
+ DBUG_RETURN(raid->Read(Buffer,Count,MyFlags));
+ }
+ else
+ DBUG_RETURN(my_pread(Filedes, Buffer, Count, offset, MyFlags));
+ }
+
+ uint my_raid_pwrite(int Filedes, const byte *Buffer, uint Count,
+ my_off_t offset, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_pwrite");
+ DBUG_PRINT("enter",("Fd: %d Buffer: %lx Count: %u offset: %u MyFlags: %d",
+ Filedes, Buffer, Count, offset, MyFlags));
+ if (is_raid(Filedes))
+ {
+ assert(offset != MY_FILEPOS_ERROR);
+
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,Filedes,RaidFd**));
+ /* Returning value isn't important because real seek is done later. */
+ raid->Seek(offset,MY_SEEK_SET,MyFlags);
+ DBUG_RETURN(raid->Write(Buffer,Count,MyFlags));
+ }
+ else
+ DBUG_RETURN(my_pwrite(Filedes, Buffer, Count, offset, MyFlags));
+ }
+
+ int my_raid_lock(File fd, int locktype, my_off_t start, my_off_t length,
+ myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_lock");
+ DBUG_PRINT("enter",("Fd: %d start: %u length: %u MyFlags: %d",
+ fd, start, length, MyFlags));
+ if (my_disable_locking)
+ DBUG_RETURN(0);
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Lock(locktype, start, length, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_lock(fd, locktype, start, length, MyFlags));
+ }
+
+ int my_raid_close(File fd, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_close");
+ DBUG_PRINT("enter",("Fd: %d MyFlags: %d",
+ fd, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ RaidFd *tmp=0;
+ set_dynamic(&RaidFd::_raid_map,(char*) &tmp,fd);
+ int res = raid->Close(MyFlags);
+ delete raid;
+ DBUG_RETURN(res);
+ }
+ else
+ DBUG_RETURN(my_close(fd, MyFlags));
+ }
+
+ int my_raid_chsize(File fd, my_off_t newlength, myf MyFlags)
+ {
+ DBUG_ENTER("my_raid_chsize");
+ DBUG_PRINT("enter",("Fd: %d newlength: %u MyFlags: %d",
+ fd, newlength, MyFlags));
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Chsize(fd, newlength, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_chsize(fd, newlength, MyFlags));
+ }
+
+ int my_raid_rename(const char *from, const char *to,
+ uint raid_chunks, myf MyFlags)
+ {
+ char from_tmp[FN_REFLEN];
+ char to_tmp[FN_REFLEN];
+ DBUG_ENTER("my_raid_rename");
+
+ uint from_pos = dirname_length(from);
+ uint to_pos = dirname_length(to);
+ memcpy(from_tmp, from, from_pos);
+ memcpy(to_tmp, to, to_pos);
+ for (uint i = 0 ; i < raid_chunks ; i++ )
+ {
+ sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
+ sprintf(to_tmp+to_pos,"%02x/%s", i, to+ to_pos);
+ /* Convert if not unix */
+ unpack_filename(from_tmp, from_tmp);
+ unpack_filename(to_tmp,to_tmp);
+ if (my_rename(from_tmp, to_tmp, MyFlags))
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+ }
+
+ int my_raid_delete(const char *from, uint raid_chunks, myf MyFlags)
+ {
+ char from_tmp[FN_REFLEN];
+ uint from_pos = dirname_length(from);
+ DBUG_ENTER("my_raid_delete");
+
+ if (!raid_chunks)
+ DBUG_RETURN(my_delete(from,MyFlags));
+ for (uint i = 0 ; i < raid_chunks ; i++ )
+ {
+ memcpy(from_tmp, from, from_pos);
+ sprintf(from_tmp+from_pos,"%02x/%s", i, from + from_pos);
+ /* Convert if not unix */
+ unpack_filename(from_tmp, from_tmp);
+ if (my_delete(from_tmp, MyFlags))
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+ }
+
+ int my_raid_redel(const char *old_name, const char *new_name,
+ uint raid_chunks, myf MyFlags)
+ {
+ char new_name_buff[FN_REFLEN], old_name_buff[FN_REFLEN];
+ char *new_end, *old_end;
+ uint i,old_length,new_length;
+ int error=0;
+ DBUG_ENTER("my_raid_redel");
+
+ old_end=old_name_buff+dirname_part(old_name_buff,old_name);
+ old_length=dirname_length(old_name);
+ new_end=new_name_buff+dirname_part(new_name_buff,new_name);
+ new_length=dirname_length(new_name);
+ for (i=0 ; i < raid_chunks ; i++)
+ {
+ MY_STAT status;
+ sprintf(new_end,"%02x",i);
+ if (my_stat(new_name_buff,&status, MYF(0)))
+ {
+ DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
+ }
+ else
+ {
+ if (my_mkdir(new_name_buff,0777,MYF(0)))
+ {
+ DBUG_PRINT("error",("mkdir failed for %02x",i));
+ DBUG_RETURN(-1);
+ }
+ }
+ strxmov(strend(new_end),"/",new_name+new_length,NullS);
+ sprintf(old_end,"%02x/%s",i, old_name+old_length);
+ if (my_redel(old_name_buff, new_name_buff, MyFlags))
+ error=1;
+ }
+ DBUG_RETURN(error);
+ }
+}
+
+int my_raid_fstat(int fd, MY_STAT *stat_area, myf MyFlags )
+{
+ DBUG_ENTER("my_raid_fstat");
+ if (is_raid(fd))
+ {
+ RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+ DBUG_RETURN(raid->Fstat(fd, stat_area, MyFlags));
+ }
+ else
+ DBUG_RETURN(my_fstat(fd, stat_area, MyFlags));
+}
+
+
+/* -------------- RaidFd base class begins ----------------*/
+/*
+ RaidFd - raided file is identified by file descriptor
+ this is useful when we open/write/read/close files
+*/
+
+
+bool RaidFd::
+IsRaid(File fd)
+{
+ DBUG_ENTER("RaidFd::IsRaid");
+ DBUG_RETURN((uint) fd < _raid_map.elements &&
+ *dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
+}
+
+
+RaidFd::
+RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize)
+ :_raid_type(raid_type), _raid_chunks(raid_chunks),
+ _raid_chunksize(raid_chunksize), _position(0), _fd_vector(0),
+ _size(RAID_SIZE_UNKNOWN)
+{
+ DBUG_ENTER("RaidFd::RaidFd");
+ DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %d",
+ raid_type, raid_chunks, raid_chunksize));
+
+ /* TODO: Here we should add checks if the malloc fails */
+ _seek_vector=0; /* In case of errors */
+ my_multi_malloc(MYF(MY_WME),
+ &_seek_vector,sizeof(off_t)*_raid_chunks,
+ &_fd_vector, sizeof(File) *_raid_chunks,
+ NullS);
+ if (!RaidFd::_raid_map.buffer)
+ { /* Not initied */
+ pthread_mutex_lock(&THR_LOCK_open); /* Ensure that no other thread */
+ if (!RaidFd::_raid_map.buffer) /* has done init in between */
+ init_raid();
+ pthread_mutex_unlock(&THR_LOCK_open);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+RaidFd::
+~RaidFd() {
+ DBUG_ENTER("RaidFd::~RaidFd");
+ /* We don't have to free _fd_vector ! */
+ my_free((char*) _seek_vector, MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_VOID_RETURN;
+}
+
+
+File RaidFd::
+Create(const char *FileName, int CreateFlags, int access_flags, myf MyFlags)
+{
+ char RaidFdFileName[FN_REFLEN];
+ DBUG_ENTER("RaidFd::Create");
+ DBUG_PRINT("enter",
+ ("FileName: %s CreateFlags: %d access_flags: %d MyFlags: %d",
+ FileName, CreateFlags, access_flags, MyFlags));
+ char DirName[FN_REFLEN];
+ uint pos = dirname_part(DirName, FileName);
+ MY_STAT status;
+ if (!_seek_vector)
+ DBUG_RETURN(-1); /* Not enough memory */
+
+ uint i = _raid_chunks-1;
+ do
+ {
+ /* Create subdir */
+ (void)sprintf(RaidFdFileName,"%s%02x", DirName,i);
+ unpack_dirname(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
+ if (my_stat(RaidFdFileName,&status, MYF(0)))
+ {
+ DBUG_PRINT("info",("%02x exists, skipping directory creation",i));
+ }
+ else
+ {
+ if (my_mkdir(RaidFdFileName,0777,MYF(0)))
+ {
+ DBUG_PRINT("error",("mkdir failed for %d",i));
+ goto error;
+ }
+ }
+ /* Create file */
+ sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
+ unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
+ _fd = my_create(RaidFdFileName, CreateFlags ,access_flags, (myf)MyFlags);
+ if (_fd < 0)
+ goto error;
+ _fd_vector[i]=_fd;
+ _seek_vector[i]=RAID_SEEK_DONE;
+ } while (i--);
+ _size=0;
+ DBUG_RETURN(_fd); /* Last filenr is pointer to map */
+
+error:
+ {
+ int save_errno=my_errno;
+ while (++i < _raid_chunks)
+ {
+ my_close(_fd_vector[i],MYF(0));
+ sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
+ unpack_filename(RaidFdFileName,RaidFdFileName);
+ my_delete(RaidFdFileName,MYF(0));
+ }
+ my_errno=save_errno;
+ }
+ DBUG_RETURN(-1);
+}
+
+
+File RaidFd::
+Open(const char *FileName, int Flags, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Open");
+ DBUG_PRINT("enter",("FileName: %s Flags: %d MyFlags: %d",
+ FileName, Flags, MyFlags));
+ char DirName[FN_REFLEN];
+ uint pos = dirname_part(DirName, FileName);
+ if (!_seek_vector)
+ DBUG_RETURN(-1); /* Not enough memory */
+
+ for( uint i = 0 ; i < _raid_chunks ; i++ )
+ {
+ char RaidFdFileName[FN_REFLEN];
+ sprintf(RaidFdFileName,"%s%02x/%s",DirName, i, FileName + pos);
+ unpack_filename(RaidFdFileName,RaidFdFileName); /* Convert if not unix */
+ _fd = my_open(RaidFdFileName, Flags, MyFlags);
+ if (_fd < 0)
+ {
+ int save_errno=my_errno;
+ while (i-- != 0)
+ my_close(_fd_vector[i],MYF(0));
+ my_errno=save_errno;
+ DBUG_RETURN(_fd);
+ }
+ _fd_vector[i]=_fd;
+ _seek_vector[i]=RAID_SEEK_DONE;
+ }
+ Seek(0L,MY_SEEK_END,MYF(0)); // Trick. We just need to know, how big the file is
+ DBUG_PRINT("info",("MYD file logical size: %llu", _size));
+ DBUG_RETURN(_fd);
+}
+
+
+int RaidFd::
+Write(const byte *Buffer, uint Count, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Write");
+ DBUG_PRINT("enter",("Count: %d MyFlags: %d",
+ Count, MyFlags));
+ const byte *bufptr = Buffer;
+ uint res=0, GotBytes, ReadNowCount;
+
+ // Loop until data is written
+ do {
+ Calculate();
+ // Do seeks when neccessary
+ if (_seek_vector[_this_block] != RAID_SEEK_DONE)
+ {
+ if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
+ MY_SEEK_SET,
+ MyFlags) == MY_FILEPOS_ERROR)
+ DBUG_RETURN(-1);
+ _seek_vector[_this_block]=RAID_SEEK_DONE;
+ }
+ ReadNowCount = min(Count, _remaining_bytes);
+ GotBytes = my_write(_fd_vector[_this_block], bufptr, ReadNowCount,
+ MyFlags);
+ DBUG_PRINT("loop",("Wrote bytes: %d", GotBytes));
+ if (GotBytes == MY_FILE_ERROR)
+ DBUG_RETURN(-1);
+ res+= GotBytes;
+ if (MyFlags & (MY_NABP | MY_FNABP))
+ GotBytes=ReadNowCount;
+ bufptr += GotBytes;
+ Count -= GotBytes;
+ _position += GotBytes;
+ } while(Count);
+ set_if_bigger(_size,_position);
+ DBUG_RETURN(res);
+}
+
+
+int RaidFd::
+Read(const byte *Buffer, uint Count, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Read");
+ DBUG_PRINT("enter",("Count: %d MyFlags: %d",
+ Count, MyFlags));
+ byte *bufptr = (byte *)Buffer;
+ uint res= 0, GotBytes, ReadNowCount;
+
+ // Loop until all data is read (Note that Count may be 0)
+ while (Count)
+ {
+ Calculate();
+ // Do seek when neccessary
+ if (_seek_vector[_this_block] != RAID_SEEK_DONE)
+ {
+ if (my_seek(_fd_vector[_this_block], _seek_vector[_this_block],
+ MY_SEEK_SET,
+ MyFlags) == MY_FILEPOS_ERROR)
+ DBUG_RETURN(-1);
+ _seek_vector[_this_block]=RAID_SEEK_DONE;
+ }
+ // and read
+ ReadNowCount = min(Count, _remaining_bytes);
+ GotBytes = my_read(_fd_vector[_this_block], bufptr, ReadNowCount,
+ MyFlags & ~(MY_NABP | MY_FNABP));
+ DBUG_PRINT("loop",("Got bytes: %u", GotBytes));
+ if (GotBytes == MY_FILE_ERROR)
+ DBUG_RETURN(-1);
+ if (!GotBytes) // End of file.
+ {
+ DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? -1 : (int) res);
+ }
+ res+= GotBytes;
+ bufptr += GotBytes;
+ Count -= GotBytes;
+ _position += GotBytes;
+ }
+ DBUG_RETURN((MyFlags & (MY_NABP | MY_FNABP)) ? 0 : res);
+}
+
+
+int RaidFd::
+Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Lock");
+ DBUG_PRINT("enter",("locktype: %d start: %lu length: %lu MyFlags: %d",
+ locktype, start, length, MyFlags));
+ my_off_t bufptr = start;
+ // Loop until all data is locked
+ while(length)
+ {
+ Calculate();
+ for (uint i = _this_block ; (i < _raid_chunks) && length ; i++ )
+ {
+ uint ReadNowCount = min(length, _remaining_bytes);
+ uint GotBytes = my_lock(_fd_vector[i], locktype, bufptr, ReadNowCount,
+ MyFlags);
+ if ((int) GotBytes == -1)
+ DBUG_RETURN(-1);
+ bufptr += ReadNowCount;
+ length -= ReadNowCount;
+ Calculate();
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
+int RaidFd::
+Close(myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Close");
+ DBUG_PRINT("enter",("MyFlags: %d",
+ MyFlags));
+ for (uint i = 0 ; i < _raid_chunks ; ++i )
+ {
+ int err = my_close(_fd_vector[i], MyFlags);
+ if (err != 0)
+ DBUG_RETURN(err);
+ }
+ /* _fd_vector is erased when RaidFd is released */
+ DBUG_RETURN(0);
+}
+
+
+my_off_t RaidFd::
+Seek(my_off_t pos,int whence,myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Seek");
+ DBUG_PRINT("enter",("Pos: %lu Whence: %d MyFlags: %d",
+ (ulong) pos, whence, MyFlags));
+ switch (whence) {
+ case MY_SEEK_CUR:
+ // FIXME: This is wrong, what is going on there
+ // Just I am relied on fact that MySQL 3.23.7 never uses MY_SEEK_CUR
+ // for anything else except things like ltell()
+ break;
+ case MY_SEEK_SET:
+ if ( _position != pos) // we can be already in right place
+ {
+ uint i;
+ off_t _rounds;
+ _position = pos;
+ Calculate();
+ _rounds = _total_block / _raid_chunks; // INT() assumed
+ _rounds*= _raid_chunksize;
+ for (i = 0; i < _raid_chunks ; i++ )
+ if ( i < _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize;
+ else if ( i == _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize -_remaining_bytes;
+ else // if ( i > _this_block )
+ _seek_vector[i] = _rounds;
+ }
+ break;
+ case MY_SEEK_END:
+ if (_size==RAID_SIZE_UNKNOWN) // We don't know table size yet
+ {
+ uint i;
+ _position = 0;
+ for (i = 0; i < _raid_chunks ; i++ )
+ {
+ my_off_t newpos = my_seek(_fd_vector[i], 0L, MY_SEEK_END, MyFlags);
+ if (newpos == MY_FILEPOS_ERROR)
+ DBUG_RETURN (MY_FILEPOS_ERROR);
+ _seek_vector[i]=RAID_SEEK_DONE;
+ _position += newpos;
+ }
+ _size=_position;
+ }
+ else if (_position != _size) // Aren't we also already in the end?
+ {
+ uint i;
+ off_t _rounds;
+ _position = _size;
+ Calculate();
+ _rounds = _total_block / _raid_chunks; // INT() assumed
+ _rounds*= _raid_chunksize;
+ for (i = 0; i < _raid_chunks ; i++ )
+ if ( i < _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize;
+ else if ( i == _this_block )
+ _seek_vector[i] = _rounds + _raid_chunksize - _remaining_bytes;
+ else // if ( i > _this_block )
+ _seek_vector[i] = _rounds;
+ _position=_size;
+ }
+ }
+ DBUG_RETURN(_position);
+}
+
+
+my_off_t RaidFd::
+Tell(myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Tell");
+ DBUG_PRINT("enter",("MyFlags: %d _position %d",
+ MyFlags,_position));
+ DBUG_RETURN(_position);
+}
+
+int RaidFd::
+Chsize(File fd, my_off_t newlength, myf MyFlags)
+{
+ DBUG_ENTER("RaidFd::Chsize");
+ DBUG_PRINT("enter",("Fd: %d, newlength: %d, MyFlags: %d",
+ fd, newlength,MyFlags));
+ _position = newlength;
+ Calculate();
+ uint _rounds = _total_block / _raid_chunks; // INT() assumed
+ for (uint i = 0; i < _raid_chunks ; i++ )
+ {
+ int newpos;
+ if ( i < _this_block )
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + (_rounds + 1) *
+ _raid_chunksize,
+ MyFlags);
+ else if ( i == _this_block )
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + _rounds *
+ _raid_chunksize + (newlength % _raid_chunksize),
+ MyFlags);
+ else // this means: i > _this_block
+ newpos = my_chsize(_fd_vector[i],
+ _this_block * _raid_chunksize + _rounds *
+ _raid_chunksize, MyFlags);
+ if (newpos)
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+int RaidFd::
+Fstat(int fd, MY_STAT *stat_area, myf MyFlags )
+{
+ DBUG_ENTER("RaidFd::Fstat");
+ DBUG_PRINT("enter",("fd: %d MyFlags: %d",fd,MyFlags));
+ uint i;
+ int error=0;
+ MY_STAT my_stat;
+ stat_area->st_size=0;
+ stat_area->st_mtime=0;
+ stat_area->st_atime=0;
+ stat_area->st_ctime=0;
+
+ for(i=0 ; i < _raid_chunks ; i++)
+ {
+ if (my_fstat(_fd_vector[i],&my_stat,MyFlags))
+ error=1;
+ stat_area->st_size+=my_stat.st_size;
+ set_if_bigger(stat_area->st_mtime,my_stat.st_mtime);
+ set_if_bigger(stat_area->st_atime,my_stat.st_atime);
+ set_if_bigger(stat_area->st_ctime,my_stat.st_ctime);
+ }
+ DBUG_RETURN(error);
+}
+
+#endif /* defined(USE_RAID) && !defined(MYSQL_CLIENT) */
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
new file mode 100644
index 00000000000..d715f69e38a
--- /dev/null
+++ b/mysys/safemalloc.c
@@ -0,0 +1,518 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ * [This posting refers to an article entitled "oops, corrupted memory
+ * again!" in net.lang.c. I am posting it here because it is source.]
+ *
+ * My tool for approaching this problem is to build another level of data
+ * abstraction on top of malloc() and free() that implements some checking.
+ * This does a number of things for you:
+ * - Checks for overruns and underruns on allocated data
+ * - Keeps track of where in the program the memory was malloc'ed
+ * - Reports on pieces of memory that were not free'ed
+ * - Records some statistics such as maximum memory used
+ * - Marks newly malloc'ed and newly free'ed memory with special values
+ * You can use this scheme to:
+ * - Find bugs such as overrun, underrun, etc because you know where
+ * a piece of data was malloc'ed and where it was free'ed
+ * - Find bugs where memory was not free'ed
+ * - Find bugs where newly malloc'ed memory is used without initializing
+ * - Find bugs where newly free'ed memory is still used
+ * - Determine how much memory your program really uses
+ * - and other things
+ */
+
+/*
+ * To implement my scheme you must have a C compiler that has __LINE__ and
+ * __FILE__ macros. If your compiler doesn't have these then (a) buy another:
+ * compilers that do are available on UNIX 4.2bsd based systems and the PC,
+ * and probably on other machines; or (b) change my scheme somehow. I have
+ * recomendations on both these points if you would like them (e-mail please).
+ *
+ * There are 4 functions in my package:
+ * char *NEW( uSize ) Allocate memory of uSize bytes
+ * (equivalent to malloc())
+ * char *REA( pPtr, uSize) Allocate memory of uSize bytes, move data and
+ * free pPtr.
+ * (equivalent to realloc())
+ * FREE( pPtr ) Free memory allocated by NEW
+ * (equivalent to free())
+ * TERMINATE(file) End system, report errors and stats on file
+ * I personally use two more functions, but have not included them here:
+ * char *STRSAVE( sPtr ) Save a copy of the string in dynamic memory
+ * char *RENEW( pPtr, uSize )
+ * (equivalent to realloc())
+ */
+
+/*
+ * Memory sub-system, written by Bjorn Benson
+ Fixed to use my_sys scheme by Michael Widenius
+ */
+
+#ifndef SAFEMALLOC
+#define SAFEMALLOC /* Get protos from my_sys */
+#endif
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include "my_static.h"
+#include "mysys_err.h"
+
+#define pNext tInt._pNext
+#define pPrev tInt._pPrev
+#define sFileName tInt._sFileName
+#define uLineNum tInt._uLineNum
+#define uDataSize tInt._uDataSize
+#define lSpecialValue tInt._lSpecialValue
+
+ /* Static functions prototypes */
+
+static int check_ptr(const char *where, byte *ptr, const char *sFile,
+ uint uLine);
+static int _checkchunk(struct remember *pRec, const char *sFile, uint uLine);
+
+/*
+ * Note: both these refer to the NEW'ed
+ * data only. They do not include
+ * malloc() roundoff or the extra
+ * space required by the remember
+ * structures.
+ */
+
+#define ALLOC_VAL (uchar) 0xA5 /* NEW'ed memory is filled with this */
+ /* value so that references to it will */
+ /* end up being very strange. */
+#define FREE_VAL (uchar) 0x8F /* FREE'ed memory is filled with this */
+ /* value so that references to it will */
+ /* also end up being strange. */
+
+#define MAGICKEY 0x14235296 /* A magic value for underrun key */
+#define MAGICEND0 0x68 /* Magic values for overrun keys */
+#define MAGICEND1 0x34 /* " */
+#define MAGICEND2 0x7A /* " */
+#define MAGICEND3 0x15 /* " */
+
+ /* Warning: do not change the MAGICEND? values to */
+ /* something with the high bit set. Various C */
+ /* compilers (like the 4.2bsd one) do not do the */
+ /* sign extension right later on in this code and */
+ /* you will get erroneous errors. */
+
+
+/*
+ * gptr _mymalloc( uint uSize, my_string sFile, uint uLine, MyFlags )
+ * Allocate some memory.
+ */
+
+gptr _mymalloc (uint uSize, const char *sFile, uint uLine, myf MyFlags)
+{
+ struct remember *pTmp;
+ DBUG_ENTER("_mymalloc");
+ DBUG_PRINT("enter",("Size: %u",uSize));
+
+ if (!sf_malloc_quick)
+ (void) _sanity (sFile, uLine);
+
+ /* Allocate the physical memory */
+ pTmp = (struct remember *) malloc (
+ sizeof (struct irem) /* remember data */
+ + sf_malloc_prehunc
+ + uSize /* size requested */
+ + 4 /* overrun mark */
+ + sf_malloc_endhunc
+ );
+
+ /* Check if there isn't anymore memory avaiable */
+ if (pTmp == NULL)
+ {
+ if (MyFlags & MY_FAE)
+ error_handler_hook=fatal_error_handler_hook;
+ if (MyFlags & (MY_FAE+MY_WME))
+ {
+ char buff[SC_MAXWIDTH];
+ my_errno=errno;
+ sprintf(buff,"Out of memory at line %d, '%s'", uLine, sFile);
+ my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
+ sprintf(buff,"needed %d byte (%ldk), memory in use: %ld bytes (%ldk)",
+ uSize, (uSize + 1023L) / 1024L,
+ lMaxMemory, (lMaxMemory + 1023L) / 1024L);
+ my_message(EE_OUTOFMEMORY,buff,MYF(ME_BELL+ME_WAITTANG));
+ }
+ DBUG_PRINT("error",("Out of memory, in use: %ld at line %d, '%s'",
+ lMaxMemory,uLine, sFile));
+ if (MyFlags & MY_FAE)
+ exit(1);
+ DBUG_RETURN ((gptr) NULL);
+ }
+
+ /* Fill up the structure */
+ *((long*) ((char*) &pTmp -> lSpecialValue+sf_malloc_prehunc)) = MAGICKEY;
+ pTmp -> aData[uSize + sf_malloc_prehunc+0] = MAGICEND0;
+ pTmp -> aData[uSize + sf_malloc_prehunc+1] = MAGICEND1;
+ pTmp -> aData[uSize + sf_malloc_prehunc+2] = MAGICEND2;
+ pTmp -> aData[uSize + sf_malloc_prehunc+3] = MAGICEND3;
+ pTmp -> sFileName = (my_string) sFile;
+ pTmp -> uLineNum = uLine;
+ pTmp -> uDataSize = uSize;
+ pTmp -> pPrev = NULL;
+
+ /* Add this remember structure to the linked list */
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ if ((pTmp->pNext=pRememberRoot))
+ {
+ pRememberRoot -> pPrev = pTmp;
+ }
+ pRememberRoot = pTmp;
+
+ /* Keep the statistics */
+ lCurMemory += uSize;
+ if (lCurMemory > lMaxMemory) {
+ lMaxMemory = lCurMemory;
+ }
+ cNewCount++;
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+
+ /* Set the memory to the aribtrary wierd value */
+#ifdef HAVE_purify
+ if (MyFlags & MY_ZEROFILL)
+#endif
+ bfill(&pTmp -> aData[sf_malloc_prehunc],uSize,
+ (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL));
+ /* Return a pointer to the real data */
+ DBUG_PRINT("exit",("ptr: %lx",&(pTmp -> aData[sf_malloc_prehunc])));
+ if (sf_min_adress > &(pTmp -> aData[sf_malloc_prehunc]))
+ sf_min_adress = &(pTmp -> aData[sf_malloc_prehunc]);
+ if (sf_max_adress < &(pTmp -> aData[sf_malloc_prehunc]))
+ sf_max_adress = &(pTmp -> aData[sf_malloc_prehunc]);
+ DBUG_RETURN ((gptr) &(pTmp -> aData[sf_malloc_prehunc]));
+}
+
+/*
+ * Allocate some new memory and move old memoryblock there.
+ * Free then old memoryblock
+ */
+
+gptr _myrealloc (register gptr pPtr, register uint uSize,
+ const char *sFile, uint uLine, myf MyFlags)
+{
+ struct remember *pRec;
+ gptr ptr;
+ DBUG_ENTER("_myrealloc");
+
+ if (!pPtr && (MyFlags & MY_ALLOW_ZERO_PTR))
+ DBUG_RETURN(_mymalloc(uSize,sFile,uLine,MyFlags));
+
+ if (!sf_malloc_quick)
+ (void) _sanity (sFile, uLine);
+
+ if (check_ptr("Reallocating",(byte*) pPtr,sFile,uLine))
+ DBUG_RETURN((gptr) NULL);
+
+ pRec = (struct remember *) ((char*) pPtr - sizeof (struct irem)-
+ sf_malloc_prehunc);
+ if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+ != MAGICKEY)
+ {
+ fprintf (stderr, "Reallocating unallocated data at line %d, '%s'\n",
+ uLine, sFile);
+ DBUG_PRINT("safe",("Reallocating unallocated data at line %d, '%s'",
+ uLine, sFile));
+ (void) fflush(stderr);
+ DBUG_RETURN((gptr) NULL);
+ }
+
+ if ((ptr=_mymalloc(uSize,sFile,uLine,MyFlags))) /* Allocate new area */
+ {
+ uSize=min(uSize,pRec-> uDataSize); /* Move as much as possibly */
+ memcpy((byte*) ptr,pPtr,(size_t) uSize); /* Copy old data */
+ _myfree(pPtr,sFile,uLine,0); /* Free not needed area */
+ }
+ else
+ {
+ if (MyFlags & MY_HOLD_ON_ERROR)
+ DBUG_RETURN(pPtr);
+ if (MyFlags & MY_FREE_ON_ERROR)
+ _myfree(pPtr,sFile,uLine,0);
+ }
+ DBUG_RETURN(ptr);
+} /* _myrealloc */
+
+
+/*
+ * void _myfree( my_string pPtr, my_string sFile, uint uLine, myf myflags)
+ * Deallocate some memory.
+ */
+
+void _myfree (gptr pPtr, const char *sFile, uint uLine, myf myflags)
+{
+ struct remember *pRec;
+ DBUG_ENTER("_myfree");
+ DBUG_PRINT("enter",("ptr: %lx",pPtr));
+
+ if (!sf_malloc_quick)
+ (void) _sanity (sFile, uLine);
+
+ if ((!pPtr && (myflags & MY_ALLOW_ZERO_PTR)) ||
+ check_ptr("Freeing",(byte*) pPtr,sFile,uLine))
+ DBUG_VOID_RETURN;
+
+ /* Calculate the address of the remember structure */
+ pRec = (struct remember *) ((byte*) pPtr-sizeof(struct irem)-
+ sf_malloc_prehunc);
+
+ /* Check to make sure that we have a real remember structure */
+ /* Note: this test could fail for four reasons: */
+ /* (1) The memory was already free'ed */
+ /* (2) The memory was never new'ed */
+ /* (3) There was an underrun */
+ /* (4) A stray pointer hit this location */
+
+ if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+ != MAGICKEY)
+ {
+ fprintf (stderr, "Freeing unallocated data at line %d, '%s'\n",
+ uLine, sFile);
+ DBUG_PRINT("safe",("Unallocated data at line %d, '%s'",uLine,sFile));
+ (void) fflush(stderr);
+ DBUG_VOID_RETURN;
+ }
+
+ /* Remove this structure from the linked list */
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ if (pRec -> pPrev) {
+ pRec -> pPrev -> pNext = pRec -> pNext;
+ } else {
+ pRememberRoot = pRec -> pNext;
+ }
+ if (pRec -> pNext) {
+ pRec -> pNext -> pPrev = pRec -> pPrev;
+ }
+ /* Handle the statistics */
+ lCurMemory -= pRec -> uDataSize;
+ cNewCount--;
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+
+#ifndef HAVE_purify
+ /* Mark this data as free'ed */
+ bfill(&pRec->aData[sf_malloc_prehunc],pRec->uDataSize,(pchar) FREE_VAL);
+#endif
+ *((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc)) = ~MAGICKEY;
+
+ /* Actually free the memory */
+ free ((my_string ) pRec);
+ DBUG_VOID_RETURN;
+}
+
+ /* Check if we have a wrong pointer */
+
+static int check_ptr(const char *where, byte *ptr, const char *sFile,
+ uint uLine)
+{
+ if (!ptr)
+ {
+ fprintf (stderr, "%s NULL pointer at line %d, '%s'\n",
+ where,uLine, sFile);
+ DBUG_PRINT("safe",("Null pointer at line %d '%s'", uLine, sFile));
+ (void) fflush(stderr);
+ return 1;
+ }
+#ifndef _MSC_VER
+ if ((long) ptr & (MY_ALIGN(1,sizeof(char *))-1))
+ {
+ fprintf (stderr, "%s wrong aligned pointer at line %d, '%s'\n",
+ where,uLine, sFile);
+ DBUG_PRINT("safe",("Wrong aligned pointer at line %d, '%s'",
+ uLine,sFile));
+ (void) fflush(stderr);
+ return 1;
+ }
+#endif
+ if (ptr < sf_min_adress || ptr > sf_max_adress)
+ {
+ fprintf (stderr, "%s pointer out of range at line %d, '%s'\n",
+ where,uLine, sFile);
+ DBUG_PRINT("safe",("Pointer out of range at line %d '%s'",
+ uLine,sFile));
+ (void) fflush(stderr);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * TERMINATE(FILE *file)
+ * Report on all the memory pieces that have not been
+ * free'ed as well as the statistics.
+ */
+
+void TERMINATE (FILE *file)
+{
+ struct remember *pPtr;
+ DBUG_ENTER("TERMINATE");
+ pthread_mutex_lock(&THR_LOCK_malloc);
+
+ /* Report the difference between number of calls to */
+ /* NEW and the number of calls to FREE. >0 means more */
+ /* NEWs than FREEs. <0, etc. */
+
+ if (cNewCount)
+ {
+ if (file)
+ {
+ fprintf (file, "cNewCount: %d\n", cNewCount);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",("cNewCount: %d",cNewCount));
+ }
+
+ /* Report on all the memory that was allocated with NEW */
+ /* but not free'ed with FREE. */
+
+ if ((pPtr=pRememberRoot))
+ {
+ if (file)
+ {
+ fprintf(file, "Memory that was not free'ed (%ld bytes):\n",lCurMemory);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",("Memory that was not free'ed (%ld bytes):",lCurMemory));
+ while (pPtr)
+ {
+ if (file)
+ {
+ fprintf (file,
+ "\t%6u bytes at 0x%09lx, allocated at line %4u in '%s'\n",
+ pPtr -> uDataSize,
+ (ulong) &(pPtr -> aData[sf_malloc_prehunc]),
+ pPtr -> uLineNum, pPtr -> sFileName);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",
+ ("%6u bytes at 0x%09lx, allocated at line %4d in '%s'",
+ pPtr -> uDataSize, &(pPtr -> aData[sf_malloc_prehunc]),
+ pPtr -> uLineNum, pPtr -> sFileName));
+ pPtr = pPtr -> pNext;
+ }
+ }
+ /* Report the memory usage statistics */
+ if (file)
+ {
+ fprintf (file, "Maximum memory usage: %ld bytes (%ldk)\n",
+ lMaxMemory, (lMaxMemory + 1023L) / 1024L);
+ (void) fflush(file);
+ }
+ DBUG_PRINT("safe",("Maximum memory usage: %ld bytes (%ldk)",
+ lMaxMemory, (lMaxMemory + 1023L) / 1024L));
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ DBUG_VOID_RETURN;
+}
+
+
+ /* Returns 0 if chunk is ok */
+
+static int _checkchunk (register struct remember *pRec, const char *sFile,
+ uint uLine)
+{
+ reg1 uint uSize;
+ reg2 my_string magicp;
+ reg3 int flag=0;
+
+ /* Check for a possible underrun */
+ if (*((long*) ((char*) &pRec -> lSpecialValue+sf_malloc_prehunc))
+ != MAGICKEY)
+ {
+ fprintf (stderr, "Memory allocated at %s:%d was underrun,",
+ pRec -> sFileName, pRec -> uLineNum);
+ fprintf (stderr, " discovered at %s:%d\n", sFile, uLine);
+ (void) fflush(stderr);
+ DBUG_PRINT("safe",("Underrun at %lx, allocated at %s:%d",
+ &(pRec -> aData[sf_malloc_prehunc]),
+ pRec -> sFileName,
+ pRec -> uLineNum));
+ flag=1;
+ }
+
+ /* Check for a possible overrun */
+ uSize = pRec -> uDataSize;
+ magicp = &(pRec -> aData[uSize+sf_malloc_prehunc]);
+ if (*magicp++ != MAGICEND0 ||
+ *magicp++ != MAGICEND1 ||
+ *magicp++ != MAGICEND2 ||
+ *magicp++ != MAGICEND3)
+ {
+ fprintf (stderr, "Memory allocated at %s:%d was overrun,",
+ pRec -> sFileName, pRec -> uLineNum);
+ fprintf (stderr, " discovered at '%s:%d'\n", sFile, uLine);
+ (void) fflush(stderr);
+ DBUG_PRINT("safe",("Overrun at %lx, allocated at %s:%d",
+ &(pRec -> aData[sf_malloc_prehunc]),
+ pRec -> sFileName,
+ pRec -> uLineNum));
+ flag=1;
+ }
+ return(flag);
+}
+
+
+ /* Returns how many wrong chunks */
+
+int _sanity (const char *sFile, uint uLine)
+{
+ reg1 struct remember *pTmp;
+ reg2 int flag=0;
+ uint count=0;
+
+ pthread_mutex_lock(&THR_LOCK_malloc);
+ count=cNewCount;
+ for (pTmp = pRememberRoot; pTmp != NULL && count-- ; pTmp = pTmp -> pNext)
+ flag+=_checkchunk (pTmp, sFile, uLine);
+ pthread_mutex_unlock(&THR_LOCK_malloc);
+ if (count || pTmp)
+ {
+ const char *format="Safemalloc link list destroyed, discovered at '%s:%d'";
+ fprintf (stderr, format, sFile, uLine); fputc('\n',stderr);
+ (void) fflush(stderr);
+ DBUG_PRINT("safe",(format, sFile, uLine));
+ flag=1;
+ }
+ return flag;
+} /* _sanity */
+
+
+ /* malloc and copy */
+
+gptr _my_memdup(const byte *from, uint length, const char *sFile, uint uLine,
+ myf MyFlags)
+{
+ gptr ptr;
+ if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return(ptr);
+} /*_my_memdup */
+
+
+my_string _my_strdup(const char *from, const char *sFile, uint uLine,
+ myf MyFlags)
+{
+ gptr ptr;
+ uint length=(uint) strlen(from)+1;
+ if ((ptr=_mymalloc(length,sFile,uLine,MyFlags)) != 0)
+ memcpy((byte*) ptr, (byte*) from,(size_t) length);
+ return((my_string) ptr);
+} /* _my_strdup */
diff --git a/mysys/string.c b/mysys/string.c
new file mode 100644
index 00000000000..f7e265a43e6
--- /dev/null
+++ b/mysys/string.c
@@ -0,0 +1,117 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Code for handling strings with can grow dynamicly.
+ Copyright Monty Program KB.
+ By monty.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+
+my_bool init_dynamic_string(DYNAMIC_STRING *str, const char *init_str,
+ uint init_alloc, uint alloc_increment)
+{
+ uint length;
+ DBUG_ENTER("init_dynamic_string");
+
+ if (!alloc_increment)
+ alloc_increment=128;
+ length=1;
+ if (init_str && (length=strlen(init_str)+1) < init_alloc)
+ init_alloc=((length+alloc_increment-1)/alloc_increment)*alloc_increment;
+ if (!init_alloc)
+ init_alloc=alloc_increment;
+
+ if (!(str->str=(char*) my_malloc(init_alloc,MYF(MY_WME))))
+ DBUG_RETURN(TRUE);
+ str->length=length-1;
+ if (init_str)
+ memcpy(str->str,init_str,length);
+ str->max_length=init_alloc;
+ str->alloc_increment=alloc_increment;
+ DBUG_RETURN(FALSE);
+}
+
+my_bool dynstr_set(DYNAMIC_STRING *str, const char *init_str)
+{
+ uint length;
+ DBUG_ENTER("dynstr_set");
+
+ if (init_str && (length=strlen(init_str)+1) > str->max_length)
+ {
+ str->max_length=((length+str->alloc_increment-1)/str->alloc_increment)*
+ str->alloc_increment;
+ if (!str->max_length)
+ str->max_length=str->alloc_increment;
+ if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
+ DBUG_RETURN(TRUE);
+ }
+ if (init_str)
+ {
+ str->length=length-1;
+ memcpy(str->str,init_str,length);
+ }
+ else
+ str->length=0;
+ DBUG_RETURN(FALSE);
+}
+
+my_bool dynstr_realloc(DYNAMIC_STRING *str, ulong additional_size)
+{
+ DBUG_ENTER("dynstr_realloc");
+
+ if (!additional_size) DBUG_RETURN(FALSE);
+ if (str->length + additional_size > str->max_length)
+ {
+ str->max_length=((str->length + additional_size+str->alloc_increment-1)/
+ str->alloc_increment)*str->alloc_increment;
+ if (!(str->str=(char*) my_realloc(str->str,str->max_length,MYF(MY_WME))))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+my_bool dynstr_append(DYNAMIC_STRING *str, const char *append)
+{
+ char *new_ptr;
+ uint length=(uint) strlen(append)+1;
+ if (str->length+length > str->max_length)
+ {
+ uint new_length=(str->length+length+str->alloc_increment-1)/
+ str->alloc_increment;
+ new_length*=str->alloc_increment;
+ if (!(new_ptr=(char*) my_realloc(str->str,new_length,MYF(MY_WME))))
+ return TRUE;
+ str->str=new_ptr;
+ str->max_length=new_length;
+ }
+ memcpy(str->str + str->length,append,length);
+ str->length+=length-1;
+ return FALSE;
+}
+
+void dynstr_free(DYNAMIC_STRING *str)
+{
+ if (str->str)
+ {
+ my_free(str->str,MYF(MY_WME));
+ str->str=0;
+ }
+}
diff --git a/mysys/test_charset.c b/mysys/test_charset.c
new file mode 100644
index 00000000000..a04bdbd9a58
--- /dev/null
+++ b/mysys/test_charset.c
@@ -0,0 +1,59 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include <global.h>
+#include <m_ctype.h>
+#include <my_sys.h>
+#include <mysql_version.h>
+
+#include <stdio.h>
+
+extern void _print_csinfo();
+
+int main(int argc, char **argv) {
+ const char *the_set = MYSQL_CHARSET;
+ char *cs_list;
+ int argcnt = 1;
+
+ my_init();
+
+ if (argc > argcnt && argv[argcnt][0] == '-' && argv[argcnt][1] == '#')
+ DBUG_PUSH(argv[argcnt++]+2);
+
+ if (argc > argcnt)
+ the_set = argv[argcnt++];
+
+ if (argc > argcnt)
+ charsets_dir = argv[argcnt++];
+
+ if (set_default_charset_by_name(the_set, MYF(MY_WME)))
+ return 1;
+
+ puts("CHARSET INFO:");
+ _print_csinfo(default_charset_info);
+ fflush(stdout);
+
+ cs_list = list_charsets(MYF(MY_COMPILED_SETS | MY_CONFIG_SETS));
+ printf("LIST OF CHARSETS (compiled + *.conf):\n%s\n", cs_list);
+ free(cs_list);
+
+ cs_list = list_charsets(MYF(MY_INDEX_SETS | MY_LOADED_SETS));
+ printf("LIST OF CHARSETS (index + loaded):\n%s\n", cs_list);
+ free(cs_list);
+
+ return 0;
+}
diff --git a/mysys/test_dir.c b/mysys/test_dir.c
new file mode 100644
index 00000000000..fafdde137b6
--- /dev/null
+++ b/mysys/test_dir.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* TODO: Test all functions */
+
+#define USES_TYPES
+#include "mysys_priv.h"
+#include "my_dir.h"
+
+int main(int argc, char *argv[])
+{
+ MY_DIR *a;
+ uint f;
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+
+ if (--argc > 0 && (*(++argv))[0] == '-' && (*argv)[1] == '#' )
+ DBUG_PUSH (*argv+2);
+
+ a = my_dir("./", 0);
+ for (f = 0; f < a->number_off_files; f++)
+ {
+ printf("%s\n", a->dir_entry[f].name);
+ }
+
+ a = my_dir("./", MY_WANT_STAT);
+ for (f = 0; f < a->number_off_files; f++)
+ {
+ printf("%s %d %d %d %s\n", a->dir_entry[f].name,
+ (int) a->dir_entry[f].mystat.st_size,
+ (int) a->dir_entry[f].mystat.st_uid,
+ (int) a->dir_entry[f].mystat.st_gid,
+ S_ISDIR(a->dir_entry[f].mystat.st_mode) ? "dir" : "");
+ }
+ return 0;
+}
diff --git a/mysys/test_fn.c b/mysys/test_fn.c
new file mode 100644
index 00000000000..224b899ebe1
--- /dev/null
+++ b/mysys/test_fn.c
@@ -0,0 +1,70 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+
+const char *test_names[]=
+{
+ "/usr/my/include/srclib/myfunc/dbug/test",
+ "test",
+ "dbug/test",
+ "/usr/my/srclib/myfunc/dbug/test",
+ "/usr/monty/oldcopy/jazz/setupp.frm",
+ "~/monty.tst",
+ "~/dbug/monty.tst",
+ "./hejsan",
+ "./dbug/test",
+ "../dbug/test",
+ "../myfunc/test",
+ "../../monty/rutedit",
+ "/usr/monty//usr/monty/rutedit",
+ "/usr/./monty/rutedit",
+ "/usr/my/../monty/rutedit",
+ "/usr/my/~/rutedit",
+ "~/../my",
+ "~/../my/srclib/myfunc/test",
+ "~/../my/srclib/myfunc/./dbug/test",
+ "/../usr/my/srclib/dbug",
+ "c/../my",
+ "/c/../my",
+ NullS,
+};
+
+int main(int argc __attribute__((unused)), char **argv)
+{
+ const char **pos;
+ char buff[FN_REFLEN],buff2[FN_REFLEN];
+ DBUG_ENTER ("main");
+ DBUG_PROCESS (argv[0]);
+ MY_INIT(argv[0]);
+
+ if (argv[1] && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ for (pos=test_names; *pos ; pos++)
+ {
+ printf("org : '%s'\n",*pos);
+ printf("pack: '%s'\n",fn_format(buff,*pos,"","",8));
+ printf("unpack: '%s'\n",fn_format(buff2,*pos,"","",4));
+ if (strcmp(unpack_filename(buff,buff),buff2) != 0)
+ {
+ printf("error on cmp: '%s' != '%s'\n",buff,buff2);
+ }
+ puts("");
+ }
+ DBUG_RETURN(0);
+}
diff --git a/mysys/test_vsnprintf.c b/mysys/test_vsnprintf.c
new file mode 100644
index 00000000000..b9ffb014181
--- /dev/null
+++ b/mysys/test_vsnprintf.c
@@ -0,0 +1,45 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include "mysys_priv.h"
+
+static void my_printf(const char * fmt, ...)
+{
+ char buf[32];
+ int n;
+ va_list ar;
+ va_start(ar, fmt);
+ n = my_vsnprintf(buf, sizeof(buf),fmt, ar);
+ printf(buf);
+ printf("n=%d, strlen=%d\n", n, strlen(buf));
+ va_end(ar);
+}
+
+int main()
+{
+
+ my_printf("Hello\n");
+ my_printf("Hello int, %d\n", 1);
+ my_printf("Hello string '%s'\n", "I am a string");
+ my_printf("Hello hack hack hack hack hack hack hack %d\n", 1);
+ my_printf("Hello %d hack %d\n", 1, 4);
+ my_printf("Hello %d hack hack hack hack hack %d\n", 1, 4);
+ my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack");
+ my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1);
+ my_printf("Hello %u\n", 1);
+ return 0;
+}
diff --git a/mysys/testhash.c b/mysys/testhash.c
new file mode 100644
index 00000000000..a8fbf800595
--- /dev/null
+++ b/mysys/testhash.c
@@ -0,0 +1,291 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Test av hash libarary: stor test */
+
+#include <global.h>
+#include <my_sys.h>
+#include <hash.h>
+#include <m_string.h>
+
+#define MAX_RECORDS 100000
+#define MAX_KEYS 3
+
+static int get_options(int argc, char *argv[]);
+static int do_test();
+static int rnd(int max_value);
+
+static uint testflag=0,recant=10000,reclength=37;
+static uint16 key1[1000];
+
+#ifdef DBUG_OFF
+#define hash_check(A) 0
+#else
+my_bool hash_check(HASH *hash);
+#endif
+void free_record(void *record);
+
+static byte *hash2_key(const byte *rec,uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length=(uint) (uchar) rec[reclength-1];
+ return (byte*) rec;
+}
+
+ /* Huvudprogrammet */
+
+int main(int argc,char *argv[])
+{
+ MY_INIT(argv[0]);
+ DBUG_PROCESS(argv[0]);
+
+ get_options(argc,argv);
+
+ exit(do_test());
+}
+
+static int do_test()
+{
+ register uint i,j;
+ uint n1,n2,n3;
+ uint write_count,update,delete;
+ ulong pos;
+ unsigned long key_check;
+ char *record,*recpos,oldrecord[120],key[10];
+ HASH hash,hash2;
+ DBUG_ENTER("do_test");
+
+ write_count=update=delete=0;
+ key_check=0;
+ bzero((char*) key1,sizeof(key1[0])*1000);
+
+ printf("- Creating hash\n");
+ if (hash_init(&hash,recant/2,0,6,0,free_record,0))
+ goto err;
+ printf("- Writing records:s\n");
+
+ for (i=0 ; i < recant ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*5,MAX_RECORDS));
+ record= (char*) my_malloc(reclength,MYF(MY_FAE));
+ sprintf(record,"%6d:%4d:%8d:Pos: %4d ",n1,n2,n3,write_count);
+ if (hash_insert(&hash,record))
+ {
+ printf("Error: %d in write at record: %d\n",my_errno,i);
+ goto err;
+ }
+ key1[n1]++;
+ key_check+=n1;
+ write_count++;
+ }
+ if (hash_check(&hash))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ printf("- Delete\n");
+ for (i=0 ; i < write_count/10 ; i++)
+ {
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (j != 0)
+ {
+ sprintf(key,"%6d",j);
+ if (!(recpos=hash_search(&hash,key,0)))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ key1[atoi(recpos)]--;
+ key_check-=atoi(recpos);
+ memcpy(oldrecord,recpos,reclength);
+ if (hash_delete(&hash,recpos))
+ {
+ printf("error: %d; can't delete record: \"%s\"\n", my_errno,oldrecord);
+ goto err;
+ }
+ delete++;
+ if (testflag == 2 && hash_check(&hash))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+ }
+ }
+ if (hash_check(&hash))
+ {
+ puts("Hash keys crashed");
+ goto err;
+ }
+
+ printf("- Update\n");
+ for (i=0 ; i < write_count/10 ; i++)
+ {
+ n1=rnd(1000); n2=rnd(100); n3=rnd(min(recant*2,MAX_RECORDS));
+ for (j=rnd(1000) ; j>0 && key1[j] == 0 ; j--) ;
+ if (j)
+ {
+ sprintf(key,"%6d",j);
+ if (!(recpos=hash_search(&hash,key,0)))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ key1[atoi(recpos)]--;
+ key_check=key_check-atoi(recpos)+n1;
+ key1[n1]++;
+ sprintf(recpos,"%6d:%4d:%8d:XXX: %4d ",n1,n2,n3,update);
+ update++;
+ if (hash_update(&hash,recpos,key,0))
+ {
+ printf("can't update key1: \"%s\"\n",key);
+ goto err;
+ }
+ if (testflag == 3 && hash_check(&hash))
+ {
+ printf("Heap keys crashed for %d update\n",update);
+ goto err;
+ }
+ }
+ }
+ if (hash_check(&hash))
+ {
+ puts("Heap keys crashed");
+ goto err;
+ }
+
+ for (j=0 ; j < 1000 ; j++)
+ if (key1[j] > 1)
+ break;
+ if (key1[j] > 1)
+ {
+ printf("- Testing identical read\n");
+ sprintf(key,"%6d",j);
+ pos=1;
+ if (!(recpos=hash_search(&hash,key,0)))
+ {
+ printf("can't find key1: \"%s\"\n",key);
+ goto err;
+ }
+ while (hash_next(&hash,key,0) && pos < (ulong) (key1[j]+10))
+ pos++;
+ if (pos != (ulong) key1[j])
+ {
+ printf("Found %ld copies of key: %s. Should be %d",pos,key,key1[j]);
+ goto err;
+ }
+ }
+ printf("- Creating output heap-file 2\n");
+ if (hash_init(&hash2,hash.records,0,0,hash2_key,free_record,0))
+ goto err;
+
+ printf("- Copying and removing records\n");
+ pos=0;
+ while ((recpos=hash_element(&hash,0)))
+ {
+ record=(byte*) my_malloc(reclength,MYF(MY_FAE));
+ memcpy(record,recpos,reclength);
+ record[reclength-1]=rnd(5)+1;
+ if (hash_insert(&hash2,record))
+ {
+ printf("Got error when inserting record: %*s",reclength,record);
+ goto err;
+ }
+ key_check-=atoi(record);
+ write_count++;
+ if (hash_delete(&hash,recpos))
+ {
+ printf("Got error when deleting record: %*s",reclength,recpos);
+ goto err;
+ }
+ if (testflag==4)
+ {
+ if (hash_check(&hash) || hash_check(&hash2))
+ {
+ puts("Hash keys crashed");
+ goto err;
+ }
+ }
+ pos++;
+ }
+ if (hash_check(&hash) || hash_check(&hash2))
+ {
+ puts("Hash keys crashed");
+ goto err;
+ }
+ if (key_check != 0)
+ {
+ printf("Key check didn't get to 0 (%ld)\n",key_check);
+ }
+
+ printf("\nFollowing test have been made:\n");
+ printf("Write records: %d\nUpdate records: %d\nDelete records: %d\n", write_count,
+ update,delete);
+ hash_free(&hash); hash_free(&hash2);
+ my_end(MY_GIVE_INFO);
+ DBUG_RETURN(0);
+err:
+ printf("Got error: %d when using hashing\n",my_errno);
+ DBUG_RETURN(-1);
+} /* main */
+
+
+ /* l{ser optioner */
+ /* OBS! intierar endast DEBUG - ingen debuggning h{r ! */
+
+static int get_options(int argc, char **argv)
+{
+ char *pos,*progname;
+ DEBUGGER_OFF;
+
+ progname= argv[0];
+
+ while (--argc >0 && *(pos = *(++argv)) == '-' ) {
+ switch(*++pos) {
+ case 'm': /* records */
+ recant=atoi(++pos);
+ break;
+ case 't':
+ testflag=atoi(++pos); /* testmod */
+ break;
+ case 'V':
+ case 'I':
+ case '?':
+ printf("%s Ver 1.0 for %s at %s\n",progname,SYSTEM_TYPE,MACHINE_TYPE);
+ puts("TCX Datakonsult AB, by Monty, for your professional use\n");
+ printf("Usage: %s [-?ABIKLWv] [-m#] [-t#]\n",progname);
+ exit(0);
+ case '#':
+ DEBUGGER_ON;
+ DBUG_PUSH (++pos);
+ break;
+ }
+ }
+ return 0;
+} /* get options */
+
+ /* Ge ett randomv{rde inom ett intervall 0 <=x <= n */
+
+static int rnd(int max_value)
+{
+ return (int) ((rand() & 32767)/32767.0*max_value);
+} /* rnd */
+
+
+void free_record(void *record)
+{
+ my_free(record,MYF(0));
+}
diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c
new file mode 100644
index 00000000000..a681c1b110d
--- /dev/null
+++ b/mysys/thr_alarm.c
@@ -0,0 +1,874 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+#include <global.h>
+#include <errno.h>
+#include <my_pthread.h>
+#include <signal.h>
+#include <my_sys.h>
+#include <m_string.h>
+#include <queues.h>
+#include "thr_alarm.h"
+
+#ifdef THREAD
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h> /* AIX needs this for fd_set */
+#endif
+
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
+
+static my_bool alarm_aborted=1;
+my_bool thr_alarm_inited=0;
+
+#if !defined(__WIN__) && !defined(__OS2__)
+#ifndef DONT_USE_THR_ALARM /* thr_alarm disabled */
+
+static pthread_mutex_t LOCK_alarm;
+static sigset_t full_signal_set;
+static QUEUE alarm_queue;
+pthread_t alarm_thread;
+
+#ifdef USE_ALARM_THREAD
+static pthread_cond_t COND_alarm;
+static void *alarm_handler(void *arg);
+#define reschedule_alarms() pthread_cond_signal(&COND_alarm)
+#else
+#define reschedule_alarms() pthread_kill(alarm_thread,THR_SERVER_ALARM)
+#endif
+
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+static sig_handler thread_alarm(int sig __attribute__((unused)));
+#endif
+
+static int compare_ulong(void *not_used __attribute__((unused)),
+ byte *a_ptr,byte* b_ptr)
+{
+ ulong a=*((ulong*) a_ptr),b= *((ulong*) b_ptr);
+ return (a < b) ? -1 : (a == b) ? 0 : 1;
+}
+
+void init_thr_alarm(uint max_alarms)
+{
+ sigset_t s;
+ DBUG_ENTER("init_thr_alarm");
+ alarm_aborted=0;
+ init_queue(&alarm_queue,max_alarms+1,offsetof(ALARM,expire_time),0,
+ compare_ulong,NullS);
+ sigfillset(&full_signal_set); /* Neaded to block signals */
+ pthread_mutex_init(&LOCK_alarm,NULL);
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+#if defined(HAVE_mit_thread)
+ sigset(THR_CLIENT_ALARM,thread_alarm); /* int. thread system calls */
+#else
+ {
+ struct sigaction sact;
+ sact.sa_flags = 0;
+ sact.sa_handler = thread_alarm;
+ sigaction(THR_CLIENT_ALARM, &sact, (struct sigaction*) 0);
+ }
+#endif
+#endif
+ sigemptyset(&s);
+ sigaddset(&s, THR_SERVER_ALARM);
+ alarm_thread=pthread_self();
+#if defined(USE_ALARM_THREAD)
+ {
+ pthread_attr_t thr_attr;
+ pthread_attr_init(&thr_attr);
+ pthread_cond_init(&COND_alarm,NULL);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,8196);
+
+ my_pthread_attr_setprio(&thr_attr,100); /* Very high priority */
+ VOID(pthread_create(&alarm_thread,&thr_attr,alarm_handler,NULL));
+ VOID(pthread_attr_destroy(&thr_attr));
+ }
+#elif defined(USE_ONE_SIGNAL_HAND)
+ pthread_sigmask(SIG_BLOCK, &s, NULL); /* used with sigwait() */
+#if THR_SERVER_ALARM == THR_CLIENT_ALARM
+ sigset(THR_CLIENT_ALARM,process_alarm); /* Linuxthreads */
+ pthread_sigmask(SIG_UNBLOCK, &s, NULL);
+#endif
+#else
+ pthread_sigmask(SIG_UNBLOCK, &s, NULL);
+ sigset(THR_SERVER_ALARM,process_alarm);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+/*
+** Request alarm after sec seconds.
+** A pointer is returned with points to a non-zero int when the alarm has been
+** given. This can't be called from the alarm-handling thread.
+** Returns 0 if no more alarms are allowed (aborted by process)
+*/
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
+{
+ ulong now;
+ sigset_t old_mask;
+ my_bool reschedule;
+ DBUG_ENTER("thr_alarm");
+ DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
+
+ now=(ulong) time((time_t*) 0);
+ pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
+ if (alarm_aborted)
+ { /* No signal thread */
+ DBUG_PRINT("info", ("alarm aborted"));
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ if (alarm_queue.elements == alarm_queue.max_elements)
+ {
+ DBUG_PRINT("info", ("alarm queue full"));
+ fprintf(stderr,"Warning: thr_alarm queue is full\n");
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ reschedule= (!alarm_queue.elements ||
+ (int) (((ALARM*) queue_top(&alarm_queue))->expire_time - now) >
+ (int) sec);
+ if (!alarm_data)
+ {
+ if (!(alarm_data=(ALARM*) my_malloc(sizeof(ALARM),MYF(MY_WME))))
+ {
+ DBUG_PRINT("info", ("failed my_malloc()"));
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_RETURN(1);
+ }
+ alarm_data->malloced=1;
+ }
+ else
+ alarm_data->malloced=0;
+ alarm_data->expire_time=now+sec;
+ alarm_data->alarmed=0;
+ alarm_data->thread=pthread_self();
+ queue_insert(&alarm_queue,(byte*) alarm_data);
+
+ /* Reschedule alarm if the current one has more than sec left */
+ if (reschedule)
+ {
+ DBUG_PRINT("info", ("reschedule"));
+ if (pthread_equal(pthread_self(),alarm_thread))
+ alarm(sec); /* purecov: inspected */
+ else
+ reschedule_alarms(); /* Reschedule alarms */
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ (*alrm)= &alarm_data->alarmed;
+ DBUG_RETURN(0);
+}
+
+
+/*
+** Remove alarm from list of alarms
+*/
+
+void thr_end_alarm(thr_alarm_t *alarmed)
+{
+ ALARM *alarm_data;
+ sigset_t old_mask;
+ uint i;
+ bool found=0;
+ DBUG_ENTER("thr_end_alarm");
+
+ pthread_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm);
+
+ alarm_data= (ALARM*) ((byte*) *alarmed - offsetof(ALARM,alarmed));
+ for (i=0 ; i < alarm_queue.elements ; i++)
+ {
+ if ((ALARM*) queue_element(&alarm_queue,i) == alarm_data)
+ {
+ queue_remove(&alarm_queue,i),MYF(0);
+ if (alarm_data->malloced)
+ my_free((gptr) alarm_data,MYF(0));
+ found=1;
+ break;
+ }
+ }
+ if (!found)
+ {
+#ifdef MAIN
+ printf("Warning: Didn't find alarm %lx in queue of %d alarms\n",
+ (long) *alarmed, alarm_queue.elements);
+#endif
+ DBUG_PRINT("warning",("Didn't find alarm %lx in queue\n",*alarmed));
+ }
+ if (alarm_aborted && !alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+ DBUG_VOID_RETURN;
+}
+
+ /*
+ Come here when some alarm in queue is due.
+ Mark all alarms with are finnished in list.
+ Shedule alarms to be sent again after 1-10 sec (many alarms at once)
+ If alarm_aborted is set then all alarms are given and resent
+ every second.
+ */
+
+sig_handler process_alarm(int sig __attribute__((unused)))
+{
+ sigset_t old_mask;
+ ALARM *alarm_data;
+ DBUG_ENTER("process_alarm");
+ DBUG_PRINT("info",("sig: %d active alarms: %d",sig,alarm_queue.elements));
+
+#if THR_SERVER_ALARM == THR_CLIENT_ALARM
+ if (!pthread_equal(pthread_self(),alarm_thread))
+ {
+#if defined(MAIN) && !defined(__bsdi__)
+ printf("thread_alarm\n"); fflush(stdout);
+#endif
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(THR_CLIENT_ALARM,process_alarm); /* int. thread system calls */
+#endif
+ DBUG_VOID_RETURN;
+ }
+#endif
+
+#if defined(MAIN) && !defined(__bsdi__)
+ printf("process_alarm\n"); fflush(stdout);
+#endif
+#ifndef USE_ALARM_THREAD
+ pthread_sigmask(SIG_SETMASK,&full_signal_set,&old_mask);
+ pthread_mutex_lock(&LOCK_alarm);
+#endif
+ if (alarm_queue.elements)
+ {
+ if (alarm_aborted)
+ {
+ uint i;
+ for (i=0 ; i < alarm_queue.elements ;)
+ {
+ alarm_data=(ALARM*) queue_element(&alarm_queue,i);
+ alarm_data->alarmed=1; /* Info to thread */
+ if (pthread_equal(alarm_data->thread,alarm_thread) ||
+ pthread_kill(alarm_data->thread, THR_CLIENT_ALARM))
+ {
+#ifdef MAIN
+ printf("Warning: pthread_kill couldn't find thread!!!\n");
+#endif
+ queue_remove(&alarm_queue,i); /* No thread. Remove alarm */
+ }
+ else
+ i++; /* Signal next thread */
+ }
+#ifndef USE_ALARM_THREAD
+ if (alarm_queue.elements)
+ alarm(1); /* Signal soon again */
+#endif
+ }
+ else
+ {
+ ulong now=(ulong) time((time_t*) 0);
+ ulong next=now+10-(now%10);
+ while ((alarm_data=(ALARM*) queue_top(&alarm_queue))->expire_time <= now)
+ {
+ alarm_data->alarmed=1; /* Info to thread */
+ DBUG_PRINT("info",("sending signal to waiting thread"));
+ if (pthread_equal(alarm_data->thread,alarm_thread) ||
+ pthread_kill(alarm_data->thread, THR_CLIENT_ALARM))
+ {
+#ifdef MAIN
+ printf("Warning: pthread_kill couldn't find thread!!!\n");
+#endif
+ queue_remove(&alarm_queue,0); /* No thread. Remove alarm */
+ if (!alarm_queue.elements)
+ break;
+ }
+ else
+ {
+ alarm_data->expire_time=next;
+ queue_replaced(&alarm_queue);
+ }
+ }
+#ifndef USE_ALARM_THREAD
+ if (alarm_queue.elements)
+ {
+#ifdef __bsdi__
+ alarm(0); /* Remove old alarm */
+#endif
+ alarm((uint) (alarm_data->expire_time-now));
+ }
+#endif
+ }
+ }
+#ifndef USE_ALARM_THREAD
+#if defined(DONT_REMEMBER_SIGNAL) && !defined(USE_ONE_SIGNAL_HAND)
+ sigset(THR_SERVER_ALARM,process_alarm);
+#endif
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_sigmask(SIG_SETMASK,&old_mask,NULL);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Shedule all alarms now.
+** When all alarms are given, Free alarm memory and don't allow more alarms.
+*/
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ pthread_mutex_lock(&LOCK_alarm);
+ if (!alarm_aborted)
+ {
+ DBUG_PRINT("info",("Resheduling %d waiting alarms",alarm_queue.elements));
+ alarm_aborted=1; /* mark aborted */
+ if (!alarm_queue.elements)
+ delete_queue(&alarm_queue);
+ if (pthread_equal(pthread_self(),alarm_thread))
+ alarm(1); /* Shut down everything soon */
+ else
+ reschedule_alarms();
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Remove another thread from the alarm
+*/
+
+void thr_alarm_kill(pthread_t thread_id)
+{
+ uint i;
+ pthread_mutex_lock(&LOCK_alarm);
+ for (i=0 ; i < alarm_queue.elements ; i++)
+ {
+ if (pthread_equal(((ALARM*) queue_element(&alarm_queue,i))->thread,
+ thread_id))
+ {
+ ALARM *tmp=(ALARM*) queue_remove(&alarm_queue,i);
+ tmp->expire_time=0;
+ queue_insert(&alarm_queue,(byte*) tmp);
+ reschedule_alarms();
+ break;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_alarm);
+}
+
+
+/*
+** This is here for thread to get interruptet from read/write/fcntl
+** ARGSUSED
+*/
+
+#if THR_CLIENT_ALARM != SIGALRM || defined(USE_ALARM_THREAD)
+static sig_handler thread_alarm(int sig)
+{
+#ifdef MAIN
+ printf("thread_alarm\n"); fflush(stdout);
+#endif
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(sig,thread_alarm); /* int. thread system calls */
+#endif
+}
+#endif
+
+
+#ifdef HAVE_TIMESPEC_TS_SEC
+#define tv_sec ts_sec
+#define tv_nsec ts_nsec
+#endif
+
+/* set up a alarm thread with uses 'sleep' to sleep between alarms */
+
+#ifdef USE_ALARM_THREAD
+static void *alarm_handler(void *arg __attribute__((unused)))
+{
+ int error;
+ struct timespec abstime;
+#ifdef MAIN
+ puts("Starting alarm thread");
+#endif
+ my_thread_init();
+ pthread_mutex_lock(&LOCK_alarm);
+ for (;;)
+ {
+ if (alarm_queue.elements)
+ {
+ ulong sleep_time,now=time((time_t*) 0);
+ if (alarm_aborted)
+ sleep_time=now+1;
+ else
+ sleep_time= ((ALARM*) queue_top(&alarm_queue))->expire_time;
+ if (sleep_time > now)
+ {
+ abstime.tv_sec=sleep_time;
+ abstime.tv_nsec=0;
+ if ((error=pthread_cond_timedwait(&COND_alarm,&LOCK_alarm,&abstime)) &&
+ error != ETIME && error != ETIMEDOUT)
+ {
+#ifdef MAIN
+ printf("Got error: %d from ptread_cond_timedwait (errno: %d)\n",
+ error,errno);
+#endif
+ }
+ }
+ }
+ else if (alarm_aborted)
+ break;
+ else if ((error=pthread_cond_wait(&COND_alarm,&LOCK_alarm)))
+ {
+#ifdef MAIN
+ printf("Got error: %d from ptread_cond_wait (errno: %d)\n",
+ error,errno);
+#endif
+ }
+ process_alarm(0);
+ }
+ bzero((char*) &alarm_thread,sizeof(alarm_thread)); /* For easy debugging */
+ pthread_mutex_unlock(&LOCK_alarm);
+ pthread_exit(0);
+ return 0; /* Impossible */
+}
+#endif
+
+
+#ifdef MAIN
+
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+
+#ifdef HPUX
+typedef int * fd_set_ptr;
+#else
+typedef fd_set * fd_set_ptr;
+#endif
+
+static void *test_thread(void *arg)
+{
+ int i,param=*((int*) arg),wait_time,retry;
+ time_t start_time;
+ thr_alarm_t got_alarm;
+ fd_set fd;
+ FD_ZERO(&fd);
+ my_thread_init();
+ printf("Tread %d (%s) started\n",param,my_thread_name()); fflush(stdout);
+ for (i=1 ; i <= 10 ; i++)
+ {
+ wait_time=param ? 11-i : i;
+ start_time=time((time_t*) 0);
+ if (thr_alarm(&got_alarm,wait_time,0))
+ {
+ printf("Thread: %s Alarms aborted\n",my_thread_name());
+ break;
+ }
+ if (wait_time == 3)
+ {
+ printf("Thread: %s Simulation of no alarm needed\n",my_thread_name());
+ fflush(stdout);
+ }
+ else
+ {
+ for (retry=0 ; !thr_got_alarm(got_alarm) && retry < 10 ; retry++)
+ {
+ printf("Thread: %s Waiting %d sec\n",my_thread_name(),wait_time);
+ select(0,(fd_set_ptr) &fd,0,0,0);
+ }
+ if (!thr_got_alarm(got_alarm))
+ {
+ printf("Thread: %s didn't get an alarm. Aborting!\n",
+ my_thread_name());
+ break;
+ }
+ if (wait_time == 7)
+ { /* Simulate alarm-miss */
+ fd_set readFDs;
+ uint max_connection=fileno(stdin);
+ FD_ZERO(&readFDs);
+ FD_SET(max_connection,&readFDs);
+ retry=0;
+ for (;;)
+ {
+ printf("Thread: %s Simulating alarm miss\n",my_thread_name());
+ fflush(stdout);
+ if (select(max_connection+1, (fd_set_ptr) &readFDs,0,0,0) < 0)
+ {
+ if (errno == EINTR)
+ break; /* Got new interrupt */
+ printf("Got errno: %d from select. Retrying..\n",errno);
+ if (retry++ >= 3)
+ {
+ printf("Warning: Interrupt of select() doesn't set errno!\n");
+ break;
+ }
+ }
+ else /* This shouldn't happen */
+ {
+ if (!FD_ISSET(max_connection,&readFDs))
+ {
+ printf("Select interrupted, but errno not set\n");
+ fflush(stdout);
+ if (retry++ >= 3)
+ break;
+ continue;
+ }
+ VOID(getchar()); /* Somebody was playing */
+ }
+ }
+ }
+ }
+ printf("Thread: %s Slept for %d (%d) sec\n",my_thread_name(),
+ (int) (time((time_t*) 0)-start_time), wait_time); fflush(stdout);
+ thr_end_alarm(&got_alarm);
+ fflush(stdout);
+ }
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((gptr) arg);
+ return 0;
+}
+
+#ifdef USE_ONE_SIGNAL_HAND
+static sig_handler print_signal_warning(int sig)
+{
+ printf("Warning: Got signal %d from thread %s\n",sig,my_thread_name());
+ fflush(stdout);
+#ifdef DONT_REMEMBER_SIGNAL
+ sigset(sig,print_signal_warning); /* int. thread system calls */
+#endif
+ if (sig == SIGALRM)
+ alarm(2); /* reschedule alarm */
+}
+#endif
+
+
+
+static void *signal_hand(void *arg __attribute__((unused)))
+{
+ sigset_t set;
+ int sig,error,err_count=0;;
+
+ my_thread_init();
+ pthread_detach_this_thread();
+ init_thr_alarm(10); /* Setup alarm handler */
+ pthread_mutex_lock(&LOCK_thread_count); /* Required by bsdi */
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+
+ sigemptyset(&set); /* Catch all signals */
+ sigaddset(&set,SIGINT);
+ sigaddset(&set,SIGQUIT);
+ sigaddset(&set,SIGTERM);
+#if THR_CLIENT_ALARM != SIGHUP
+ sigaddset(&set,SIGHUP);
+#endif
+#ifdef SIGTSTP
+ sigaddset(&set,SIGTSTP);
+#endif
+#ifdef USE_ONE_SIGNAL_HAND
+ sigaddset(&set,THR_SERVER_ALARM); /* For alarms */
+ puts("Starting signal and alarm handling thread");
+#else
+ puts("Starting signal handling thread");
+#endif
+ printf("server alarm: %d thread alarm: %d\n",
+ THR_SERVER_ALARM,THR_CLIENT_ALARM);
+ DBUG_PRINT("info",("Starting signal and alarm handling thread"));
+ for(;;)
+ {
+ while ((error=my_sigwait(&set,&sig)) == EINTR)
+ printf("sigwait restarted\n");
+ if (error)
+ {
+ fprintf(stderr,"Got error %d from sigwait\n",error);
+ if (err_count++ > 5)
+ exit(1); /* Too many errors in test */
+ continue;
+ }
+#ifdef USE_ONE_SIGNAL_HAND
+ if (sig != THR_SERVER_ALARM)
+#endif
+ printf("Main thread: Got signal %d\n",sig);
+ switch (sig) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ case SIGHUP:
+ printf("Aborting nicely\n");
+ end_thr_alarm();
+ break;
+#ifdef SIGTSTP
+ case SIGTSTP:
+ printf("Aborting\n");
+ exit(1);
+ return 0; /* Keep some compilers happy */
+#endif
+#ifdef USE_ONE_SIGNAL_HAND
+ case THR_SERVER_ALARM:
+ process_alarm(sig);
+ break;
+#endif
+ }
+ }
+}
+
+
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int i,*param,error;
+ sigset_t set;
+ MY_INIT(argv[0]);
+
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ pthread_mutex_init(&LOCK_thread_count,NULL);
+ pthread_cond_init(&COND_thread_count,NULL);
+
+ /* Start a alarm handling thread */
+ sigemptyset(&set);
+ sigaddset(&set,SIGINT);
+ sigaddset(&set,SIGQUIT);
+ sigaddset(&set,SIGTERM);
+ sigaddset(&set,SIGHUP);
+ signal(SIGTERM,SIG_DFL); /* If it's blocked by parent */
+#ifdef SIGTSTP
+ sigaddset(&set,SIGTSTP);
+#endif
+ sigaddset(&set,THR_SERVER_ALARM);
+ sigdelset(&set,THR_CLIENT_ALARM);
+ (void) pthread_sigmask(SIG_SETMASK,&set,NULL);
+#ifdef NOT_USED
+ sigemptyset(&set);
+ sigaddset(&set,THR_CLIENT_ALARM);
+ VOID(pthread_sigmask(SIG_UNBLOCK, &set, (sigset_t*) 0));
+#endif
+
+ pthread_attr_init(&thr_attr);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&thr_attr,65536L);
+
+ /* Start signal thread and wait for it to start */
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ pthread_create(&tid,&thr_attr,signal_hand,NULL);
+ VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ DBUG_PRINT("info",("signal thread created"));
+
+ thr_setconcurrency(3);
+ pthread_attr_setscope(&thr_attr,PTHREAD_SCOPE_PROCESS);
+ printf("Main thread: %s\n",my_thread_name());
+ for (i=0 ; i < 2 ; i++)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param= i;
+ pthread_mutex_lock(&LOCK_thread_count);
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ printf("Can't create thread %d, error: %d\n",i,error);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ pthread_attr_destroy(&thr_attr);
+ pthread_mutex_lock(&LOCK_thread_count);
+ while (thread_count)
+ {
+ VOID(pthread_cond_wait(&COND_thread_count,&LOCK_thread_count));
+ if (thread_count == 1)
+ {
+ printf("Calling end_thr_alarm. This should cancel the last thread\n");
+ end_thr_alarm();
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ printf("Test succeeded\n");
+ return 0;
+}
+#endif /* MAIN */
+
+#else /* DONT_USE_THR_ALARM */
+
+#ifdef MAIN
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ printf("thr_alarm disabled with DONT_USE_THR_ALARM\n");
+ exit(1);
+}
+#endif
+#endif
+
+/*****************************************************************************
+** thr_alarm for OS/2
+*****************************************************************************/
+
+#elif defined(__OS2__)
+
+#define INCL_BASE
+#define INCL_NOPMAPI
+#include <os2.h>
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
+{
+ APIRET rc;
+ if (alarm_aborted)
+ {
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ }
+ if (!(rc = DosCreateEventSem(NULL,(HEV *)&alrm->event,DC_SEM_SHARED,FALSE)))
+ {
+ printf("Error creating event semaphore! [%d] \n",rc);
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ }
+ if (!(rc = DosAsyncTimer((long) sec*1000L, (HSEM) alrm->event,(HTIMER *) &alrm->crono))) {
+ printf("Error starting async timer! [%d] \n",rc);
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono=0;
+ alrm->event=0;
+ return 1;
+ } /* endif */
+
+ return 1;
+}
+
+
+bool thr_got_alarm(thr_alarm_t *alrm)
+{
+ APIRET rc;
+
+ if (alrm->crono)
+ {
+ rc = DosWaitEventSem((HEV) alrm->event, SEM_IMMEDIATE_RETURN);
+ if (rc == 0) {
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono = 0;
+ alrm->event = 0;
+ } /* endif */
+ }
+ return !alrm->crono || alarm_aborted;
+}
+
+
+void thr_end_alarm(thr_alarm_t *alrm)
+{
+ if (alrm->crono)
+ {
+ DosStopTimer((HTIMER) alrm->crono);
+ DosCloseEventSem((HEV) alrm->event);
+ alrm->crono = 0;
+ alrm->event = 0;
+ }
+}
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ alarm_aborted=1; /* No more alarms */
+ DBUG_VOID_RETURN;
+}
+
+void init_thr_alarm(uint max_alarm)
+{
+ DBUG_ENTER("init_thr_alarm");
+ alarm_aborted=0; /* Yes, Gimmie alarms */
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MAIN
+void main()
+{
+ printf("hello world\n");
+}
+#endif
+
+/*****************************************************************************
+** thr_alarm for win95
+*****************************************************************************/
+
+#else /* __WIN__ */
+
+bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm)
+{
+ if (alarm_aborted)
+ {
+ alrm->crono=0;
+ return 1;
+ }
+ if (!(alrm->crono=SetTimer(NULL,0,(long) sec*1000L, (TIMERPROC) NULL)))
+ return 1;
+ return 0;
+}
+
+
+bool thr_got_alarm(thr_alarm_t *alrm)
+{
+ MSG msg;
+ if (alrm->crono)
+ {
+ PeekMessage(&msg,NULL,WM_TIMER,WM_TIMER,PM_REMOVE) ;
+ if (msg.message == WM_TIMER || alarm_aborted)
+ {
+ KillTimer(NULL, alrm->crono);
+ alrm->crono = 0;
+ }
+ }
+ return !alrm->crono || alarm_aborted;
+}
+
+
+void thr_end_alarm(thr_alarm_t *alrm)
+{
+ if (alrm->crono)
+ {
+ KillTimer(NULL, alrm->crono);
+ alrm->crono = 0;
+ }
+}
+
+void end_thr_alarm(void)
+{
+ DBUG_ENTER("end_thr_alarm");
+ alarm_aborted=1; /* No more alarms */
+ DBUG_VOID_RETURN;
+}
+
+#endif /* __WIN__ */
+
+#endif
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
new file mode 100644
index 00000000000..5c0803c6402
--- /dev/null
+++ b/mysys/thr_lock.c
@@ -0,0 +1,1288 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+Read and write locks for Posix threads. All tread must acquire
+all locks it needs through thr_multi_lock() to avoid dead-locks.
+A lock consists of a master lock (THR_LOCK), and lock instances
+(THR_LOCK_DATA).
+Any thread can have any number of lock instances (read and write:s) on
+any lock. All lock instances must be freed.
+Locks are prioritized according to:
+
+The current lock types are:
+
+TL_READ # Low priority read
+TL_READ_HIGH_PRIORITY # High priority read
+TL_READ_NO_INSERT # Read without concurrent inserts
+TL_WRITE_ALLOW_WRITE # Write lock that allows other writers
+TL_WRITE_ALLOW_READ # Write lock, but allow reading
+TL_WRITE_CONCURRENT_INSERT
+ # Insert that can be mixed when selects
+TL_WRITE_DELAYED # Used by delayed insert
+ # Allows lower locks to take over
+TL_WRITE_LOW_PRIORITY # Low priority write
+TL_WRITE # High priority write
+TL_WRITE_ONLY # High priority write
+ # Abort all new lock request with an error
+
+Locks are prioritized according to:
+
+WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
+WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
+
+Locks in the same privilege level are scheduled in first-in-first-out order.
+
+To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
+should put a pointer to the following functions in the lock structure:
+(If the pointer is zero (default), the function is not called)
+
+check_status:
+ Before giving a lock of type TL_WRITE_CONCURRENT_INSERT,
+ we check if this function exists and returns 0.
+ If not, then the lock is upgraded to TL_WRITE_LOCK
+ In MyISAM this is a simple check if the insert can be done
+ at the end of the datafile.
+update_status:
+ Before a write lock is released, this function is called.
+ In MyISAM this functions updates the count and length of the datafile
+get_status:
+ When one gets a lock this functions is called.
+ In MyISAM this stores the number of rows and size of the datafile
+ for concurrent reads.
+
+The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
+TL_WRITE_CONCURRENT_INSERT or one TL_WRITE_DELAYED lock at the same time as
+multiple read locks.
+
+*/
+
+#if !defined(MAIN) && !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
+#define DBUG_OFF
+#endif
+
+#include "mysys_priv.h"
+#include "thr_lock.h"
+#include <m_string.h>
+#include <errno.h>
+
+my_bool thr_lock_inited=0;
+
+#ifdef THREAD
+
+/* The following constants are only for debug output */
+#define MAX_THREADS 100
+#define MAX_LOCKS 100
+
+
+static LIST *thread_list; /* List of threads in use */
+ulong max_write_lock_count= ~(ulong) 0L;
+
+static inline pthread_cond_t *get_cond(void)
+{
+ return &my_thread_var->suspend;
+}
+
+/*
+** For the future (now the thread specific cond is alloced by my_pthread.c)
+*/
+
+my_bool init_thr_lock()
+{
+ thr_lock_inited=1;
+ return 0;
+}
+
+#ifdef EXTRA_DEBUG
+static int found_errors=0;
+
+static int check_lock(struct st_lock_list *list, const char* lock_type,
+ const char *where, my_bool same_thread)
+{
+ THR_LOCK_DATA *data,**prev;
+ uint count=0;
+ pthread_t first_thread;
+ LINT_INIT(first_thread);
+
+ prev= &list->data;
+ if (list->data)
+ {
+ enum thr_lock_type last_lock_type=list->data->type;
+
+ if (same_thread && list->data)
+ first_thread=list->data->thread;
+ for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
+ {
+ if (data->type != last_lock_type)
+ last_lock_type=TL_IGNORE;
+ if (data->prev != prev)
+ {
+ fprintf(stderr,
+ "Warning: prev link %d didn't point at previous lock at %s: %s\n",
+ count, lock_type, where);
+ return 1;
+ }
+ if (same_thread && ! pthread_equal(data->thread,first_thread) &&
+ last_lock_type != TL_WRITE_ALLOW_WRITE)
+ {
+ fprintf(stderr,
+ "Warning: Found locks from different threads in %s: %s\n",
+ lock_type,where);
+ return 1;
+ }
+ prev= &data->next;
+ }
+ if (data)
+ {
+ fprintf(stderr,"Warning: found too many locks at %s: %s\n",
+ lock_type,where);
+ return 1;
+ }
+ }
+ if (prev != list->last)
+ {
+ fprintf(stderr,"Warning: last didn't point at last lock at %s: %s\n",
+ lock_type, where);
+ return 1;
+ }
+ return 0;
+}
+
+static void check_locks(THR_LOCK *lock, const char *where,
+ my_bool allow_no_locks)
+{
+ if (!found_errors)
+ {
+ if (check_lock(&lock->write,"write",where,1) |
+ check_lock(&lock->write_wait,"write_wait",where,0) |
+ check_lock(&lock->read,"read",where,0) |
+ check_lock(&lock->read_wait,"read_wait",where,0))
+ found_errors=1;
+
+ if (!found_errors)
+ {
+ uint count=0;
+ THR_LOCK_DATA *data;
+ for (data=lock->read.data ; data ; data=data->next)
+ {
+ if ((int) data->type == (int) TL_READ_NO_INSERT)
+ count++;
+ }
+ if (count != lock->read_no_write_count)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Locks read_no_write_count was %u when it should have been %u\n", where, lock->read_no_write_count,count);
+ }
+
+ if (!lock->write.data)
+ {
+ if (!allow_no_locks && !lock->read.data &&
+ (lock->write_wait.data || lock->read_wait.data))
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': No locks in use but locks are in wait queue\n",
+ where);
+ }
+ if (!lock->write_wait.data)
+ {
+ if (!allow_no_locks && lock->read_wait.data)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': No write locks and waiting read locks\n",
+ where);
+ }
+ }
+ else
+ {
+ if (!allow_no_locks &&
+ (((lock->write_wait.data->type == TL_WRITE_CONCURRENT_INSERT ||
+ lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE) &&
+ !lock->read_no_write_count) ||
+ lock->write_wait.data->type == TL_WRITE_ALLOW_READ ||
+ (lock->write_wait.data->type == TL_WRITE_DELAYED &&
+ !lock->read.data)))
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Write lock %d waiting while no exclusive read locks\n",where,(int) lock->write_wait.data->type);
+ }
+ }
+ }
+ else
+ { /* Have write lock */
+ if (lock->write_wait.data)
+ {
+ if (!allow_no_locks &&
+ lock->write.data->type == TL_WRITE_ALLOW_WRITE &&
+ lock->write_wait.data->type == TL_WRITE_ALLOW_WRITE)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Found WRITE_ALLOW_WRITE lock waiting for WRITE_ALLOW_WRITE lock\n",
+ where);
+ }
+ }
+ if (lock->read.data)
+ {
+ if ((!pthread_equal(lock->write.data->thread,lock->read.data->thread) &&
+ lock->write.data->type > TL_WRITE_DELAYED) ||
+ ((lock->write.data->type == TL_WRITE_CONCURRENT_INSERT ||
+ lock->write.data->type == TL_WRITE_ALLOW_WRITE) &&
+ lock->read_no_write_count))
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Found lock that is write and read locked\n",
+ where);
+ }
+ }
+ if (lock->read_wait.data)
+ {
+ if (!allow_no_locks && lock->write.data->type <= TL_WRITE_DELAYED &&
+ lock->read_wait.data->type <= TL_READ_HIGH_PRIORITY)
+ {
+ found_errors=1;
+ fprintf(stderr,
+ "Warning at '%s': Found read lock of type %d waiting for write lock of type %d\n",
+ where,
+ (int) lock->read_wait.data->type,
+ (int) lock->write.data->type);
+ }
+ }
+ }
+ }
+ if (found_errors)
+ {
+ DBUG_PRINT("error",("Found wrong lock"));
+ }
+ }
+}
+
+#else /* EXTRA_DEBUG */
+#define check_locks(A,B,C)
+#endif
+
+
+ /* Initialize a lock */
+
+void thr_lock_init(THR_LOCK *lock)
+{
+ DBUG_ENTER("thr_lock_init");
+ bzero((char*) lock,sizeof(*lock));
+ VOID(pthread_mutex_init(&lock->mutex,NULL));
+ lock->read.last= &lock->read.data;
+ lock->read_wait.last= &lock->read_wait.data;
+ lock->write_wait.last= &lock->write_wait.data;
+ lock->write.last= &lock->write.data;
+
+ pthread_mutex_lock(&THR_LOCK_lock); /* Add to locks in use */
+ lock->list.data=(void*) lock;
+ thread_list=list_add(thread_list,&lock->list);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ DBUG_VOID_RETURN;
+}
+
+
+void thr_lock_delete(THR_LOCK *lock)
+{
+ DBUG_ENTER("thr_lock_delete");
+ VOID(pthread_mutex_destroy(&lock->mutex));
+ pthread_mutex_lock(&THR_LOCK_lock);
+ thread_list=list_delete(thread_list,&lock->list);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+ DBUG_VOID_RETURN;
+}
+
+ /* Initialize a lock instance */
+
+void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
+{
+ data->lock=lock;
+ data->type=TL_UNLOCK;
+ data->thread=pthread_self();
+ data->thread_id=my_thread_id(); /* for debugging */
+ data->status_param=param;
+}
+
+
+static inline my_bool have_old_read_lock(THR_LOCK_DATA *data,pthread_t thread)
+{
+ for ( ; data ; data=data->next)
+ {
+ if ((pthread_equal(data->thread,thread)))
+ return 1; /* Already locked by thread */
+ }
+ return 0;
+}
+
+static inline my_bool have_specific_lock(THR_LOCK_DATA *data,
+ enum thr_lock_type type)
+{
+ for ( ; data ; data=data->next)
+ {
+ if (data->type == type)
+ return 1;
+ }
+ return 0;
+}
+
+
+static my_bool wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
+ my_bool in_wait_list)
+{
+ pthread_cond_t *cond=get_cond();
+ struct st_my_thread_var *thread_var=my_thread_var;
+ int result;
+
+ if (!in_wait_list)
+ {
+ (*wait->last)=data; /* Wait for lock */
+ data->prev= wait->last;
+ wait->last= &data->next;
+ }
+
+ /* Set up control struct to allow others to abort locks */
+ pthread_mutex_lock(&thread_var->mutex);
+ thread_var->current_mutex= &data->lock->mutex;
+ thread_var->current_cond= cond;
+ pthread_mutex_unlock(&thread_var->mutex);
+
+ data->cond=cond;
+ do
+ {
+ pthread_cond_wait(cond,&data->lock->mutex);
+ } while (data->cond == cond && !thread_var->abort);
+
+ if (data->cond || data->type == TL_UNLOCK)
+ {
+ if (data->cond) /* aborted */
+ {
+ if (((*data->prev)=data->next)) /* remove from wait-list */
+ data->next->prev= data->prev;
+ else
+ wait->last=data->prev;
+ }
+ data->type=TL_UNLOCK; /* No lock */
+ result=1; /* Didn't get lock */
+ check_locks(data->lock,"failed wait_for_lock",0);
+ }
+ else
+ {
+ result=0;
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ check_locks(data->lock,"got wait_for_lock",0);
+ }
+ pthread_mutex_unlock(&data->lock->mutex);
+
+ /* The following must be done after unlock of lock->mutex */
+ pthread_mutex_lock(&thread_var->mutex);
+ thread_var->current_mutex= 0;
+ thread_var->current_cond= 0;
+ pthread_mutex_unlock(&thread_var->mutex);
+ return result;
+}
+
+
+int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type)
+{
+ THR_LOCK *lock=data->lock;
+ int result=0;
+ DBUG_ENTER("thr_lock");
+
+ data->next=0;
+ data->type=lock_type;
+ data->thread=pthread_self(); /* Must be reset ! */
+ data->thread_id=my_thread_id(); /* Must be reset ! */
+ VOID(pthread_mutex_lock(&lock->mutex));
+ DBUG_PRINT("lock",("data: %lx thread: %ld lock: %lx type: %d",
+ data,data->thread_id,lock,(int) lock_type));
+ check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ?
+ "enter read_lock" : "enter write_lock",0);
+ if ((int) lock_type <= (int) TL_READ_NO_INSERT)
+ {
+ /* Request for READ lock */
+ if (lock->write.data)
+ {
+ /* We can get allow a read lock even if there is already a write lock
+ one the table in one the following cases:
+ - This thread alread have a write lock on the table
+ - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
+ and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
+ - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
+ and the read lock is not TL_READ_NO_INSERT
+ */
+
+ DBUG_PRINT("lock",("write locked by thread: %ld",
+ lock->write.data->thread_id));
+ if (pthread_equal(data->thread,lock->write.data->thread) ||
+ (lock->write.data->type <= TL_WRITE_DELAYED &&
+ (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) ||
+ (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
+ lock->write.data->type != TL_WRITE_ALLOW_READ))))
+ { /* Already got a write lock */
+ (*lock->read.last)=data; /* Add to running FIFO */
+ data->prev=lock->read.last;
+ lock->read.last= &data->next;
+ if ((int) lock_type == (int) TL_READ_NO_INSERT)
+ lock->read_no_write_count++;
+ check_locks(lock,"read lock with old write lock",0);
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param);
+ goto end;
+ }
+ if (lock->write.data->type == TL_WRITE_ONLY)
+ {
+ /* We are not allowed to get a READ lock in this case */
+ data->type=TL_UNLOCK;
+ result=1; /* Can't wait for this one */
+ goto end;
+ }
+ }
+ else if (!lock->write_wait.data ||
+ lock->write_wait.data->type <= TL_WRITE_LOW_PRIORITY ||
+ lock_type == TL_READ_HIGH_PRIORITY ||
+ have_old_read_lock(lock->read.data,data->thread))
+ { /* No important write-locks */
+ (*lock->read.last)=data; /* Add to running FIFO */
+ data->prev=lock->read.last;
+ lock->read.last= &data->next;
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param);
+ if ((int) lock_type == (int) TL_READ_NO_INSERT)
+ lock->read_no_write_count++;
+ check_locks(lock,"read lock with no write locks",0);
+ goto end;
+ }
+ /* Can't get lock yet; Wait for it */
+ DBUG_RETURN(wait_for_lock(&lock->read_wait,data,0));
+ }
+ else /* Request for WRITE lock */
+ {
+ if (lock_type == TL_WRITE_DELAYED)
+ {
+ if (lock->write.data && lock->write.data->type == TL_WRITE_ONLY)
+ {
+ data->type=TL_UNLOCK;
+ result=1; /* Can't wait for this one */
+ goto end;
+ }
+ /*
+ if there is a TL_WRITE_ALLOW_READ lock, we have to wait for a lock
+ (TL_WRITE_ALLOW_READ is used for ALTER TABLE in MySQL)
+ */
+ if ((!lock->write.data ||
+ lock->write.data->type != TL_WRITE_ALLOW_READ) &&
+ !have_specific_lock(lock->write_wait.data,TL_WRITE_ALLOW_READ) &&
+ (lock->write.data || lock->read.data))
+ {
+ /* Add delayed write lock to write_wait queue, and return at once */
+ (*lock->write_wait.last)=data;
+ data->prev=lock->write_wait.last;
+ lock->write_wait.last= &data->next;
+ data->cond=get_cond();
+ if (lock->get_status)
+ (*lock->get_status)(data->status_param);
+ goto end;
+ }
+ }
+ else if (lock_type == TL_WRITE_CONCURRENT_INSERT && ! lock->check_status)
+ data->type=lock_type= TL_WRITE; /* not supported */
+
+ if (lock->write.data) /* If there is a write lock */
+ {
+ if (lock->write.data->type == TL_WRITE_ONLY)
+ {
+ /* We are not allowed to get a lock in this case */
+ data->type=TL_UNLOCK;
+ result=1; /* Can't wait for this one */
+ goto end;
+ }
+
+ /*
+ The following test will not work if the old lock was a
+ TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
+ the same thread, but this will never happen within MySQL.
+ */
+ if (pthread_equal(data->thread,lock->write.data->thread) ||
+ (lock_type == TL_WRITE_ALLOW_WRITE &&
+ !lock->write_wait.data &&
+ lock->write.data->type == TL_WRITE_ALLOW_WRITE))
+ {
+ /* We have already got a write lock or all locks are
+ TL_WRITE_ALLOW_WRITE */
+ (*lock->write.last)=data; /* Add to running fifo */
+ data->prev=lock->write.last;
+ lock->write.last= &data->next;
+ check_locks(lock,"second write lock",0);
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ goto end;
+ }
+ DBUG_PRINT("lock",("write locked by thread: %ld",
+ lock->write.data->thread_id));
+ }
+ else
+ {
+ if (!lock->write_wait.data)
+ { /* no scheduled write locks */
+ if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ (*lock->check_status)(data->status_param))
+ data->type=lock_type=TL_WRITE; /* Upgrade lock */
+
+ if (!lock->read.data ||
+ (lock_type <= TL_WRITE_DELAYED &&
+ ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
+ lock_type != TL_WRITE_ALLOW_WRITE) ||
+ !lock->read_no_write_count)))
+ {
+ (*lock->write.last)=data; /* Add as current write lock */
+ data->prev=lock->write.last;
+ lock->write.last= &data->next;
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ check_locks(lock,"only write lock",0);
+ goto end;
+ }
+ }
+ DBUG_PRINT("lock",("write locked by thread: %ld, type: %ld",
+ lock->read.data->thread_id,data->type));
+ }
+ DBUG_RETURN(wait_for_lock(&lock->write_wait,data,0));
+ }
+end:
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(result);
+}
+
+
+static inline void free_all_read_locks(THR_LOCK *lock,
+ bool using_concurrent_insert)
+{
+ THR_LOCK_DATA *data=lock->read_wait.data;
+
+ check_locks(lock,"before freeing read locks",1);
+
+ /* move all locks from read_wait list to read list */
+ (*lock->read.last)=data;
+ data->prev=lock->read.last;
+ lock->read.last=lock->read_wait.last;
+
+ /* Clear read_wait list */
+ lock->read_wait.last= &lock->read_wait.data;
+
+ do
+ {
+ pthread_cond_t *cond=data->cond;
+ if ((int) data->type == (int) TL_READ_NO_INSERT)
+ {
+ if (using_concurrent_insert)
+ {
+ /*
+ We can't free this lock;
+ Link lock away from read chain back into read_wait chain
+ */
+ if (((*data->prev)=data->next))
+ data->next->prev=data->prev;
+ else
+ lock->read.last=data->prev;
+ *lock->read_wait.last= data;
+ data->prev= lock->read_wait.last;
+ lock->read_wait.last= &data->next;
+ continue;
+ }
+ lock->read_no_write_count++;
+ }
+ DBUG_PRINT("lock",("giving read lock to thread: %ld",
+ data->thread_id));
+ data->cond=0; /* Mark thread free */
+ VOID(pthread_cond_signal(cond));
+ } while ((data=data->next));
+ *lock->read_wait.last=0;
+ if (!lock->read_wait.data)
+ lock->write_lock_count=0;
+ check_locks(lock,"after giving read locks",0);
+}
+
+ /* Unlock lock and free next thread on same lock */
+
+void thr_unlock(THR_LOCK_DATA *data)
+{
+ THR_LOCK *lock=data->lock;
+ enum thr_lock_type lock_type=data->type;
+ DBUG_ENTER("thr_unlock");
+ DBUG_PRINT("lock",("data: %lx thread: %ld lock: %lx",
+ data,data->thread_id,lock));
+ pthread_mutex_lock(&lock->mutex);
+ check_locks(lock,"start of release lock",0);
+
+ if (((*data->prev)=data->next)) /* remove from lock-list */
+ data->next->prev= data->prev;
+ else if (lock_type <= TL_READ_NO_INSERT)
+ lock->read.last=data->prev;
+ else if (lock_type == TL_WRITE_DELAYED && data->cond)
+ {
+ /* This only happens in extreme circumstances when a
+ write delayed lock that is waiting for a lock */
+ lock->write_wait.last=data->prev; /* Put it on wait queue */
+ }
+ else
+ lock->write.last=data->prev;
+ if (lock_type >= TL_WRITE_CONCURRENT_INSERT && lock->update_status)
+ (*lock->update_status)(data->status_param);
+ if (lock_type == TL_READ_NO_INSERT)
+ lock->read_no_write_count--;
+ data->type=TL_UNLOCK; /* Mark unlocked */
+ check_locks(lock,"after releasing lock",1);
+
+ if (!lock->write.data) /* If no active read locks */
+ {
+ data=lock->write_wait.data;
+ if (!lock->read.data) /* If no more locks in use */
+ {
+ /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
+ if (data &&
+ (data->type != TL_WRITE_LOW_PRIORITY || !lock->read_wait.data ||
+ lock->read_wait.data->type == TL_READ))
+ {
+ if (lock->write_lock_count++ > max_write_lock_count)
+ {
+ /* Too many write locks in a row; Release all waiting read locks */
+ lock->write_lock_count=0;
+ if (lock->read_wait.data)
+ {
+ DBUG_PRINT("info",("Freeing all read_locks because of max_write_lock_count"));
+ free_all_read_locks(lock,0);
+ goto end;
+ }
+ }
+ for (;;)
+ {
+ if (((*data->prev)=data->next)) /* remove from wait-list */
+ data->next->prev= data->prev;
+ else
+ lock->write_wait.last=data->prev;
+ (*lock->write.last)=data; /* Put in execute list */
+ data->prev=lock->write.last;
+ data->next=0;
+ lock->write.last= &data->next;
+ if (data->type == TL_WRITE_CONCURRENT_INSERT &&
+ (*lock->check_status)(data->status_param))
+ data->type=TL_WRITE; /* Upgrade lock */
+ DBUG_PRINT("lock",("giving write lock of type %d to thread: %ld",
+ data->type,data->thread_id));
+ {
+ pthread_cond_t *cond=data->cond;
+ data->cond=0; /* Mark thread free */
+ VOID(pthread_cond_signal(cond)); /* Start waiting thread */
+ }
+ if (data->type != TL_WRITE_ALLOW_WRITE ||
+ !lock->write_wait.data ||
+ lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
+ break;
+ data=lock->write_wait.data; /* Free this too */
+ }
+ if (data->type >= TL_WRITE_LOW_PRIORITY)
+ {
+ check_locks(lock,"giving write lock",0);
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+ }
+ /* Release possible read locks together with the write lock */
+ }
+ if (lock->read_wait.data)
+ free_all_read_locks(lock,
+ data &&
+ (data->type == TL_WRITE_CONCURRENT_INSERT ||
+ data->type == TL_WRITE_ALLOW_WRITE));
+ else
+ {
+ DBUG_PRINT("lock",("No locks to free"));
+ }
+ }
+ else if (data &&
+ (lock_type=data->type) <= TL_WRITE_DELAYED &&
+ ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
+ lock_type != TL_WRITE_ALLOW_WRITE) ||
+ !lock->read_no_write_count))
+ {
+ /*
+ For DELAYED, ALLOW_READ, WRITE_ALLOW_WRITE or CONCURRENT_INSERT locks
+ start WRITE locks together with the READ locks
+ */
+ if (lock_type == TL_WRITE_CONCURRENT_INSERT &&
+ (*lock->check_status)(data->status_param))
+ {
+ data->type=TL_WRITE; /* Upgrade lock */
+ if (lock->read_wait.data)
+ free_all_read_locks(lock,0);
+ goto end;
+ }
+ do {
+ pthread_cond_t *cond=data->cond;
+ if (((*data->prev)=data->next)) /* remove from wait-list */
+ data->next->prev= data->prev;
+ else
+ lock->write_wait.last=data->prev;
+ (*lock->write.last)=data; /* Put in execute list */
+ data->prev=lock->write.last;
+ lock->write.last= &data->next;
+ data->next=0; /* Only one write lock */
+ data->cond=0; /* Mark thread free */
+ VOID(pthread_cond_signal(cond)); /* Start waiting thread */
+ } while (lock_type == TL_WRITE_ALLOW_WRITE &&
+ (data=lock->write_wait.data) &&
+ data->type == TL_WRITE_ALLOW_WRITE);
+ if (lock->read_wait.data)
+ free_all_read_locks(lock,
+ (lock_type == TL_WRITE_CONCURRENT_INSERT ||
+ lock_type == TL_WRITE_ALLOW_WRITE));
+ }
+ else if (lock->read_wait.data)
+ free_all_read_locks(lock,0);
+ }
+end:
+ check_locks(lock,"thr_unlock",0);
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+** Get all locks in a specific order to avoid dead-locks
+** Sort acording to lock position and put write_locks before read_locks if
+** lock on same lock.
+*/
+
+
+#define LOCK_CMP(A,B) ((byte*) (A->lock) - (uint) ((A)->type) < (byte*) (B->lock)- (uint) ((B)->type))
+
+static void sort_locks(THR_LOCK_DATA **data,uint count)
+{
+ THR_LOCK_DATA **pos,**end,**prev,*tmp;
+
+ /* Sort locks with insertion sort (fast because almost always few locks) */
+
+ for (pos=data+1,end=data+count; pos < end ; pos++)
+ {
+ tmp= *pos;
+ if (LOCK_CMP(tmp,pos[-1]))
+ {
+ prev=pos;
+ do {
+ prev[0]=prev[-1];
+ } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
+ prev[0]=tmp;
+ }
+ }
+}
+
+
+int thr_multi_lock(THR_LOCK_DATA **data,uint count)
+{
+ THR_LOCK_DATA **pos,**end;
+ DBUG_ENTER("thr_multi_lock");
+ DBUG_PRINT("lock",("data: %lx count: %d",data,count));
+ if (count > 1)
+ sort_locks(data,count);
+ /* lock everything */
+ for (pos=data,end=data+count; pos < end ; pos++)
+ {
+ if (thr_lock(*pos,(*pos)->type))
+ { /* Aborted */
+ thr_multi_unlock(data,(uint) (pos-data));
+ DBUG_RETURN(1);
+ }
+#ifdef MAIN
+ printf("Thread: %s Got lock: %lx type: %d\n",my_thread_name(),
+ (long) pos[0]->lock, pos[0]->type); fflush(stdout);
+#endif
+ }
+ /*
+ Ensure that all get_locks() have the same status
+ If we lock the same table multiple times, we must use the same
+ status_param!
+ */
+#if !defined(DONT_USE_RW_LOCKS)
+ if (count > 1)
+ {
+ THR_LOCK_DATA *last_lock= end[-1];
+ pos=end-1;
+ do
+ {
+ pos--;
+ if (last_lock->lock == (*pos)->lock &&
+ last_lock->lock->copy_status)
+ {
+ if (last_lock->type <= TL_READ_NO_INSERT)
+ {
+ THR_LOCK_DATA **read_lock;
+ /*
+ If we are locking the same table with read locks we must ensure
+ that all tables share the status of the last write lock or
+ the same read lock.
+ */
+ for (;
+ (*pos)->type <= TL_READ_NO_INSERT &&
+ pos != data &&
+ pos[-1]->lock == (*pos)->lock ;
+ pos--) ;
+
+ read_lock = pos+1;
+ do
+ {
+ (last_lock->lock->copy_status)((*read_lock)->status_param,
+ (*pos)->status_param);
+ } while (*(read_lock++) != last_lock);
+ last_lock= (*pos); /* Point at last write lock */
+ }
+ else
+ (*last_lock->lock->copy_status)((*pos)->status_param,
+ last_lock->status_param);
+ }
+ else
+ last_lock=(*pos);
+ } while (pos != data);
+ }
+#endif
+ DBUG_RETURN(0);
+}
+
+ /* free all locks */
+
+void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
+{
+ THR_LOCK_DATA **pos,**end;
+ DBUG_ENTER("thr_multi_unlock");
+ DBUG_PRINT("lock",("data: %lx count: %d",data,count));
+
+ for (pos=data,end=data+count; pos < end ; pos++)
+ {
+#ifdef MAIN
+ printf("Thread: %s Rel lock: %lx type: %d\n",
+ my_thread_name(), (long) pos[0]->lock, pos[0]->type);
+ fflush(stdout);
+#endif
+ if ((*pos)->type != TL_UNLOCK)
+ thr_unlock(*pos);
+ else
+ {
+ DBUG_PRINT("lock",("Free lock: data: %lx thread: %ld lock: %lx",
+ *pos,(*pos)->thread_id,(*pos)->lock));
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+/* Abort all threads waiting for a lock. The lock will be upgraded to a
+ TL_WRITE_ONLY to abort any new accesses to the lock
+*/
+
+void thr_abort_locks(THR_LOCK *lock)
+{
+ THR_LOCK_DATA *data;
+ DBUG_ENTER("thr_abort_locks");
+ pthread_mutex_lock(&lock->mutex);
+
+ for (data=lock->read_wait.data; data ; data=data->next)
+ {
+ data->type=TL_UNLOCK; /* Mark killed */
+ pthread_cond_signal(data->cond);
+ data->cond=0; /* Removed from list */
+ }
+ for (data=lock->write_wait.data; data ; data=data->next)
+ {
+ data->type=TL_UNLOCK;
+ pthread_cond_signal(data->cond);
+ data->cond=0;
+ }
+ lock->read_wait.last= &lock->read_wait.data;
+ lock->write_wait.last= &lock->write_wait.data;
+ lock->read_wait.data=lock->write_wait.data=0;
+ if (lock->write.data)
+ lock->write.data->type=TL_WRITE_ONLY;
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_VOID_RETURN;
+}
+
+
+/* Upgrade a WRITE_DELAY lock to a WRITE_LOCK */
+
+my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data)
+{
+ THR_LOCK *lock=data->lock;
+ DBUG_ENTER("thr_upgrade_write_delay_lock");
+
+ pthread_mutex_lock(&lock->mutex);
+ if (data->type == TL_UNLOCK || data->type == TL_WRITE) /* Aborted */
+ {
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(data->type == TL_UNLOCK);
+ }
+ check_locks(lock,"before upgrading lock",0);
+ /* TODO: Upgrade to TL_WRITE_CONCURRENT_INSERT in some cases */
+ data->type=TL_WRITE; /* Upgrade lock */
+
+ /* Check if someone has given us the lock */
+ if (!data->cond)
+ {
+ if (!lock->read.data) /* No read locks */
+ { /* We have the lock */
+ if (data->lock->get_status)
+ (*data->lock->get_status)(data->status_param);
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(0);
+ }
+
+ if (((*data->prev)=data->next)) /* remove from lock-list */
+ data->next->prev= data->prev;
+ else
+ lock->write.last=data->prev;
+
+ if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
+ data->next->prev= &data->next;
+ else
+ lock->write_wait.last= &data->next;
+ data->prev= &lock->write_wait.data;
+ lock->write_wait.data=data;
+ check_locks(lock,"upgrading lock",0);
+ }
+ DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
+}
+
+
+/* downgrade a WRITE lock to a WRITE_DELAY lock if there is pending locks */
+
+my_bool thr_reschedule_write_lock(THR_LOCK_DATA *data)
+{
+ THR_LOCK *lock=data->lock;
+ DBUG_ENTER("thr_reschedule_write_lock");
+
+ pthread_mutex_lock(&lock->mutex);
+ if (!lock->read_wait.data) /* No waiting read locks */
+ {
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(0);
+ }
+
+ data->type=TL_WRITE_DELAYED;
+ if (lock->update_status)
+ (*lock->update_status)(data->status_param);
+ if (((*data->prev)=data->next)) /* remove from lock-list */
+ data->next->prev= data->prev;
+ else
+ lock->write.last=data->prev;
+
+ if ((data->next=lock->write_wait.data)) /* Put first in lock_list */
+ data->next->prev= &data->next;
+ else
+ lock->write_wait.last= &data->next;
+ data->prev= &lock->write_wait.data;
+ data->cond=get_cond(); /* This was zero */
+ lock->write_wait.data=data;
+ free_all_read_locks(lock,0);
+
+ pthread_mutex_unlock(&lock->mutex);
+ DBUG_RETURN(thr_upgrade_write_delay_lock(data));
+}
+
+
+#include <my_sys.h>
+
+static void thr_print_lock(const char* name,struct st_lock_list *list)
+{
+ THR_LOCK_DATA *data,**prev;
+ uint count=0;
+
+ if (list->data)
+ {
+ printf("%-10s: ",name);
+ prev= &list->data;
+ for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next)
+ {
+ printf("%lx (%lu:%d); ",(ulong) data,data->thread_id,(int) data->type);
+ if (data->prev != prev)
+ printf("\nWarning: prev didn't point at previous lock\n");
+ prev= &data->next;
+ }
+ puts("");
+ if (prev != list->last)
+ printf("Warning: last didn't point at last lock\n");
+ }
+}
+
+void thr_print_locks(void)
+{
+ LIST *list;
+ uint count=0;
+
+ pthread_mutex_lock(&THR_LOCK_lock);
+ puts("Current locks:");
+ for (list=thread_list ; list && count++ < MAX_THREADS ; list=rest(list))
+ {
+ THR_LOCK *lock=(THR_LOCK*) list->data;
+ VOID(pthread_mutex_lock(&lock->mutex));
+ printf("lock: %lx:",(ulong) lock);
+ if ((lock->write_wait.data || lock->read_wait.data) &&
+ (! lock->read.data && ! lock->write.data))
+ printf(" WARNING: ");
+ if (lock->write.data)
+ printf(" write");
+ if (lock->write_wait.data)
+ printf(" write_wait");
+ if (lock->read.data)
+ printf(" read");
+ if (lock->read_wait.data)
+ printf(" read_wait");
+ puts("");
+ thr_print_lock("write",&lock->write);
+ thr_print_lock("write_wait",&lock->write_wait);
+ thr_print_lock("read",&lock->read);
+ thr_print_lock("read_wait",&lock->read_wait);
+ VOID(pthread_mutex_unlock(&lock->mutex));
+ puts("");
+ }
+ fflush(stdout);
+ pthread_mutex_unlock(&THR_LOCK_lock);
+}
+
+#ifdef MAIN
+
+struct st_test {
+ uint lock_nr;
+ enum thr_lock_type lock_type;
+};
+
+THR_LOCK locks[5]; /* 4 locks */
+
+struct st_test test_0[] = {{0,TL_READ}}; /* One lock */
+struct st_test test_1[] = {{0,TL_READ},{0,TL_WRITE}}; /* Read and write lock of lock 0 */
+struct st_test test_2[] = {{1,TL_WRITE},{0,TL_READ},{2,TL_READ}};
+struct st_test test_3[] = {{2,TL_WRITE},{1,TL_READ},{0,TL_READ}}; /* Deadlock with test_2 ? */
+struct st_test test_4[] = {{0,TL_WRITE},{0,TL_READ},{0,TL_WRITE},{0,TL_READ}};
+struct st_test test_5[] = {{0,TL_READ},{1,TL_READ},{2,TL_READ},{3,TL_READ}}; /* Many reads */
+struct st_test test_6[] = {{0,TL_WRITE},{1,TL_WRITE},{2,TL_WRITE},{3,TL_WRITE}}; /* Many writes */
+struct st_test test_7[] = {{3,TL_READ}};
+struct st_test test_8[] = {{1,TL_READ_NO_INSERT},{2,TL_READ_NO_INSERT},{3,TL_READ_NO_INSERT}}; /* Should be quick */
+struct st_test test_9[] = {{4,TL_READ_HIGH_PRIORITY}};
+struct st_test test_10[] ={{4,TL_WRITE}};
+struct st_test test_11[] = {{0,TL_WRITE_LOW_PRIORITY},{1,TL_WRITE_LOW_PRIORITY},{2,TL_WRITE_LOW_PRIORITY},{3,TL_WRITE_LOW_PRIORITY}}; /* Many writes */
+struct st_test test_12[] = {{0,TL_WRITE_ALLOW_READ},{1,TL_WRITE_ALLOW_READ},{2,TL_WRITE_ALLOW_READ},{3,TL_WRITE_ALLOW_READ}}; /* Many writes */
+struct st_test test_13[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_WRITE_CONCURRENT_INSERT},{2,TL_WRITE_CONCURRENT_INSERT},{3,TL_WRITE_CONCURRENT_INSERT}};
+struct st_test test_14[] = {{0,TL_WRITE_CONCURRENT_INSERT},{1,TL_READ}};
+struct st_test test_15[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_READ}};
+struct st_test test_16[] = {{0,TL_WRITE_ALLOW_WRITE},{1,TL_WRITE_ALLOW_WRITE}};
+
+struct st_test *tests[] = {test_0,test_1,test_2,test_3,test_4,test_5,test_6,
+ test_7,test_8,test_9,test_10,test_11,test_12,
+ test_13,test_14,test_15,test_16};
+int lock_counts[]= {sizeof(test_0)/sizeof(struct st_test),
+ sizeof(test_1)/sizeof(struct st_test),
+ sizeof(test_2)/sizeof(struct st_test),
+ sizeof(test_3)/sizeof(struct st_test),
+ sizeof(test_4)/sizeof(struct st_test),
+ sizeof(test_5)/sizeof(struct st_test),
+ sizeof(test_6)/sizeof(struct st_test),
+ sizeof(test_7)/sizeof(struct st_test),
+ sizeof(test_8)/sizeof(struct st_test),
+ sizeof(test_9)/sizeof(struct st_test),
+ sizeof(test_10)/sizeof(struct st_test),
+ sizeof(test_11)/sizeof(struct st_test),
+ sizeof(test_12)/sizeof(struct st_test),
+ sizeof(test_13)/sizeof(struct st_test),
+ sizeof(test_14)/sizeof(struct st_test),
+ sizeof(test_15)/sizeof(struct st_test),
+ sizeof(test_16)/sizeof(struct st_test)
+};
+
+
+static pthread_cond_t COND_thread_count;
+static pthread_mutex_t LOCK_thread_count;
+static uint thread_count;
+static ulong sum=0;
+
+#define MAX_LOCK_COUNT 8
+
+/* The following functions is for WRITE_CONCURRENT_INSERT */
+
+static void test_get_status(void* param __attribute__((unused)))
+{
+}
+
+static void test_copy_status(void* to __attribute__((unused)) ,
+ void *from __attribute__((unused)))
+{
+}
+
+static my_bool test_check_status(void* param __attribute__((unused)))
+{
+ return 0;
+}
+
+
+static void *test_thread(void *arg)
+{
+ int i,j,param=*((int*) arg);
+ THR_LOCK_DATA data[MAX_LOCK_COUNT];
+ THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT];
+ my_thread_init();
+
+ printf("Thread %s (%d) started\n",my_thread_name(),param); fflush(stdout);
+
+ for (i=0; i < lock_counts[param] ; i++)
+ thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL);
+ for (j=1 ; j < 10 ; j++) /* try locking 10 times */
+ {
+ for (i=0; i < lock_counts[param] ; i++)
+ { /* Init multi locks */
+ multi_locks[i]= &data[i];
+ data[i].type= tests[param][i].lock_type;
+ }
+ thr_multi_lock(multi_locks,lock_counts[param]);
+ pthread_mutex_lock(&LOCK_thread_count);
+ {
+ int tmp=rand() & 7; /* Do something from 0-2 sec */
+ if (tmp == 0)
+ sleep(1);
+ else if (tmp == 1)
+ sleep(2);
+ else
+ {
+ ulong k;
+ for (k=0 ; k < (ulong) (tmp-2)*100000L ; k++)
+ sum+=k;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_thread_count);
+ thr_multi_unlock(multi_locks,lock_counts[param]);
+ }
+
+ printf("Tread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
+ thr_print_locks();
+ pthread_mutex_lock(&LOCK_thread_count);
+ thread_count--;
+ VOID(pthread_cond_signal(&COND_thread_count)); /* Tell main we are ready */
+ pthread_mutex_unlock(&LOCK_thread_count);
+ free((gptr) arg);
+ return 0;
+}
+
+
+int main(int argc __attribute__((unused)),char **argv __attribute__((unused)))
+{
+ pthread_t tid;
+ pthread_attr_t thr_attr;
+ int i,*param,error;
+ MY_INIT(argv[0]);
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '#')
+ DBUG_PUSH(argv[1]+2);
+
+ printf("Main thread: %s\n",my_thread_name());
+
+ if ((error=pthread_cond_init(&COND_thread_count,NULL)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_mutex_init(&LOCK_thread_count,NULL)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_cond_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+
+ for (i=0 ; i < (int) array_elements(locks) ; i++)
+ {
+ thr_lock_init(locks+i);
+ locks[i].check_status= test_check_status;
+ locks[i].update_status=test_get_status;
+ locks[i].copy_status= test_copy_status;
+ locks[i].get_status= test_get_status;
+ }
+ if ((error=pthread_attr_init(&thr_attr)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_init (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED)))
+ {
+ fprintf(stderr,
+ "Got error: %d from pthread_attr_setdetachstate (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+#ifndef pthread_attr_setstacksize /* void return value */
+ if ((error=pthread_attr_setstacksize(&thr_attr,65536L)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_attr_setstacksize (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+#endif
+#ifdef HAVE_THR_SETCONCURRENCY
+ VOID(thr_setconcurrency(2));
+#endif
+ for (i=0 ; i < (int) array_elements(lock_counts) ; i++)
+ {
+ param=(int*) malloc(sizeof(int));
+ *param=i;
+
+ if ((error=pthread_mutex_lock(&LOCK_thread_count)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_mutex_lock (errno: %d)",
+ error,errno);
+ exit(1);
+ }
+ if ((error=pthread_create(&tid,&thr_attr,test_thread,(void*) param)))
+ {
+ fprintf(stderr,"Got error: %d from pthread_create (errno: %d)\n",
+ error,errno);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ exit(1);
+ }
+ thread_count++;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ }
+
+ pthread_attr_destroy(&thr_attr);
+ if ((error=pthread_mutex_lock(&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_mutex_lock\n",error);
+ while (thread_count)
+ {
+ if ((error=pthread_cond_wait(&COND_thread_count,&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_cond_wait\n",error);
+ }
+ if ((error=pthread_mutex_unlock(&LOCK_thread_count)))
+ fprintf(stderr,"Got error: %d from pthread_mutex_unlock\n",error);
+ for (i=0 ; i < (int) array_elements(locks) ; i++)
+ thr_lock_delete(locks+i);
+#ifdef EXTRA_DEBUG
+ if (found_errors)
+ printf("Got %d warnings\n",found_errors);
+ else
+#endif
+ printf("Test succeeded\n");
+ return 0;
+}
+#endif
+
+#endif
diff --git a/mysys/thr_mutex.c b/mysys/thr_mutex.c
new file mode 100644
index 00000000000..7eea5be473b
--- /dev/null
+++ b/mysys/thr_mutex.c
@@ -0,0 +1,214 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* This makes a wrapper for mutex handling to make it easier to debug mutex */
+
+#include <global.h>
+#if defined(HAVE_LINUXTHREADS) && !defined (__USE_UNIX98)
+#define __USE_UNIX98 /* To get rw locks under Linux */
+#endif
+#include <m_string.h>
+#if defined(THREAD) && defined(SAFE_MUTEX)
+#undef SAFE_MUTEX /* Avoid safe_mutex redefinitions */
+#include <my_pthread.h>
+
+#ifndef DO_NOT_REMOVE_THREAD_WRAPPERS
+/* Remove wrappers */
+#undef pthread_mutex_init
+#undef pthread_mutex_lock
+#undef pthread_mutex_unlock
+#undef pthread_mutex_destroy
+#undef pthread_cond_wait
+#undef pthread_cond_timedwait
+#ifdef HAVE_NONPOSIX_PTHREAD_MUTEX_INIT
+#define pthread_mutex_init(a,b) my_pthread_mutex_init((a),(b))
+#endif
+#endif
+
+int safe_mutex_init(safe_mutex_t *mp,
+ const pthread_mutexattr_t *attr __attribute__((unused)))
+{
+ bzero((char*) mp,sizeof(*mp));
+#ifdef HAVE_LINUXTHREADS /* Some extra safety */
+ {
+ pthread_mutexattr_t tmp;
+ pthread_mutexattr_init(&tmp);
+ pthread_mutexattr_setkind_np(&tmp,PTHREAD_MUTEX_ERRORCHECK_NP);
+ pthread_mutex_init(&mp->global,&tmp);
+ pthread_mutex_init(&mp->mutex, &tmp);
+ pthread_mutexattr_destroy(&tmp);
+ }
+#else
+ pthread_mutex_init(&mp->global,NULL);
+ pthread_mutex_init(&mp->mutex,attr);
+#endif
+ return 0;
+}
+
+int safe_mutex_lock(safe_mutex_t *mp,const char *file, uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count > 0 && pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to lock mutex at %s, line %d, when the mutex was already locked at %s, line %d\n",
+ file,line,mp->file,mp->line);
+ abort();
+ }
+ pthread_mutex_unlock(&mp->global);
+ error=pthread_mutex_lock(&mp->mutex);
+ if (error || (error=pthread_mutex_lock(&mp->global)))
+ {
+ fprintf(stderr,"Got error %d when trying to lock mutex at %s, line %d\n",
+ error, file, line);
+ abort();
+ }
+ if (mp->count++)
+ {
+ fprintf(stderr,"safe_mutex: Error in thread libray: Got mutex at %s, line %d more than 1 time\n", file,line);
+ abort();
+ }
+ mp->thread=pthread_self();
+ mp->file= (char*) file;
+ mp->line=line;
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+
+int safe_mutex_unlock(safe_mutex_t *mp,const char *file, uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count == 0)
+ {
+ fprintf(stderr,"safe_mutex: Trying to unlock mutex that wasn't locked at %s, line %d\n Last used at %s, line: %d\n",
+ file,line,mp->file ? mp->file : "",mp->line);
+ abort();
+ }
+ if (!pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to unlock mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
+ file,line,mp->file,mp->line);
+ abort();
+ }
+ mp->count--;
+ error=pthread_mutex_unlock(&mp->mutex);
+ if (error)
+ {
+ fprintf(stderr,"safe_mutex: Got error: %d when trying to unlock mutex at %s, line %d\n", error, file, line);
+ abort();
+ }
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+
+int safe_cond_wait(pthread_cond_t *cond, safe_mutex_t *mp, const char *file,
+ uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count == 0)
+ {
+ fprintf(stderr,"safe_mutex: Trying to cond_wait on a unlocked mutex at %s, line %d\n",file,line);
+ abort();
+ }
+ if (!pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to cond_wait on a mutex at %s, line %d that was locked by another thread at: %s, line: %d\n",
+ file,line,mp->file,mp->line);
+ abort();
+ }
+
+ if (mp->count-- != 1)
+ {
+ fprintf(stderr,"safe_mutex: Count was %d on locked mutex at %s, line %d\n",
+ mp->count+1, file, line);
+ abort();
+ }
+ pthread_mutex_unlock(&mp->global);
+ error=pthread_cond_wait(cond,&mp->mutex);
+ pthread_mutex_lock(&mp->global);
+ if (error)
+ {
+ fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_wait at %s, line %d\n", error, file, line);
+ abort();
+ }
+ if (mp->count++)
+ {
+ fprintf(stderr,
+ "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d\n",
+ mp->count-1, my_thread_id(), file, line);
+ abort();
+ }
+ mp->thread=pthread_self();
+ mp->file= (char*) file;
+ mp->line=line;
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+
+int safe_cond_timedwait(pthread_cond_t *cond, safe_mutex_t *mp,
+ struct timespec *abstime,
+ const char *file, uint line)
+{
+ int error;
+ pthread_mutex_lock(&mp->global);
+ if (mp->count != 1 || !pthread_equal(pthread_self(),mp->thread))
+ {
+ fprintf(stderr,"safe_mutex: Trying to cond_wait at %s, line %d on a not hold mutex\n",file,line);
+ abort();
+ }
+ mp->count--; /* Mutex will be released */
+ pthread_mutex_unlock(&mp->global);
+ error=pthread_cond_timedwait(cond,&mp->mutex,abstime);
+#ifdef EXTRA_DEBUG
+ if (error && (error != EINTR && error != ETIMEDOUT))
+ {
+ fprintf(stderr,"safe_mutex: Got error: %d when doing a safe_mutex_timedwait at %s, line %d\n", error, file, line);
+ }
+#endif
+ pthread_mutex_lock(&mp->global);
+ if (mp->count++)
+ {
+ fprintf(stderr,
+ "safe_mutex: Count was %d in thread %lx when locking mutex at %s, line %d (error: %d)\n",
+ mp->count-1, my_thread_id(), file, line, error);
+ abort();
+ }
+ mp->thread=pthread_self();
+ mp->file= (char*) file;
+ mp->line=line;
+ pthread_mutex_unlock(&mp->global);
+ return error;
+}
+
+int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
+{
+ if (mp->count != 0)
+ {
+ fprintf(stderr,"safe_mutex: Trying to destroy a mutex that was locked at %s, line %d at %s, line %d\n",
+ mp->file,mp->line, file, line);
+ abort();
+ }
+ pthread_mutex_destroy(&mp->global);
+ return pthread_mutex_destroy(&mp->mutex);
+}
+
+#endif /* SAFE_MUTEX */
diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c
new file mode 100644
index 00000000000..fc2eea551da
--- /dev/null
+++ b/mysys/thr_rwlock.c
@@ -0,0 +1,139 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Synchronization - readers / writer thread locks */
+
+#include "mysys_priv.h"
+#include <my_pthread.h>
+#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT)
+
+/*
+ * Source base from Sun Microsystems SPILT, simplified
+ * for MySQL use -- Joshua Chamas
+ */
+
+/*
+* Multithreaded Demo Source
+*
+* Copyright (C) 1995 by Sun Microsystems, Inc.
+* All rights reserved.
+*
+* This file is a product of SunSoft, Inc. and is provided for
+* unrestricted use provided that this legend is included on all
+* media and as a part of the software program in whole or part.
+* Users may copy, modify or distribute this file at will.
+*
+* THIS FILE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+* THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+*
+* This file is provided with no support and without any obligation on the
+* part of SunSoft, Inc. to assist in its use, correction, modification or
+* enhancement.
+*
+* SUNSOFT AND SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT
+* TO THE INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
+* FILE OR ANY PART THEREOF.
+*
+* IN NO EVENT WILL SUNSOFT OR SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
+* LOST REVENUE OR PROFITS OR OTHER SPECIAL, INDIRECT AND CONSEQUENTIAL
+* DAMAGES, EVEN IF THEY HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
+* DAMAGES.
+*
+* SunSoft, Inc.
+* 2550 Garcia Avenue
+* Mountain View, California 94043
+*/
+
+int my_rwlock_init( rw_lock_t *rwp, void *arg __attribute__((unused)))
+{
+ pthread_condattr_t cond_attr;
+
+ pthread_mutex_init( &rwp->lock, NULL );
+ pthread_condattr_init( &cond_attr );
+ pthread_cond_init( &rwp->readers, &cond_attr );
+ pthread_cond_init( &rwp->writers, &cond_attr );
+ pthread_condattr_destroy(&cond_attr);
+
+ rwp->state = 0;
+ rwp->waiters = 0;
+
+ return( 0 );
+}
+
+int my_rwlock_destroy( rw_lock_t *rwp ) {
+ pthread_mutex_destroy( &rwp->lock );
+ pthread_cond_destroy( &rwp->readers );
+ pthread_cond_destroy( &rwp->writers );
+
+ return( 0 );
+}
+
+int my_rw_rdlock( rw_lock_t *rwp ) {
+ pthread_mutex_lock(&rwp->lock);
+
+ /* active or queued writers */
+ while ( ( rwp->state < 0 ) && rwp->waiters )
+ pthread_cond_wait( &rwp->readers, &rwp->lock);
+
+ rwp->state++;
+ pthread_mutex_unlock(&rwp->lock);
+
+ return( 0 );
+}
+
+int my_rw_wrlock( rw_lock_t *rwp ) {
+
+ pthread_mutex_lock(&rwp->lock);
+ rwp->waiters++; /* another writer queued */
+
+ while ( rwp->state )
+ pthread_cond_wait( &rwp->writers, &rwp->lock);
+
+ rwp->state = -1;
+
+ if ( ( --rwp->waiters == 0 ) && ( rwp->state >= 0 ) )
+ pthread_cond_broadcast( &rwp->readers );
+
+ pthread_mutex_unlock( &rwp->lock );
+
+ return( 0 );
+}
+
+int my_rw_unlock( rw_lock_t *rwp ) {
+ DBUG_PRINT("rw_unlock",
+ ("state: %d waiters: %d", rwp->state, rwp->waiters));
+ pthread_mutex_lock(&rwp->lock);
+
+ if ( rwp->state == -1 ) { /* writer releasing */
+ rwp->state = 0; /* mark as available */
+
+ if ( rwp->waiters ) /* writers queued */
+ pthread_cond_signal( &rwp->writers );
+ else
+ pthread_cond_broadcast( &rwp->readers );
+ } else {
+ if ( --rwp->state == 0 ) /* no more readers */
+ pthread_cond_signal( &rwp->writers );
+ }
+
+ pthread_mutex_unlock( &rwp->lock );
+
+ return( 0 );
+}
+
+#endif
diff --git a/mysys/tree.c b/mysys/tree.c
new file mode 100644
index 00000000000..259fc5fb9d0
--- /dev/null
+++ b/mysys/tree.c
@@ -0,0 +1,513 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/*
+ Code for handling red-black (balanced) binary trees.
+ key in tree is allocated accrding to following:
+ 1) If free_element function is given to init_tree or size < 0 then tree
+ will not allocate keys and only a pointer to each key is saved in tree.
+ key_sizes must be 0 to init and search.
+ compare and search functions uses and returns key-pointer.
+ 2) if key_size is given to init_tree then each node will continue the
+ key and calls to insert_key may increase length of key.
+ if key_size > sizeof(pointer) and key_size is a multiple of 8 (double
+ allign) then key will be put on a 8 alligned adress. Else
+ the key will be on adress (element+1). This is transparent for user
+ compare and search functions uses a pointer to given key-argument.
+ 3) If init_tree - keysize is 0 then key_size must be given to tree_insert
+ and tree_insert will alloc space for key.
+ compare and search functions uses a pointer to given key-argument.
+
+ The actual key in TREE_ELEMENT is saved as a pointer or after the
+ TREE_ELEMENT struct.
+ If one uses only pointers in tree one can use tree_set_pointer() to
+ change address of data.
+ Copyright Monty Program KB.
+ By monty.
+*/
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <my_tree.h>
+
+#define BLACK 1
+#define RED 0
+#define DEFAULT_ALLOC_SIZE (8192-MALLOC_OVERHEAD)
+
+static void delete_tree_element(TREE *,TREE_ELEMENT *);
+static int tree_walk_left_root_right(TREE *,TREE_ELEMENT *,
+ tree_walk_action,void *);
+static int tree_walk_right_root_left(TREE *,TREE_ELEMENT *,
+ tree_walk_action,void *);
+static void left_rotate(TREE_ELEMENT **parent,TREE_ELEMENT *leaf);
+static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf);
+static void rb_insert(TREE *tree,TREE_ELEMENT ***parent,
+ TREE_ELEMENT *leaf);
+static void rb_delete_fixup(TREE *tree,TREE_ELEMENT ***parent);
+
+
+ /* The actuall code for handling binary trees */
+
+void init_tree(TREE *tree, uint default_alloc_size, int size,
+ qsort_cmp compare, my_bool with_delete,
+ void (*free_element) (void *))
+{
+ DBUG_ENTER("init_tree");
+ DBUG_PRINT("enter",("tree: %lx size: %d",tree,size));
+
+ if (!default_alloc_size)
+ default_alloc_size= DEFAULT_ALLOC_SIZE;
+ bzero((gptr) &tree->null_element,sizeof(tree->null_element));
+ tree->root= &tree->null_element;
+ tree->compare=compare;
+ tree->size_of_element=size > 0 ? (uint) size : 0;
+ tree->free=free_element;
+ tree->elements_in_tree=0;
+ tree->null_element.colour=BLACK;
+ tree->null_element.left=tree->null_element.right=0;
+ if (!free_element && size >= 0 &&
+ ((uint) size <= sizeof(void*) || ((uint) size & (sizeof(void*)-1))))
+ {
+ tree->offset_to_key=sizeof(TREE_ELEMENT); /* Put key after element */
+ /* Fix allocation size so that we don't loose any memory */
+ default_alloc_size/=(sizeof(TREE_ELEMENT)+size);
+ if (!default_alloc_size)
+ default_alloc_size=1;
+ default_alloc_size*=(sizeof(TREE_ELEMENT)+size);
+ }
+ else
+ {
+ tree->offset_to_key=0; /* use key through pointer */
+ tree->size_of_element+=sizeof(void*);
+ }
+ if (!(tree->with_delete=with_delete))
+ {
+ init_alloc_root(&tree->mem_root, default_alloc_size);
+ tree->mem_root.min_malloc=(sizeof(TREE_ELEMENT)+tree->size_of_element);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void delete_tree(TREE *tree)
+{
+ DBUG_ENTER("delete_tree");
+ DBUG_PRINT("enter",("tree: %lx",tree));
+
+ if (tree->root) /* If initialized */
+ {
+ if (tree->with_delete)
+ delete_tree_element(tree,tree->root);
+ else
+ {
+ if (tree->free)
+ delete_tree_element(tree,tree->root);
+ free_root(&tree->mem_root);
+ }
+ }
+ tree->root= &tree->null_element;
+ tree->elements_in_tree=0;
+
+ DBUG_VOID_RETURN;
+}
+
+static void delete_tree_element(TREE *tree, TREE_ELEMENT *element)
+{
+ if (element != &tree->null_element)
+ {
+ delete_tree_element(tree,element->left);
+ delete_tree_element(tree,element->right);
+ if (tree->free)
+ (*tree->free)(ELEMENT_KEY(tree,element));
+ if (tree->with_delete)
+ my_free((void*) element,MYF(0));
+ }
+}
+
+ /* Code for insert, search and delete of elements */
+ /* parent[0] = & parent[-1][0]->left ||
+ parent[0] = & parent[-1][0]->right */
+
+
+TREE_ELEMENT *tree_insert(TREE *tree, void *key, uint key_size)
+{
+ int cmp;
+ TREE_ELEMENT *element,***parent;
+
+ parent= tree->parents;
+ *parent = &tree->root; element= tree->root;
+ for (;;)
+ {
+ if (element == &tree->null_element ||
+ (cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ break;
+ if (cmp < 0)
+ {
+ *++parent= &element->right; element= element->right;
+ }
+ else
+ {
+ *++parent = &element->left; element= element->left;
+ }
+ }
+ if (element == &tree->null_element)
+ {
+ key_size+=tree->size_of_element;
+ if (tree->with_delete)
+ element=(TREE_ELEMENT *) my_malloc(sizeof(TREE_ELEMENT)+key_size,
+ MYF(MY_WME));
+ else
+ element=(TREE_ELEMENT *)
+ alloc_root(&tree->mem_root,sizeof(TREE_ELEMENT)+key_size);
+ if (!element)
+ return(NULL);
+ **parent=element;
+ element->left=element->right= &tree->null_element;
+ if (!tree->offset_to_key)
+ {
+ if (key_size == sizeof(void*)) /* no length, save pointer */
+ *((void**) (element+1))=key;
+ else
+ {
+ *((void**) (element+1))= (void*) ((void **) (element+1)+1);
+ memcpy((byte*) *((void **) (element+1)),key,
+ (size_t) (key_size-sizeof(void*)));
+ }
+ }
+ else
+ memcpy((byte*) element+tree->offset_to_key,key,(size_t) key_size);
+ element->count=1; /* May give warning in purify */
+ tree->elements_in_tree++;
+ rb_insert(tree,parent,element); /* rebalance tree */
+ }
+ else
+ element->count++;
+ return element;
+}
+
+
+int tree_delete(TREE *tree, void *key)
+{
+ int cmp,remove_colour;
+ TREE_ELEMENT *element,***parent, ***org_parent, *nod;
+ if (!tree->with_delete)
+ return 1; /* not allowed */
+
+ parent= tree->parents;
+ *parent= &tree->root; element= tree->root;
+ for (;;)
+ {
+ if (element == &tree->null_element)
+ return 1; /* Was not in tree */
+ if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ break;
+ if (cmp < 0)
+ {
+ *++parent= &element->right; element= element->right;
+ }
+ else
+ {
+ *++parent = &element->left; element= element->left;
+ }
+ }
+ if (element->left == &tree->null_element)
+ {
+ (**parent)=element->right;
+ remove_colour= element->colour;
+ }
+ else if (element->right == &tree->null_element)
+ {
+ (**parent)=element->left;
+ remove_colour= element->colour;
+ }
+ else
+ {
+ org_parent= parent;
+ *++parent= &element->right; nod= element->right;
+ while (nod->left != &tree->null_element)
+ {
+ *++parent= &nod->left; nod= nod->left;
+ }
+ (**parent)=nod->right; /* unlink nod from tree */
+ remove_colour= nod->colour;
+ org_parent[0][0]=nod; /* put y in place of element */
+ org_parent[1]= &nod->right;
+ nod->left=element->left;
+ nod->right=element->right;
+ nod->colour=element->colour;
+ }
+ if (remove_colour == BLACK)
+ rb_delete_fixup(tree,parent);
+ my_free((gptr) element,MYF(0));
+ tree->elements_in_tree--;
+ return 0;
+}
+
+
+void *tree_search(TREE *tree, void *key)
+{
+ int cmp;
+ TREE_ELEMENT *element=tree->root;
+
+ for (;;)
+ {
+ if (element == &tree->null_element)
+ return (void*) 0;
+ if ((cmp=(*tree->compare)(ELEMENT_KEY(tree,element),key)) == 0)
+ return ELEMENT_KEY(tree,element);
+ if (cmp < 0)
+ element=element->right;
+ else
+ element=element->left;
+ }
+}
+
+
+int tree_walk(TREE *tree, tree_walk_action action, void *argument, TREE_WALK visit)
+{
+ switch (visit) {
+ case left_root_right:
+ return tree_walk_left_root_right(tree,tree->root,action,argument);
+ case right_root_left:
+ return tree_walk_right_root_left(tree,tree->root,action,argument);
+ }
+ return 0; /* Keep gcc happy */
+}
+
+static int tree_walk_left_root_right(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
+{
+ int error;
+ if (element->left) /* Not null_element */
+ {
+ if ((error=tree_walk_left_root_right(tree,element->left,action,
+ argument)) == 0 &&
+ (error=(*action)(ELEMENT_KEY(tree,element),
+ (element_count) element->count,
+ argument)) == 0)
+ error=tree_walk_left_root_right(tree,element->right,action,argument);
+ return error;
+ }
+ return 0;
+}
+
+static int tree_walk_right_root_left(TREE *tree, TREE_ELEMENT *element, tree_walk_action action, void *argument)
+{
+ int error;
+ if (element->right) /* Not null_element */
+ {
+ if ((error=tree_walk_right_root_left(tree,element->right,action,
+ argument)) == 0 &&
+ (error=(*action)(ELEMENT_KEY(tree,element),
+ (element_count) element->count,
+ argument)) == 0)
+ error=tree_walk_right_root_left(tree,element->left,action,argument);
+ return error;
+ }
+ return 0;
+}
+
+
+ /* Functions to fix up the tree after insert and delete */
+
+static void left_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
+{
+ TREE_ELEMENT *y;
+
+ y=leaf->right;
+ leaf->right=y->left;
+ parent[0]=y;
+ y->left=leaf;
+}
+
+static void right_rotate(TREE_ELEMENT **parent, TREE_ELEMENT *leaf)
+{
+ TREE_ELEMENT *x;
+
+ x=leaf->left;
+ leaf->left=x->right;
+ parent[0]=x;
+ x->right=leaf;
+}
+
+static void rb_insert(TREE *tree, TREE_ELEMENT ***parent, TREE_ELEMENT *leaf)
+{
+ TREE_ELEMENT *y,*par,*par2;
+
+ leaf->colour=RED;
+ while (leaf != tree->root && (par=parent[-1][0])->colour == RED)
+ {
+ if (par == (par2=parent[-2][0])->left)
+ {
+ y= par2->right;
+ if (y->colour == RED)
+ {
+ par->colour=BLACK;
+ y->colour=BLACK;
+ leaf=par2;
+ parent-=2;
+ leaf->colour=RED; /* And the loop continues */
+ }
+ else
+ {
+ if (leaf == par->right)
+ {
+ left_rotate(parent[-1],par);
+ par=leaf; /* leaf is now parent to old leaf */
+ }
+ par->colour=BLACK;
+ par2->colour=RED;
+ right_rotate(parent[-2],par2);
+ break;
+ }
+ }
+ else
+ {
+ y= par2->left;
+ if (y->colour == RED)
+ {
+ par->colour=BLACK;
+ y->colour=BLACK;
+ leaf=par2;
+ parent-=2;
+ leaf->colour=RED; /* And the loop continues */
+ }
+ else
+ {
+ if (leaf == par->left)
+ {
+ right_rotate(parent[-1],par);
+ par=leaf;
+ }
+ par->colour=BLACK;
+ par2->colour=RED;
+ left_rotate(parent[-2],par2);
+ break;
+ }
+ }
+ }
+ tree->root->colour=BLACK;
+}
+
+static void rb_delete_fixup(TREE *tree, TREE_ELEMENT ***parent)
+{
+ TREE_ELEMENT *x,*w,*par;
+
+ x= **parent;
+ while (x != tree->root && x->colour == BLACK)
+ {
+ if (x == (par=parent[-1][0])->left)
+ {
+ w=par->right;
+ if (w->colour == RED)
+ {
+ w->colour=BLACK;
+ par->colour=RED;
+ left_rotate(parent[-1],par);
+ parent[0]= &w->left;
+ *++parent= &par->left;
+ w=par->right;
+ }
+ if (w->left->colour == BLACK && w->right->colour == BLACK)
+ {
+ w->colour=RED;
+ x=par;
+ parent--;
+ }
+ else
+ {
+ if (w->right->colour == BLACK)
+ {
+ w->left->colour=BLACK;
+ w->colour=RED;
+ right_rotate(&par->right,w);
+ w=par->right;
+ }
+ w->colour=par->colour;
+ par->colour=BLACK;
+ w->right->colour=BLACK;
+ left_rotate(parent[-1],par);
+ x=tree->root;
+ break;
+ }
+ }
+ else
+ {
+ w=par->left;
+ if (w->colour == RED)
+ {
+ w->colour=BLACK;
+ par->colour=RED;
+ right_rotate(parent[-1],par);
+ parent[0]= &w->right;
+ *++parent= &par->right;
+ w=par->left;
+ }
+ if (w->right->colour == BLACK && w->left->colour == BLACK)
+ {
+ w->colour=RED;
+ x=par;
+ parent--;
+ }
+ else
+ {
+ if (w->left->colour == BLACK)
+ {
+ w->right->colour=BLACK;
+ w->colour=RED;
+ left_rotate(&par->left,w);
+ w=par->left;
+ }
+ w->colour=par->colour;
+ par->colour=BLACK;
+ w->left->colour=BLACK;
+ right_rotate(parent[-1],par);
+ x=tree->root;
+ break;
+ }
+ }
+ }
+ x->colour=BLACK;
+}
+
+
+#ifdef TESTING_TREES
+
+ /* Test that the proporties for a red-black tree holds */
+
+static int test_rb_tree(TREE_ELEMENT *element)
+{
+ int count_l,count_r;
+
+ if (!element->left)
+ return 0; /* Found end of tree */
+ if (element->colour == RED &&
+ (element->left->colour == RED || element->right->colour == RED))
+ {
+ printf("Wrong tree: Found two red in a row\n");
+ return -1;
+ }
+ count_l=test_rb_tree(element->left);
+ count_r=test_rb_tree(element->right);
+ if (count_l >= 0 && count_r >= 0)
+ {
+ if (count_l == count_r)
+ return count_l+(element->colour == BLACK);
+ printf("Wrong tree: Incorrect black-count: %d - %d\n",count_l,count_r);
+ }
+ return -1;
+}
+
+#endif
diff --git a/mysys/typelib.c b/mysys/typelib.c
new file mode 100644
index 00000000000..903a7304065
--- /dev/null
+++ b/mysys/typelib.c
@@ -0,0 +1,106 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA */
+
+/* Functions to handle typelib */
+
+#include "mysys_priv.h"
+#include <m_string.h>
+#include <m_ctype.h>
+
+/***************************************************************************
+** Search after a fieldtype. Endspace in x is not compared.
+** If part, uniq field is found and full_name == 0 then x is expanded
+** to full field.
+** full_name has the following bit values:
+** If & 1 accept only hole names
+** If & 2 don't expand if half field
+** If & 4 allow #number# as type
+****************************************************************************/
+
+int find_type(my_string x, TYPELIB *typelib, uint full_name)
+{
+ int find,pos,findpos;
+ reg1 my_string i;
+ reg2 const char *j;
+ DBUG_ENTER("find_type");
+ DBUG_PRINT("enter",("x: '%s' lib: %lx",x,typelib));
+
+ if (!typelib->count)
+ {
+ DBUG_PRINT("exit",("no count"));
+ DBUG_RETURN(0);
+ }
+ LINT_INIT(findpos);
+ find=0;
+ for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
+ {
+ for (i=x ; *i && toupper(*i) == toupper(*j) ; i++, j++) ;
+ if (! *j)
+ {
+ while (*i == ' ')
+ i++; /* skipp_end_space */
+ if (! *i)
+ DBUG_RETURN(pos+1);
+ }
+ if (! *i)
+ {
+ find++;
+ findpos=pos;
+ }
+ }
+ if (find == 0 && (full_name & 4) && x[0] == '#' && strend(x)[-1] == '#' &&
+ (findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
+ find=1;
+ else if (find == 0 || ! x[0])
+ {
+ DBUG_PRINT("exit",("Couldn't find type"));
+ DBUG_RETURN(0);
+ }
+ else if (find != 1 || (full_name & 1))
+ {
+ DBUG_PRINT("exit",("Too many possybilities"));
+ DBUG_RETURN(-1);
+ }
+ if (!(full_name & 2))
+ (void) strmov(x,typelib->type_names[findpos]);
+ DBUG_RETURN(findpos+1);
+} /* find_type */
+
+
+ /* Get name of type nr 'nr' */
+ /* Warning first type is 1, 0 = empty field */
+
+void make_type(register my_string to, register uint nr, register TYPELIB *typelib)
+{
+ DBUG_ENTER("make_type");
+ if (!nr)
+ to[0]=0;
+ else
+ (void) strmov(to,get_type(typelib,nr-1));
+ DBUG_VOID_RETURN;
+} /* make_type */
+
+
+ /* Get type */
+ /* Warning first type is 0 */
+
+const char *get_type(TYPELIB *typelib, uint nr)
+{
+ if (nr < (uint) typelib->count && typelib->type_names)
+ return(typelib->type_names[nr]);
+ return "?";
+}