summaryrefslogtreecommitdiff
path: root/libs/pbd
diff options
context:
space:
mode:
authorTaybin Rutkin <taybin@taybin.com>2006-06-29 22:21:30 +0000
committerTaybin Rutkin <taybin@taybin.com>2006-06-29 22:21:30 +0000
commit481f7c39655afec832ac10430dd61a3bb464aa58 (patch)
treecde736699cbe49374a6aaa079258f88c1d0c7059 /libs/pbd
parentd1a4f74ef2c86042a0cbe0e83e611596df27575f (diff)
Fixed i18n system.
Renamed pbd3 back to pbd, since it's version 4.1 now. Very minor fixes git-svn-id: svn://localhost/ardour2/trunk@656 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/pbd')
-rw-r--r--libs/pbd/.cvsignore5
-rw-r--r--libs/pbd/AUTHORS0
-rw-r--r--libs/pbd/COPYING340
-rw-r--r--libs/pbd/ChangeLog10
-rw-r--r--libs/pbd/NEWS0
-rw-r--r--libs/pbd/README0
-rw-r--r--libs/pbd/SConscript68
-rw-r--r--libs/pbd/base_ui.cc88
-rw-r--r--libs/pbd/basename.cc20
-rw-r--r--libs/pbd/convert.cc212
-rw-r--r--libs/pbd/dmalloc.cc102
-rw-r--r--libs/pbd/error.cc7
-rw-r--r--libs/pbd/gettext.h82
-rw-r--r--libs/pbd/i18n.h11
-rw-r--r--libs/pbd/libpbd.pc.in11
-rw-r--r--libs/pbd/libpbd.spec.in70
-rw-r--r--libs/pbd/mountpoint.cc158
-rw-r--r--libs/pbd/path.cc164
-rw-r--r--libs/pbd/pathscanner.cc203
-rw-r--r--libs/pbd/pbd/.DS_Storebin0 -> 6148 bytes
-rw-r--r--libs/pbd/pbd/.cvsignore1
-rw-r--r--libs/pbd/pbd/abstract_ui.cc149
-rw-r--r--libs/pbd/pbd/abstract_ui.h79
-rw-r--r--libs/pbd/pbd/base_ui.h46
-rw-r--r--libs/pbd/pbd/basename.h13
-rw-r--r--libs/pbd/pbd/compose.h393
-rw-r--r--libs/pbd/pbd/convert.h40
-rw-r--r--libs/pbd/pbd/error.h32
-rw-r--r--libs/pbd/pbd/failed_constructor.h11
-rw-r--r--libs/pbd/pbd/fastlog.h40
-rw-r--r--libs/pbd/pbd/forkexec.h9
-rw-r--r--libs/pbd/pbd/mathfix.h34
-rw-r--r--libs/pbd/pbd/mountpoint.h28
-rw-r--r--libs/pbd/pbd/path.h113
-rw-r--r--libs/pbd/pbd/pathscanner.h66
-rw-r--r--libs/pbd/pbd/pool.h75
-rw-r--r--libs/pbd/pbd/pthread_utils.h23
-rw-r--r--libs/pbd/pbd/receiver.h50
-rw-r--r--libs/pbd/pbd/restartable_rw.h7
-rw-r--r--libs/pbd/pbd/ringbuffer.h284
-rw-r--r--libs/pbd/pbd/ringbufferNPT.h275
-rw-r--r--libs/pbd/pbd/selectable.h102
-rw-r--r--libs/pbd/pbd/stacktrace.h10
-rw-r--r--libs/pbd/pbd/stl_delete.h89
-rw-r--r--libs/pbd/pbd/stl_functors.h93
-rw-r--r--libs/pbd/pbd/strsplit.h9
-rw-r--r--libs/pbd/pbd/textreceiver.h44
-rw-r--r--libs/pbd/pbd/thrown_error.h39
-rw-r--r--libs/pbd/pbd/tokenizer.h49
-rw-r--r--libs/pbd/pbd/touchable.h89
-rw-r--r--libs/pbd/pbd/transmitter.h110
-rw-r--r--libs/pbd/pbd/undo.h96
-rw-r--r--libs/pbd/pbd/whitespace.h8
-rw-r--r--libs/pbd/pbd/xml++.h129
-rw-r--r--libs/pbd/pool.cc144
-rw-r--r--libs/pbd/pthread_utils.cc133
-rw-r--r--libs/pbd/receiver.cc58
-rw-r--r--libs/pbd/stacktrace.cc42
-rw-r--r--libs/pbd/strsplit.cc41
-rw-r--r--libs/pbd/textreceiver.cc66
-rw-r--r--libs/pbd/transmitter.cc115
-rw-r--r--libs/pbd/undo.cc146
-rw-r--r--libs/pbd/whitespace.cc30
-rw-r--r--libs/pbd/xml++.cc422
64 files changed, 5383 insertions, 0 deletions
diff --git a/libs/pbd/.cvsignore b/libs/pbd/.cvsignore
new file mode 100644
index 0000000000..e9a15e81e9
--- /dev/null
+++ b/libs/pbd/.cvsignore
@@ -0,0 +1,5 @@
+libpbd.pc
+libpbd.spec
+version.cc
+*.os
+*.dylib
diff --git a/libs/pbd/AUTHORS b/libs/pbd/AUTHORS
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libs/pbd/AUTHORS
diff --git a/libs/pbd/COPYING b/libs/pbd/COPYING
new file mode 100644
index 0000000000..d60c31a97a
--- /dev/null
+++ b/libs/pbd/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+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 software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, 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 redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies 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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+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 program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/libs/pbd/ChangeLog b/libs/pbd/ChangeLog
new file mode 100644
index 0000000000..59e92915ba
--- /dev/null
+++ b/libs/pbd/ChangeLog
@@ -0,0 +1,10 @@
+2005-12-02 Taybin Rutkin <taybin@earthlink.net>
+ * libpbd now allocates warning, info, error, and fatal itself.
+ * Incremented version to 3.1.
+
+2005-04-01 Taybin Rutkin <taybin@earthlink.net>
+ * Updated to support sigc++-2.0.
+ * Incremented version to 3.0.0.
+
+2004-08-04 Taybin Rutkin <taybin@earthlink.net>
+ * Added support for gcc-3.4
diff --git a/libs/pbd/NEWS b/libs/pbd/NEWS
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libs/pbd/NEWS
diff --git a/libs/pbd/README b/libs/pbd/README
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/libs/pbd/README
diff --git a/libs/pbd/SConscript b/libs/pbd/SConscript
new file mode 100644
index 0000000000..a9166d9505
--- /dev/null
+++ b/libs/pbd/SConscript
@@ -0,0 +1,68 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env libraries i18n install_prefix')
+
+pbd = env.Copy()
+
+domain = 'libpbd'
+
+pbd.Append(DOMAIN=domain,MAJOR=4,MINOR=1,MICRO=0)
+pbd.Append(CXXFLAGS="-DPACKAGE=\\\"" + domain + "\\\"")
+pbd.Append(CXXFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+pbd.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+pbd.Append(PACKAGE=domain)
+pbd.Append(POTFILE=domain + '.pot')
+
+pbd_files = Split("""
+basename.cc
+base_ui.cc
+convert.cc
+dmalloc.cc
+error.cc
+mountpoint.cc
+path.cc
+pathscanner.cc
+pool.cc
+pthread_utils.cc
+receiver.cc
+stacktrace.cc
+strsplit.cc
+textreceiver.cc
+transmitter.cc
+undo.cc
+version.cc
+whitespace.cc
+xml++.cc
+""")
+
+conf = Configure(pbd)
+if conf.CheckFunc('getmntent'):
+ conf.env.Append(CCFLAGS="-DHAVE_GETMNTENT")
+if conf.CheckCHeader('execinfo.h'):
+ conf.env.Append(CXXFLAGS="-DHAVE_EXECINFO")
+pbd = conf.Finish()
+
+pbd.Merge ([ libraries['sigc2'], libraries['xml'], libraries['glibmm2'], libraries['glib2'] ])
+
+pbd.VersionBuild(['version.cc','pbd/version.h'], 'SConscript')
+
+libpbd = pbd.SharedLibrary('pbd', pbd_files)
+Default(libpbd)
+
+mount_env = Environment(CCFLAGS='-DTEST_MOUNTPOINT -Ilibs/pbd')
+mount_env.Program('mountpoint', 'mountpoint.cc')
+
+if env['NLS']:
+ i18n (pbd, pbd_files, env)
+
+env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2'), libpbd))
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript', 'i18n.h', 'gettext.h', 'pbd/abstract_ui.cc' ] +
+ pbd_files +
+ glob.glob('po/*.po') +
+ glob.glob('pbd/*.h')))
diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc
new file mode 100644
index 0000000000..d3c8d5e4c7
--- /dev/null
+++ b/libs/pbd/base_ui.cc
@@ -0,0 +1,88 @@
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pbd/base_ui.h>
+#include <pbd/error.h>
+#include <pbd/compose.h>
+#include <pbd/failed_constructor.h>
+
+#include "i18n.h"
+
+using namespace std;
+using namespace PBD;
+
+uint32_t BaseUI::rt_bit = 1;
+BaseUI::RequestType BaseUI::CallSlot = BaseUI::new_request_type();
+
+BaseUI::BaseUI (string str, bool with_signal_pipe)
+ : _name (str)
+{
+ /* odd pseudo-singleton semantics */
+
+ base_ui_instance = this;
+
+ signal_pipe[0] = -1;
+ signal_pipe[1] = -1;
+
+ if (with_signal_pipe) {
+ if (setup_signal_pipe ()) {
+ throw failed_constructor ();
+ }
+ }
+}
+
+BaseUI::~BaseUI()
+{
+ if (signal_pipe[0] >= 0) {
+ close (signal_pipe[0]);
+ }
+
+ if (signal_pipe[1] >= 0) {
+ close (signal_pipe[1]);
+ }
+}
+
+BaseUI::RequestType
+BaseUI::new_request_type ()
+{
+ RequestType rt;
+
+ /* XXX catch out-of-range */
+
+ rt = RequestType (rt_bit);
+ rt_bit <<= 1;
+
+ return rt;
+}
+
+int
+BaseUI::setup_signal_pipe ()
+{
+ /* setup the pipe that other threads send us notifications/requests
+ through.
+ */
+
+ if (pipe (signal_pipe)) {
+ error << string_compose (_("%1-UI: cannot create error signal pipe (%2)"), _name, std::strerror (errno))
+ << endmsg;
+
+ return -1;
+ }
+
+ if (fcntl (signal_pipe[0], F_SETFL, O_NONBLOCK)) {
+ error << string_compose (_("%1-UI: cannot set O_NONBLOCK on signal read pipe (%2)"), _name, std::strerror (errno))
+ << endmsg;
+ return -1;
+ }
+
+ if (fcntl (signal_pipe[1], F_SETFL, O_NONBLOCK)) {
+ error << string_compose (_("%1-UI: cannot set O_NONBLOCK on signal write pipe (%2)"), _name, std::strerror (errno))
+ << endmsg;
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/libs/pbd/basename.cc b/libs/pbd/basename.cc
new file mode 100644
index 0000000000..a51e393b78
--- /dev/null
+++ b/libs/pbd/basename.cc
@@ -0,0 +1,20 @@
+#include <iostream>
+#include <string.h>
+#include <pbd/basename.h>
+
+
+// implement this using Glib::path_get_basename
+std::string
+PBD::basename_nosuffix (const std::string& str)
+{
+ std::string::size_type slash = str.find_last_of ('/');
+ std::string noslash;
+
+ if (slash == std::string::npos) {
+ noslash = str;
+ } else {
+ noslash = str.substr (slash+1);
+ }
+
+ return noslash.substr (0, noslash.find_last_of ('.'));
+}
diff --git a/libs/pbd/convert.cc b/libs/pbd/convert.cc
new file mode 100644
index 0000000000..60d39c91e2
--- /dev/null
+++ b/libs/pbd/convert.cc
@@ -0,0 +1,212 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <cmath>
+#include <stdint.h>
+
+#include "pbd/convert.h"
+
+#include "i18n.h"
+
+using std::string;
+using std::vector;
+
+namespace PBD {
+
+string
+short_version (string orig, string::size_type target_length)
+{
+ /* this tries to create a recognizable abbreviation
+ of "orig" by removing characters until we meet
+ a certain target length.
+
+ note that we deliberately leave digits in the result
+ without modification.
+ */
+
+
+ string::size_type pos;
+
+ /* remove white-space and punctuation, starting at end */
+
+ while (orig.length() > target_length) {
+ if ((pos = orig.find_last_of (_("\"\n\t ,<.>/?:;'[{}]~`!@#$%^&*()_-+="))) == string::npos) {
+ break;
+ }
+ orig.replace (pos, 1, "");
+ }
+
+ /* remove lower-case vowels, starting at end */
+
+ while (orig.length() > target_length) {
+ if ((pos = orig.find_last_of (_("aeiou"))) == string::npos) {
+ break;
+ }
+ orig.replace (pos, 1, "");
+ }
+
+ /* remove upper-case vowels, starting at end */
+
+ while (orig.length() > target_length) {
+ if ((pos = orig.find_last_of (_("AEIOU"))) == string::npos) {
+ break;
+ }
+ orig.replace (pos, 1, "");
+ }
+
+ /* remove lower-case consonants, starting at end */
+
+ while (orig.length() > target_length) {
+ if ((pos = orig.find_last_of (_("bcdfghjklmnpqrtvwxyz"))) == string::npos) {
+ break;
+ }
+ orig.replace (pos, 1, "");
+ }
+
+ /* remove upper-case consonants, starting at end */
+
+ while (orig.length() > target_length) {
+ if ((pos = orig.find_last_of (_("BCDFGHJKLMNPQRTVWXYZ"))) == string::npos) {
+ break;
+ }
+ orig.replace (pos, 1, "");
+ }
+
+ /* whatever the length is now, use it */
+
+ return orig;
+}
+
+int
+atoi (const string& s)
+{
+ return std::atoi (s.c_str());
+}
+
+double
+atof (const string& s)
+{
+ return std::atof (s.c_str());
+}
+
+vector<string>
+internationalize (const char **array)
+{
+ vector<string> v;
+
+ for (uint32_t i = 0; array[i]; ++i) {
+ v.push_back (_(array[i]));
+ }
+
+ return v;
+}
+
+static int32_t
+int_from_hex (char hic, char loc)
+{
+ int hi; /* hi byte */
+ int lo; /* low byte */
+
+ hi = (int) hic;
+
+ if( ('0'<=hi) && (hi<='9') ) {
+ hi -= '0';
+ } else if( ('a'<= hi) && (hi<= 'f') ) {
+ hi -= ('a'-10);
+ } else if( ('A'<=hi) && (hi<='F') ) {
+ hi -= ('A'-10);
+ }
+
+ lo = (int) loc;
+
+ if( ('0'<=lo) && (lo<='9') ) {
+ lo -= '0';
+ } else if( ('a'<=lo) && (lo<='f') ) {
+ lo -= ('a'-10);
+ } else if( ('A'<=lo) && (lo<='F') ) {
+ lo -= ('A'-10);
+ }
+
+ return lo + (16 * hi);
+}
+
+void
+url_decode (string& url)
+{
+ string::iterator last;
+ string::iterator next;
+
+ for (string::iterator i = url.begin(); i != url.end(); ++i) {
+ if ((*i) == '+') {
+ *i = ' ';
+ }
+ }
+
+ if (url.length() <= 3) {
+ return;
+ }
+
+ last = url.end();
+
+ --last; /* points at last char */
+ --last; /* points at last char - 1 */
+
+ for (string::iterator i = url.begin(); i != last; ) {
+
+ if (*i == '%') {
+
+ next = i;
+
+ url.erase (i);
+
+ i = next;
+ ++next;
+
+ if (isxdigit (*i) && isxdigit (*next)) {
+ /* replace first digit with char */
+ *i = int_from_hex (*i,*next);
+ ++i; /* points at 2nd of 2 digits */
+ url.erase (i);
+ }
+ } else {
+ ++i;
+ }
+ }
+}
+
+string
+length2string (const int32_t frames, const float sample_rate)
+{
+ int secs = (int) (frames / sample_rate);
+ int hrs = secs / 3600;
+ secs -= (hrs * 3600);
+ int mins = secs / 60;
+ secs -= (mins * 60);
+
+ int total_secs = (hrs * 3600) + (mins * 60) + secs;
+ int frames_remaining = (int) floor (frames - (total_secs * sample_rate));
+ float fractional_secs = (float) frames_remaining / sample_rate;
+
+ char duration_str[32];
+ sprintf (duration_str, "%02d:%02d:%05.2f", hrs, mins, (float) secs + fractional_secs);
+
+ return duration_str;
+}
+
+} // namespace PBD
diff --git a/libs/pbd/dmalloc.cc b/libs/pbd/dmalloc.cc
new file mode 100644
index 0000000000..0e730946c8
--- /dev/null
+++ b/libs/pbd/dmalloc.cc
@@ -0,0 +1,102 @@
+/*
+ * file that facilitates C++ program debugging.
+ *
+ * Copyright 1995 by Gray Watson
+ *
+ * This file is part of the dmalloc package.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * NON-COMMERCIAL purpose and without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies, and that the name of Gray Watson not be used in
+ * advertising or publicity pertaining to distribution of the document
+ * or software without specific, written prior permission.
+ *
+ * Please see the PERMISSIONS file or contact the author for information
+ * about commercial licenses.
+ *
+ * Gray Watson makes no representations about the suitability of the
+ * software described herein for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * The author may be contacted via http://www.letters.com/~gray/
+ *
+ * $Id$
+ */
+
+/*
+ * This file is used to effectively redirect new to the more familiar
+ * malloc and delete to the more familiar free so they can be debugged
+ * with the debug malloc library.. They also give the known error
+ * behavior, too.
+ *
+ * Compile and link this in with the C++ program you want to debug.
+ *
+ * NOTE: I am not a C++ hacker so feedback in the form of other hints
+ * and ideas for C++ users would be much appreciated.
+ */
+
+#ifdef DEBUG_MALLOC
+
+extern "C" {
+#include <stdlib.h>
+#include <dmalloc.h>
+#include "/usr/local/src/dmalloc-4.1.2/return.h"
+}
+
+/*
+ * An overload function for the C++ new.
+ */
+void *
+operator new(size_t size)
+{
+ char *file;
+ GET_RET_ADDR(file);
+
+ /* handle correct C++ semantics for an alloc of size 0 */
+
+ if (size == 0) size = 1;
+
+ return _malloc_leap(file, 0, size);
+}
+
+/*
+ * An overload function for the C++ new[].
+ */
+void *
+operator new[](size_t size)
+{
+ char *file;
+ GET_RET_ADDR(file);
+
+ /* handle correct C++ semantics for an alloc of size 0 */
+
+ if (size == 0) size = 1;
+
+ return _malloc_leap(file, 0, size);
+}
+
+/*
+ * An overload function for the C++ delete.
+ */
+void
+operator delete(void *pnt)
+{
+ char *file;
+ GET_RET_ADDR(file);
+ _free_leap(file, 0, pnt);
+}
+
+/*
+ * An overload function for the C++ delete[]. Thanks to Jens Krinke
+ * <j.krinke@gmx.de>
+ */
+void
+operator delete[](void *pnt)
+{
+ char *file;
+ GET_RET_ADDR(file);
+ _free_leap(file, 0, pnt);
+}
+
+#endif
diff --git a/libs/pbd/error.cc b/libs/pbd/error.cc
new file mode 100644
index 0000000000..a6f8fb7f8f
--- /dev/null
+++ b/libs/pbd/error.cc
@@ -0,0 +1,7 @@
+#include <pbd/error.h>
+
+Transmitter PBD::error (Transmitter::Error);
+Transmitter PBD::info (Transmitter::Info);
+Transmitter PBD::fatal (Transmitter::Fatal);
+Transmitter PBD::warning (Transmitter::Warning);
+
diff --git a/libs/pbd/gettext.h b/libs/pbd/gettext.h
new file mode 100644
index 0000000000..339c74ffe7
--- /dev/null
+++ b/libs/pbd/gettext.h
@@ -0,0 +1,82 @@
+/* Convenience header for conditional use of GNU <libintl.h>.
+ Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc.
+
+ This program 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, 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library 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. */
+
+#ifndef _LIBGETTEXT_H
+#define _LIBGETTEXT_H 1
+
+/* NLS can be disabled through the configure --disable-nls option. */
+#if ENABLE_NLS
+
+/* Get declarations of GNU message catalog functions. */
+# include <libintl.h>
+
+#else
+
+/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which
+ chokes if dcgettext is defined as a macro. So include it now, to make
+ later inclusions of <locale.h> a NOP. We don't include <libintl.h>
+ as well because people using "gettext.h" will not include <libintl.h>,
+ and also including <libintl.h> would fail on SunOS 4, whereas <locale.h>
+ is OK. */
+#if defined(__sun)
+# include <locale.h>
+#endif
+
+/* Disabled NLS.
+ The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions.
+ On pre-ANSI systems without 'const', the config.h file is supposed to
+ contain "#define const". */
+
+/* other headers may have included libintl.h */
+
+# undef gettext
+# undef dgettext
+# undef dcgettext
+# undef ngettext
+# undef dngettext
+# undef dcngettext
+# undef textdomain
+# undef bindtextdomain
+# undef bind_textdomain_codeset
+
+# define gettext(Msgid) ((const char *) (Msgid))
+# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
+# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
+# define ngettext(Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dngettext(Domainname, Msgid1, Msgid2, N) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
+ ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
+# define textdomain(Domainname) ((const char *) (Domainname))
+# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
+
+#endif
+
+/* A pseudo function call that serves as a marker for the automated
+ extraction of messages, but does not call gettext(). The run-time
+ translation is done at a different place in the code.
+ The argument, String, should be a literal string. Concatenated strings
+ and other string expressions won't work.
+ The macro's expansion is not parenthesized, so that it is suitable as
+ initializer for static 'char[]' or 'const char[]' variables. */
+#define gettext_noop(String) String
+
+#endif /* _LIBGETTEXT_H */
diff --git a/libs/pbd/i18n.h b/libs/pbd/i18n.h
new file mode 100644
index 0000000000..7c79d2eb53
--- /dev/null
+++ b/libs/pbd/i18n.h
@@ -0,0 +1,11 @@
+#ifndef __i18n_h__
+#define __i18n_h__
+
+#include <pbd/compose.h>
+#include "gettext.h"
+
+#define _(Text) dgettext (PACKAGE, Text)
+#define N_(Text) gettext_noop (Text)
+#define X_(Text) (Text)
+
+#endif // __i18n_h__
diff --git a/libs/pbd/libpbd.pc.in b/libs/pbd/libpbd.pc.in
new file mode 100644
index 0000000000..14d0208845
--- /dev/null
+++ b/libs/pbd/libpbd.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@/pbd
+
+Name: libpbd
+Version: @VERSION@
+Description: libpbd, a library of useful, generic C++ objects
+Requires:
+Libs: -L${libdir} -lpbd @NON_PKG_LIBS@
+Cflags: -I${includedir} @NON_PKG_CFLAGS@
diff --git a/libs/pbd/libpbd.spec.in b/libs/pbd/libpbd.spec.in
new file mode 100644
index 0000000000..d50622d638
--- /dev/null
+++ b/libs/pbd/libpbd.spec.in
@@ -0,0 +1,70 @@
+Summary: A general purpose programming library
+%define lib_name pbd
+Name: lib%{lib_name}
+Version: @VERSION@
+Release: 2
+Copyright: GPL
+Source: .
+Url: http://www.quasimodo.org
+Vendor: Paul Davis <paul@linuxaudiosystems.com>
+Packager: jfm3 <jfm3@acm.org>
+Group: System Environment/Libraries
+Prefix: %{_prefix}
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+
+This library implements a number of programming utilities used by Paul
+Davis (formerly Paul Barton-Davis, hence the name). It is used in
+some of his Open Source software projects. See
+http://ardour.sf.net/ for examples.
+
+%prep
+%setup -q
+
+%build
+CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure $ARCH_FLAGS --prefix=%{prefix}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d -m 755 $RPM_BUILD_ROOT%{prefix}/{{include,lib}/%{lib_name}}
+make install INSTALL="%(which install) -p" prefix=$RPM_BUILD_ROOT%{prefix}
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc README AUTHORS NEWS COPYING*
+%{prefix}/lib/libpbd.so*
+
+%package devel
+Summary: A general purpose programming library -- developer version.
+Group: System Environment/Libraries
+
+%description devel
+
+This library implements a number of programming utilities used by Paul
+Davis (formerly Paul Barton-Davis, hence the name). It is used in
+some of his Open Source software projects. See
+http://ardour.sf.net/ for examples.
+
+This package holds static libraries and headers needed by developers
+who wish to use libpbd in their programs.
+
+%files devel
+%defattr(-,root,root)
+%{prefix}/include/pbd/*
+%{prefix}/lib/libpbd.a
+%{prefix}/lib/libpbd.la
+%{prefix}/bin/pbd-config
+%{prefix}/share/aclocal/pbd.m4
+%{prefix}/share/aclocal/unique_args.m4
+
diff --git a/libs/pbd/mountpoint.cc b/libs/pbd/mountpoint.cc
new file mode 100644
index 0000000000..c1bcb375f3
--- /dev/null
+++ b/libs/pbd/mountpoint.cc
@@ -0,0 +1,158 @@
+/*
+ Copyright (C) 2002 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <cstdio>
+#include <string>
+#include <limits.h>
+
+#include <pbd/mountpoint.h>
+
+using std::string;
+
+#if HAVE_GETMNTENT
+#include <mntent.h>
+
+struct mntent_sorter {
+ bool operator() (const mntent *a, const mntent *b) {
+ return strcmp (a->mnt_dir, b->mnt_dir);
+ }
+};
+
+string
+mountpoint (string path)
+{
+ FILE *mntf;
+ mntent *mnt;
+ unsigned int maxmatch = 0;
+ unsigned int matchlen;
+ const char *cpath = path.c_str();
+ char best[PATH_MAX+1];
+
+ if ((mntf = setmntent ("/etc/mtab", "r")) == 0) {
+ return "";
+ }
+
+ best[0] = '\0';
+
+ while ((mnt = getmntent (mntf))) {
+ unsigned int n;
+
+ n = 0;
+ matchlen = 0;
+
+ /* note: strcmp's semantics are not
+ strict enough to use for this.
+ */
+
+ while (cpath[n] && mnt->mnt_dir[n]) {
+ if (cpath[n] != mnt->mnt_dir[n]) {
+ break;
+ }
+ matchlen++;
+ n++;
+ }
+
+ if (cpath[matchlen] == '\0') {
+
+ endmntent (mntf);
+ return mnt->mnt_dir;
+
+ } else {
+
+ if (matchlen > maxmatch) {
+ snprintf (best, sizeof(best), "%s", mnt->mnt_dir);
+ maxmatch = matchlen;
+ }
+ }
+ }
+
+ endmntent (mntf);
+
+ return best;
+}
+
+#else // !HAVE_GETMNTENT
+
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+
+string
+mountpoint (string path)
+{
+ struct statfs *mntbufp = 0;
+ int count;
+ unsigned int maxmatch = 0;
+ unsigned int matchlen;
+ const char *cpath = path.c_str();
+ char best[PATH_MAX+1];
+
+ if ((count = getmntinfo(&mntbufp, MNT_NOWAIT)) == 0) {
+ free(mntbufp);
+ return "\0";
+ }
+
+ best[0] = '\0';
+
+ for (int i = 0; i < count; ++i) {
+ unsigned int n = 0;
+ matchlen = 0;
+
+ /* note: strcmp's semantics are not
+ strict enough to use for this.
+ */
+
+ while (cpath[n] && mntbufp[i].f_mntonname[n]) {
+ if (cpath[n] != mntbufp[i].f_mntonname[n]) {
+ break;
+ }
+ matchlen++;
+ n++;
+ }
+
+ if (cpath[matchlen] == '\0') {
+ snprintf(best, sizeof(best), "%s", mntbufp[i].f_mntonname);
+ free(mntbufp);
+ return best;
+
+ } else {
+
+ if (matchlen > maxmatch) {
+ snprintf (best, sizeof(best), "%s", mntbufp[i].f_mntonname);
+ maxmatch = matchlen;
+ }
+ }
+ }
+
+ free(mntbufp);
+
+ return best;
+}
+#endif // HAVE_GETMNTENT
+
+#ifdef TEST_MOUNTPOINT
+
+main (int argc, char *argv[])
+{
+ printf ("mp of %s = %s\n", argv[1], mountpoint (argv[1]).c_str());
+ exit (0);
+}
+
+#endif // TEST_MOUNTPOINT
diff --git a/libs/pbd/path.cc b/libs/pbd/path.cc
new file mode 100644
index 0000000000..80f916c9ae
--- /dev/null
+++ b/libs/pbd/path.cc
@@ -0,0 +1,164 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <cerrno>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
+
+#include <pbd/path.h>
+#include <pbd/tokenizer.h>
+
+namespace PBD {
+
+Path::Path ()
+{
+
+}
+
+Path::Path (const string& path)
+{
+ vector<string> tmp;
+
+ if(!tokenize ( path, string(":;"), std::back_inserter (tmp))) {
+ g_warning ("%s : %s\n", G_STRLOC, G_STRFUNC);
+ return;
+ }
+
+ add_readable_directories (tmp);
+}
+
+Path::Path (const vector<string>& paths)
+{
+ add_readable_directories (paths);
+}
+
+Path::Path (const Path& other)
+ : m_dirs(other.m_dirs)
+{
+
+}
+
+bool
+Path::readable_directory (const string& directory_path)
+{
+ if (g_access (directory_path.c_str(), R_OK) == 0) {
+ if (Glib::file_test(directory_path, Glib::FILE_TEST_IS_DIR)) {
+ return true;
+ } else {
+ g_warning (" %s : Path exists but is not a directory\n", G_STRLOC);
+ }
+ } else {
+ g_warning ("%s : %s : %s\n", G_STRLOC, directory_path.c_str(), g_strerror(errno));
+ }
+ return false;
+}
+
+void
+Path::add_readable_directory (const string& directory_path)
+{
+ if(readable_directory(directory_path)) {
+ m_dirs.push_back(directory_path);
+ }
+}
+
+void
+Path::add_readable_directories (const vector<string>& paths)
+{
+ for(vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
+ add_readable_directory (*i);
+ }
+}
+
+const string
+Path::path_string() const
+{
+ string path;
+
+ for (vector<string>::const_iterator i = m_dirs.begin(); i != m_dirs.end(); ++i) {
+ path += (*i);
+ path += G_SEARCHPATH_SEPARATOR;
+ }
+
+ g_message ("%s : %s", G_STRLOC, path.c_str());
+
+ return path.substr (0, path.length() - 1); // drop final colon
+}
+
+const Path&
+Path::operator= (const Path& path)
+{
+ m_dirs = path.m_dirs;
+ return *this;
+}
+
+const Path&
+Path::operator+= (const string& directory_path)
+{
+ add_readable_directory (directory_path);
+ return *this;
+}
+
+const Path
+operator+ (const Path& lhs_path, const Path& rhs_path)
+{
+ Path tmp_path(lhs_path); // does this do what I think it does.
+ // concatenate paths into new Path
+ tmp_path.m_dirs.insert(tmp_path.m_dirs.end(), rhs_path.m_dirs.begin(), rhs_path.m_dirs.end());
+ return tmp_path;
+}
+
+Path&
+Path::add_subdirectory_to_path (const string& subdir)
+{
+ vector<string> tmp;
+ string directory_path;
+
+ for (vector<string>::iterator i = m_dirs.begin(); i != m_dirs.end(); ++i) {
+ directory_path = Glib::build_filename (*i, subdir);
+ if(readable_directory(directory_path)) {
+ tmp.push_back(directory_path);
+ }
+ }
+ m_dirs = tmp;
+ return *this;
+}
+
+bool
+find_file_in_path (const Path& path, const string& filename, string& resulting_path)
+{
+ for (vector<string>::const_iterator i = path.dirs().begin(); i != path.dirs().end(); ++i) {
+ resulting_path = Glib::build_filename ((*i), filename);
+ if (g_access (resulting_path.c_str(), R_OK) == 0) {
+ g_message ("File %s found in Path : %s\n", resulting_path.c_str(),
+ path.path_string().c_str());
+ return true;
+ }
+ }
+
+ g_warning ("%s : Could not locate file %s in path %s\n", G_STRLOC, filename.c_str(),
+ path.path_string().c_str());
+
+ return false;
+}
+
+} // namespace PBD
+
diff --git a/libs/pbd/pathscanner.cc b/libs/pbd/pathscanner.cc
new file mode 100644
index 0000000000..2af227a3a0
--- /dev/null
+++ b/libs/pbd/pathscanner.cc
@@ -0,0 +1,203 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <cstdlib>
+#include <cstdio>
+#include <vector>
+#include <dirent.h>
+
+#include <pbd/error.h>
+#include <pbd/pathscanner.h>
+#include <pbd/stl_delete.h>
+
+using namespace PBD;
+
+vector<string *> *
+PathScanner::operator() (const string &dirpath, const string &regexp,
+ bool match_fullpath, bool return_fullpath,
+ long limit)
+
+{
+ int err;
+ char msg[256];
+
+ if ((err = regcomp (&compiled_pattern, regexp.c_str(),
+ REG_EXTENDED|REG_NOSUB))) {
+
+ regerror (err, &compiled_pattern,
+ msg, sizeof (msg));
+
+ error << "Cannot compile soundfile regexp for use ("
+ << msg
+ << ")"
+ << endmsg;
+
+ return 0;
+ }
+
+ return run_scan (dirpath, &PathScanner::regexp_filter,
+ (bool (*)(const string &, void *)) 0,
+ 0,
+ match_fullpath,
+ return_fullpath,
+ limit);
+}
+
+vector<string *> *
+PathScanner::run_scan (const string &dirpath,
+ bool (PathScanner::*memberfilter)(const string &),
+ bool (*filter)(const string &, void *),
+ void *arg,
+ bool match_fullpath, bool return_fullpath,
+ long limit)
+
+{
+ vector<string *> *result = 0;
+ DIR *dir;
+ struct dirent *finfo;
+ char *pathcopy = strdup (dirpath.c_str());
+ char *thisdir;
+ char fullpath[PATH_MAX+1];
+ string search_str;
+ string *newstr;
+ long nfound = 0;
+
+ if ((thisdir = strtok (pathcopy, ":")) == 0 ||
+ strlen (thisdir) == 0) {
+ free (pathcopy);
+ return 0;
+ }
+
+ result = new vector<string *>;
+
+ do {
+
+ if ((dir = opendir (thisdir)) == 0) {
+ continue;
+ }
+
+ while ((finfo = readdir (dir)) != 0) {
+
+ snprintf (fullpath, sizeof(fullpath), "%s/%s",
+ thisdir, finfo->d_name);
+
+ if (match_fullpath) {
+ search_str = fullpath;
+ } else {
+ search_str = finfo->d_name;
+ }
+
+ /* handle either type of function ptr */
+
+ if (memberfilter) {
+ if (!(this->*memberfilter)(search_str)) {
+ continue;
+ }
+ } else {
+ if (!filter(search_str, arg)) {
+ continue;
+ }
+ }
+
+ if (return_fullpath) {
+ newstr = new string (fullpath);
+ } else {
+ newstr = new string (finfo->d_name);
+ }
+
+ result->push_back (newstr);
+ nfound++;
+ }
+
+ closedir (dir);
+
+ } while ((limit < 0 || (nfound < limit)) && (thisdir = strtok (0, ":")));
+
+ free (pathcopy);
+ return result;
+}
+
+string *
+PathScanner::find_first (const string &dirpath,
+ const string &regexp,
+ bool match_fullpath,
+ bool return_fullpath)
+{
+ vector<string *> *res;
+ string *ret;
+ int err;
+ char msg[256];
+
+ if ((err = regcomp (&compiled_pattern, regexp.c_str(),
+ REG_EXTENDED|REG_NOSUB))) {
+
+ regerror (err, &compiled_pattern,
+ msg, sizeof (msg));
+
+ error << "Cannot compile soundfile regexp for use (" << msg << ")" << endmsg;
+
+
+ return 0;
+ }
+
+ res = run_scan (dirpath,
+ &PathScanner::regexp_filter,
+ (bool (*)(const string &, void *)) 0,
+ 0,
+ match_fullpath,
+ return_fullpath,
+ 1);
+
+ if (res->size() == 0) {
+ ret = 0;
+ } else {
+ ret = res->front();
+ }
+ vector_delete (res);
+ delete res;
+ return ret;
+}
+
+string *
+PathScanner::find_first (const string &dirpath,
+ bool (*filter)(const string &, void *),
+ void *arg,
+ bool match_fullpath,
+ bool return_fullpath)
+{
+ vector<string *> *res;
+ string *ret;
+
+ res = run_scan (dirpath,
+ (bool (PathScanner::*)(const string &)) 0,
+ filter,
+ 0,
+ match_fullpath,
+ return_fullpath, 1);
+
+ if (res->size() == 0) {
+ ret = 0;
+ } else {
+ ret = res->front();
+ }
+ vector_delete (res);
+ delete res;
+ return ret;
+}
diff --git a/libs/pbd/pbd/.DS_Store b/libs/pbd/pbd/.DS_Store
new file mode 100644
index 0000000000..5008ddfcf5
--- /dev/null
+++ b/libs/pbd/pbd/.DS_Store
Binary files differ
diff --git a/libs/pbd/pbd/.cvsignore b/libs/pbd/pbd/.cvsignore
new file mode 100644
index 0000000000..67020331ba
--- /dev/null
+++ b/libs/pbd/pbd/.cvsignore
@@ -0,0 +1 @@
+version.h
diff --git a/libs/pbd/pbd/abstract_ui.cc b/libs/pbd/pbd/abstract_ui.cc
new file mode 100644
index 0000000000..0e34787a2d
--- /dev/null
+++ b/libs/pbd/pbd/abstract_ui.cc
@@ -0,0 +1,149 @@
+#include <unistd.h>
+
+#include <pbd/abstract_ui.h>
+#include <pbd/pthread_utils.h>
+#include <pbd/failed_constructor.h>
+
+template <typename RequestObject>
+AbstractUI<RequestObject>::AbstractUI (string name, bool with_signal_pipes)
+ : BaseUI (name, with_signal_pipes)
+{
+ if (pthread_key_create (&thread_request_buffer_key, 0)) {
+ cerr << _("cannot create thread request buffer key") << endl;
+ throw failed_constructor();
+ }
+
+ PBD::ThreadCreated.connect (mem_fun (*this, &AbstractUI<RequestObject>::register_thread));
+ PBD::ThreadCreatedWithRequestSize.connect (mem_fun (*this, &AbstractUI<RequestObject>::register_thread_with_request_count));
+}
+
+template <typename RequestObject> void
+AbstractUI<RequestObject>::register_thread (pthread_t thread_id, string name)
+{
+ register_thread_with_request_count (thread_id, name, 256);
+}
+
+template <typename RequestObject> void
+AbstractUI<RequestObject>::register_thread_with_request_count (pthread_t thread_id, string thread_name, uint32_t num_requests)
+{
+ RequestBuffer* b = new RequestBuffer (num_requests);
+
+ {
+ Glib::Mutex::Lock lm (request_buffer_map_lock);
+ request_buffers[thread_id] = b;
+ }
+
+ pthread_setspecific (thread_request_buffer_key, b);
+}
+
+template <typename RequestObject> RequestObject*
+AbstractUI<RequestObject>::get_request (RequestType rt)
+{
+ RequestBuffer* rbuf = static_cast<RequestBuffer*>(pthread_getspecific (thread_request_buffer_key));
+
+ if (rbuf == 0) {
+ /* Cannot happen, but if it does we can't use the error reporting mechanism */
+ cerr << _("programming error: ")
+ << string_compose (X_("no %1-UI request buffer found for thread %2"), name(), pthread_name())
+ << endl;
+ abort ();
+ }
+
+ RequestBufferVector vec;
+
+ rbuf->get_write_vector (&vec);
+
+ if (vec.len[0] == 0) {
+ if (vec.len[1] == 0) {
+ cerr << string_compose (X_("no space in %1-UI request buffer for thread %2"), name(), pthread_name())
+ << endl;
+ return 0;
+ } else {
+ vec.buf[1]->type = rt;
+ return vec.buf[1];
+ }
+ } else {
+ vec.buf[0]->type = rt;
+ return vec.buf[0];
+ }
+}
+
+template <typename RequestObject> void
+AbstractUI<RequestObject>::handle_ui_requests ()
+{
+ RequestBufferMapIterator i;
+
+ request_buffer_map_lock.lock ();
+
+ for (i = request_buffers.begin(); i != request_buffers.end(); ++i) {
+
+ RequestBufferVector vec;
+
+ while (true) {
+
+ /* we must process requests 1 by 1 because
+ the request may run a recursive main
+ event loop that will itself call
+ handle_ui_requests. when we return
+ from the request handler, we cannot
+ expect that the state of queued requests
+ is even remotely consistent with
+ the condition before we called it.
+ */
+
+ i->second->get_read_vector (&vec);
+
+ if (vec.len[0] == 0) {
+ break;
+ } else {
+ /* request_factory/copy constructor does a deep
+ copy of the Request object,
+ unlike Ringbuffer::read()
+ */
+
+ RequestObject req (*vec.buf[0]);
+ i->second->increment_read_ptr (1);
+ request_buffer_map_lock.unlock ();
+ do_request (&req);
+ request_buffer_map_lock.lock ();
+ }
+ }
+ }
+
+ request_buffer_map_lock.unlock ();
+}
+
+template <typename RequestObject> void
+AbstractUI<RequestObject>::send_request (RequestObject *req)
+{
+ if (base_instance() == 0) {
+ return; /* XXX is this the right thing to do ? */
+ }
+
+ if (caller_is_ui_thread()) {
+ // cerr << "GUI thread sent request " << req << " type = " << req->type << endl;
+ do_request (req);
+ } else {
+ RequestBuffer* rbuf = static_cast<RequestBuffer*> (pthread_getspecific (thread_request_buffer_key));
+
+ if (rbuf == 0) {
+ /* can't use the error system to report this, because this
+ thread isn't registered!
+ */
+ cerr << _("programming error: ")
+ << string_compose (X_("AbstractUI::send_request() called from %1, but no request buffer exists for that thread"), pthread_name())
+ << endl;
+ abort ();
+ }
+
+ // cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl;
+
+ rbuf->increment_write_ptr (1);
+
+ if (signal_pipe[1] >= 0) {
+ const char c = 0;
+ write (signal_pipe[1], &c, 1);
+ }
+ }
+}
+
diff --git a/libs/pbd/pbd/abstract_ui.h b/libs/pbd/pbd/abstract_ui.h
new file mode 100644
index 0000000000..f80db7bf1a
--- /dev/null
+++ b/libs/pbd/pbd/abstract_ui.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __pbd_abstract_ui_h__
+#define __pbd_abstract_ui_h__
+
+#include <map>
+#include <string>
+#include <pthread.h>
+
+#include <sigc++/sigc++.h>
+
+#include <glibmm/thread.h>
+
+#include <pbd/receiver.h>
+#include <pbd/ringbufferNPT.h>
+#include <pbd/base_ui.h>
+
+class Touchable;
+
+template <class RequestObject>
+class AbstractUI : public BaseUI
+{
+ public:
+ AbstractUI (std::string name, bool with_signal_pipe);
+ virtual ~AbstractUI() {}
+
+ virtual bool caller_is_ui_thread() = 0;
+
+ void call_slot (sigc::slot<void> el_slot) {
+ RequestObject *req = get_request (BaseUI::CallSlot);
+
+ if (req == 0) {
+ return;
+ }
+
+ req->slot = el_slot;
+ send_request (req);
+ }
+
+ void register_thread (pthread_t, std::string);
+ void register_thread_with_request_count (pthread_t, std::string, uint32_t num_requests);
+
+ protected:
+ typedef RingBufferNPT<RequestObject> RequestBuffer;
+ typedef typename RequestBuffer::rw_vector RequestBufferVector;
+ typedef typename std::map<pthread_t,RequestBuffer*>::iterator RequestBufferMapIterator;
+
+ Glib::Mutex request_buffer_map_lock;
+ typedef std::map<pthread_t,RequestBuffer*> RequestBufferMap;
+ RequestBufferMap request_buffers;
+ pthread_key_t thread_request_buffer_key;
+ RequestObject* get_request (RequestType);
+ void handle_ui_requests ();
+ void send_request (RequestObject *);
+
+ virtual void do_request (RequestObject *) = 0;
+};
+
+#endif /* __pbd_abstract_ui_h__ */
+
+
diff --git a/libs/pbd/pbd/base_ui.h b/libs/pbd/pbd/base_ui.h
new file mode 100644
index 0000000000..b4570f8707
--- /dev/null
+++ b/libs/pbd/pbd/base_ui.h
@@ -0,0 +1,46 @@
+#ifndef __pbd_base_ui_h__
+#define __pbd_base_ui_h__
+
+#include <string>
+#include <stdint.h>
+
+#include <sigc++/slot.h>
+#include <sigc++/trackable.h>
+
+class BaseUI : virtual public sigc::trackable {
+ public:
+ BaseUI (std::string name, bool with_signal_pipes);
+ virtual ~BaseUI();
+
+ BaseUI* base_instance() { return base_ui_instance; }
+
+ std::string name() const { return _name; }
+
+ bool ok() const { return _ok; }
+
+ enum RequestType {
+ range_guarantee = ~0
+ };
+
+ struct BaseRequestObject {
+ RequestType type;
+ sigc::slot<void> the_slot;
+ };
+
+ static RequestType new_request_type();
+ static RequestType CallSlot;
+
+ protected:
+ int signal_pipe[2];
+ bool _ok;
+
+ private:
+ std::string _name;
+ BaseUI* base_ui_instance;
+
+ static uint32_t rt_bit;
+
+ int setup_signal_pipe ();
+};
+
+#endif /* __pbd_base_ui_h__ */
diff --git a/libs/pbd/pbd/basename.h b/libs/pbd/pbd/basename.h
new file mode 100644
index 0000000000..35aebe166c
--- /dev/null
+++ b/libs/pbd/pbd/basename.h
@@ -0,0 +1,13 @@
+#ifndef __stupid_basename_h__
+#define __stupid_basename_h__
+
+#include <string>
+
+namespace PBD
+{
+
+extern std::string basename_nosuffix (const std::string&);
+
+};
+
+#endif // __stupid_basename_h__
diff --git a/libs/pbd/pbd/compose.h b/libs/pbd/pbd/compose.h
new file mode 100644
index 0000000000..0df9519aaf
--- /dev/null
+++ b/libs/pbd/pbd/compose.h
@@ -0,0 +1,393 @@
+/* Defines String::compose(fmt, arg...) for easy, i18n-friendly
+ * composition of strings.
+ *
+ * Version 1.0.
+ *
+ * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+//
+// Basic usage is like
+//
+// std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
+//
+// See http://www.cs.auc.dk/~olau/compose/ or the included README.compose for
+// more details.
+//
+
+#ifndef STRING_COMPOSE_H
+#define STRING_COMPOSE_H
+
+#include <sstream>
+#include <string>
+#include <list>
+#include <map> // for multimap
+
+namespace StringPrivate
+{
+ // the actual composition class - using string::compose is cleaner, so we
+ // hide it here
+ class Composition
+ {
+ public:
+ // initialize and prepare format string on the form "text %1 text %2 etc."
+ explicit Composition(std::string fmt);
+
+ // supply an replacement argument starting from %1
+ template <typename T>
+ Composition &arg(const T &obj);
+
+ // compose and return string
+ std::string str() const;
+
+ private:
+ std::ostringstream os;
+ int arg_no;
+
+ // we store the output as a list - when the output string is requested, the
+ // list is concatenated to a string; this way we can keep iterators into
+ // the list instead of into a string where they're possibly invalidated on
+ // inserting a specification string
+ typedef std::list<std::string> output_list;
+ output_list output;
+
+ // the initial parse of the format string fills in the specification map
+ // with positions for each of the various %?s
+ typedef std::multimap<int, output_list::iterator> specification_map;
+ specification_map specs;
+ };
+
+ // helper for converting spec string numbers
+ inline int char_to_int(char c)
+ {
+ switch (c) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ default: return -1000;
+ }
+ }
+
+ inline bool is_number(int n)
+ {
+ switch (n) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+
+ // implementation of class Composition
+ template <typename T>
+ inline Composition &Composition::arg(const T &obj)
+ {
+ os << obj;
+
+ std::string rep = os.str();
+
+ if (!rep.empty()) { // manipulators don't produce output
+ for (specification_map::const_iterator i = specs.lower_bound(arg_no),
+ end = specs.upper_bound(arg_no); i != end; ++i) {
+ output_list::iterator pos = i->second;
+ ++pos;
+
+ output.insert(pos, rep);
+ }
+
+ os.str(std::string());
+ //os.clear();
+ ++arg_no;
+ }
+
+ return *this;
+ }
+
+ inline Composition::Composition(std::string fmt)
+ : arg_no(1)
+ {
+ std::string::size_type b = 0, i = 0;
+
+ // fill in output with the strings between the %1 %2 %3 etc. and
+ // fill in specs with the positions
+ while (i < fmt.length()) {
+ if (fmt[i] == '%' && i + 1 < fmt.length()) {
+ if (fmt[i + 1] == '%') { // catch %%
+ fmt.replace(i, 2, "%");
+ ++i;
+ }
+ else if (is_number(fmt[i + 1])) { // aha! a spec!
+ // save string
+ output.push_back(fmt.substr(b, i - b));
+
+ int n = 1; // number of digits
+ int spec_no = 0;
+
+ do {
+ spec_no += char_to_int(fmt[i + n]);
+ spec_no *= 10;
+ ++n;
+ } while (i + n < fmt.length() && is_number(fmt[i + n]));
+
+ spec_no /= 10;
+ output_list::iterator pos = output.end();
+ --pos; // safe since we have just inserted a string>
+
+ specs.insert(specification_map::value_type(spec_no, pos));
+
+ // jump over spec string
+ i += n;
+ b = i;
+ }
+ else
+ ++i;
+ }
+ else
+ ++i;
+ }
+
+ if (i - b > 0) // add the rest of the string
+ output.push_back(fmt.substr(b, i - b));
+ }
+
+ inline std::string Composition::str() const
+ {
+ // assemble string
+ std::string str;
+
+ for (output_list::const_iterator i = output.begin(), end = output.end();
+ i != end; ++i)
+ str += *i;
+
+ return str;
+ }
+}
+
+// now for the real thing(s)
+//namespace PBD
+//{
+ // a series of functions which accept a format string on the form "text %1
+ // more %2 less %3" and a number of templated parameters and spits out the
+ // composited string
+ template <typename T1>
+ inline std::string string_compose(const std::string &fmt, const T1 &o1)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1);
+ return c.str();
+ }
+
+ template <typename T1, typename T2>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9,
+ const T10 &o10)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
+ .arg(o10);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9,
+ const T10 &o10, const T11 &o11)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
+ .arg(o10).arg(o11);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9,
+ const T10 &o10, const T11 &o11, const T12 &o12)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
+ .arg(o10).arg(o11).arg(o12);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9,
+ const T10 &o10, const T11 &o11, const T12 &o12,
+ const T13 &o13)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
+ .arg(o10).arg(o11).arg(o12).arg(o13);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9,
+ const T10 &o10, const T11 &o11, const T12 &o12,
+ const T13 &o13, const T14 &o14)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
+ .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
+ return c.str();
+ }
+
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14,
+ typename T15>
+ inline std::string string_compose(const std::string &fmt,
+ const T1 &o1, const T2 &o2, const T3 &o3,
+ const T4 &o4, const T5 &o5, const T6 &o6,
+ const T7 &o7, const T8 &o8, const T9 &o9,
+ const T10 &o10, const T11 &o11, const T12 &o12,
+ const T13 &o13, const T14 &o14, const T15 &o15)
+ {
+ StringPrivate::Composition c(fmt);
+ c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
+ .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
+ return c.str();
+ }
+//}
+
+
+#endif // STRING_COMPOSE_H
diff --git a/libs/pbd/pbd/convert.h b/libs/pbd/pbd/convert.h
new file mode 100644
index 0000000000..12e63ba6fc
--- /dev/null
+++ b/libs/pbd/pbd/convert.h
@@ -0,0 +1,40 @@
+/*
+ Copyright (C) 2002 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __pbd_convert_h__
+#define __pbd_convert_h__
+
+#include <string>
+#include <vector>
+
+namespace PBD {
+
+std::string short_version (std::string, std::string::size_type target_length);
+
+int atoi (const std::string&);
+double atof (const std::string&);
+void url_decode (std::string&);
+
+std::string length2string (const int32_t frames, const float sample_rate);
+
+std::vector<std::string> internationalize (const char **);
+
+} //namespace PBD
+
+#endif /* __pbd_convert_h__ */
diff --git a/libs/pbd/pbd/error.h b/libs/pbd/pbd/error.h
new file mode 100644
index 0000000000..4136f02ee2
--- /dev/null
+++ b/libs/pbd/pbd/error.h
@@ -0,0 +1,32 @@
+/*
+ Copyright (C) 1998-2006 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+#ifndef __libpbd_error_h__
+#define __libpbd_error_h__
+
+#include "transmitter.h"
+
+namespace PBD {
+ extern Transmitter error;
+ extern Transmitter info;
+ extern Transmitter warning;
+ extern Transmitter fatal;
+}
+
+#endif // __libpbd_error_h__
diff --git a/libs/pbd/pbd/failed_constructor.h b/libs/pbd/pbd/failed_constructor.h
new file mode 100644
index 0000000000..62eb6c0d71
--- /dev/null
+++ b/libs/pbd/pbd/failed_constructor.h
@@ -0,0 +1,11 @@
+#ifndef __pbd_failed_constructor_h__
+#define __pbd_failed_constructor_h__
+
+#include <exception>
+
+class failed_constructor : public std::exception {
+ public:
+ virtual const char *what() const throw() { return "failed constructor"; }
+};
+
+#endif /* __pbd_failed_constructor_h__ */
diff --git a/libs/pbd/pbd/fastlog.h b/libs/pbd/pbd/fastlog.h
new file mode 100644
index 0000000000..4269705a44
--- /dev/null
+++ b/libs/pbd/pbd/fastlog.h
@@ -0,0 +1,40 @@
+/* Copyright unknown. Code by Laurent de Soras <laurent@ohmforce.com>.
+ */
+
+#ifndef __pbd_fastlog_h__
+#define __pbd_fastlog_h__
+
+#include <math.h> /* for HUGE_VAL */
+
+static inline float fast_log2 (float val)
+{
+ /* don't use reinterpret_cast<> because that prevents this
+ from being used by pure C code (for example, GnomeCanvasItems)
+ */
+ union {float f; int i;} t;
+ t.f = val;
+ int * const exp_ptr = &t.i;
+ int x = *exp_ptr;
+ const int log_2 = ((x >> 23) & 255) - 128;
+ x &= ~(255 << 23);
+ x += 127 << 23;
+ *exp_ptr = x;
+
+ val = ((-1.0f/3) * t.f + 2) * t.f - 2.0f/3;
+
+ return (val + log_2);
+}
+
+static inline float fast_log (const float val)
+{
+ return (fast_log2 (val) * 0.69314718f);
+}
+
+static inline float fast_log10 (const float val)
+{
+ return fast_log2(val) / 3.312500f;
+}
+
+static inline float minus_infinity() { return -HUGE_VAL; }
+
+#endif /* __pbd_fastlog_h__ */
diff --git a/libs/pbd/pbd/forkexec.h b/libs/pbd/pbd/forkexec.h
new file mode 100644
index 0000000000..2af3711390
--- /dev/null
+++ b/libs/pbd/pbd/forkexec.h
@@ -0,0 +1,9 @@
+#ifndef __forkexec_h__
+#define __forkexec_h__
+
+#include <unistd.h>
+
+pid_t forkexec(char **argv, char **envp, int outpipe[2], int inpipe[2]);
+pid_t forkexec_cmd(char *cmd, char **envp, int outpipe[2], int inpipe[2]);
+
+#endif // __forkexec_h__
diff --git a/libs/pbd/pbd/mathfix.h b/libs/pbd/pbd/mathfix.h
new file mode 100644
index 0000000000..f0dc7e491e
--- /dev/null
+++ b/libs/pbd/pbd/mathfix.h
@@ -0,0 +1,34 @@
+/*
+ Copyright (C) 2005 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __pbd_mathfix_h__
+#define __pbd_mathfix_h__
+
+/* this is necessary to support older releases of OSX where
+ they moved around some of the standard math functions
+*/
+
+#ifdef __APPLE__
+#define powf pow
+#define sqrtf sqrt
+#endif
+
+
+#endif
diff --git a/libs/pbd/pbd/mountpoint.h b/libs/pbd/pbd/mountpoint.h
new file mode 100644
index 0000000000..86ccc58190
--- /dev/null
+++ b/libs/pbd/pbd/mountpoint.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __pbd_mountpoint_h__
+#define __pbd_mountpoint_h__
+
+#include <string>
+
+std::string mountpoint (std::string path);
+
+#endif // __pbd_mountpoint_h__
diff --git a/libs/pbd/pbd/path.h b/libs/pbd/pbd/path.h
new file mode 100644
index 0000000000..0b77a7c237
--- /dev/null
+++ b/libs/pbd/pbd/path.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PBD_PATH
+#define PBD_PATH
+
+#include <string>
+#include <vector>
+
+namespace PBD {
+
+using std::string;
+using std::vector;
+
+/**
+ The Path class is a helper class for getting a vector of absolute
+ paths contained in a path string where a path string contains
+ absolute directory paths separated by a colon(:) or a semi-colon(;)
+ on windows.
+ */
+class Path {
+public:
+
+ /**
+ Create an empty Path.
+ */
+ Path ();
+
+ /**
+ Initialize Path from a string, each absolute path contained
+ in the "path" will be accessed to ensure it exists and is
+ readable.
+ \param path A path string.
+ */
+ Path (const string& path);
+
+ /**
+ Initialize Path from a vector of path strings, each absolute
+ path contained in paths will be accessed to ensure it
+ exists and is readable.
+ \param path A path string.
+ */
+ Path (const vector<string>& paths);
+
+ Path(const Path& path);
+
+ /**
+ Indicate whether there are any directories in m_dirs, if Path is
+ initialized with an empty string as the result of for instance
+ calling Glib::getenv where the environment variable doesn't
+ exist or if none of the directories in the path string are
+ accessible then false is returned.
+
+ \return true if there are any paths in m_paths.
+ */
+ //operator bool () const { return !m_dirs.empty(); }
+
+ /**
+ \return vector containing the absolute paths to the directories
+ contained
+ */
+ operator const vector<string>& () const { return m_dirs; }
+
+ /**
+ \return vector containing the absolute paths to the directories
+ contained
+ */
+ const vector<string>& dirs () const { return m_dirs; }
+
+ const string path_string() const;
+
+ const Path& operator= (const Path& path);
+
+ const Path& operator+= (const string& directory_path);
+
+ Path& add_subdirectory_to_path (const string& subdirectory);
+
+protected:
+
+ friend const Path operator+ (const Path&, const Path&);
+
+ bool readable_directory (const string& directory_path);
+
+ void add_readable_directory (const string& directory_path);
+
+ void add_readable_directories (const vector<string>& paths);
+
+ vector<string> m_dirs;
+
+};
+
+bool find_file_in_path (const Path& path, const string& filename, string& resulting_path_to_file);
+
+} // namespace PBD
+
+#endif // PBD_PATH
+
+
diff --git a/libs/pbd/pbd/pathscanner.h b/libs/pbd/pbd/pathscanner.h
new file mode 100644
index 0000000000..346e7858c4
--- /dev/null
+++ b/libs/pbd/pbd/pathscanner.h
@@ -0,0 +1,66 @@
+#ifndef __libmisc_pathscanner_h__
+#define __libmisc_pathscanner_h__
+
+#include <vector>
+#include <string>
+#include <regex.h>
+
+using std::string;
+using std::vector;
+
+class PathScanner
+
+{
+ public:
+ vector<string *> *operator() (const string &dirpath,
+ bool (*filter)(const string &, void *arg),
+ void *arg,
+ bool match_fullpath = true,
+ bool return_fullpath = true,
+ long limit = -1) {
+ return run_scan (dirpath,
+ (bool (PathScanner::*)(const string &)) 0,
+ filter,
+ arg,
+ match_fullpath,
+ return_fullpath,
+ limit);
+ }
+
+ vector<string *> *operator() (const string &dirpath,
+ const string &regexp,
+ bool match_fullpath = true,
+ bool return_fullpath = true,
+ long limit = -1);
+
+
+ string *find_first (const string &dirpath,
+ const string &regexp,
+ bool match_fullpath = true,
+ bool return_fullpath = true);
+
+ string *find_first (const string &dirpath,
+ bool (*filter)(const string &, void *),
+ void *arg,
+ bool match_fullpath = true,
+ bool return_fullpath = true);
+
+ private:
+ regex_t compiled_pattern;
+
+ bool regexp_filter (const string &str) {
+ return regexec (&compiled_pattern, str.c_str(), 0, 0, 0) == 0;
+ }
+
+ vector<string *> *run_scan (const string &dirpath,
+ bool (PathScanner::*mfilter) (const string &),
+ bool (*filter)(const string &, void *),
+ void *arg,
+ bool match_fullpath,
+ bool return_fullpath,
+ long limit);
+
+
+};
+
+#endif // __libmisc_pathscanner_h__
diff --git a/libs/pbd/pbd/pool.h b/libs/pbd/pbd/pool.h
new file mode 100644
index 0000000000..f8e19e72fb
--- /dev/null
+++ b/libs/pbd/pbd/pool.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __qm_pool_h__
+#define __qm_pool_h__
+
+#include <vector>
+#include <string>
+
+#include <glibmm/thread.h>
+
+#include <pbd/ringbuffer.h>
+
+class Pool
+{
+ public:
+ Pool (std::string name, unsigned long item_size, unsigned long nitems);
+ virtual ~Pool ();
+
+ virtual void *alloc ();
+ virtual void release (void *);
+
+ std::string name() const { return _name; }
+
+ private:
+ RingBuffer<void*>* free_list;
+ std::string _name;
+ void *block;
+};
+
+class SingleAllocMultiReleasePool : public Pool
+{
+ public:
+ SingleAllocMultiReleasePool (std::string name, unsigned long item_size, unsigned long nitems);
+ ~SingleAllocMultiReleasePool ();
+
+ virtual void *alloc ();
+ virtual void release (void *);
+
+ private:
+ Glib::Mutex* m_lock;
+};
+
+
+class MultiAllocSingleReleasePool : public Pool
+{
+ public:
+ MultiAllocSingleReleasePool (std::string name, unsigned long item_size, unsigned long nitems);
+ ~MultiAllocSingleReleasePool ();
+
+ virtual void *alloc ();
+ virtual void release (void *);
+
+ private:
+ Glib::Mutex* m_lock;
+};
+
+#endif // __qm_pool_h__
diff --git a/libs/pbd/pbd/pthread_utils.h b/libs/pbd/pbd/pthread_utils.h
new file mode 100644
index 0000000000..482b5b54cf
--- /dev/null
+++ b/libs/pbd/pbd/pthread_utils.h
@@ -0,0 +1,23 @@
+#ifndef __pbd_pthread_utils__
+#define __pbd_pthread_utils__
+
+#include <pthread.h>
+#include <signal.h>
+#include <string>
+#include <stdint.h>
+
+#include <sigc++/sigc++.h>
+
+int pthread_create_and_store (std::string name, pthread_t *thread, pthread_attr_t *attr, void * (*start_routine)(void *), void * arg);
+void pthread_cancel_one (pthread_t thread);
+void pthread_kill_all (int signum);
+void pthread_cancel_all ();
+void pthread_exit_pbd (void* status);
+std::string pthread_name ();
+
+namespace PBD {
+ extern sigc::signal<void,pthread_t,std::string> ThreadCreated;
+ extern sigc::signal<void,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
+}
+
+#endif /* __pbd_pthread_utils__ */
diff --git a/libs/pbd/pbd/receiver.h b/libs/pbd/pbd/receiver.h
new file mode 100644
index 0000000000..5ce238df63
--- /dev/null
+++ b/libs/pbd/pbd/receiver.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __libmisc_receiver_h__
+#define __libmisc_receiver_h__
+
+#include <vector>
+
+#include <sigc++/sigc++.h>
+
+#include "transmitter.h"
+
+using std::vector;
+
+class strstream;
+
+class Receiver : virtual public sigc::trackable
+{
+ public:
+ Receiver ();
+ virtual ~Receiver ();
+
+ void listen_to (Transmitter &);
+ void hangup ();
+
+ protected:
+ virtual void receive (Transmitter::Channel, const char *) = 0;
+
+ private:
+ vector<sigc::connection *> connections;
+};
+
+#endif // __libmisc_receiver_h__
diff --git a/libs/pbd/pbd/restartable_rw.h b/libs/pbd/pbd/restartable_rw.h
new file mode 100644
index 0000000000..ee84e4e295
--- /dev/null
+++ b/libs/pbd/pbd/restartable_rw.h
@@ -0,0 +1,7 @@
+#ifndef __libmisc_restartable_rw__h__
+#define __libmisc_restartable_rw__h__
+
+extern int restartable_write (int fd, unsigned char *buf, size_t cnt);
+extern int restartable_read (int fd, unsigned char *buf, size_t cnt);
+
+#endif // __libmisc_restartable_rw__h__
diff --git a/libs/pbd/pbd/ringbuffer.h b/libs/pbd/pbd/ringbuffer.h
new file mode 100644
index 0000000000..1d9c9b04e3
--- /dev/null
+++ b/libs/pbd/pbd/ringbuffer.h
@@ -0,0 +1,284 @@
+/*
+ Copyright (C) 2000 Paul Davis & Benno Senoner
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef ringbuffer_h
+#define ringbuffer_h
+
+//#include <sys/mman.h>
+
+#include <glib.h>
+
+template<class T>
+class RingBuffer
+{
+ public:
+ RingBuffer (size_t sz) {
+ size_t power_of_two;
+
+ for (power_of_two = 1; 1U<<power_of_two < sz; power_of_two++);
+
+ size = 1<<power_of_two;
+ size_mask = size;
+ size_mask -= 1;
+ buf = new T[size];
+ reset ();
+
+ };
+
+ virtual ~RingBuffer() {
+ delete [] buf;
+ }
+
+ void reset () {
+ /* !!! NOT THREAD SAFE !!! */
+ g_atomic_int_set (&write_ptr, 0);
+ g_atomic_int_set (&read_ptr, 0);
+ }
+
+ void set (size_t r, size_t w) {
+ /* !!! NOT THREAD SAFE !!! */
+ g_atomic_int_set (&write_ptr, w);
+ g_atomic_int_set (&read_ptr, r);
+ }
+
+ size_t read (T *dest, size_t cnt);
+ size_t write (T *src, size_t cnt);
+
+ struct rw_vector {
+ T *buf[2];
+ size_t len[2];
+ };
+
+ void get_read_vector (rw_vector *);
+ void get_write_vector (rw_vector *);
+
+ void decrement_read_ptr (size_t cnt) {
+ g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) - cnt) & size_mask);
+ }
+
+ void increment_read_ptr (size_t cnt) {
+ g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) + cnt) & size_mask);
+ }
+
+ void increment_write_ptr (size_t cnt) {
+ g_atomic_int_set (&write_ptr, (g_atomic_int_get(&write_ptr) + cnt) & size_mask);
+ }
+
+ size_t write_space () {
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ return ((r - w + size) & size_mask) - 1;
+ } else if (w < r) {
+ return (r - w) - 1;
+ } else {
+ return size - 1;
+ }
+ }
+
+ size_t read_space () {
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ return w - r;
+ } else {
+ return (w - r + size) & size_mask;
+ }
+ }
+
+ T *buffer () { return buf; }
+ size_t get_write_ptr () const { return g_atomic_int_get (&write_ptr); }
+ size_t get_read_ptr () const { return g_atomic_int_get (&read_ptr); }
+ size_t bufsize () const { return size; }
+
+ protected:
+ T *buf;
+ size_t size;
+ mutable gint write_ptr;
+ mutable gint read_ptr;
+ size_t size_mask;
+};
+
+template<class T> size_t
+RingBuffer<T>::read (T *dest, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_read;
+ size_t n1, n2;
+ size_t priv_read_ptr;
+
+ priv_read_ptr=g_atomic_int_get(&read_ptr);
+
+ if ((free_cnt = read_space ()) == 0) {
+ return 0;
+ }
+
+ to_read = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = priv_read_ptr + to_read;
+
+ if (cnt2 > size) {
+ n1 = size - priv_read_ptr;
+ n2 = cnt2 & size_mask;
+ } else {
+ n1 = to_read;
+ n2 = 0;
+ }
+
+ memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));
+ priv_read_ptr = (priv_read_ptr + n1) & size_mask;
+
+ if (n2) {
+ memcpy (dest+n1, buf, n2 * sizeof (T));
+ priv_read_ptr = n2;
+ }
+
+ g_atomic_int_set(&read_ptr, priv_read_ptr);
+ return to_read;
+}
+
+template<class T> size_t
+RingBuffer<T>::write (T *src, size_t cnt)
+
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_write;
+ size_t n1, n2;
+ size_t priv_write_ptr;
+
+ priv_write_ptr=g_atomic_int_get(&write_ptr);
+
+ if ((free_cnt = write_space ()) == 0) {
+ return 0;
+ }
+
+ to_write = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = priv_write_ptr + to_write;
+
+ if (cnt2 > size) {
+ n1 = size - priv_write_ptr;
+ n2 = cnt2 & size_mask;
+ } else {
+ n1 = to_write;
+ n2 = 0;
+ }
+
+ memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));
+ priv_write_ptr = (priv_write_ptr + n1) & size_mask;
+
+ if (n2) {
+ memcpy (buf, src+n1, n2 * sizeof (T));
+ priv_write_ptr = n2;
+ }
+
+ g_atomic_int_set(&write_ptr, priv_write_ptr);
+ return to_write;
+}
+
+template<class T> void
+RingBuffer<T>::get_read_vector (RingBuffer<T>::rw_vector *vec)
+
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ free_cnt = w - r;
+ } else {
+ free_cnt = (w - r + size) & size_mask;
+ }
+
+ cnt2 = r + free_cnt;
+
+ if (cnt2 > size) {
+ /* Two part vector: the rest of the buffer after the
+ current write ptr, plus some from the start of
+ the buffer.
+ */
+
+ vec->buf[0] = &buf[r];
+ vec->len[0] = size - r;
+ vec->buf[1] = buf;
+ vec->len[1] = cnt2 & size_mask;
+
+ } else {
+
+ /* Single part vector: just the rest of the buffer */
+
+ vec->buf[0] = &buf[r];
+ vec->len[0] = free_cnt;
+ vec->len[1] = 0;
+ }
+}
+
+template<class T> void
+RingBuffer<T>::get_write_vector (RingBuffer<T>::rw_vector *vec)
+
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ free_cnt = ((r - w + size) & size_mask) - 1;
+ } else if (w < r) {
+ free_cnt = (r - w) - 1;
+ } else {
+ free_cnt = size - 1;
+ }
+
+ cnt2 = w + free_cnt;
+
+ if (cnt2 > size) {
+
+ /* Two part vector: the rest of the buffer after the
+ current write ptr, plus some from the start of
+ the buffer.
+ */
+
+ vec->buf[0] = &buf[w];
+ vec->len[0] = size - w;
+ vec->buf[1] = buf;
+ vec->len[1] = cnt2 & size_mask;
+ } else {
+ vec->buf[0] = &buf[w];
+ vec->len[0] = free_cnt;
+ vec->len[1] = 0;
+ }
+}
+
+
+#endif /* __ringbuffer_h__ */
diff --git a/libs/pbd/pbd/ringbufferNPT.h b/libs/pbd/pbd/ringbufferNPT.h
new file mode 100644
index 0000000000..fee2efce3d
--- /dev/null
+++ b/libs/pbd/pbd/ringbufferNPT.h
@@ -0,0 +1,275 @@
+/*
+ Copyright (C) 2000 Paul Davis & Benno Senoner
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef ringbuffer_npt_h
+#define ringbuffer_npt_h
+
+//#include <sys/mman.h>
+
+#include <glib.h>
+
+/* ringbuffer class where the element size is not required to be a power of two */
+
+template<class T>
+class RingBufferNPT
+{
+ public:
+ RingBufferNPT (size_t sz) {
+ size = sz;
+ buf = new T[size];
+ reset ();
+
+ };
+
+ virtual ~RingBufferNPT() {
+ delete [] buf;
+ }
+
+ void reset () {
+ /* !!! NOT THREAD SAFE !!! */
+ g_atomic_int_set (&write_ptr, 0);
+ g_atomic_int_set (&read_ptr, 0);
+ }
+
+ void set (size_t r, size_t w) {
+ /* !!! NOT THREAD SAFE !!! */
+ g_atomic_int_set (&write_ptr, w);
+ g_atomic_int_set (&read_ptr, r);
+ }
+
+ size_t read (T *dest, size_t cnt);
+ size_t write (T *src, size_t cnt);
+
+ struct rw_vector {
+ T *buf[2];
+ size_t len[2];
+ };
+
+ void get_read_vector (rw_vector *);
+ void get_write_vector (rw_vector *);
+
+ void decrement_read_ptr (size_t cnt) {
+ g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) - cnt) % size);
+ }
+
+ void increment_read_ptr (size_t cnt) {
+ g_atomic_int_set (&read_ptr, (g_atomic_int_get(&read_ptr) + cnt) % size);
+ }
+
+ void increment_write_ptr (size_t cnt) {
+ g_atomic_int_set (&write_ptr, (g_atomic_int_get(&write_ptr) + cnt) % size);
+ }
+
+ size_t write_space () {
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ return ((r - w + size) % size) - 1;
+ } else if (w < r) {
+ return (r - w) - 1;
+ } else {
+ return size - 1;
+ }
+ }
+
+ size_t read_space () {
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ return w - r;
+ } else {
+ return (w - r + size) % size;
+ }
+ }
+
+ T *buffer () { return buf; }
+ size_t get_write_ptr () const { return g_atomic_int_get (&write_ptr); }
+ size_t get_read_ptr () const { return g_atomic_int_get (&read_ptr); }
+ size_t bufsize () const { return size; }
+
+ protected:
+ T *buf;
+ size_t size;
+ mutable gint write_ptr;
+ mutable gint read_ptr;
+};
+
+template<class T> size_t
+RingBufferNPT<T>::read (T *dest, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_read;
+ size_t n1, n2;
+ size_t priv_read_ptr;
+
+ priv_read_ptr=g_atomic_int_get(&read_ptr);
+
+ if ((free_cnt = read_space ()) == 0) {
+ return 0;
+ }
+
+ to_read = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = priv_read_ptr + to_read;
+
+ if (cnt2 > size) {
+ n1 = size - priv_read_ptr;
+ n2 = cnt2 % size;
+ } else {
+ n1 = to_read;
+ n2 = 0;
+ }
+
+ memcpy (dest, &buf[priv_read_ptr], n1 * sizeof (T));
+ priv_read_ptr = (priv_read_ptr + n1) % size;
+
+ if (n2) {
+ memcpy (dest+n1, buf, n2 * sizeof (T));
+ priv_read_ptr = n2;
+ }
+
+ g_atomic_int_set(&read_ptr, priv_read_ptr);
+ return to_read;
+}
+
+template<class T> size_t
+RingBufferNPT<T>::write (T *src, size_t cnt)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t to_write;
+ size_t n1, n2;
+ size_t priv_write_ptr;
+
+ priv_write_ptr=g_atomic_int_get(&write_ptr);
+
+ if ((free_cnt = write_space ()) == 0) {
+ return 0;
+ }
+
+ to_write = cnt > free_cnt ? free_cnt : cnt;
+
+ cnt2 = priv_write_ptr + to_write;
+
+ if (cnt2 > size) {
+ n1 = size - priv_write_ptr;
+ n2 = cnt2 % size;
+ } else {
+ n1 = to_write;
+ n2 = 0;
+ }
+
+ memcpy (&buf[priv_write_ptr], src, n1 * sizeof (T));
+ priv_write_ptr = (priv_write_ptr + n1) % size;
+
+ if (n2) {
+ memcpy (buf, src+n1, n2 * sizeof (T));
+ priv_write_ptr = n2;
+ }
+
+ g_atomic_int_set(&write_ptr, priv_write_ptr);
+ return to_write;
+}
+
+template<class T> void
+RingBufferNPT<T>::get_read_vector (RingBufferNPT<T>::rw_vector *vec)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ free_cnt = w - r;
+ } else {
+ free_cnt = (w - r + size) % size;
+ }
+
+ cnt2 = r + free_cnt;
+
+ if (cnt2 > size) {
+ /* Two part vector: the rest of the buffer after the
+ current write ptr, plus some from the start of
+ the buffer.
+ */
+
+ vec->buf[0] = &buf[r];
+ vec->len[0] = size - r;
+ vec->buf[1] = buf;
+ vec->len[1] = cnt2 % size;
+
+ } else {
+
+ /* Single part vector: just the rest of the buffer */
+
+ vec->buf[0] = &buf[r];
+ vec->len[0] = free_cnt;
+ vec->len[1] = 0;
+ }
+}
+
+template<class T> void
+RingBufferNPT<T>::get_write_vector (RingBufferNPT<T>::rw_vector *vec)
+{
+ size_t free_cnt;
+ size_t cnt2;
+ size_t w, r;
+
+ w = g_atomic_int_get (&write_ptr);
+ r = g_atomic_int_get (&read_ptr);
+
+ if (w > r) {
+ free_cnt = ((r - w + size) % size) - 1;
+ } else if (w < r) {
+ free_cnt = (r - w) - 1;
+ } else {
+ free_cnt = size - 1;
+ }
+
+ cnt2 = w + free_cnt;
+
+ if (cnt2 > size) {
+
+ /* Two part vector: the rest of the buffer after the
+ current write ptr, plus some from the start of
+ the buffer.
+ */
+
+ vec->buf[0] = &buf[w];
+ vec->len[0] = size - w;
+ vec->buf[1] = buf;
+ vec->len[1] = cnt2 % size;
+ } else {
+ vec->buf[0] = &buf[w];
+ vec->len[0] = free_cnt;
+ vec->len[1] = 0;
+ }
+}
+
+#endif /* __ringbuffer_npt_h__ */
diff --git a/libs/pbd/pbd/selectable.h b/libs/pbd/pbd/selectable.h
new file mode 100644
index 0000000000..470bc3cfcc
--- /dev/null
+++ b/libs/pbd/pbd/selectable.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __selectable_h__
+#define __selectable_h__
+
+#include <list>
+#include <string>
+#include <stdio.h>
+
+#include <sigc++/sigc++.h>
+
+#include <sys/types.h>
+
+namespace Select {
+ enum Condition {
+ Readable = 0x1,
+ Writable = 0x2,
+ Exception = 0x4
+ };
+
+class Selectable : public sigc::trackable
+
+{
+ public:
+ Selectable (int fd);
+ Selectable (const std::string &, int flags, int mode = 0);
+ Selectable (FILE *);
+ ~Selectable ();
+
+ sigc::signal<void,Selectable *,Select::Condition> readable;
+ sigc::signal<void,Selectable *,Select::Condition> writable;
+ sigc::signal<void,Selectable *,Select::Condition> exceptioned;
+
+ int fd() { return _fd; }
+ bool ok() { return _ok; }
+
+ protected:
+ void selected (unsigned int condition);
+ int condition;
+ int _fd;
+
+ friend class Selector;
+
+ private:
+ enum {
+ fromFD,
+ fromPath,
+ fromFILE
+ };
+
+ bool _ok;
+ int _type;
+ std::string path;
+};
+
+class Selector {
+ private:
+ int post_select (fd_set *, fd_set *, fd_set *);
+ int _max_fd;
+
+ typedef std::list<Selectable *> Selectables;
+ Selectables selectables;
+ pthread_mutex_t list_lock;
+
+ static bool use_list_lock;
+
+ public:
+ Selector ();
+
+ void multithreaded (bool yn) {
+ use_list_lock = yn;
+ }
+
+ void add (int condition, Selectable *s);
+ void remove (Selectable *);
+ int select (unsigned long usecs);
+};
+
+
+
+} /* namespace */
+
+
+#endif // __selectable_h__
diff --git a/libs/pbd/pbd/stacktrace.h b/libs/pbd/pbd/stacktrace.h
new file mode 100644
index 0000000000..d7278bd35a
--- /dev/null
+++ b/libs/pbd/pbd/stacktrace.h
@@ -0,0 +1,10 @@
+#ifndef __libpbd_stacktrace_h__
+#define __libpbd_stacktrace_h__
+
+#include <ostream>
+
+namespace PBD {
+ void stacktrace (std::ostream& out);
+}
+
+#endif /* __libpbd_stacktrace_h__ */
diff --git a/libs/pbd/pbd/stl_delete.h b/libs/pbd/pbd/stl_delete.h
new file mode 100644
index 0000000000..6e5bfa0734
--- /dev/null
+++ b/libs/pbd/pbd/stl_delete.h
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __libmisc_stl_delete_h__
+#define __libmisc_stl_delete_h__
+
+/* To actually use any of these deletion functions, you need to
+ first include the revelant container type header.
+*/
+#if defined(_CPP_VECTOR) || defined(_GLIBCXX_VECTOR) || defined(__SGI_STL_VECTOR)
+template<class T> void vector_delete (std::vector<T *> *vec)
+{
+ typename std::vector<T *>::iterator i;
+
+ for (i = vec->begin(); i != vec->end(); i++) {
+ delete *i;
+ }
+ vec->clear ();
+}
+#endif // _CPP_VECTOR || _GLIBCXX_VECTOR || __SGI_STL_VECTOR
+
+#if defined(_CPP_MAP) || defined(_GLIBCXX_MAP) || defined(__SGI_STL_MAP)
+template<class K, class T> void map_delete (std::map<K, T *> *m)
+{
+ typename std::map<K, T *>::iterator i;
+
+ for (i = m->begin(); i != m->end(); i++) {
+ delete (*i).second;
+ }
+ m->clear ();
+}
+#endif // _CPP_MAP || _GLIBCXX_MAP || __SGI_STL_MAP
+
+#if defined(_CPP_LIST) || defined(_GLIBCXX_LIST) || defined(__SGI_STL_LIST)
+template<class T> void list_delete (std::list<T *> *l)
+{
+ typename std::list<T *>::iterator i;
+
+ for (i = l->begin(); i != l->end(); i++) {
+ delete (*i);
+ }
+
+ l->clear ();
+}
+#endif // _CPP_LIST || _GLIBCXX_LIST || __SGI_STL_LIST
+
+#if defined(_CPP_SLIST) || defined(_GLIBCXX_SLIST) || defined(__SGI_STL_SLIST)
+template<class T> void slist_delete (std::slist<T *> *l)
+{
+ typename std::slist<T *>::iterator i;
+
+ for (i = l->begin(); i != l->end(); i++) {
+ delete (*i);
+ }
+
+ l->clear ();
+}
+#endif // _CPP_SLIST || _GLIBCXX_SLIST || __SGI_STL_SLIST
+
+#if defined(_CPP_SET) || defined(_GLIBCXX_SET) || defined(__SGI_STL_SET)
+template<class T> void set_delete (std::set<T *> *sset)
+{
+ typename std::set<T *>::iterator i;
+
+ for (i = sset->begin(); i != sset->end(); i++) {
+ delete *i;
+ }
+ sset->erase (sset->begin(), sset->end());
+}
+#endif // _CPP_SET || _GLIBCXX_SET || __SGI_STL_SET
+
+#endif // __libmisc_stl_delete_h__
diff --git a/libs/pbd/pbd/stl_functors.h b/libs/pbd/pbd/stl_functors.h
new file mode 100644
index 0000000000..4a96e91a28
--- /dev/null
+++ b/libs/pbd/pbd/stl_functors.h
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __stl_functors_h__
+#define __stl_functors_h__
+
+#include <string>
+
+#ifndef LESS_STRING_P
+struct less<std::string *> {
+ bool operator()(std::string *s1, std::string *s2) const {
+ return *s1 < *s2;
+ }
+};
+#define LESS_STRING_P
+#endif // LESS_STRING_P
+
+#ifndef LESS_CONST_STRING_P
+struct less<const std::string *> {
+ bool operator()(const std::string *s1, const std::string *s2) const {
+ return *s1 < *s2;
+ }
+};
+#define LESS_CONST_STRING_P
+#endif // LESS_CONST_STRING_P
+
+#ifndef LESS_CONST_CHAR_P
+struct less<const char *>
+{
+ bool operator()(const char* s1, const char* s2) const {
+ return strcmp(s1, s2) < 0;
+ }
+};
+#define LESS_CONST_CHAR_P
+#endif // LESS_CONST_CHAR_P
+
+#ifndef LESS_CONST_FLOAT_P
+struct less<const float *>
+{
+ bool operator()(const float *n1, const float *n2) const {
+ return *n1 < *n2;
+ }
+};
+#define LESS_CONST_FLOAT_P
+#endif // LESS_CONST_FLOAT_P
+
+#ifndef EQUAL_TO_CONST_CHAR_P
+struct equal_to<const char *>
+{
+ bool operator()(const char *s1, const char *s2) const {
+ return strcmp (s1, s2) == 0;
+ }
+};
+#define EQUAL_TO_CONST_CHAR_P
+#endif // EQUAL_TO_CONST_CHAR_P
+
+#ifndef EQUAL_TO_STRING_P
+struct equal_to<std::string *>
+{
+ bool operator()(const std::string *s1, const std::string *s2) const {
+ return *s1 == *s2;
+ }
+};
+#define EQUAL_TO_STRING_P
+#endif // EQUAL_TO_STRING_P
+
+#ifndef LESS_CONST_STRING_R
+struct less<const std::string &> {
+ bool operator() (const std::string &s1, const std::string &s2) {
+ return s1 < s2;
+ }
+};
+#define LESS_CONST_STRING_R
+#endif // EQUAL_TO_STRING_P
+
+#endif // __stl_functors_h__
diff --git a/libs/pbd/pbd/strsplit.h b/libs/pbd/pbd/strsplit.h
new file mode 100644
index 0000000000..e55ad1c825
--- /dev/null
+++ b/libs/pbd/pbd/strsplit.h
@@ -0,0 +1,9 @@
+#ifndef __pbd_strplit_h__
+#define __pbd_strplit_h__
+
+#include <string>
+#include <vector>
+
+extern void split (std::string, std::vector<std::string>&, char);
+
+#endif // __pbd_strplit_h__
diff --git a/libs/pbd/pbd/textreceiver.h b/libs/pbd/pbd/textreceiver.h
new file mode 100644
index 0000000000..b8bfe5bc78
--- /dev/null
+++ b/libs/pbd/pbd/textreceiver.h
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __libmisc_textreceiver_h__
+#define __libmisc_textreceiver_h__
+
+#include <string>
+
+#include "receiver.h"
+
+using std::string;
+using std::cout;
+using std::endl;
+
+class TextReceiver : public Receiver
+{
+ public:
+ TextReceiver (const string &n);
+
+ protected:
+ void receive (Transmitter::Channel, const char *);
+
+ private:
+ string name;
+};
+
+#endif //__libmisc_textreceiver_h__
diff --git a/libs/pbd/pbd/thrown_error.h b/libs/pbd/pbd/thrown_error.h
new file mode 100644
index 0000000000..83cf8acfac
--- /dev/null
+++ b/libs/pbd/pbd/thrown_error.h
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+#ifndef __qm_thrown_error_h__
+#define __qm_thrown_error_h__
+
+#include "transmitter.h"
+
+#define SAFE_THROW(T) \
+ T *sent = new T; \
+ (*sent) << rdbuf(); \
+ throw sent
+
+class ThrownError : public Transmitter {
+ public:
+ ThrownError () : Transmitter (Transmitter::Throw) {}
+ protected:
+ virtual void deliver () = 0;
+};
+
+#endif // __qm_thrown_error_h__
+
+
diff --git a/libs/pbd/pbd/tokenizer.h b/libs/pbd/pbd/tokenizer.h
new file mode 100644
index 0000000000..a976b79341
--- /dev/null
+++ b/libs/pbd/pbd/tokenizer.h
@@ -0,0 +1,49 @@
+#ifndef PBD_TOKENIZER
+#define PBD_TOKENIZER
+
+#include <iterator>
+#include <string>
+
+namespace PBD {
+
+/**
+ Tokenize string, this should work for standard
+ strings aswell as Glib::ustring. This is a bit of a hack,
+ there are much better string tokenizing patterns out there.
+*/
+template<typename StringType, typename Iter>
+unsigned int
+tokenize(const StringType& str,
+ const StringType& delims,
+ Iter it)
+{
+ typename StringType::size_type start_pos = 0;
+ typename StringType::size_type end_pos = 0;
+ unsigned int token_count = 0;
+
+ do {
+ start_pos = str.find_first_not_of(delims, start_pos);
+ end_pos = str.find_first_of(delims, start_pos);
+ if (start_pos != end_pos) {
+ if (end_pos == str.npos) {
+ end_pos = str.length();
+ }
+ *it++ = str.substr(start_pos, end_pos - start_pos);
+ ++token_count;
+ start_pos = str.find_first_not_of(delims, end_pos + 1);
+ }
+ } while (start_pos != str.npos);
+
+ if (start_pos != str.npos) {
+ *it++ = str.substr(start_pos, str.length() - start_pos);
+ ++token_count;
+ }
+
+ return token_count;
+}
+
+} // namespace PBD
+
+#endif // PBD_TOKENIZER
+
+
diff --git a/libs/pbd/pbd/touchable.h b/libs/pbd/pbd/touchable.h
new file mode 100644
index 0000000000..0298574dfa
--- /dev/null
+++ b/libs/pbd/pbd/touchable.h
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 1999 Paul Barton-Davis
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __pbd_touchable_h__
+#define __pbd_touchable_h__
+
+class Touchable
+{
+ public:
+ Touchable() : _delete_after_touch (false) {}
+ virtual ~Touchable() {}
+
+ void set_delete_after_touch (bool yn) { _delete_after_touch = yn; }
+ bool delete_after_touch() const { return _delete_after_touch; }
+
+ virtual void touch () = 0;
+
+ protected:
+ bool _delete_after_touch;
+};
+
+template<class T>
+class DynamicTouchable : public Touchable
+{
+ public:
+ DynamicTouchable (T& t, void (T::*m)(void))
+ : object (t), method (m) { set_delete_after_touch (true); }
+
+ void touch () {
+ (object.*method)();
+ }
+
+ protected:
+ T& object;
+ void (T::*method)(void);
+};
+
+template<class T1, class T2>
+class DynamicTouchable1 : public Touchable
+{
+ public:
+ DynamicTouchable1 (T1& t, void (T1::*m)(T2), T2 a)
+ : object (t), method (m), arg (a) { set_delete_after_touch (true); }
+
+ void touch () {
+ (object.*method)(arg);
+ }
+
+ protected:
+ T1& object;
+ void (T1::*method)(T2);
+ T2 arg;
+};
+
+template<class T1, class T2, class T3>
+class DynamicTouchable2 : public Touchable
+{
+ public:
+ DynamicTouchable2 (T1& t, void (T1::*m)(T2, T3), T2 a1, T3 a2)
+ : object (t), method (m), arg1 (a1), arg2 (a2) { set_delete_after_touch (true); }
+
+ void touch () {
+ (object.*method)(arg1, arg2);
+ }
+
+ protected:
+ T1& object;
+ void (T1::*method)(T2,T3);
+ T2 arg1;
+ T3 arg2;
+};
+
+#endif // __pbd_touchable_h__
diff --git a/libs/pbd/pbd/transmitter.h b/libs/pbd/pbd/transmitter.h
new file mode 100644
index 0000000000..357cb9965f
--- /dev/null
+++ b/libs/pbd/pbd/transmitter.h
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __libmisc_transmitter_h__
+#define __libmisc_transmitter_h__
+
+#include <sstream>
+#include <iostream>
+
+#include <sigc++/sigc++.h>
+
+using std::cout;
+using std::cerr;
+using std::endl;
+
+class Transmitter : public std::stringstream
+
+{
+ public:
+ enum Channel {
+ Info,
+ Error,
+ Warning,
+ Fatal,
+ Throw
+ };
+
+ Transmitter (Channel);
+
+ sigc::signal<void,Channel, const char *> &sender() {
+ return *send;
+ }
+
+ bool does_not_return ();
+
+ protected:
+ virtual void deliver ();
+ friend std::ostream& endmsg (std::ostream &);
+
+ private:
+ Channel channel;
+ sigc::signal<void, Channel, const char *> *send;
+
+ sigc::signal<void, Channel, const char *> info;
+ sigc::signal<void, Channel, const char *> warning;
+ sigc::signal<void, Channel, const char *> error;
+ sigc::signal<void, Channel, const char *> fatal;
+};
+
+/* for EGCS 2.91.66, if this function is not compiled within the same
+ compilation unit as the one where a ThrownError is thrown, then
+ nothing will catch the error. This is a pretty small function, so
+ inlining it here seems like a reasonable workaround.
+*/
+
+inline std::ostream &
+endmsg (std::ostream &ostr)
+
+{
+ Transmitter *t;
+
+ /* There is a serious bug in the Cygnus/GCC libstdc++ library:
+ cout is not actually an ostream, but a trick was played
+ to make the compiler think that it is. This will cause
+ the dynamic_cast<> to fail with SEGV. So, first check to
+ see if ostr == cout, and handle it specially.
+ */
+
+ if (&ostr == &cout) {
+ cout << endl;
+ return ostr;
+ } else if (&ostr == &cerr) {
+ cerr << endl;
+ return ostr;
+ }
+
+ if ((t = dynamic_cast<Transmitter *> (&ostr)) != 0) {
+ t->deliver ();
+ } else {
+ /* hmm. not a Transmitter, so just put a newline on
+ it and assume that that will be enough.
+ */
+
+ ostr << endl;
+ }
+
+ return ostr;
+}
+
+
+extern "C" { void pbd_c_error (const char *); }
+
+#endif // __libmisc_transmitter_h__
diff --git a/libs/pbd/pbd/undo.h b/libs/pbd/pbd/undo.h
new file mode 100644
index 0000000000..f067635ed3
--- /dev/null
+++ b/libs/pbd/pbd/undo.h
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2002 Brett Viren & Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#ifndef __lib_pbd_undo_h__
+#define __lib_pbd_undo_h__
+
+#include <string>
+#include <list>
+#include <sigc++/slot.h>
+#include <sys/time.h>
+
+using std::string;
+using std::list;
+
+typedef sigc::slot<void> UndoAction;
+
+class UndoCommand
+{
+ public:
+ UndoCommand ();
+ UndoCommand (const UndoCommand&);
+ UndoCommand& operator= (const UndoCommand&);
+
+ void clear ();
+
+ void add_undo (const UndoAction&);
+ void add_redo (const UndoAction&);
+ void add_redo_no_execute (const UndoAction&);
+
+ void undo();
+ void redo();
+
+ void set_name (const string& str) {
+ _name = str;
+ }
+ const string& name() const { return _name; }
+
+ void set_timestamp (struct timeval &t) {
+ _timestamp = t;
+ }
+
+ const struct timeval& timestamp() const {
+ return _timestamp;
+ }
+
+ private:
+ list<UndoAction> redo_actions;
+ list<UndoAction> undo_actions;
+ struct timeval _timestamp;
+ string _name;
+};
+
+class UndoHistory
+{
+ public:
+ UndoHistory() {}
+ ~UndoHistory() {}
+
+ void add (UndoCommand uc);
+ void undo (unsigned int n);
+ void redo (unsigned int n);
+
+ unsigned long undo_depth() const { return UndoList.size(); }
+ unsigned long redo_depth() const { return RedoList.size(); }
+
+ string next_undo() const { return (UndoList.empty() ? string("") : UndoList.back().name()); }
+ string next_redo() const { return (RedoList.empty() ? string("") : RedoList.back().name()); }
+
+ void clear ();
+ void clear_undo ();
+ void clear_redo ();
+
+ private:
+ list<UndoCommand> UndoList;
+ list<UndoCommand> RedoList;
+};
+
+
+#endif /* __lib_pbd_undo_h__ */
diff --git a/libs/pbd/pbd/whitespace.h b/libs/pbd/pbd/whitespace.h
new file mode 100644
index 0000000000..6620a8fb50
--- /dev/null
+++ b/libs/pbd/pbd/whitespace.h
@@ -0,0 +1,8 @@
+#ifndef __pbd_whitespace_h__
+#define __pbd_whitespace_h__
+
+#include <string>
+
+extern void strip_whitespace_edges (std::string& str);
+
+#endif // __pbd_whitespace_h__
diff --git a/libs/pbd/pbd/xml++.h b/libs/pbd/pbd/xml++.h
new file mode 100644
index 0000000000..afb896e1d5
--- /dev/null
+++ b/libs/pbd/pbd/xml++.h
@@ -0,0 +1,129 @@
+/* xml++.h
+ * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
+ * are covered by the GNU Lesser General Public License, which should be
+ * included with libxml++ as the file COPYING.
+ */
+
+#include <string>
+#include <list>
+#include <map>
+#include <cstdio>
+#include <cstdarg>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#ifndef __XML_H
+#define __XML_H
+
+using std::string;
+using std::map;
+using std::list;
+
+class XMLTree;
+class XMLNode;
+class XMLProperty;
+
+typedef list<XMLNode *> XMLNodeList;
+typedef XMLNodeList::iterator XMLNodeIterator;
+typedef XMLNodeList::const_iterator XMLNodeConstIterator;
+typedef list<XMLProperty*> XMLPropertyList;
+typedef XMLPropertyList::iterator XMLPropertyIterator;
+typedef XMLPropertyList::const_iterator XMLPropertyConstIterator;
+typedef map<string, XMLProperty*> XMLPropertyMap;
+
+class XMLTree {
+private:
+ string _filename;
+ XMLNode *_root;
+ int _compression;
+ bool _initialized;
+
+public:
+ XMLTree();
+ XMLTree(const string &fn);
+ XMLTree(const XMLTree *);
+ ~XMLTree();
+
+ bool initialized() const { return _initialized; };
+ XMLNode *root() const { return _root; };
+ XMLNode *set_root(XMLNode *n) { _initialized = true; return _root = n; };
+
+ const string & filename() const { return _filename; };
+ const string & set_filename(const string &fn) { return _filename = fn; };
+
+ int compression() const { return _compression; };
+ int set_compression(int);
+
+ bool read();
+ bool read(const string &fn) { set_filename(fn); return read(); };
+ bool read_buffer(const string &);
+
+ bool write() const;
+ bool write(const string &fn) { set_filename(fn); return write(); };
+
+ void debug (FILE*) const;
+
+ const string & write_buffer() const;
+};
+
+class XMLNode {
+private:
+ bool _initialized;
+ string _name;
+ bool _is_content;
+ string _content;
+ XMLNodeList _children;
+ XMLPropertyList _proplist;
+ XMLPropertyMap _propmap;
+
+public:
+ XMLNode(const string &);
+ XMLNode(const string &, const string &);
+ XMLNode(const XMLNode&);
+ ~XMLNode();
+
+ bool initialized() const { return _initialized; };
+ const string name() const { return _name; };
+
+ bool is_content() const { return _is_content; };
+ const string & content() const { return _content; };
+ const string & set_content(const string &);
+ XMLNode *add_content(const string & = string());
+
+ const XMLNodeList & children(const string & = string()) const;
+ XMLNode *add_child(const char *);
+ XMLNode *add_child_copy(const XMLNode&);
+ void add_child_nocopy (XMLNode&);
+
+ const XMLPropertyList & properties() const { return _proplist; };
+ XMLProperty *property(const char * );
+ const XMLProperty *property(const char * n) const
+ { return ((XMLNode *) this)->property(n); };
+ XMLProperty *add_property(const char *, const string &);
+ XMLProperty *add_property(const char *, const char * = "");
+
+ void remove_property(const string &);
+
+ /** Remove all nodes with the name passed to remove_nodes */
+ void remove_nodes(const string &);
+ /** Remove and delete all nodes with the name passed to remove_nodes */
+ void remove_nodes_and_delete(const string &);
+};
+
+class XMLProperty {
+private:
+ string _name;
+ string _value;
+
+public:
+ XMLProperty(const string &n, const string &v = string());
+ ~XMLProperty();
+
+ const string & name() const { return _name; };
+ const string & value() const { return _value; };
+ const string & set_value(const string &v) { return _value = v; };
+};
+
+#endif /* __XML_H */
+
diff --git a/libs/pbd/pool.cc b/libs/pbd/pool.cc
new file mode 100644
index 0000000000..089766482d
--- /dev/null
+++ b/libs/pbd/pool.cc
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <iostream>
+#include <vector>
+
+#include <pbd/pool.h>
+#include <pbd/error.h>
+
+using namespace std;
+using namespace PBD;
+
+Pool::Pool (string n, unsigned long item_size, unsigned long nitems)
+{
+ _name = n;
+
+ free_list = new RingBuffer<void*> (nitems);
+
+ /* since some overloaded ::operator new() might use this,
+ its important that we use a "lower level" allocator to
+ get more space.
+ */
+
+ block = malloc (nitems * item_size);
+
+ void **ptrlist = (void **) malloc (sizeof (void *) * nitems);
+
+ for (unsigned long i = 0; i < nitems; i++) {
+ ptrlist[i] = static_cast<void *> (static_cast<char*>(block) + (i * item_size));
+ }
+
+ free_list->write (ptrlist, nitems);
+
+ free (ptrlist);
+}
+
+Pool::~Pool ()
+{
+ free (block);
+}
+
+void *
+Pool::alloc ()
+{
+ void *ptr;
+
+// cerr << _name << " pool " << " alloc, thread = " << pthread_name() << " space = " << free_list->read_space() << endl;
+
+ if (free_list->read (&ptr, 1) < 1) {
+ fatal << "CRITICAL: " << _name << " POOL OUT OF MEMORY - RECOMPILE WITH LARGER SIZE!!" << endmsg;
+ /*NOTREACHED*/
+ return 0;
+ } else {
+ return ptr;
+ }
+};
+
+void
+Pool::release (void *ptr)
+{
+ free_list->write (&ptr, 1);
+// cerr << _name << ": release, now has " << free_list->read_space() << endl;
+}
+
+/*---------------------------------------------*/
+
+MultiAllocSingleReleasePool::MultiAllocSingleReleasePool (string n, unsigned long isize, unsigned long nitems)
+ : Pool (n, isize, nitems),
+ m_lock(0)
+{
+}
+
+MultiAllocSingleReleasePool::~MultiAllocSingleReleasePool ()
+{
+ if(m_lock) delete m_lock;
+}
+
+SingleAllocMultiReleasePool::SingleAllocMultiReleasePool (string n, unsigned long isize, unsigned long nitems)
+ : Pool (n, isize, nitems),
+ m_lock(0)
+{
+}
+
+SingleAllocMultiReleasePool::~SingleAllocMultiReleasePool ()
+{
+ if(m_lock) delete m_lock;
+}
+
+void*
+MultiAllocSingleReleasePool::alloc ()
+{
+ void *ptr;
+ if(!m_lock) {
+ m_lock = new Glib::Mutex();
+ // umm, I'm not sure that this doesn't also allocate memory.
+ if(!m_lock) error << "cannot create Glib::Mutex in pool.cc" << endmsg;
+ }
+
+ Glib::Mutex::Lock guard(*m_lock);
+ ptr = Pool::alloc ();
+ return ptr;
+}
+
+void
+MultiAllocSingleReleasePool::release (void* ptr)
+{
+ Pool::release (ptr);
+}
+
+void*
+SingleAllocMultiReleasePool::alloc ()
+{
+ return Pool::alloc ();
+}
+
+void
+SingleAllocMultiReleasePool::release (void* ptr)
+{
+ if(!m_lock) {
+ m_lock = new Glib::Mutex();
+ // umm, I'm not sure that this doesn't also allocate memory.
+ if(!m_lock) error << "cannot create Glib::Mutex in pool.cc" << endmsg;
+ }
+ Glib::Mutex::Lock guard(*m_lock);
+ Pool::release (ptr);
+}
+
diff --git a/libs/pbd/pthread_utils.cc b/libs/pbd/pthread_utils.cc
new file mode 100644
index 0000000000..db242cea7b
--- /dev/null
+++ b/libs/pbd/pthread_utils.cc
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2002 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <map>
+#include <iostream>
+#include <string>
+#include <stdint.h>
+
+#include <pbd/pthread_utils.h>
+
+using namespace std;
+
+typedef std::map<string,pthread_t> ThreadMap;
+static ThreadMap all_threads;
+static pthread_mutex_t thread_map_lock = PTHREAD_MUTEX_INITIALIZER;
+
+namespace PBD {
+ sigc::signal<void,pthread_t,std::string> ThreadCreated;
+ sigc::signal<void,pthread_t,std::string,uint32_t> ThreadCreatedWithRequestSize;
+}
+
+using namespace PBD;
+
+int
+pthread_create_and_store (string name, pthread_t *thread, pthread_attr_t *attr, void * (*start_routine)(void *), void * arg)
+{
+ int ret;
+
+ if ((ret = pthread_create (thread, attr, start_routine, arg)) == 0) {
+ std::pair<string,pthread_t> newpair;
+ newpair.first = name;
+ newpair.second = *thread;
+
+ pthread_mutex_lock (&thread_map_lock);
+ all_threads.insert (newpair);
+
+ pthread_mutex_unlock (&thread_map_lock);
+ }
+
+ return ret;
+}
+
+string
+pthread_name ()
+{
+ pthread_t self = pthread_self();
+ string str;
+
+ pthread_mutex_lock (&thread_map_lock);
+ for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
+ if (i->second == self) {
+ str = i->first;
+ pthread_mutex_unlock (&thread_map_lock);
+ return str;
+ }
+ }
+ pthread_mutex_unlock (&thread_map_lock);
+ return "unknown";
+}
+
+void
+pthread_kill_all (int signum)
+{
+ pthread_mutex_lock (&thread_map_lock);
+ for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
+ if (i->second != pthread_self()) {
+ pthread_kill (i->second, signum);
+ }
+ }
+ all_threads.clear();
+ pthread_mutex_unlock (&thread_map_lock);
+}
+
+void
+pthread_cancel_all ()
+{
+ pthread_mutex_lock (&thread_map_lock);
+ for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
+ if (i->second != pthread_self()) {
+ pthread_cancel (i->second);
+ }
+ }
+ all_threads.clear();
+ pthread_mutex_unlock (&thread_map_lock);
+}
+
+void
+pthread_cancel_one (pthread_t thread)
+{
+ pthread_mutex_lock (&thread_map_lock);
+ for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
+ if (i->second == thread) {
+ all_threads.erase (i);
+ break;
+ }
+ }
+
+ pthread_cancel (thread);
+ pthread_mutex_unlock (&thread_map_lock);
+}
+
+void
+pthread_exit_pbd (void* status)
+{
+ pthread_t thread = pthread_self();
+
+ pthread_mutex_lock (&thread_map_lock);
+ for (ThreadMap::iterator i = all_threads.begin(); i != all_threads.end(); ++i) {
+ if (i->second == thread) {
+ all_threads.erase (i);
+ break;
+ }
+ }
+ pthread_mutex_unlock (&thread_map_lock);
+ pthread_exit (status);
+}
diff --git a/libs/pbd/receiver.cc b/libs/pbd/receiver.cc
new file mode 100644
index 0000000000..5e7c10de70
--- /dev/null
+++ b/libs/pbd/receiver.cc
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <vector>
+
+#include <pbd/receiver.h>
+#include <pbd/transmitter.h>
+
+using namespace sigc;
+
+Receiver::Receiver () {}
+
+Receiver::~Receiver ()
+
+{
+ hangup ();
+}
+
+void
+Receiver::hangup ()
+{
+ vector<sigc::connection *>::iterator i;
+
+ for (i = connections.begin(); i != connections.end (); i++) {
+ (*i)->disconnect ();
+ delete *i;
+ }
+
+ connections.erase (connections.begin(), connections.end());
+}
+
+void
+Receiver::listen_to (Transmitter &transmitter)
+
+{
+ sigc::connection *c = new sigc::connection;
+
+ (*c) = transmitter.sender().connect(mem_fun(*this, &Receiver::receive));
+
+ connections.push_back (c);
+}
diff --git a/libs/pbd/stacktrace.cc b/libs/pbd/stacktrace.cc
new file mode 100644
index 0000000000..1e7dfa08e9
--- /dev/null
+++ b/libs/pbd/stacktrace.cc
@@ -0,0 +1,42 @@
+#include <pbd/stacktrace.h>
+#include <iostream>
+
+/* Obtain a backtrace and print it to stdout. */
+
+#ifdef HAVE_EXECINFO
+
+#include <execinfo.h>
+#include <stdlib.h>
+
+void
+PBD::stacktrace (std::ostream& out)
+{
+ void *array[200];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 200);
+ strings = backtrace_symbols (array, size);
+
+ if (strings) {
+
+ printf ("Obtained %zd stack frames.\n", size);
+
+ for (i = 0; i < size; i++) {
+ out << strings[i] << std::endl;
+ }
+
+ free (strings);
+ }
+}
+
+#else
+
+void
+PBD::stacktrace (std::ostream& out)
+{
+ out << "stack tracing is not enabled on this platform" << std::endl;
+}
+
+#endif /* HAVE_EXECINFO */
diff --git a/libs/pbd/strsplit.cc b/libs/pbd/strsplit.cc
new file mode 100644
index 0000000000..7f29a77887
--- /dev/null
+++ b/libs/pbd/strsplit.cc
@@ -0,0 +1,41 @@
+#include <pbd/strsplit.h>
+
+using namespace std;
+
+void
+split (string str, vector<string>& result, char splitchar)
+{
+ string::size_type pos;
+ string remaining;
+ string::size_type len = str.length();
+ int cnt;
+
+ cnt = 0;
+
+ if (str.empty()) {
+ return;
+ }
+
+ for (string::size_type n = 0; n < len; ++n) {
+ if (str[n] == splitchar) {
+ cnt++;
+ }
+ }
+
+ if (cnt == 0) {
+ result.push_back (str);
+ return;
+ }
+
+ remaining = str;
+
+ while ((pos = remaining.find_first_of (':')) != string::npos) {
+ result.push_back (remaining.substr (0, pos));
+ remaining = remaining.substr (pos+1);
+ }
+
+ if (remaining.length()) {
+
+ result.push_back (remaining);
+ }
+}
diff --git a/libs/pbd/textreceiver.cc b/libs/pbd/textreceiver.cc
new file mode 100644
index 0000000000..43620e9830
--- /dev/null
+++ b/libs/pbd/textreceiver.cc
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <iostream>
+#include <cstdlib>
+
+#include <pbd/textreceiver.h>
+
+TextReceiver::TextReceiver (const string &n)
+
+{
+ name = n;
+}
+
+void
+TextReceiver::receive (Transmitter::Channel chn, const char *str)
+
+{
+ const char *prefix = "";
+
+ switch (chn) {
+ case Transmitter::Error:
+ prefix = ": [ERROR]: ";
+ break;
+ case Transmitter::Info:
+ prefix = ": [INFO]: ";
+ break;
+ case Transmitter::Warning:
+ prefix = ": [WARNING]: ";
+ break;
+ case Transmitter::Fatal:
+ prefix = ": [FATAL]: ";
+ break;
+ case Transmitter::Throw:
+ /* this isn't supposed to happen */
+ abort ();
+ }
+
+ /* note: iostreams are already thread-safe: no external
+ lock required.
+ */
+
+ cout << name << prefix << str << endl;
+
+ if (chn == Transmitter::Fatal) {
+ exit (9);
+ }
+}
+
diff --git a/libs/pbd/transmitter.cc b/libs/pbd/transmitter.cc
new file mode 100644
index 0000000000..876a9d86e5
--- /dev/null
+++ b/libs/pbd/transmitter.cc
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 1998-99 Paul Barton-Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <cstdlib>
+#include <signal.h>
+#include <iostream>
+#include <string>
+
+#include <pbd/transmitter.h>
+#include <pbd/error.h>
+
+using std::string;
+using std::ios;
+
+Transmitter::Transmitter (Channel c)
+{
+ channel = c;
+ switch (c) {
+ case Error:
+ send = &error;
+ break;
+ case Warning:
+ send = &warning;
+ break;
+ case Info:
+ send = &info;
+ break;
+ case Fatal:
+ send = &fatal;
+ break;
+ case Throw:
+ /* we should never call Transmitter::deliver
+ for thrown messages (because its overridden in the
+ class heirarchy). force a segv if we do.
+ */
+ send = 0;
+ break;
+ }
+}
+
+void
+Transmitter::deliver ()
+
+{
+ string foo;
+
+ /* NOTE: this is just a default action for a Transmitter or a
+ derived class. Any class can override this to produce some
+ other action when deliver() is called.
+ */
+
+ *this << '\0';
+
+ /* send the SigC++ signal */
+
+ foo = str();
+ (*send) (channel, foo.c_str());
+
+ /* XXX when or how can we delete this ? */
+ // delete foo;
+
+ /* return to a pristine state */
+
+ clear ();
+ seekp (0, ios::beg);
+ seekg (0, ios::beg);
+
+ /* do the right thing if this should not return */
+
+ if (does_not_return()) {
+ sigset_t mask;
+
+ sigemptyset (&mask);
+ sigsuspend (&mask);
+ /*NOTREACHED*/
+ exit (1);
+ }
+}
+
+bool
+Transmitter::does_not_return ()
+
+{
+ if (channel == Fatal || channel == Throw) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+extern "C" {
+ void pbd_c_error (const char *str)
+
+ {
+ PBD::error << str << endmsg;
+ }
+}
diff --git a/libs/pbd/undo.cc b/libs/pbd/undo.cc
new file mode 100644
index 0000000000..f2f11b1c5c
--- /dev/null
+++ b/libs/pbd/undo.cc
@@ -0,0 +1,146 @@
+/*
+ Copyright (C) 2001 Brett Viren & Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <iostream>
+
+#include <pbd/undo.h>
+
+using namespace std;
+using namespace sigc;
+
+UndoCommand::UndoCommand ()
+{
+}
+
+UndoCommand::UndoCommand (const UndoCommand& rhs)
+{
+ _name = rhs._name;
+ clear ();
+ undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end());
+ redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end());
+}
+
+UndoCommand&
+UndoCommand::operator= (const UndoCommand& rhs)
+{
+ if (this == &rhs) return *this;
+ _name = rhs._name;
+ clear ();
+ undo_actions.insert(undo_actions.end(),rhs.undo_actions.begin(),rhs.undo_actions.end());
+ redo_actions.insert(redo_actions.end(),rhs.redo_actions.begin(),rhs.redo_actions.end());
+ return *this;
+}
+
+void
+UndoCommand::add_undo (const UndoAction& action)
+{
+ undo_actions.push_back (action);
+}
+
+void
+UndoCommand::add_redo (const UndoAction& action)
+{
+ redo_actions.push_back (action);
+ redo_actions.back()(); // operator()
+}
+
+void
+UndoCommand::add_redo_no_execute (const UndoAction& action)
+{
+ redo_actions.push_back (action);
+}
+
+void
+UndoCommand::clear ()
+{
+ undo_actions.clear ();
+ redo_actions.clear ();
+}
+
+void
+UndoCommand::undo ()
+{
+ cerr << "Undo " << _name << endl;
+ for (list<UndoAction>::reverse_iterator i = undo_actions.rbegin(); i != undo_actions.rend(); ++i) {
+ (*i)();
+ }
+}
+
+void
+UndoCommand::redo ()
+{
+ cerr << "Redo " << _name << endl;
+ for (list<UndoAction>::iterator i = redo_actions.begin(); i != redo_actions.end(); ++i) {
+ (*i)();
+ }
+}
+
+void
+UndoHistory::add (UndoCommand uc)
+{
+ UndoList.push_back (uc);
+}
+
+void
+UndoHistory::undo (unsigned int n)
+{
+ while (n--) {
+ if (UndoList.size() == 0) {
+ return;
+ }
+ UndoCommand uc = UndoList.back ();
+ UndoList.pop_back ();
+ uc.undo ();
+ RedoList.push_back (uc);
+ }
+}
+
+void
+UndoHistory::redo (unsigned int n)
+{
+ while (n--) {
+ if (RedoList.size() == 0) {
+ return;
+ }
+ UndoCommand cmd = RedoList.back ();
+ RedoList.pop_back ();
+ cmd.redo ();
+ UndoList.push_back (cmd);
+ }
+}
+
+void
+UndoHistory::clear_redo ()
+{
+ RedoList.clear ();
+}
+
+void
+UndoHistory::clear_undo ()
+{
+ UndoList.clear ();
+}
+
+void
+UndoHistory::clear ()
+{
+ RedoList.clear ();
+ UndoList.clear ();
+}
diff --git a/libs/pbd/whitespace.cc b/libs/pbd/whitespace.cc
new file mode 100644
index 0000000000..7f74940457
--- /dev/null
+++ b/libs/pbd/whitespace.cc
@@ -0,0 +1,30 @@
+#include <pbd/whitespace.h>
+
+using namespace std;
+
+void
+strip_whitespace_edges (string& str)
+{
+ string::size_type i;
+ string::size_type len;
+ string::size_type s;
+
+ len = str.length();
+
+ for (i = 0; i < len; ++i) {
+ if (isgraph (str[i])) {
+ break;
+ }
+ }
+
+ s = i;
+
+ for (i = len - 1; i >= 0; --i) {
+ if (isgraph (str[i])) {
+ break;
+ }
+ }
+
+ str = str.substr (s, (i - s) + 1);
+}
+
diff --git a/libs/pbd/xml++.cc b/libs/pbd/xml++.cc
new file mode 100644
index 0000000000..e496d8b2fd
--- /dev/null
+++ b/libs/pbd/xml++.cc
@@ -0,0 +1,422 @@
+/* xml++.cc
+ * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
+ * are covered by the GNU Lesser General Public License, which should be
+ * included with libxml++ as the file COPYING.
+ */
+
+#include <pbd/xml++.h>
+#include <libxml/debugXML.h>
+
+static XMLNode *readnode(xmlNodePtr);
+static void writenode(xmlDocPtr, XMLNode *, xmlNodePtr, int);
+
+XMLTree::XMLTree()
+ : _filename(),
+ _root(),
+ _compression(0),
+ _initialized(false)
+{
+}
+
+XMLTree::XMLTree(const string &fn)
+ : _filename(fn),
+ _root(0),
+ _compression(0),
+ _initialized(false)
+{
+ read();
+}
+
+XMLTree::XMLTree(const XMLTree * from)
+{
+ _filename = from->filename();
+ _root = new XMLNode(*from->root());
+ _compression = from->compression();
+ _initialized = true;
+}
+
+XMLTree::~XMLTree()
+{
+ if (_initialized && _root)
+ delete _root;
+}
+
+int
+XMLTree::set_compression(int c)
+{
+ if (c > 9)
+ c = 9;
+
+ if (c < 0)
+ c = 0;
+
+ _compression = c;
+
+ return _compression;
+}
+
+bool
+XMLTree::read(void)
+{
+ xmlDocPtr doc;
+
+ if (_root) {
+ delete _root;
+ _root = 0;
+ }
+
+ xmlKeepBlanksDefault(0);
+
+ doc = xmlParseFile(_filename.c_str());
+ if (!doc) {
+ _initialized = false;
+ return false;
+ }
+
+ _root = readnode(xmlDocGetRootElement(doc));
+ xmlFreeDoc(doc);
+ _initialized = true;
+
+ return true;
+}
+
+bool
+XMLTree::read_buffer(const string & buffer)
+{
+ xmlDocPtr doc;
+
+ _filename = "";
+
+ if (_root) {
+ delete _root;
+ _root = 0;
+ }
+
+ doc = xmlParseMemory((char *) buffer.c_str(), buffer.length());
+ if (!doc) {
+ _initialized = false;
+ return false;
+ }
+
+ _root = readnode(xmlDocGetRootElement(doc));
+ xmlFreeDoc(doc);
+ _initialized = true;
+
+ return true;
+}
+
+bool
+XMLTree::write(void) const
+{
+ xmlDocPtr doc;
+ XMLNodeList children;
+ int result;
+
+ xmlKeepBlanksDefault(0);
+ doc = xmlNewDoc((xmlChar *) "1.0");
+ xmlSetDocCompressMode(doc, _compression);
+ writenode(doc, _root, doc->children, 1);
+ result = xmlSaveFormatFile(_filename.c_str(), doc, 1);
+ xmlFreeDoc(doc);
+
+ if (result == -1)
+ return false;
+
+ return true;
+}
+
+void
+XMLTree::debug(FILE* out) const
+{
+ xmlDocPtr doc;
+ XMLNodeList children;
+
+ xmlKeepBlanksDefault(0);
+ doc = xmlNewDoc((xmlChar *) "1.0");
+ xmlSetDocCompressMode(doc, _compression);
+ writenode(doc, _root, doc->children, 1);
+ xmlDebugDumpDocument (out, doc);
+ xmlFreeDoc(doc);
+}
+
+const string &
+XMLTree::write_buffer(void) const
+{
+ static string retval;
+ char *ptr;
+ int len;
+ xmlDocPtr doc;
+ XMLNodeList children;
+
+ xmlKeepBlanksDefault(0);
+ doc = xmlNewDoc((xmlChar *) "1.0");
+ xmlSetDocCompressMode(doc, _compression);
+ writenode(doc, _root, doc->children, 1);
+ xmlDocDumpMemory(doc, (xmlChar **) & ptr, &len);
+ xmlFreeDoc(doc);
+
+ retval = ptr;
+
+ free(ptr);
+
+ return retval;
+}
+
+XMLNode::XMLNode(const string & n)
+ : _name(n), _is_content(false), _content(string())
+{
+
+ if (_name.empty())
+ _initialized = false;
+ else
+ _initialized = true;
+}
+
+XMLNode::XMLNode(const string & n, const string & c)
+ :_name(string()), _is_content(true), _content(c)
+{
+ _initialized = true;
+}
+
+XMLNode::XMLNode(const XMLNode& from)
+ : _initialized(false)
+{
+ XMLPropertyList props;
+ XMLPropertyIterator curprop;
+ XMLNodeList nodes;
+ XMLNodeIterator curnode;
+
+ _name = from.name();
+ set_content(from.content());
+
+ props = from.properties();
+ for (curprop = props.begin(); curprop != props.end(); curprop++)
+ add_property((*curprop)->name().c_str(), (*curprop)->value());
+
+ nodes = from.children();
+ for (curnode = nodes.begin(); curnode != nodes.end(); curnode++)
+ add_child_copy(**curnode);
+}
+
+XMLNode::~XMLNode()
+{
+ XMLNodeIterator curchild;
+ XMLPropertyIterator curprop;
+
+ for (curchild = _children.begin(); curchild != _children.end();
+ curchild++)
+ delete *curchild;
+
+ for (curprop = _proplist.begin(); curprop != _proplist.end();
+ curprop++)
+ delete *curprop;
+}
+
+const string &
+XMLNode::set_content(const string & c)
+{
+ if (c.empty())
+ _is_content = false;
+ else
+ _is_content = true;
+
+ _content = c;
+
+ return _content;
+}
+
+const XMLNodeList &
+XMLNode::children(const string & n) const
+{
+ static XMLNodeList retval;
+ XMLNodeConstIterator cur;
+
+ if (n.length() == 0)
+ return _children;
+
+ retval.erase(retval.begin(), retval.end());
+
+ for (cur = _children.begin(); cur != _children.end(); cur++)
+ if ((*cur)->name() == n)
+ retval.insert(retval.end(), *cur);
+
+ return retval;
+}
+
+XMLNode *
+XMLNode::add_child(const char * n)
+{
+ return add_child_copy(XMLNode (n));
+}
+
+void
+XMLNode::add_child_nocopy (XMLNode& n)
+{
+ _children.insert(_children.end(), &n);
+}
+
+XMLNode *
+XMLNode::add_child_copy(const XMLNode& n)
+{
+ XMLNode *copy = new XMLNode (n);
+ _children.insert(_children.end(), copy);
+ return copy;
+}
+
+XMLNode *
+XMLNode::add_content(const string & c)
+{
+ return add_child_copy(XMLNode (string(), c));
+}
+
+XMLProperty *
+XMLNode::property(const char * n)
+{
+ string ns(n);
+ if (_propmap.find(ns) == _propmap.end())
+ return 0;
+ return _propmap[ns];
+}
+
+XMLProperty *
+XMLNode::add_property(const char * n, const string & v)
+{
+ string ns(n);
+ if(_propmap.find(ns) != _propmap.end()){
+ remove_property(ns);
+ }
+
+ XMLProperty *tmp = new XMLProperty(ns, v);
+
+ if (!tmp)
+ return 0;
+
+ _propmap[tmp->name()] = tmp;
+ _proplist.insert(_proplist.end(), tmp);
+
+ return tmp;
+}
+
+XMLProperty *
+XMLNode::add_property(const char * n, const char * v)
+{
+ string vs(v);
+ return add_property(n, vs);
+}
+
+void
+XMLNode::remove_property(const string & n)
+{
+ if (_propmap.find(n) != _propmap.end()) {
+ _proplist.remove(_propmap[n]);
+ _propmap.erase(n);
+ }
+}
+
+void
+XMLNode::remove_nodes(const string & n)
+{
+ XMLNodeIterator i = _children.begin();
+ XMLNodeIterator tmp;
+
+ while (i != _children.end()) {
+ tmp = i;
+ ++tmp;
+ if ((*i)->name() == n) {
+ _children.erase (i);
+ }
+ i = tmp;
+ }
+}
+
+void
+XMLNode::remove_nodes_and_delete(const string & n)
+{
+ XMLNodeIterator i = _children.begin();
+ XMLNodeIterator tmp;
+
+ while (i != _children.end()) {
+ tmp = i;
+ ++tmp;
+ if ((*i)->name() == n) {
+ delete *i;
+ _children.erase (i);
+ }
+ i = tmp;
+ }
+}
+
+XMLProperty::XMLProperty(const string &n, const string &v)
+ : _name(n),
+ _value(v)
+{
+}
+
+XMLProperty::~XMLProperty()
+{
+}
+
+static XMLNode *
+readnode(xmlNodePtr node)
+{
+ string name, content;
+ xmlNodePtr child;
+ XMLNode *tmp;
+ xmlAttrPtr attr;
+
+ if (node->name)
+ name = (char *) node->name;
+
+ tmp = new XMLNode(name);
+
+ for (attr = node->properties; attr; attr = attr->next) {
+ content = "";
+ if (attr->children)
+ content = (char *) attr->children->content;
+ tmp->add_property((char *) attr->name, content);
+ }
+
+ if (node->content)
+ tmp->set_content((char *) node->content);
+ else
+ tmp->set_content(string());
+
+ for (child = node->children; child; child = child->next)
+ tmp->add_child_nocopy (*readnode(child));
+
+ return tmp;
+}
+
+static void
+writenode(xmlDocPtr doc, XMLNode * n, xmlNodePtr p, int root =
+ 0)
+{
+ XMLPropertyList props;
+ XMLPropertyIterator curprop;
+ XMLNodeList children;
+ XMLNodeIterator curchild;
+ xmlNodePtr node;
+
+ if (root)
+ node = doc->children =
+ xmlNewDocNode(doc, 0, (xmlChar *) n->name().c_str(), 0);
+
+ else
+ node = xmlNewChild(p, 0, (xmlChar *) n->name().c_str(), 0);
+
+ if (n->is_content()) {
+ node->type = XML_TEXT_NODE;
+ xmlNodeSetContentLen(node, (const xmlChar *) n->content().c_str(),
+ n->content().length());
+ }
+
+ props = n->properties();
+ for (curprop = props.begin(); curprop != props.end(); curprop++)
+ xmlSetProp(node, (xmlChar *) (*curprop)->name().c_str(),
+ (xmlChar *) (*curprop)->value().c_str());
+
+ children = n->children();
+ for (curchild = children.begin(); curchild != children.end();
+ curchild++)
+ writenode(doc, *curchild, node);
+}