diff options
author | Taybin Rutkin <taybin@taybin.com> | 2006-06-29 22:21:30 +0000 |
---|---|---|
committer | Taybin Rutkin <taybin@taybin.com> | 2006-06-29 22:21:30 +0000 |
commit | 481f7c39655afec832ac10430dd61a3bb464aa58 (patch) | |
tree | cde736699cbe49374a6aaa079258f88c1d0c7059 /libs/pbd | |
parent | d1a4f74ef2c86042a0cbe0e83e611596df27575f (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')
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 ®exp, + 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 ®exp, + 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 Binary files differnew file mode 100644 index 0000000000..5008ddfcf5 --- /dev/null +++ b/libs/pbd/pbd/.DS_Store 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 ®exp, + bool match_fullpath = true, + bool return_fullpath = true, + long limit = -1); + + + string *find_first (const string &dirpath, + const string ®exp, + 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); +} |