From a6e50ed6d17f606444e6bb7d4130628d36005d52 Mon Sep 17 00:00:00 2001 From: Chuck Hagenbuch Date: Sat, 24 Apr 2010 12:00:04 -0400 Subject: [PATCH] First try converting Luxor to H4-git --- luxor/.htaccess | 6 + luxor/COPYING | 280 ++++++++++++++++ luxor/README | 11 + luxor/bin/.htaccess | 1 + luxor/bin/indexer | 149 +++++++++ luxor/config/.htaccess | 1 + luxor/config/conf.xml | 43 +++ luxor/config/languages.php.dist | 286 ++++++++++++++++ luxor/config/mime_drivers.php.dist | 37 +++ luxor/config/sources.php.dist | 31 ++ luxor/docs/CHANGES | 23 ++ luxor/docs/CREDITS | 22 ++ luxor/docs/INSTALL | 175 ++++++++++ luxor/docs/TODO | 14 + luxor/index.php | 11 + luxor/js/show_var.js | 17 + luxor/lib/.htaccess | 1 + luxor/lib/Application.php | 63 ++++ luxor/lib/Driver.php | 47 +++ luxor/lib/Driver/sql.php | 564 ++++++++++++++++++++++++++++++++ luxor/lib/Files.php | 35 ++ luxor/lib/Files/plain.php | 172 ++++++++++ luxor/lib/Lang.php | 86 +++++ luxor/lib/Lang/Generic.php | 198 +++++++++++ luxor/lib/Luxor.php | 460 ++++++++++++++++++++++++++ luxor/lib/SimpleParse.php | 178 ++++++++++ luxor/lib/Tagger.php | 104 ++++++ luxor/locale/de_DE/LC_MESSAGES/luxor.mo | Bin 0 -> 158650 bytes luxor/locale/es_ES/LC_MESSAGES/luxor.mo | Bin 0 -> 150790 bytes luxor/locale/ro_RO/LC_MESSAGES/luxor.mo | Bin 0 -> 18669 bytes luxor/po/.htaccess | 1 + luxor/po/README | 1 + luxor/po/de_DE.po | 181 ++++++++++ luxor/po/es_ES.po | 169 ++++++++++ luxor/po/luxor.pot | 170 ++++++++++ luxor/po/ro_RO.po | 215 ++++++++++++ luxor/scripts/.htaccess | 1 + luxor/scripts/sql/luxor.sql | 57 ++++ luxor/search.php | 64 ++++ luxor/source.php | 157 +++++++++ luxor/symbol.php | 86 +++++ luxor/templates/.htaccess | 1 + luxor/templates/common-header.inc | 29 ++ luxor/templates/directory.html.php | 20 ++ luxor/templates/headerbar.inc | 23 ++ luxor/templates/menu.inc | 20 ++ luxor/templates/symbol.html.php | 29 ++ luxor/themes/graphics/favicon.ico | Bin 0 -> 1150 bytes luxor/themes/graphics/folder.png | Bin 0 -> 479 bytes luxor/themes/graphics/luxor.png | Bin 0 -> 508 bytes luxor/themes/graphics/parent.png | Bin 0 -> 428 bytes luxor/themes/screen.css | 60 ++++ 52 files changed, 4299 insertions(+) create mode 100644 luxor/.htaccess create mode 100644 luxor/COPYING create mode 100644 luxor/README create mode 100644 luxor/bin/.htaccess create mode 100755 luxor/bin/indexer create mode 100644 luxor/config/.htaccess create mode 100644 luxor/config/conf.xml create mode 100644 luxor/config/languages.php.dist create mode 100644 luxor/config/mime_drivers.php.dist create mode 100644 luxor/config/sources.php.dist create mode 100644 luxor/docs/CHANGES create mode 100644 luxor/docs/CREDITS create mode 100644 luxor/docs/INSTALL create mode 100644 luxor/docs/TODO create mode 100644 luxor/index.php create mode 100644 luxor/js/show_var.js create mode 100644 luxor/lib/.htaccess create mode 100644 luxor/lib/Application.php create mode 100644 luxor/lib/Driver.php create mode 100644 luxor/lib/Driver/sql.php create mode 100644 luxor/lib/Files.php create mode 100644 luxor/lib/Files/plain.php create mode 100644 luxor/lib/Lang.php create mode 100644 luxor/lib/Lang/Generic.php create mode 100644 luxor/lib/Luxor.php create mode 100644 luxor/lib/SimpleParse.php create mode 100644 luxor/lib/Tagger.php create mode 100644 luxor/locale/de_DE/LC_MESSAGES/luxor.mo create mode 100644 luxor/locale/es_ES/LC_MESSAGES/luxor.mo create mode 100644 luxor/locale/ro_RO/LC_MESSAGES/luxor.mo create mode 100644 luxor/po/.htaccess create mode 100644 luxor/po/README create mode 100644 luxor/po/de_DE.po create mode 100644 luxor/po/es_ES.po create mode 100644 luxor/po/luxor.pot create mode 100644 luxor/po/ro_RO.po create mode 100644 luxor/scripts/.htaccess create mode 100644 luxor/scripts/sql/luxor.sql create mode 100644 luxor/search.php create mode 100644 luxor/source.php create mode 100644 luxor/symbol.php create mode 100644 luxor/templates/.htaccess create mode 100644 luxor/templates/common-header.inc create mode 100644 luxor/templates/directory.html.php create mode 100644 luxor/templates/headerbar.inc create mode 100644 luxor/templates/menu.inc create mode 100644 luxor/templates/symbol.html.php create mode 100644 luxor/themes/graphics/favicon.ico create mode 100644 luxor/themes/graphics/folder.png create mode 100644 luxor/themes/graphics/luxor.png create mode 100644 luxor/themes/graphics/parent.png create mode 100644 luxor/themes/screen.css diff --git a/luxor/.htaccess b/luxor/.htaccess new file mode 100644 index 000000000..140e65f5e --- /dev/null +++ b/luxor/.htaccess @@ -0,0 +1,6 @@ + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^(.*)$ source.php?f=$1 [QSA] + diff --git a/luxor/COPYING b/luxor/COPYING new file mode 100644 index 000000000..a6b67561a --- /dev/null +++ b/luxor/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright 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 diff --git a/luxor/README b/luxor/README new file mode 100644 index 000000000..7de305cd2 --- /dev/null +++ b/luxor/README @@ -0,0 +1,11 @@ +Luxor +Version 0.1 + +What is Luxor? +----------------- + +Luxor is a port of LXR to PHP, integrated into the Horde framework. +You can find LXR at http://sourceforge.net/projects/lxr + +This software is OSI Certified Open Source Software. +OSI Certified is a certification mark of the Open Source Initiative. diff --git a/luxor/bin/.htaccess b/luxor/bin/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/luxor/bin/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/luxor/bin/indexer b/luxor/bin/indexer new file mode 100755 index 000000000..81c53643b --- /dev/null +++ b/luxor/bin/indexer @@ -0,0 +1,149 @@ +#!/usr/bin/env php + + */ + +require_once dirname(__FILE__) . '/../lib/Application.php'; +Horde_Registry::appInit('luxor'); + +// Make sure no one runs this from the web. +if (!Horde_Cli::runningFromCLI()) { + exit("Must be run from the command line\n"); +} + +// Load the CLI environment - make sure there's no time limit, init +// some variables, etc. +$cli = Horde_Cli::init(); + +// Now go ahead and load Luxor. +$session_control = 'none'; +@define('AUTH_HANDLER', true); + +$p = new Horde_Argv_Parser(array('optionList' => array( + new Horde_Argv_Option('-q', '--quiet', array('action' => 'store_true', 'help' => 'No output except errors')), + new Horde_Argv_Option('-v', '--verbose', array('action' => 'store_true', 'help' => 'Debug-level output')), +))); +list($values, $args) = $p->parseArgs(); + +if ($values->quiet && $values->verbose) { + $cli->fatal(_("Can't be both verbose and quiet")); +} +/*@TODO replace with a Horde_Log command-line logger? */ +define('VERBOSE', $values->verbose); +define('QUIET', $values->quiet); + +$first = true; +$skipped = array(); +foreach ($sources as $sourceid => $source) { + if ($args && !in_array($sourceid, $args)) { + continue; + } + $index = Luxor_Driver::factory($sourceid); + $files = Luxor_Files::factory($source['driver'], $source); + + // Clear old data out of the database. + if ($first) { + $index->clearIndex(); + $first = false; + } + + // Index files. + if (!QUIET) $cli->writeln($cli->bold(sprintf(_("Indexing %s"), $source['name']))); + genindex($files, '/'); + if (!QUIET) $cli->writeln(); + + // Reference files. + if (!QUIET) $cli->writeln($cli->bold(sprintf(_("Referencing %s"), $source['name']))); + genrefs($files, '/'); + gensearch(); + if (!QUIET) $cli->writeln(); +} + +if (VERBOSE) { + $cli->writeln($cli->yellow(_("Skipped files:"))); + ksort($skipped); + foreach (array_keys($skipped) as $file) { + $cli->writeln(' ' . $file); + } +} + +if (!QUIET) $cli->writeln($cli->green(_("DONE"))); +exit(0); + + +/** + * Functions. + */ +function genindex($files, $path) +{ + global $cli, $skipped; + + if (VERBOSE) $cli->writeln("*** $path"); + if (substr($path, -1, 1) == '/') { + $dirs = $files->getDir($path); + if (is_a($dirs, 'PEAR_Error')) { + $cli->writeln($cli->red($dirs->getMessage())); + return; + } + foreach ($dirs as $dir) { + genindex($files, $path . $dir); + } + } else { + $lang = Luxor_Lang::builder($files, $path); + if ($lang === false) { + $skipped[$path] = true; + return; + } elseif (is_a($lang, 'PEAR_Error')) { + $cli->writeln($cli->red($lang->getMessage())); + return; + } + + $result = Luxor_Tagger::processFile($files, $path, $lang); + if (is_a($result, 'PEAR_Error')) { + $cli->writeln($cli->red($result->getMessage())); + return; + } + } +} + +function genrefs($files, $path) +{ + global $cli, $skipped; + + if (VERBOSE) $cli->writeln("### $path"); + if (substr($path, -1, 1) == '/') { + $dirs = $files->getDir($path); + if (is_a($dirs, 'PEAR_Error')) { + $cli->writeln($cli->red($dirs->getMessage())); + return; + } + foreach ($dirs as $dir) { + genrefs($files, $path . $dir); + } + } else { + $lang = Luxor_Lang::builder($files, $path); + if ($lang === false) { + $skipped[$path] = true; + return; + } elseif (is_a($lang, 'PEAR_Error')) { + $cli->writeln($cli->red($lang->getMessage())); + return; + } + + $result = Luxor_Tagger::processRefs($files, $path, $lang); + if (is_a($result, 'PEAR_Error')) { + $cli->writeln($cli->red($result->getMessage())); + return; + } + } +} + +function gensearch() +{ +} diff --git a/luxor/config/.htaccess b/luxor/config/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/luxor/config/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/luxor/config/conf.xml b/luxor/config/conf.xml new file mode 100644 index 000000000..049d12087 --- /dev/null +++ b/luxor/config/conf.xml @@ -0,0 +1,43 @@ + + + + + Storage System Settings + + sql + + + + + + + + + + Paths + /usr/bin/ctags + + + + Look and feel + + get + + get + rewrite + + + true + + + + Menu Settings + + + + + + + diff --git a/luxor/config/languages.php.dist b/luxor/config/languages.php.dist new file mode 100644 index 000000000..1bd5a117c --- /dev/null +++ b/luxor/config/languages.php.dist @@ -0,0 +1,286 @@ + array( + 'C' => array('C', '\.c$', 'Generic', '8'), + 'C++' => array('C++', '\.C$|((?i)\.c\+\+$|\.cc$|\.cpp$|\.cxx$|\.h$|\.hh$|\.hpp$|\.hxx$|\.h\+\+$)', + 'Generic', '8'), + 'Java' => array('Java', '(?i)\.java$', 'Generic', '4'), + // No tabwidth specified here as an example + 'Make' => array('Make', '(?i)\.mak$|makefile*', 'Generic'), + 'Perl' => array('Perl', '(?i)\.pl$|\.pm$|\.cgi$|\.perl$', 'Generic', '4'), + 'PHP' => array('php', '(?i)\.php$|\.php3$|\.phtml|\.phpt|\.phput$', 'Generic', '2'), + 'Python' => array('Python', '(?i)\.py$|\.python$', 'Generic', '4'), + ), + + // Maps interpreter names to languages. The format is: + // regexp => langname + // regexp is matched against the part after #! on the first line of a file + // langname must match one of the keys in filetype above. + // + // This mapping is only used if the filename doesn't match a pattern above, so + // a shell script called shell.c will be recognised as a C file, not a shell file. + 'interpreters' => array( + 'perl' => 'Perl', + 'php' => 'PHP', + 'python' => 'Python' + ), + + // How to map a language name to the ectags language-force name + // if there is no mapping, then the language name is used + 'eclangnamemapping' => array( + 'C' => 'c', + 'C++' => 'c++', + 'Python' => 'python' + ), + + // Options to always feed to ectags + 'ectagsopts' => '--c-types=+px --eiffel-types=+l --fortran-types=+L', + + // lang map specifies info for each language + // what the reserved words & comment chars are + 'langmap' => array( + 'C' => array( + 'reserved' => array( + 'auto', 'break', 'case', 'char', 'const', + 'continue', 'default', 'do', 'double', + 'else', 'enum', 'extern', 'float', 'for', + 'goto', 'if', 'int', 'long', 'register', + 'return', 'short', 'signed', 'sizeof', + 'static', 'struct', 'switch', 'typedef', + 'union', 'unsigned', 'void', 'volatile', + 'while', + ), + + 'spec' => array('atom', '\\\\.', '', + 'comment', '/\*', '\*/', + 'comment', '//', "\$", + 'string', '"', '"', + 'string', "'", "'", + 'include', '#\s*include', "\$"), + + 'typemap' => array( + 'c' => 'class', + 'd' => 'macro (un)definition', + 'e' => 'enumerator', + 'f' => 'function definition', + 'g' => 'enumeration name', + 'm' => 'class, struct, or union member', + 'n' => 'namespace', + 'p' => 'function prototype or declaration', + 's' => 'structure name', + 't' => 'typedef', + 'u' => 'union name', + 'v' => 'variable definition', + 'x' => 'extern or forward variable declaration', + 'i' => 'interface'), + 'langid' => '1', + ), + + 'C++' => array( + 'reserved' => array('and', 'and_eq', 'asm', 'auto', 'bitand', + 'bitor', 'bool', 'break', 'case', 'catch', + 'char', 'class', 'const', 'const_cast', + 'continue', 'default', 'delete', 'do', + 'double', 'dynamic_cast', 'else', 'enum', + 'explicit', 'export', 'extern', 'false', + 'float', 'for', 'friend', 'goto', 'if', + 'inline', 'int', 'long', 'mutable', + 'namespace', 'new', 'not', 'not_eq', + 'operator', 'or', 'or_eq', 'private', + 'protected', 'public', 'register', + 'reinterpret_cast', 'return', 'short', + 'signed', 'sizeof', 'static', + 'static_cast','struct', 'switch', + 'template','this', 'throw', 'true','try', + 'typedef', 'typeid','typename', + 'union', 'unsigned','using', + 'virtual', 'void','volatile', + 'wchar_t', 'while','xor', + 'xor_eq'), + + 'spec' => array('atom', '\\\\.', '', + 'comment', '/\*', '\*/', + 'comment', '//', "\$", + 'string', '"', '"', + 'string', "'", "'", + 'include', '#\s*include', "\$"), + 'typemap' => array( + 'c' => 'class', + 'd' => 'macro (un)definition', + 'e' => 'enumerator', + 'f' => 'function definition', + 'g' => 'enumeration name', + 'm' => 'class, struct, or union member', + 'n' => 'namespace', + 'p' => 'function prototype or declaration', + 's' => 'structure name', + 't' => 'typedef', + 'u' => 'union name', + 'v' => 'variable definition', + 'x' => 'extern or forward variable declaration', + 'i' => 'interface'), + 'langid' => '2', + + ), + + 'Java' => array( + 'reserved' => array('break', 'case', 'continue', 'default', + 'do', 'else', 'for', 'goto', 'if', + 'return', 'static', 'switch', 'void', + 'volatile', 'while', 'public', 'class', + 'final', 'private', 'protected', + 'synchronized', 'package', 'import', + 'boolean', 'byte', 'new', 'abstract', + 'extends', 'implements', 'interface', + 'throws', 'instanceof', 'super', 'this', + 'native', 'null'), + + 'spec' => array('atom', '\\\\.', '', + 'comment', '/\*', '\*/', + 'comment', '//', "\$", + 'string', '"', '"', + 'string', "'", "'", + 'include', 'import', "\$", + 'include', 'package', "\$" + ), + 'typemap' => array( + 'c' => 'class', + 'f' => 'field', + 'i' => 'interface', + 'm' => 'method', + 'p' => 'package', + ), + 'langid' => '3', + ), + + 'Fortran' => array( + 'reserved' => array(), + 'typemap' => array( + 'b' => 'block data', + 'c' => 'common block', + 'e' => 'entry point', + 'f' => 'function', + 'i' => 'interface', + 'k' => 'type component', + 'l' => 'label', + 'L' => 'local and common block variable', + 'm' => 'module', + 'n' => 'namelist', + 'p' => 'program', + ), + 'langid' => '4', + ), + + 'Pascal' => array( + 'reserved' => array(), + 'langid' => '5', + ), + + 'COBOL' => array( + 'reserved' => array(), + 'langid' => '6', + ), + 'Perl' => array( + 'reserved' => array( + 'sub', + ), + 'spec' => array('atom', '\$\W?', '', + 'atom', '\\\\.', '', + 'include', '\buse\s+', ';', + 'include', '\brequire\s+', ';', + 'string', '"', '"', + 'comment', '#', "\$", + 'comment', "^=\\w+", "^=cut", + 'string', "'", "'"), + 'typemap' => array( + 's' => 'subroutine', + 'p' => 'package', + ), + 'langid' => '7', + + ), + 'Python' => array( + 'reserved' => array('def','print','del','pass', + 'break','continue','return', + 'raise','import','from', + 'global','exec','assert', + 'if','elif','else','while', + 'for','try','except','finally', + 'class','as','import','or', + 'and','is','in','for','if', + 'not','lambda','self', + ), + + 'spec' => array('comment', '#', "\$", + 'string', '"', '"', + 'string', "'", "'", + 'atom', '\\\\.', ''), + 'typemap' => array( + 'c' => 'class', + 'f' => 'function', + ), + 'langid' => '8', + ), + 'php' => array( + 'reserved' => array('and','$argv','$argc','break','case','class', + 'continue','default','do','die','echo','else', + 'elseif','empty','endfor','endforeach','endif', + 'endswitch','endwhile','E_ALL','E_PARSE','E_ERROR', + 'E_WARNING','exit','extends','FALSE','for','foreach', + 'function','HTTP_COOKIE_VARS','HTTP_GET_VARS', + 'HTTP_POST_VARS','HTTP_POST_FILES','HTTP_ENV_VARS', + 'HTTP_SERVER_VARS','GLOBALS','_FILES','_ENV','_REQUEST', + '_GET','_POST','_COOKIE','_SESSION','if','global','list', + 'new','not','NULL','or','parent','PHP_OS','PHP_SELF', + 'PHP_VERSION','print','return','static','switch','stdClass', + 'this','TRUE','var','xor','virtual','while','__FILE__', + '__LINE__','__sleep','__wakeup', 'header', 'global', + 'array', 'double', 'fclose', 'fopen', 'fputs', 'object', + 'is_a', 'in_array', 'is_null', 'unset', 'true', 'false', + 'null', 'define' + ), + + 'spec' => array('comment', '/\*', '\*/', + 'comment', '//', "\$", + 'comment', '#', "\$", + 'string', '"', '"', + 'string', "'", "'", + 'include', 'require_once[^[a-zA-Z0-9_\x7f-\xff]', ";", + 'include', 'include_once[^[a-zA-Z0-9_\x7f-\xff]', ";", + 'include', 'require[^[a-zA-Z0-9_\x7f-\xff]', ";", + 'include', 'include[^[a-zA-Z0-9_\x7f-\xff]', ";", + 'variable', '\$', '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*', + ), + 'typemap' => array( + 'c' => 'class', + 'f' => 'function', + ), + 'langid' => '9', + ), + 'Make' => array( + 'reserved' => array(), + 'spec' => array('comment', '#', "\$", + 'string', '"', '"', + 'string', "'", "'", + 'include', '^ *-?include', '\$'), + 'typemap' => array( + 'm' => 'macro', + ), + 'langid' => '10', + ), + ) +); diff --git a/luxor/config/mime_drivers.php.dist b/luxor/config/mime_drivers.php.dist new file mode 100644 index 000000000..6d3519150 --- /dev/null +++ b/luxor/config/mime_drivers.php.dist @@ -0,0 +1,37 @@ + 'Horde', + 'driver' => 'plain', + 'root' => dirname(__FILE__) . '/../../', + 'restrictions' => array('(.*)config/(\w*).php$') +); + +$sources['pear'] = array( + 'name' => 'PEAR', + 'driver' => 'plain', + 'root' => '/usr/local/lib/php/' +); diff --git a/luxor/docs/CHANGES b/luxor/docs/CHANGES new file mode 100644 index 000000000..8ec9668d2 --- /dev/null +++ b/luxor/docs/CHANGES @@ -0,0 +1,23 @@ +---- +v0.1 +---- + +[ben] Better support for MS-SQL. +[cjh] Support mod_rewrite style URLs in addition to GET. +[mas] Change any output of and tags to and for better + accessibility support. +[cjh] Allow disabling the show_var javascript (Bug #1270). +[jan] Add Spanish translation (Manuel Perez Ayala ). +[cjh] Cache markup of files. +[cjh] Improve layout of identifier pages. +[cjh] genxref.php is now solely a command line script and lives + in the scripts/ directory. +[cjh] Make sure to clean out the database before adding new data + so as not to get duplicate entries for identifiers. +[jan] Add German translation. +[cjh] Add symbol search functionality. +[cjh] Fix spacing of source code. +[cjh] Add options to filter out certain directories and filenames. +[jan] Add Romanian translation (Eugen Hoanca ). +[jan] Implement indexing and referencing. +[jan] Initial port from LXR. diff --git a/luxor/docs/CREDITS b/luxor/docs/CREDITS new file mode 100644 index 000000000..b1da3adcc --- /dev/null +++ b/luxor/docs/CREDITS @@ -0,0 +1,22 @@ +============================ +|| Luxor Development Team || +============================ + +=============== +Core Developers +=============== + +Jan Schneider +- initial port from LXR + + +============ +Localization +============ + +German Jan Schneider +Romanian Eugen Hoanca +Spanish Manuel Perez Ayala + + +$Horde: luxor/docs/CREDITS,v 1.4 2004/07/29 11:25:48 jan Exp $ diff --git a/luxor/docs/INSTALL b/luxor/docs/INSTALL new file mode 100644 index 000000000..49c0c16b8 --- /dev/null +++ b/luxor/docs/INSTALL @@ -0,0 +1,175 @@ +========================== +|| INSTALLING Luxor 0.1 || +========================== + +This document contains instructions for installing the Luxor web-based +luxor application on your system. + +For information on the capabilities and features of Luxor, see the file +README in the top-level directory of the Luxor distribution. + + +OBTAINING Luxor +------------------ + +Luxor can be obtained from the Horde website and FTP server, at + + http://www.horde.org/luxor/ + ftp://ftp.horde.org/pub/luxor/ + +Bleeding-edge development versions of Luxor are available via CVS; see +the file docs/HACKING in the Horde distribution for information on +accessing the Horde CVS repository. + + +PREREQUISITES +------------- + +To function properly, Luxor requires the following: + + 1. A working Horde installation. + + Luxor runs within the Horde Application Framework, a set of + common tools for Web applications written in PHP. You must + install Horde before installing Luxor. + + The Horde Framework can be obtained from the Horde website and + FTP server, at + + http://www.horde.org/horde/ + ftp://ftp.horde.org/pub/horde/ + + Many of Luxor's prerequisites are also Horde prerequisites. + Be sure to have completed all of the steps in the INSTALL + file for the Horde Framework before installing Luxor. + + 2. SQL support in PHP. + + Luxor store its data in an SQL database. Build PHP with whichever + SQL driver you require; see the Horde INSTALL file for details. + + +INSTALLING Luxor +------------------- + +Luxor is written in PHP, and must be installed in a web-accessible +directory. The precise location of this directory will differ from +system to system. Conventionally, Luxor is installed directly underneath +Horde in the webserver's document tree. + +Since Luxor is written in PHP, there is no compilation necessary; +simply expand the distribution where you want it to reside and rename +the root directory of the distribution to whatever you wish to appear +in the URL. For example, with the Apache webserver's default document +root of '/usr/local/apache/htdocs', you would type: + + cd /usr/local/apache/htdocs/horde + tar zxvf /path/to/luxor-1.0.tar.gz + mv luxor-1.0 luxor + +and would then find Luxor at the URL + + http://your-server/horde/luxor/ + + +CONFIGURING Luxor +-------------------- + +1. Configuring Horde for Luxor + + a. Register the application + + In horde/config/registry.php, find the applications['luxor'] stanza. + The 'status' parameter should already be marked '=> active'. + If you have changed the location of Luxor relative to Horde, + either in the URL or in the filesystem or both, you must + update the 'fileroot' and 'webroot' settings to their correct + values. + +2. Creating the database table + + The specific steps to create the Luxor database table depend + on which database you've chosen to use. + + First, look in scripts/sql/ to see if a script already + exists for your database type. If so, you should be + able to simply execute that script as superuser in your + database. (Note that executing the script as the "horde" user will + probably fail when granting privileges.) + + If such a script does not exist, you'll need to build your own, using + the file luxor.sql as a starting point. If you need + assistance in creating databases, you may wish to let us know on + the Luxor mailing list. + +3. Configuring Luxor. + + To configure Luxor, change to the config/ directory of the + installed distribution, and make copies of all of the configuration + "dist" files without the "dist" suffix: + + cd config/ + for foo in *.dist; do cp $foo `basename $foo .dist`; done + + Documentation on the format of those files can be found in each + file. With the exception of the conf.* files (see below), + the other files in config/ need only be modified if you wish + to customize Luxor's appearance or behavior, as the defaults will + be correct for most sites. + + You must login to Horde as a Horde Administrator to finish the + configuring of Luxor. Use the Horde "Administration" menu item to get + to the Administration page, and then click on the "Configuration" + icon to get the Configuration page. Select "Luxor" from the selection + list of applications, and click on the "Configure" button. Fill in or + change any configuration values as needed. When done click on "Generate + Luxor Configuration" to generate the conf.php file. If your web server + doesn't have write permissions to the Luxor configuration directory or + file, it will not be able to write the file. In this case, cut and + paste the returned configuration information into the file + luxor/config/conf.php. + + Note for international users: Luxor uses GNU gettext to provide local + translations of text displayed by applications; the translations are + found in the po/ directory. If a translation is not yet available + for your locale (and you wish to create one), or if you're having + trouble using a provided translation, please see the horde/docs/TRANSLATIONS + file for instructions. + +4. Testing Luxor + + Use Luxor to .... Test at + least the following: + + - .... + + +OBTAINING SUPPORT +----------------- + +If you encounter problems with Luxor, help is available! + +The Horde Frequently Asked Questions List (FAQ), available on the Web +at + + http://www.horde.org/faq/ + +The Horde Project runs a number of mailing lists, for individual +applications and for issues relating to the project as a whole. +Information, archives, and subscription information can be found at + + http://www.horde.org/mail/ + +Lastly, Horde developers, contributors and users may also be found on IRC, +on the channel #horde on the Freenode Network (irc.freenode.net). + +Please keep in mind that Luxor is free software written by volunteers. +For information on reasonable support expectations, please read + + http://www.horde.org/support.php + +Thanks for using Luxor! + +The Horde team + +$Horde: luxor/docs/INSTALL,v 1.7 2008/11/11 10:14:16 jan Exp $ diff --git a/luxor/docs/TODO b/luxor/docs/TODO new file mode 100644 index 000000000..00247a988 --- /dev/null +++ b/luxor/docs/TODO @@ -0,0 +1,14 @@ +Short term +---------- +- documentation +- standard sql for sql scripts +- PEAR::DB sequences instead of autoincrement fields +- port UI + +Mid term +-------- +- CVS File driver + +Long term +--------- +- branch support diff --git a/luxor/index.php b/luxor/index.php new file mode 100644 index 000000000..449794aeb --- /dev/null +++ b/luxor/index.php @@ -0,0 +1,11 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Driver +{ + /** + * Attempts to return a concrete Luxor_Driver instance based on $driver. + * + * @param string $driver The type of concrete Luxor_Driver subclass + * to return. The is based on the storage + * driver ($driver). The code is dynamically + * included. + * + * @param array $params (optional) A hash containing any additional + * configuration or connection parameters a + * subclass might need. + * + * @return mixed The newly created concrete Luxor_Driver instance, or + * false on an error. + */ + function factory($source, $driver = null, $params = null) + { + if (is_null($driver)) { + $driver = $GLOBALS['conf']['storage']['driver']; + } + + $driver = basename($driver); + + if (is_null($params)) { + $params = Horde::getDriverConfig('storage', $driver); + } + + $class = 'Luxor_Driver_' . $driver; + if (class_exists($class)) { + $luxor = new $class($source, $params); + } else { + $luxor = false; + } + + return $luxor; + } +} diff --git a/luxor/lib/Driver/sql.php b/luxor/lib/Driver/sql.php new file mode 100644 index 000000000..c75cbdda8 --- /dev/null +++ b/luxor/lib/Driver/sql.php @@ -0,0 +1,564 @@ + + * 'phptype' The database type (e.g. 'pgsql', 'mysql', etc.). + * 'charset' The database's internal charset. + * + * Required by some database implementations:
+ *      'hostspec'      The hostname of the database server.
+ *      'protocol'      The communication protocol ('tcp', 'unix', etc.).
+ *      'username'      The username with which to connect to the database.
+ *      'password'      The password associated with 'username'.
+ *      'database'      The name of the database.
+ *      'options'       Additional options to pass to the database.
+ *      'tty'           The TTY on which to connect to the database.
+ *      'port'          The port on which to connect to the database.
+ * + * The table structure can be created by the scripts/drivers/luxor.sql + * script. + * + * $Horde: luxor/lib/Driver/sql.php,v 1.29 2007/09/23 13:32:35 jan Exp $ + * + * @author Jan Schneider + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Driver_sql extends Luxor_Driver { + + /** + * Hash containing connection parameters. + * + * @var array + */ + var $_params = array(); + + /** + * Handle for the current database connection. + * + * @var DB + */ + var $_db; + + /** + * The id of the source that we are dealing with. + * + * @var string + */ + var $_source; + + /** + * Boolean indicating whether or not we're connected to the SQL server. + * + * @var boolean + */ + var $_connected = false; + + /** + * Symbol cache. + * + * @var array + */ + var $_symcache = array(); + + /** + * Description ID cache. + * + * @var array + */ + var $_decIdcache = array(); + + /** + * Constructs a new SQL storage object. + * + * @param string $source The name of the source. + * @param array $params A hash containing connection parameters. + */ + function Luxor_Driver_sql($source, $params = array()) + { + $this->_source = $source; + $this->_params = $params; + } + + /** + * Adds a symbol definition to the sybmol index. + * + * @param string $symname The symbol's name. + * @param integer $fileId The unique ID of the file where this symbol was + * defined. + * @param integer $line The linenumber where this symbol was defined. + * @param integer $langid The unique ID of the language the file was + * written in. + * @param integer $type The symbol type. + * + * @return mixed PEAR_Error on error, true on success. + */ + function index($symname, $fileId, $line, $langid, $type) + { + $this->_connect(); + + $symid = $this->symid($symname); + if (is_a($symid, 'PEAR_Error')) { + return $symid; + } + + /* I have no idea what this is about yet + if ($relsym) { + $relsym = $this->symid($relsym); + if (is_a($relsym, 'PEAR_Error')) { + return $relsym; + } + $relsym = $this->_db->quote($relsym); + } else { + $relsym = 'NULL'; + } + */ + + $query = 'INSERT INTO luxor_indexes (symid, fileid, line, declid)' . + ' VALUES (?, ?, ?, ?)'; + $values = array($symid, $fileId, $line, $this->getDecId($langid, $type)); + return $this->_db->query($query, $values); + } + + /** + * Add a symbol reference to the reference index. + * + * @param string $symname The name of the used symbol. + * @param integer $fileId The unique ID of the file in which the symbol + * was used. + * @param integer $line The number of line in which the symbol was used. + * + * @return mixed PEAR_Error on error, true on success. + */ + function reference($symname, $fileId, $line) + { + $this->_connect(); + + $result = $this->_db->query('INSERT INTO luxor_usage (fileid, line, symid) VALUES (?, ?, ?)', + array($fileId, $line, $this->symid($symname))); + return $result; + } + + /** + * Returns a unique ID for a given filename. + * + * @param string $filename The name of the file. + * @param string $tag The tag of the file. + * + * @return integer A unique ID for this file or PEAR_Error on error. + */ + function fileId($filename, $tag = '') + { + static $files = array(); + + /* Have we already been asked for this file? */ + if (isset($files[$filename])) { + return $files[$filename]; + } + + $this->_connect(); + + /* Has an ID already been created for this file? */ + $query = 'SELECT fileid FROM luxor_files' . + ' WHERE tag = ? AND source = ? AND filename = ?'; + $values = array($tag, $this->_source, $filename); + + $fileId = $this->_db->getOne($query, $values); + if (empty($fileId) || is_a($fileId, 'PEAR_Error')) { + return false; + } + $files[$filename] = $fileId; + + return $fileId; + } + + /** + * Created a unique ID for a given filename. + * + * @param string $filename The name of the file. + * @param string $tag The tag of the file. + * @param integer $lastmodified The timestamp the file was last modified. + * + * @return integer A unique ID for this file or PEAR_Error on error. + */ + function createFileId($filename, $tag = '', $lastmodified) + { + $this->_connect(); + + $fileId = $this->_db->nextId('luxor_files'); + if (is_a($fileId, 'PEAR_Error')) { + return $fileId; + } + + /* Create an ID for this file. */ + $query = 'INSERT INTO luxor_files (fileid, filename, source, tag, lastmodified) VALUES (?, ?, ?, ?, ?)'; + $values = array((int)$fileId, + $filename, + $this->_source, + $tag, + $lastmodified); + + $result = $this->_db->query($query, $values); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + return $fileId; + } + + /** + * Returns a unique ID for a given symbol. + * + * @param string $symname The name of the symbol. + * + * @return int A unique ID for this symbol or PEAR_Error on error. + */ + function symid($symname) + { + /* Do we have this symbol in the symbol cache yet? */ + if (!isset($this->_symcache[$symname])) { + $this->_connect(); + /* Has an ID already been created for this symbol? */ + $query = 'SELECT symid FROM luxor_symbols' . + ' WHERE source = ? AND symname = ?'; + $values = array($this->_source, $symname); + $symid = $this->_db->getOne($query, $values); + if (is_null($symid) || is_a($symid, 'PEAR_Error')) { + /* Create an ID for this symbol. */ + $symid = $this->_db->nextId('luxor_symbols'); + if (is_a($symid, 'PEAR_Error')) { + return $symid; + } + $result = $this->_db->query('INSERT INTO luxor_symbols (symid, symname, source) VALUES (?, ?, ?)', + array((int)$symid, $symname, $this->_source)); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + } + $this->_symcache[$symname] = $symid; + } + + return $this->_symcache[$symname]; + } + + /** + * Returns the name of a symbol from its unique ID. + * + * @param integer $symid The ID of the symbol + * + * @return string The name of the symbol or PEAR_Error on error + */ + function symname($symid) + { + /* Don't we have this symbol in the symbol cache yet? */ + $this->_connect(); + + if (in_array($symid, $this->_symcache)) { + return array_key($symid, $this->_symcache); + } + + $query = 'SELECT symname FROM luxor_symbols WHERE symid = ?'; + $values = array($symid); + $symname = $this->_db->getOne($query, $values); + $this->_symcache[$symname] = $symid; + + return $symname; + } + + /** + * Checks if the given name is a known symbol. + * + * @param string $symname The potential symbol name. + * + * @return integer The symbol's id or null if it wasn't a symbol. + */ + function isSymbol($symname, $altsources = array()) + { + if (!isset($this->_symcache[$symname])) { + $this->_connect(); + + $altsql = ''; + $altvalues = array(); + if (!is_array($altsources)) { + $altsources = array($altsources); + } + foreach ($altsources as $source) { + $altsql .= ' OR source = ?'; + $altvalues[] = $source; + } + + array_unshift($altvalues, $this->_source); + $values = $altvalues; + $values[] = $symname; + + $symid = $this->_db->getOne('SELECT symid FROM luxor_symbols' . + ' WHERE (source = ?' . $altsql . ')' . + ' AND symname = ?', + $values); + $this->_symcache[$symname] = $symid; + } + + return $this->_symcache[$symname]; + } + + /** + * If this file has not been indexed earlier, mark it as being + * indexed now. + * + * @param integer $fileId The file's unique ID. + * + * @return boolean True if the file has been marked as being indexed, + * false if it was already indexed. + */ + function toIndex($fileId) + { + $this->_connect(); + + $status = $this->_db->getOne('SELECT status FROM luxor_status' . + ' WHERE fileid = ?', + array($fileId)); + if (empty($status)) { + $this->_db->query('INSERT INTO luxor_status (fileid, status)' . + ' VALUES (?, 0)', + array($fileId + 0)); + } + $query = 'UPDATE luxor_status SET status = 1' . + ' WHERE fileid = ? AND status <= 0'; + $values = array($fileId); + return $this->_db->query($query, $values); + } + + /** + * If this file has not been referenced earlier, mark it as being + * referenced now. + * + * @param integer $fileId The file's unique ID. + * + * @return boolean True if the file has been marked as being referenced, + * false if it was already referenced. + */ + function toReference($fileId) + { + $this->_connect(); + + $query = 'UPDATE luxor_status SET status = 2' . + ' WHERE fileid = ? AND status <= 1'; + $values = array($fileId); + return $this->_db->query($query, $values); + } + + /** + * Return the last time the entry for a file was modified. + * + * @param string $filename The filename to check. + * + * @return integer The last modified time, or 0 if there is an error. + */ + function getLastModified($filename) + { + static $lastModified; + + if (isset($lastModified[$filename])) { + return $lastModified[$filename]; + } + + $this->_connect(); + $query = 'SELECT lastmodified FROM luxor_files' . + ' WHERE source = ? AND filename = ?'; + $values = array($this->_source, $filename); + $res = $this->_db->getOne($query, $values); + $lastModified[$filename] = is_a($res, 'PEAR_Error') ? 0 : $res; + + return $lastModified[$filename]; + } + + /** + * Empties the current symbol cache. + * + * This function should be called before parsing each new file. + * If this is not done too much memory will be used and things + * will become very slow. + */ + function clearCache() + { + $this->_symcache = array(); + } + + /** + * Cleans the database for a fresh import of data. + * + * This function should be called before parsing the source tree + * again, to avoid duplicate entries in the database. + */ + function clearIndex() + { + $this->_connect(); + + $this->_db->query('DELETE FROM luxor_declarations'); + $this->_db->query('DELETE FROM luxor_files'); + $this->_db->query('DELETE FROM luxor_indexes'); + $this->_db->query('DELETE FROM luxor_status'); + $this->_db->query('DELETE FROM luxor_symbols'); + $this->_db->query('DELETE FROM luxor_usage'); + } + + /** + * Returns an unique ID for a description of a symbol type. + * + * @param integer $lang The language's unique ID. + * @param string $string The symbol type description. + * + * return mixed A unique ID for this description or PEAR_Error on error. + */ + function getDecId($lang, $string) + { + $this->_connect(); + + if (!isset($this->_decIdcache[$lang])) { + $this->_decIdcache[$lang] = array(); + } + + if (!isset($this->_decIdcache[$lang][$string])) { + $query = 'SELECT declid FROM luxor_declarations' . + ' WHERE langid = ? AND declaration = ?'; + $values = array($lang, $string); + $decId = $this->_db->getOne($query, $values); + if (is_null($decId) || is_a($decId, 'PEAR_Error')) { + /* Create an ID for this declaration. */ + $decId = $this->_db->nextId('luxor_declarations'); + if (is_a($decId, 'PEAR_Error')) { + return $decId; + } + $this->_db->query('INSERT INTO luxor_declarations (declid, langid, declaration)' . + ' VALUES (?, ?, ?)', + array((int)$decId, $lang, $string)); + } + $this->_decIdcache[$lang][$string] = $decId; + } + + return $this->_decIdcache[$lang][$string]; + } + + /** + * Locate the definitions of a symbol. + * + * @param integer $symid The symbol id. + * @param string $tag The tag of the file. + * + * @return array Nested hash with elements 'filename', 'line', and + * 'declaration'. + */ + function getIndex($symid, $tag = '') + { + $this->_connect(); + $query = 'SELECT filename, line, declaration FROM ' . + 'luxor_files, luxor_indexes, luxor_declarations WHERE ' . + 'luxor_files.fileid = luxor_indexes.fileid AND ' . // join files to indexes + 'luxor_indexes.declid = luxor_declarations.declid AND ' . // join indexes to declarations + 'luxor_indexes.symid = ? AND ' . + 'luxor_files.tag = ? AND ' . + 'luxor_files.source = ?'; + $values = array((int)$symid, $tag, $this->_source); + + return $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC); + } + + /** + * Locate the usage of a symbol. + * + * @param integer $symid The symbol id. + * @param string $tag The tag of the file. + * + * @return array Nested hash with elements 'filename', and 'line'. + */ + function getReference($symid, $tag = '') + { + $this->_connect(); + $query = 'SELECT filename, line FROM ' . + 'luxor_usage, luxor_files WHERE ' . + 'luxor_usage.fileid = luxor_files.fileid AND ' . + 'luxor_usage.symid = ? AND ' . + 'luxor_files.tag = ? AND ' . + 'luxor_files.source = ?'; + $values = array((int)$symid, $tag, $this->_source); + + return $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC); + } + + /** + * Search for symbols matching $symbol. + * + * @param string $symbol The symbol name to search for. + * + * @return array Any symids matching $symbol. + */ + function searchSymbols($symbol) + { + $this->_connect(); + $query = 'SELECT symid, symid FROM luxor_symbols WHERE symname LIKE ?'; + $values = array($symbol . '%'); + + return $this->_db->getAssoc($query, false, $values); + } + + /** + * Get source that a symbol is from. + * + * @param $symid The symbol id. + * + * @return string The source id. + */ + function getSourceBySymbol($symid) + { + $this->_connect(); + + return $this->_db->getOne('SELECT source FROM luxor_symbols' . + ' WHERE symid = ?', + array($symid)); + } + + /** + * Attempts to open a persistent connection to the SQL server. + * + * @return boolean True on success; exits (Horde::fatal()) on error. + */ + function _connect() + { + if (!$this->_connected) { + Horde::assertDriverConfig($this->_params, 'storage', + array('phptype', 'charset')); + + if (!isset($this->_params['database'])) { + $this->_params['database'] = ''; + } + if (!isset($this->_params['username'])) { + $this->_params['username'] = ''; + } + if (!isset($this->_params['hostspec'])) { + $this->_params['hostspec'] = ''; + } + + /* Connect to the SQL server using the supplied parameters. */ + $this->_db = &DB::connect($this->_params, + array('persistent' => !empty($this->_params['persistent']))); + if (is_a($this->_db, 'PEAR_Error')) { + Horde::fatal($this->_db, __FILE__, __LINE__); + } + + // Set DB portability options. + switch ($this->_db->phptype) { + case 'mssql': + $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM); + break; + default: + $this->_db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS); + } + + $this->_connected = true; + } + + return true; + } + +} diff --git a/luxor/lib/Files.php b/luxor/lib/Files.php new file mode 100644 index 000000000..5d618bba2 --- /dev/null +++ b/luxor/lib/Files.php @@ -0,0 +1,35 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Files +{ + /** + * Attempts to return a concrete Luxor_Files instance based on $driver. + * + * @param string $driver The type of concrete Luxor_Files subclass + * to return. The is based on the repository + * driver ($driver). The code is dynamically + * included. + * @param array $params (optional) A hash containing any additional + * configuration or connection parameters a + * subclass might need. + * + * @return mixed The newly created concrete Luxor_Files instance, or + * false on an error. + */ + function factory($driver, $params = array()) + { + $driver = basename($driver); + $class = 'Luxor_Files_' . $driver; + if (class_exists($class)) { + return new $class($params); + } else { + return false; + } + } +} diff --git a/luxor/lib/Files/plain.php b/luxor/lib/Files/plain.php new file mode 100644 index 000000000..45725b1d4 --- /dev/null +++ b/luxor/lib/Files/plain.php @@ -0,0 +1,172 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Files_plain extends Luxor_Files { + + /** + * Hash containing parameters. + * + * @var array + */ + var $_params = array(); + + /** + * Constructs a new filesystem handler. + * + * @param array $params A hash containing parameters. + */ + function Luxor_Files_plain($params = array()) + { + $this->_params = $params; + } + + function getFiletime($filename) + { + return filemtime($this->toReal($filename)); + } + + function getFilesize($filename) + { + return filesize($this->toReal($filename)); + } + + /** + * Returns a file handler. + * + * @param string $filename The name of the file to open. + * + * @return ressource A handler of the file or false on error. + */ + function getFileHandle($filename) + { + return @fopen($this->toReal($filename), 'r'); + } + + /** + * Creates a temporary copy of a file. + * + * @param string $filename The name of the file to be copied. + * + * @return string The file name of the temporary copy or false + * if the file couldn't be copied. + */ + function tmpFile($filename) + { + $tmp = Horde::getTempFile('luxor'); + if (!@copy($this->toReal($filename), $tmp)) { + return false; + } + return $tmp; + } + + /** + * Returns a directory's content. Backup files are skipped and + * directories suffixed with a slash. + * + * @param string $path The directory to list. + * + * @return array An array containing all directories and files of + * the directory or PEAR_Error if the directory + * couldn't be read. + */ + function getDir($path, $release = '') + { + $path = $this->toReal($path); + + $dir = @opendir($path); + if (!$dir) { + return PEAR::raiseError(sprintf(_("Can't open directory %s"), $path)); + } + + $dirs = array(); + $files = array(); + while (($file = readdir($dir)) !== false) { + if (preg_match('/^\.|~$|\.orig$|\.bak$/i', $file) || + (is_dir($path . $file) && $file == 'CVS')) { + continue; + } + + if (is_dir($path . $file)) { + if (Luxor::isDirParsed($path . $file)) { + $dirs[] = $file . '/'; + } + } else { + if (Luxor::isFileParsed($path . $file)) { + $files[] = $file; + } + } + } + + closedir($dir); + natcasesort($dirs); + natcasesort($files); + return array_merge($dirs, $files); + } + + /** + * Returns the full path to a file. + * + * @param string $pathname The internally used (relative) name of the file. + * + * @return string The full path to the file. + */ + function toReal($pathname) + { + return $this->_params['root'] . $pathname; + } + + /** + * Checks if the given path name is a directory. + * + * @param string $pathname The path name to check. + * + * @return boolean True if the path name was a directory. + */ + function isDir($pathname) + { + return is_dir($this->toReal($pathname)); + } + + /** + * Checks if the given path name is a file. + * + * @param string $pathname The path name to check. + * + * @return boolean True if the path name was a file. + */ + function isFile($pathname) + { + return is_file($this->toReal($pathname)); + } + + function getIndex($pathname) + { + $indexname = $this->toReal($pathname) . '00-INDEX'; + if (file_exists($indexname)) { + $index = file_get_contents($indexname); + + if (preg_match_all('/\n(\S*)\s*\n\t-\s*([^\n]*)/s', $index, $match)) { + $list = array(); + $iMax = count($match[1]); + for ($i = 0; $i < $iMax; $i++) { + $list[$match[1][$i]] = $match[2][$i]; + } + return $list; + } + } + return array(); + } + + function getAnnotations($pathname) + { + return array(); + } + +} diff --git a/luxor/lib/Lang.php b/luxor/lib/Lang.php new file mode 100644 index 000000000..64dafb09a --- /dev/null +++ b/luxor/lib/Lang.php @@ -0,0 +1,86 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Lang +{ + /** + * Attempts to return a concrete Luxor_Lang instance based on $driver. + * + * @param string $driver The type of concrete Luxor_Lang subclass + * to return. The is based on the repository + * driver ($driver). The code is dynamically + * included. + * @param array $params (optional) A hash containing any additional + * configuration or connection parameters a + * subclass might need. + * + * @return mixed The newly created concrete Luxor_Lang instance, or + * false on an error. + */ + function factory($driver, $params = array()) + { + $driver = basename($driver); + $class = 'Luxor_Lang_' . $driver; + if (class_exists($class)) { + return new $class($params); + } else { + return false; + } + } + + /** + * Attempts to determine a files programming language and returns + * a parser instance for this language. + * + * @param Luxor_Files $files An instance of Luxor_Files to use for file + * operations and path name resolution. + * @param string $pathname The path name of the file to create a + * parser for. + * + * @return mixed The created concrete Luxor_Lang instance, or false + * on error. + */ + function builder($files, $pathname) + { + global $languages; + include LUXOR_BASE . '/config/languages.php'; + + /* First, check the 'filetype' hash for a matching file extension. */ + foreach ($languages['filetype'] as $type) { + if (preg_match('/' . $type[1] . '/', $pathname)) { + return Luxor_Lang::factory($type[2], $type); + } + } + + /* Next, try to detect the shebang line. */ + $fh = $files->getFileHandle($pathname); + if (!$fh || is_a($fh, 'PEAR_Error')) { + return $fh; + } + $line = fgets($fh); + if (!preg_match('/^\#!\s*(\S+)/s', $line, $match)) { + return false; + } + if (isset($languages['interpreters'][$match[1]])) { + $lang = $languages['filetype'][$languages['interpreters'][$match[1]]]; + return Luxor_Lang::factory($lang[2], $lang); + } + + return false; + } + + function processInclude($frag, $dir) + { + return preg_replace(array('/([\'"])(.*?)([\'"])/e', + '/(\\0<)(.*?)(\\0>)/e'), + array('stripslashes(\'$1\') . Luxor::incRef(\'$2\', "fixed", \'$2\', $dir) . stripslashes(\'$3\')', + 'stripslashes(\'$1\') . Luxor::incRef(\'$2\', "fixed", \'$2\') . stripslashes(\'$3\')'), + $frag); + } +} diff --git a/luxor/lib/Lang/Generic.php b/luxor/lib/Lang/Generic.php new file mode 100644 index 000000000..acb852638 --- /dev/null +++ b/luxor/lib/Lang/Generic.php @@ -0,0 +1,198 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Lang_Generic extends Luxor_Lang +{ + /** + * The current language. + * + * @var string + */ + var $_language; + + /** + * This language's copy of the 'langmap' hash from the $languages array. + * + * @var array + */ + var $_langmap; + + /** + * Constructs a new generic language parser. + * + * @param array $params A hash containing necessary parameters. + */ + public function __construct($params) + { + global $languages; + + $this->_language = $params[0]; + $this->_langmap = $languages['langmap'][$this->_language]; + } + + /** + * Indexes a file. + * + * @param string $path The full path name of the file to index. + * @param int $fileId The file's unique ID. + * + * @return mixed A PEAR_Error on error. + */ + function indexFile($path, $fileId) + { + global $conf, $index; + + $typemap = $this->_langmap['typemap']; + include LUXOR_BASE . '/config/languages.php'; + + if (isset($languages['eclangnamemapping'][$this->_language])) { + $langforce = $languages['eclangnamemapping'][$this->_language]; + } else { + $langforce = $this->_language; + } + + $version = shell_exec($conf['paths']['ectags'] . ' --version'); + if (!preg_match('/Exuberant ctags +(\d+)/i', $version, $match) || + $match[1] < 5) { + return PEAR::raiseError(sprintf(_("Exuberant ctags version 5 or above required, found version %s"), $version)); + } + + if (file_exists($conf['paths']['ectags'])) { + /* Call excuberant ctags. */ + $ectags = @popen($conf['paths']['ectags'] . ' ' . $languages['ectagsopts'] . + ' --excmd=number --language-force=' . $langforce . ' -f - ' . + $path, 'r'); + + if (!$ectags) { + return PEAR::raiseError(_("Can't run ectags.")); + } + while ($fgets = trim(fgets($ectags))) { + @list($sym, $file, $line, $type, $ext) = explode("\t", $fgets); + $line = preg_replace('/;"$/', '', $line); + preg_match('/language:(\w+)/', $ext, $match); + $ext = @$match[1]; + if (!isset($typemap[$type])) { + continue; + } + $type = $typemap[$type]; + if (!empty($ext) && preg_match('/^(struct|union|class|enum):(.*)/', $ext, $match)) { + $ext = str_replace('::', '', $match[2]); + } else { + $ext = ''; + } + + /* Build index. */ + $result = $index->index($sym, $fileId, $line, $this->_langmap['langid'], $type); + if (is_a($result, 'PEAR_Error')) { + pclose($ectags); + return $result; + } + } + pclose($ectags); + } + } + + /** + * References a file. + * + * @param string $path The full path name of the file to reference. + * @param int $fileId The file's unique ID. + * + * @return mixed A PEAR_Error on error. + */ + function referenceFile($path, $fileId) + { + global $conf, $index; + + $fp = @fopen($path, 'r'); + if (!$fp) { + return PEAR::raiseError(sprintf(_("Can't open file %s."), $path)); + } + + /* Instantiate parser. */ + $parser = new Luxor_SimpleParse($fp, 1, $this->_langmap['spec']); + + $linenum = 1; + list($btype, $frag) = $parser->nextFrag(); + while ($frag) { + $lines = array(); + if (preg_match_all('/(.*?\\n)/', $frag, $match)) { + $lines = $match[1]; + } + if (preg_match('/([^\\n]*)$/', $frag, $match)) { + $lines[] = $match[1]; + } + + if ($btype) { + /* Skip comments, strings and includes. */ + if ($btype == 'comment' || $btype == 'string' || $btype == 'include') { + $linenum += count($lines) - 1; + } + } else { + foreach ($lines as $l) { + /* Strip symbol name. */ + preg_match_all('/(?:^|[^a-zA-Z_\#])(\\~?_*[a-zA-Z][a-zA-Z0-9_]*)\b/x', $l, $match); + foreach ($match[1] as $string) { + /* Create references only for known symbols and not reserved words. */ + if (!in_array($string, $this->_langmap['reserved']) && + $index->isSymbol($string)) { + $result = $index->reference($string, $fileId, $linenum); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + } + } + $linenum++; + } + $linenum--; + } + list($btype, $frag) = $parser->nextFrag(); + } + } + + /** + * Process a chunk of code + * + * Basically, look for anything that looks like a symbol, and if + * it is then make it a hyperlink, unless it's a reserved word in this + * language. + * + * @param string $code Reference to the code to markup. + */ + function processCode($code, $altsources = array()) + { + global $index, $sourceid; + + // Make sure spacing is correct. + $code = Horde_Text_Filter::filter($code, 'space2html', array('charset' => Horde_Nls::getCharset(), 'encode' => true, 'encode_all' => true)); + + // Split all the symbols. + preg_match_all('/(^|[^\w\#&])([\w~][\w]*)\b/', $code, $match); + + // Replace symbol by link unless it's a reserved word. + $replaced = array(); + foreach ($match[2] as $id => $string) { + if (!in_array($string, $this->_langmap['reserved']) && + !in_array($match[0][$id], $replaced) && $idx = $index->isSymbol($string, $altsources)) { + + $link = Horde::applicationUrl(Horde_Util::addParameter('symbol.php', 'i', $idx)); + $link = Horde_Util::addParameter($link, 'source', $sourceid); + $match0 = str_replace($string, '' . $string . "", $match[0][$id]); + $code = str_replace($match[0][$id], $match0, $code); + $replaced[] = $match[0][$id]; + } elseif (in_array($string, $this->_langmap['reserved']) && !in_array($match[0][$id], $replaced)) { + $match0 = str_replace($string, '' . $string . "", $match[0][$id]); + $code = str_replace($match[0][$id], $match0, $code); + $replaced[] = $match[0][$id]; + } + } + + return $code; + } +} diff --git a/luxor/lib/Luxor.php b/luxor/lib/Luxor.php new file mode 100644 index 000000000..91110f318 --- /dev/null +++ b/luxor/lib/Luxor.php @@ -0,0 +1,460 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor +{ + /** + * Initial app setup code. + */ + public static function initialize() + { + global $sources, $sourceid, $source, $files, $index, $pathname; + + require LUXOR_BASE . '/config/sources.php'; + + /* Default to the first source; overridden elsewhere if necessary. */ + $sourceid = Horde_Util::getFormData('source'); + if (!isset($sources[$sourceid])) { + $sourceid = key($sources); + } + $source = $sources[$sourceid]; + $files = Luxor_Files::factory($source['driver'], $source); + $index = Luxor_Driver::factory($sourceid); + $pathname = Luxor::fixPaths(Horde_Util::getFormData('f')); + } + + /** + * Generate a URL that links into Luxor. + * + * @param string $uri The path being browsed. + * @param array $args Key/value pair of any GET parameters to append + * @param string $anchor Anchor entity name + */ + function url($uri = '', $args = array(), $anchor = '') + { + global $conf, $sourceid; + + $arglist = array_merge(array('source' => $sourceid), $args); + + if ($conf['options']['urls'] == 'rewrite') { + if (substr($uri, 0, 1) == '/') { + $uri = substr($uri, 1); + } + } else { + $arglist['f'] = $uri; + $uri = 'source.php'; + } + + $url = Horde_Util::addParameter(Horde::applicationUrl($uri), $arglist); + if (!empty($anchor)) { + $url .= "#$anchor"; + } + + return $url; + } + + /** + * Generate a list of sources available from this installation + * of Luxor. + * + * @return XHTML code representing links to the repositories + */ + function sources() + { + global $source, $sources; + + $arr = array(); + foreach ($sources as $key => $val) { + if ($val != $source) { + $arr[] = Horde::link(Luxor::url('', array('source' => $key))) . + htmlspecialchars($val['name']) . ''; + } + } + + if (count($arr)) { + return _("Other Sources") . ': ' . implode(', ', $arr); + } else { + return ''; + } + } + + /** + * Sanitizes path names passed by the user. + * + * @param string $node The path name to clean up. + * + * @return string The cleaned up path. + */ + function fixPaths($node) + { + global $files; + + $node = '/' . $node; + $node = preg_replace('|/[^/]+/\.\./|', '/', $node); + $node = preg_replace('|/\.\./|', '/', $node); + if ($files->isDir($node)) { + $node .= '/'; + } + + return preg_replace('|//+|', '/', $node); + } + + /** + * + */ + function outfun($str, $arr) + { + return str_replace("\n", "\n" . array_shift($arr), $str); + } + + function dirExpand($dir) + { + global $files, $mime_drivers, $mime_drivers_map; + + $result = Horde::loadConfiguration('mime_drivers.php', array('mime_drivers', 'mime_drivers_map'), 'horde'); + extract($result); + $result = Horde::loadConfiguration('mime_drivers.php', array('mime_drivers', 'mime_drivers_map'), 'luxor'); + if (isset($result['mime_drivers'])) { + $mime_drivers = Horde_Array::array_merge_recursive_overwrite($mime_drivers, $result['mime_drivers']); + } + if (isset($result['mime_drivers_map'])) { + $mime_drivers_map = Horde_Array::array_merge_recursive_overwrite($mime_drivers_map, $result['mime_drivers_map']); + } + + $nodes = $files->getDir($dir); + if (is_a($nodes, 'PEAR_Error')) { + return $nodes; + } + $index = $files->getIndex($dir); + if (is_a($index, 'PEAR_Error')) { + return $index; + } + + if ($dir != '/') { + array_unshift($nodes, '../'); + } + + $list = array(); + foreach ($nodes as $node) { + $link = Luxor::url($dir . $node); + $modtime = $files->getFiletime($dir . $node); + $modtime = $modtime ? gmdate('Y-m-d H:i:s', $modtime) : '-'; + $description = empty($index[$node]) ? ' ' : $index[$node]; + + if (substr($node, -1) == '/') { + $filesize = '-'; + $bytes = ''; + if ($node == '../') { + $icon = Horde::img('parent.png', _("Up to parent")); + $node = _("Parent Directory"); + } else { + $icon = Horde::img('folder.png', $node); + } + } else { + if (preg_match('/^.*\.[oa]$|^core$|^00-INDEX$/', $node)) { + continue; + } + $icon = Horde::img(Horde_Mime_Viewer::getIcon(Horde_Mime_Magic::filenameToMime($node)), '', '', ''); + $filesize = $files->getFilesize($dir . $node); + if ($filesize < 1 << 10) { + $bytes = _("bytes"); + } else { + $bytes = _("kbytes"); + $filesize = $filesize >> 10; + } + } + + $list[] = array('icon' => $icon, + 'name' => $node, + 'link' => $link, + 'filesize' => $filesize, + 'bytes' => $bytes, + 'modtime' => $modtime, + 'description' => $description); + } + + return $list; + } + + /** + * Prints a descriptive blurb at the end of directory listings. + * + * @param Luxor_File $files An instance of Luxor_File. + * @param string $path The directory where to look for a README file. + */ + function dirDesc($files, $path) + { + $table_head = '

'; + $table_foot = '
'; + if (file_exists($filename = $files->toReal($path . '/README')) || + file_exists($filename = $files->toReal($path . '/README.txt'))) { + $contents = file_get_contents($filename); + + return $table_head . Horde_Text_Filter::filter($contents, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO)) . $table_foot; + } elseif ($filename = file_exists($files->toReal($path . '/README.html'))) { + global $mime_drivers, $mime_drivers_map; + $result = Horde::loadConfiguration('mime_drivers.php', array('mime_drivers', 'mime_drivers_map'), 'horde'); + extract($result); + $result = Horde::loadConfiguration('mime_drivers.php', array('mime_drivers', 'mime_drivers_map'), 'luxor'); + $mime_drivers = Horde_Array::array_merge_recursive_overwrite($mime_drivers, $result['mime_drivers']); + $mime_drivers_map = Horde_Array::array_merge_recursive_overwrite($mime_drivers_map, $result['mime_drivers_map']); + + $contents = file_get_contents($filename); + + $mime_part = new Horde_Mime_Part('text/plain', $contents); + $mime_part->setName('README'); + $viewer = Horde_Mime_Viewer::factory($mime_part); + return $table_head . $viewer->render() . $table_foot; + } + } + + /** + * Smaller version of the markupFile() function meant for marking up + * the descriptions in source directory listings. + * + * @see markupFile() + * + * @todo most of this can be done by Horde_Text::toHtml() + */ + function markupString($string, $virtp) + { + $string = htmlspecialchars($string); + + // HTMLify email addresses and urls. + $string = preg_replace('#((ftp|http|nntp|snews|news)://(\w|\w\.\w|\~|\-|\/|\#)+(?!\.\b))#', + '$1', $string); + + // HTMLify file names, assuming file is in the current directory. + $string = preg_replace('#\b(([\w\-_\/]+\.(c|h|cc|cp|hpp|cpp|java))|README)\b#e', + '""', $string); + + return $string; + } + + function whereMenu() + { + global $pathname; + + $res = ''; + $wherePath = ''; + foreach (explode('/', $pathname) as $dir) { + $wherePath .= $dir ? "/$dir" : ''; + if (!empty($dir)) { + $res .= ' :: ' . Horde::link(Luxor::url($wherePath)) . + htmlspecialchars($dir) . ''; + } + } + return $res; + } + + function fileRef($desc, $css, $path, $line = 0, $args = array()) + { + if ($line > 0 && strlen($line) < 3) { + $line = str_repeat('0', (3 - strlen($line))) . $line; + } + + return '' . + htmlspecialchars($desc) . ''; + } + + function incRef($name, $css, $file, $paths = array()) + { + global $files; + + foreach ($paths as $dir) { + $dir = preg_replace('|/+$|', '', $dir); + $path = $dir . '/' . $file; + if ($files->isFile($path)) { + return Luxor::fileRef($name, $css, $path); + } + } + + return htmlspecialchars($name); + } + + /** + * Check if the given item is restricted from being shown. + * + * @param string $filename The filename to check + * + * @return boolean Whether or not the item is allowed to be displayed + */ + function isRestricted($filename) + { + global $source; + + if (Horde_Auth::isAdmin()) { + return false; + } + + if (isset($source['restrictions']) && is_array($source['restrictions'])) { + foreach ($source['restrictions'] as $restriction) { + if (preg_match('|' . str_replace('|', '\|', $restriction) . '|', $filename)) { + return true; + } + } + } + + return false; + } + + /** + * Check if the given directory is filtered out. + * + * @param string $dir The path to check. + * + * @return boolean True if the directory should be shown/parsed, false otherwise. + */ + function isDirParsed($dir) + { + global $source; + + if (isset($source['dirFilter']) && is_array($source['dirFilter'])) { + foreach ($source['dirFilter'] as $filter) { + if (preg_match('/' . str_replace('/', '\/', substr($filter, 1)) . '/', $dir)) { + return (substr($filter, 0, 1) == '+'); + } + } + } + + if (isset($source['dirUnmatched'])) { + return $source['dirUnmatched']; + } + return true; + } + + /** + * Check if the given file should be parsed an/or displayed. + * + * @param string $file The filename to check. + * + * @return boolean True if the file should be shown/parsed, false otherwise. + */ + function isFileParsed($file) + { + global $source; + + if (isset($source['fileFilter']) && is_array($source['fileFilter'])) { + foreach ($source['fileFilter'] as $filter) { + if (preg_match('/' . str_replace('/', '\/', substr($filter, 1)) . '/', $file, $matches)) { + return (substr($filter, 0, 1) == '+'); + } + } + } + + if (isset($source['fileUnmatched'])) { + return $source['fileUnmatched']; + } + return true; + } + + /** + * Pre- and post-fix every line of a string with strings. + */ + function fixString($string, $pre = '', $post = '') + { + $lines = preg_split('(\r\n|\n|\r)', $string); + $res = ''; + foreach ($lines as $line) { + $res .= !empty($res) ? "\n" : ''; + $res .= $pre . Horde_Text_Filter::filter($line, 'space2html', array('charset' => Horde_Nls::getCharset(), 'encode' => true, 'encode_all' => true)) . $post; + } + return $res; + } + + /** + */ + function markupfile($pathname, $fileh, $ann = array()) + { + global $files, $conf; + + preg_match_all('|^(.*/)|', $pathname, $dir); + $dir = $dir[0]; + + /* Determine the file's language and create a Luxor_Lang + * instance. */ + $lang = &Luxor_Lang::builder($files, $pathname); + if (is_a($lang, 'PEAR_Error')) { + return $lang; + } + + $html = ''; + + // A source code file. + if (!$lang) { + return false; + } + + $parser = new Luxor_SimpleParse($fileh, 1, $lang->_langmap['spec']); + $linenum = 1; + + list($btype, $frag) = $parser->nextFrag(); + $ofrag = ''; + while ($frag) { + $frag = preg_replace('/([&<>])/', chr(0) . '$1', $frag); + switch ($btype) { + case 'comment': + // Comment + // Convert mail adresses to mailto: + // &freetextmarkup($frag); + // $lang->processComment(\$frag); + $frag = Luxor::fixString($frag, '', ''); + break; + + case 'string': + $frag = Luxor::fixString($frag, '', ''); + break; + + case 'include': + // Include directive + $frag = $lang->processInclude($frag, $dir); + break; + + case 'variable': + if (!empty($conf['options']['use_show_var'])) { + $pre = sprintf('', substr($frag, 1), substr($frag, 1), substr($frag, 1)); + $frag = Luxor::fixString($frag, $pre, ''); + } else { + $frag = Luxor::fixString($frag, '', ''); + } + break; + + default: + // Code + // somehow get $source['may_reference'] into the second parameter here. + $frag = $lang->processCode($frag); + } + + $frag = preg_replace('/\0([&<>])/', '$1', $frag); + + $ofrag .= $frag; + list($btype, $frag) = $parser->nextFrag(); + } + + $lines = preg_split('(\r\n|\n|\r)', $ofrag); + foreach ($lines as $line) { + $html .= '\n"; + } + return $html . '
' . $linenum++ . '' . $line . "
'; + } + + /** + * Build Luxor's list of menu items. + */ + function getMenu($returnType = 'object') + { + global $registry; + + $menu = new Horde_Menu(Horde_Menu::MASK_ALL); + $menu->add(Horde::applicationUrl('source.php'), _("_Browse"), 'luxor.png'); + + if ($returnType == 'object') { + return $menu; + } else { + return $menu->render(); + } + } +} diff --git a/luxor/lib/SimpleParse.php b/luxor/lib/SimpleParse.php new file mode 100644 index 000000000..53318b7be --- /dev/null +++ b/luxor/lib/SimpleParse.php @@ -0,0 +1,178 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_SimpleParse { + + /** File handle. */ + var $_fileh; + + /** Current linenumber. */ + var $_line = 0; + + /** Fragments in queue. */ + var $_frags = array(); + + /** Array of body type ids. */ + var $_bodyid = array(); + + /** Fragment closing delimiters. */ + var $_term = array(); + + /** Fragmentation regexp. */ + var $_split = ''; + + /** Fragment opening regexp. */ + var $_open = ''; + + /** Tab width. */ + var $_tabwidth = 8; + + /** + * Constructor for the source code parser. + * + * @param ressource $file The file handler of the file to parse. + * + * @param int $tabhint (Unused?) + * + * @param array $blksep An array containing block seperators for + * this file's type. + * Essentially a 'spec' entry from the + * $languages array. + */ + function Luxor_SimpleParse(&$fileh, $tabhint, $blksep) + { + $this->_fileh = $fileh; + + /* Get possible block opening and closing delimiters and their meaning. */ + $open_a = array(); + while ($splice = array_splice($blksep, 0, 3)) { + $this->_bodyid[] = $splice[0]; + $open_a[] = $splice[1]; + $this->_term[] = $splice[2]; + } + + /* Build regexps for opening and delimiters and fragment splitting. */ + foreach ($open_a as $open_s) { + $this->_open .= "($open_s)|"; + $this->_split .= "$open_s|"; + } + $this->_open = substr($this->_open, 0, -1); + $this->_open = str_replace('/', '\\/', $this->_open); + + foreach ($this->_term as $term) { + if (empty($term)) { + continue; + } + $this->_split .= "$term|"; + } + $this->_split = substr($this->_split, 0, -1); + $this->_split = str_replace('/', '\\/', $this->_split); + } + + /** + * Returns the content and type of the next code fragment. + */ + function nextFrag() + { + $btype = null; + $frag = null; + $line = ''; + + while (true) { + // read one more line if we have processed + // all of the previously read line + if (!count($this->_frags)) { + $line = fgets($this->_fileh); + $this->_line++; + + if ($this->_line <= 2 && + preg_match('/^.*-[*]-.*?[ \t;]tab-width:[ \t]*([0-9]+).*-[*]-/', + $line, $match)) { + $this->_tabwidth = $match[1]; + } + + // Optimize for common case. + if (!empty($line)) { + $line = preg_replace('/^(\t+)/e', "str_repeat(' ', $this->_tabwidth * strlen('\\1'))", $line); + if (preg_match('/([^\t]*)\t/e', $line, $match)) { + $tabs = str_repeat(' ', $this->_tabwidth - (strlen($match[1]) % $this->_tabwidth)); + $line = preg_replace('/([^\t]*)\t/', '\1' . $tabs, $line); + } + + // split the line into fragments + $this->_frags = preg_split('/(' . $this->_split . ')/', $line, -1, PREG_SPLIT_DELIM_CAPTURE); + } + } + + if (!count($this->_frags)) { + break; + } + + // skip empty fragments + if (empty($this->_frags[0])) { + array_shift($this->_frags); + continue; + } + + if (!empty($frag)) { + // Check if we are inside a fragment + if (!is_null($btype)) { + $next = array_shift($this->_frags); + + // Some ugly special casing for escaped quotes. + if (substr($frag, -1, 1) == '\\' && substr($frag, -2, 2) != '\\\\' && + (substr($next, 0, 1) == '"' || substr($next, 0, 1) == "'")) { + $frag .= $next; + $next = substr($next, 1); + } else { + // Add to the fragment + $frag .= $next; + } + + // We are done if this was the terminator + if (preg_match('/^' . str_replace('/', '\\/', $this->_term[$btype]) . '$/', $next)) { + // Return what we have + break; + } + } else { + // Is the start of a frag? + if (preg_match('/^' . $this->_open . '$/', $this->_frags[0])) { + // Return what we have + break; + } else { + // Add to the fragment and keep looking + $frag .= array_shift($this->_frags); + } + } + } else { + // Find the blocktype of the current block + $frag = array_shift($this->_frags); + if (preg_match_all('/^' . $this->_open . '$/', $frag, $match)) { + array_shift($match); + foreach ($match as $id => $matched) { + if ($matched[0] == $frag) { + $btype = $id; + break; + } + } + if (is_null($btype)) { + //return the fragment as unknown. + break; + } + } + } + } + + // Clear text block type + if (!is_null($btype)) { + $btype = $this->_bodyid[$btype]; + } + return array($btype, $frag); + } + +} diff --git a/luxor/lib/Tagger.php b/luxor/lib/Tagger.php new file mode 100644 index 000000000..f4d6cf4af --- /dev/null +++ b/luxor/lib/Tagger.php @@ -0,0 +1,104 @@ + + * @since Luxor 0.1 + * @package Luxor + */ +class Luxor_Tagger { + + /** + * Indexes a file. + * Parses the files contents for symbols and creates indexes in the + * storage backend for the file itself and the symbols it defines. + * + * @param Luxor_Driver $files An instance of a storage backend driver. + * @param string $pathname The (relative) pathname of the file to + * be processed. + * @param Luxor_Lang $lang The language object for $pathname. + * + * @return mixed A PEAR_Error if an error occured. + */ + function processFile($files, $pathname, $lang) + { + global $index; + + /* Get the unique ID for this file. */ + $fileId = $index->fileId($pathname); + if ($fileId === false) { + $fileId = $index->createFileId($pathname, '', $files->getFiletime($pathname)); + } elseif (is_a($fileId, 'PEAR_Error')) { + return $fileId; + } + + /* Update the file's status. */ + $result = $index->toIndex($fileId); + if ($result === false) { + return PEAR::raiseError(sprintf(_("%s was already indexed."), $pathname)); + } elseif (is_a($result, 'PEAR_Error')) { + return $result; + } + + /* Empty symbol cache. */ + $index->clearCache(); + + /* Find symbols defined by this file. */ + $path = $files->tmpFile($pathname); + if (!$path) { + return PEAR::raiseError(sprintf(_("Can't create copy of file %s."), $pathname)); + } + $result = $lang->indexFile($path, $fileId); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + } + + /** + * References a file. + * Parses the files contents for symbols and creates references to the + * files where these symbols are defined. + * + * @param Luxor_Driver $files An instance of a storage backend driver. + * @param string $pathname The (relative) pathname of the file to + * be referenced. + * @param Luxor_Lang $lang The language object for $pathname. + * + * @return mixed A PEAR_Error if an error occured. + */ + function processRefs($files, $pathname, $lang) + { + global $index; + + /* Get the unique ID for this file. */ + $fileId = $index->fileId($pathname); + if ($fileId === false) { + $fileId = $index->createFileId($pathname, '', $files->getFiletime($pathname)); + } + if (is_a($fileId, 'PEAR_Error')) { + return $fileId; + } + + /* Update the file's status. */ + $result = $index->toReference($fileId); + if ($result === false) { + return PEAR::raiseError(sprintf(_("%s was already indexed."), $pathname)); + } elseif (is_a($result, 'PEAR_Error')) { + return $result; + } + + /* Empty symbol cache. */ + $index->clearCache(); + + /* Create references to symbol definitions. */ + $path = $files->tmpFile($pathname); + if (!$path) { + return PEAR::raiseError(sprintf(_("Can't create copy of file %s."), $pathname)); + } + $result = $lang->referenceFile($path, $fileId); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + } + +} diff --git a/luxor/locale/de_DE/LC_MESSAGES/luxor.mo b/luxor/locale/de_DE/LC_MESSAGES/luxor.mo new file mode 100644 index 0000000000000000000000000000000000000000..ca6a29ceddfd336282489885c57fdaff5a646f58 GIT binary patch literal 158650 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 NI$r41tiBu`{}&TMv6uh= literal 0 HcmV?d00001 diff --git a/luxor/locale/ro_RO/LC_MESSAGES/luxor.mo b/luxor/locale/ro_RO/LC_MESSAGES/luxor.mo new file mode 100644 index 0000000000000000000000000000000000000000..474bd4230a838c5f920af345e2876ba360f7b897 GIT binary patch literal 18669 zcmbuHdz@WWb;mczLj!_DaI@W&jgPK*MNFH03Hhtg2#cQ{{3sgmvTQ2o&??ss{EbcbHIE2 z{k`B~?mq>-1pFST{(k}TXO4fNs~>=;a=!vx0B!`=gCqX_PEh@P96TO;2-LV91z!Mu z9egpk4?F|>6?i^)5{;e+UIrcsUJYt~o59n-QBeI&fogXeRC_mpG-2KcYToyQOTmXg zwf9r-<>3E-YVRx>6U!HZx?cvWor^qP398Z+Tme20ycJY??*=8e4}jN$9|gs? z-+~&)0)!WUXMmDdAEhBg%^&bP(-%&7E{9Fr4URy!w?>2A} z90Os!c>+WQ&Cfjk9|+6LX)km3Xay*~4ucnh;~;k5F=L(F$H^A$`yTDg0HYNwZ3f>3yA^f+2{|;^g zr>F#L%p)KoG(Q2=zIlby>tjHT_cZW1;36;p&j(D@EGpD z35st|f#UBo{{4{`I6XZP)cj8O_W`JS=Y!JAW#Dn(T2TF51ug)0fJcI3pvp%ef2PKV z;eVP7b1C=8gXO-JsU>r$O=K%b?nS+}}S5t~`Qu32HqZ z)9d=6dGY;RQ2bm4YCQ~qCxCAR&j4=&Rqhj@+W$N# zzB~$I`pu6)ma6#;sCl2h+}Y!PP;wXrHJ=?Is%%~jioZ93$ARwzHJ=ZGF91Icia%cg z`7>YVL-zf*AS!E4T;ce2F{tsa0d4!B*4L{+wU_z(xBC0L{QZNV`gsgI8GH&9f1U-nF3Whu}$I)8F3;ieDcDrBC;QvM&#V>i-9z*3*wb$?1PV@$orq(yI4- z@EY(8@OW^_;~r4*yaklJ?gcfTPlA%yXF*K0+2`>$;8EPa=pxteSsoXH>gPOA?=J+^ z|E1s}Z~&D4#h}`K2gnf3gP{2EQ~&<>i(UO*5LGoRLD_){DE>}?(x2CZlH;wQ`1S!% za=aT<`A0zM%hy0u)BG3sLU19AL-W7b<9bkXzXnwM1xQhI3#jou45Aw5zd`K>i}-*A z<~1NgHg|xC);tOFXBUy)_pzAtz5(j}CqTX52kQN)Y)*QAHK_M*0rmc~p!$6VRJlc~ zUH{jCD*sM@|2U|6zXmC4mawU*-XzFUF&_cd-nT%t^E`~7>c0|Hy=hST^#CY7ei79C zzX9$7{}mL!HnJI>1>OL@7~Bhr&+qs5p9fFp{wZ)h_;XP5TzR?U^R=MlGXb6oCZObc zGuQ)u29*B(7(5Mp8dUk;fs*4f{l;Jd%?aR*;2KbN=1btefd2u$4}5H$G26kN1IGLn z_#k*YSY=RE@K>PPzkY+OpM&c6!=TpN$3W@tL!j3ABcSH_I4J%-4Qd=`U*Y&N1ipm( zF;ING5tLrt4!#upC@6k?8C3iGKH0fpIkX!39JCqwV@Ov5y#_i_H(b|4OYJwO!yobA zSAy60?^=_(J_$VvJr4a5^kGQXr=V@n-$VZdl^5p2UQh7(c_@dDf-ZvYggy?{AYE^T z&a&T(`D^fY=mY+~gm3d@)Ze@U{1Egi=ue<`LVp33*ZF+;26Q^q2b}~BKre%IeawM* zE%4{NV4Me86jo<~W*Sg#Jk9Dsb219*9Sx-I z1}c+LWh$x$V^J;L-Kz$6hj|dzTpMvxjrK&nzF18sX)~y($B81NR-D+jH>O!N z3WlSJIB#Y%y=KLQ!DL!wxmi87wm%pTn_(@8vMkMlNg7Wpl_H~d-|D4fYfb;q(yc?L zzgi6%VVvnp7Ug+~V`(~N`fG8>lO%|1wP=F2ro&nh*@5Pbs1lFI8e;!+7}vtFS`=_! ztLA-XU7R&1tKp0p*gj$g!djG6!;CM<;$|>b#IJ|I7UjLZ zTm?ond7n0Bf^>ZLTNs%H)i{eP%`}^#ny+P_&uS?vl7MpIgloGJ)q<^A%6RK=u90R< zGZ58yHkl@o8IV{kZ^zO-c3fe?07|)?m!BWZqy;QUnw^3Uxtl~x&A1*hgIbzL!N#c8 z==d7!K&a_%|D?Q0>kT?EC=*K7L`LI*MBep4S~T209E4eAGM;9PX#oqR5%n;eDjFTk zX}z(G=+NEQjE4DCP*1Cc<+2&bQusa`jYnC8YMb@z&3eQ*!)G%b3mN|FiU`h*^H4(O zaTJ_)<BadBhT{mJenZ7)&SP#220nYvXpQ z`Fq!t*{~<9H(;<`CoF^wdsrq-=C*L%hATI1URbW%TAZNku(e%a!{+sUi*j3{<83j9 z#X;4q`UVUJr#jBvq}1E3C+P)6C*%I!-2nMpnw1CE#CU zrI>8O@TA9s>-)Dd{fr(|Vvo6^U`aSxTE6!gtIiwKdSvtwl=i~jxV2-g5pQLa9JAc_ zk(s<1)%}YdjJ762`tHN?n;!8 zkiaGxQt^P7R~30_f23#mOnoe^AreZ=@vhA`Gw3ar8ALVh+73q3MqJ6wU|O-8Kp)>G zXwE`fG=bsSjF8i(%M>97OPZ7 zzmj6VE6p0Fez4d>xpg6%NK*B8l0^fn>TeIi+o2(Yaj5ap2<*}h(VbC@S8#>3;r4}R zck4+L^8+U>w{tTT)l+@uxq2MJfK6gPhGv41qK;jfF`Jo-*&Lx#X0uf`yLnkwF%|8P z?t5!1u{^SxxV6pr-ovRpa?M~cfTfy9QGIm%F#1*1XVb0h>*4np7HA@d(`k?$aK~cB z;$sfW?Nx7OuJ~laZ_=(jbC)(Z5R(pYYx`7GGf=C*N9Mo>7+rrAmln3whC zPRawPcxJ12VLJAZ4*$ov6~DEHGDp~#bUJ3yhe7USuWd|Aj2GHxd(EtZ-TE%wD;3`O zEu+)+nASF>HPE{AtD2YC_sLT2g6(m%yN^P3nMdo|40{_HEY`+WO%_{DwbhPA+AW8c z6|xH2OJmN+9;AUzsg*WtzuJ|_Fw3Ln0s3!Bd*<%8>Nn*B)SU0g57Gpx5uu%xCTgsXni{AEf>v=3cIfXEFDKG%=sKAEf%c=6;a+hno8& zu3IB|HdCLog?Y_<&f4>v_?*=bF>l=O+OwJUT=nNO=eg?6YsR+na8$Eqk5j7-C|yQ& zJ|igN>H%ub*T@~X_Pj=4dSB0`ckjR*pow`+eeUYdb_R2(T(iiCBc!dP)o@yi%!tlq zrT;L3udWjUd$~5Rki$%t+Y@jS$;-}C7v$iu9OXWi5$xoETnTN2B4J120PlBrj*zre zZ&zzZdzv8*aj)s-z(=ic0JdzTizocW&8Q=ltW>c&)Vw7`X7#| za;(c}gzDmplrD&m4va)i=b+2A#(lT$2F}M4JFV1uSXF;WP2C|?9hH@=E3010GG%WR znk4#AIxch`?}hzSaicTnWJYvoz@M_`rNy(H1bg%+Y=oa!kMo>S(TuNPPYCm?AZO5w zD5OJ>XP^``eq)1U%t&ER*k)8diWx-}e1JtlRz!#45sqPo97w8ZlcVdbEa0m-HGTHYiBylT(Fli8lmC3+zxYue`PIODrBOSpMmx+^{ zq68=o)M#^(s0@;Jkp}!=A~T~3(%9kSq!EW8lGnMm6oRm9n_V(XiC7@%V4{|e!6Upl z$z*8L(1xIz5tLz7sIrQh z#>tVXTP7_|AMV&R;c7KjkVxZ)Ya9TwEUt8+-mx|hw zqGML)?7WaVN8;iShZ>2uhgLJCAg-2E>~eldQ76h3)NOQzLnKiVPL=3=QZ85*c5W32 zTnz>lH`%a8*_Ngxm34&5DwAduVaXcSW&C^1w&6juO@d?d>56&j#LwceA+L4;XRR1d zr(J;aIe`vzgZ5f&5ur?S+#T&|ux5wiHPy6INSYKw^)aQ%1jp=cNmNDxwZX95WrJv| zp)oZu->T8j&ga33e0Gp_8>XTRxNZ*##T%Yvt<73D3Lu#sVV1y<63;O^qG*cX%#Ns5 z(dIy(i}LbriT#eDYK8Qe$dnI<@7!s2Mj?SYqfOl}W*fOBTxWM2x7w^}YQ^1EcE9j0 z8r{2kEDM&d9fd1X)-uav7TUG!baNXg?6qB4VOKk2$(RruvmcA771`=?GIB9g%3QwB zY)s#_VxuBna5e*i6cjA&4SYO8iyX5t!P4>-Y}mNuM4yJz9X_!S6xs6cN(FCEx3FR) zwtL;yt}Me1<~kSHwL$(x`3+`lM&X<(2h#&#R#o(47Y0n9#2jc2>C+tAgdr`&L|f z!7^$t7-XIGuzsu>r&(XHp_m{bzcFPYg~94bcaxVF*;ttLuseCMu$)N;w2p3x|* z_XWdgJxpRmu{vIUNpiV1=e&1PQQ+P*n^?O*7PLK^<-N-m47i=EM=P~2kQ2C+5PzIp zW}QrShBcc;w)9+b$*N0xmbVLQn4~LuHV_7tQSS>b8H<|>43V!bEmTpzrhER`c?({^EZk}fPJLS+>r zHiwWL9T6`8=~Mxmr5ovCPA)0OVT0B%nzlI`HAbg!vIpXNqsZV9-fEh}W6ZbDTpJgm z#*?56bkLo%QwTU$L6sow!~ROsO4`{v_~>IASJKQ1Oj=H?zNleOdTk)ST~Ru#lR&H( zVOg$-ZOP3AYdC16VzL(eq#}uBYR|T2_Af%&vYGuFVF<|9C;Wz^q>v);XgIVDc9YuzfN z1}ihmAe%HP3%1^n!Bg5V4sDuGSt#aNgCAChdcTGT_IDEIbY14jmLAyikwZRr(1FQItQsbbK6`TUDy%vqAC2@spnb#j)q8aG~?7*cA z_c92H2!YwWVAz!xl%PYOyJed64PD#O99Mh9OEvP1A8r*Va zsa~_vf;yr4_1@3q8Jij9tU(5bHE45!2*8H5t>~M1UTa_336=7 z1fFA)wIyAXG9kg(`$SR)c`v-Fv-`X#`qm~#e``m7BNu%n#Z2{wp9rBy8-Qpjc<#Z$eO)#R()D1sb| znbt7Et>-pAAeMH#8N$mvhu`N_Mb>ycAG0?|Fnlr3hLj zLfjral2Fzh4;m4Q-P@XREw(I>HZ0BKfSgb&K{BRbf{ljL1EGpSGj_fRNg~{)(BC+h zzRh1HD5Vgd&1P_rLDCF6j(#H$+SH<)7kl35$T@bcK_w=g5PU|m>ut$$bdSR~1MGUM zG?^hW8SXNJMZzyn$Vjrqa+Zq$tJ|A&Zz_#xzjRa4(GYiqp9}jIb9H2W&ZG?W7_)ZhsUd|4aL6Ddr|7T86DtX!wh* zWaJ_0wdF~rb_#K>T2ctbd$BQ?45~=a)fZvux$4X@!ui)MCfC-r(~g9-Y3(`f9XHbNV|~)i zdu#TPK_nuHrc+K*@&|F3*;w4xS_UbC?VQob-LMtde%DkNkQMAr@!!~!6no(i z=aOymeDzS4xX)Z+(`nuTcPA_k@4SmRksSCXZXWMkD$nkp)s)ymg*{bKhnBNerr~T6 zA40G`i|uzbvxz@{T-SK~d90t`ATwgMW{I$lmSmLlJH(i-IrdWofEHm+GIDP88PNrWQ9GBJVKhB=AZmhF%;`|!gX5H-3xSe(@+YN|9R;k+J z2P3fYMy)EVfSgK|i)&S2gl;8H$9oHc94v8)wlZ`3aRI;8`JS!Z91?PaZkDb3u%sqY zDHJ1s(0V25oZD9x+@BBDf}jQ{1L-jI1}Wt@&vu3KE8HwTkZ8(5p-B;Eein`ES8L7p z+Tw|QE5WclZRE$NMCTBsPrK>7V{>jT88%~?4KLs&T0{Iy&_yGOCSltMdpX&nc$_+m zBn@+(SyAEx^ZW5=FDmF4TuV?bQM1x>WUr&Q4f{*vW%5nzAQ|V!OgvG`9_A#KxDnPQ z5xd&#T;=CuDP)A~czSi_w%T05RKuZG*YJ(_83U)NJzo>y;XK}+@_vg(7QR7-Fj9!n zweA+qp@+o36j49cqO^xp8bz<4Zkf7-oa44DZ??Peai};|jL0nmmaA_~q})z?8gPhzlfmho?NRY-S!D#I^#Xs1=AlA% zTd}&OJq*iK9^%EsP+OD)qowX#hRjCzRdvMagHFOKVskb&`G?qoQ5Qv!%7z4F_?dpN zN&lLNXhO<=q2M{, 2003-2008. +# +msgid "" +msgstr "" +"Project-Id-Version: Luxor 0.1-cvs\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2008-09-18 11:24+0200\n" +"PO-Revision-Date: 2008-09-18 12:08+0200\n" +"Last-Translator: Jan Schneider \n" +"Language-Team: i18n@lists.horde.org\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: symbol.php:74 +#, php-format +msgid "%s :: Symbol \"%s\"" +msgstr "%s :: Symbol \"%s\"" + +#: lib/Tagger.php:38 lib/Tagger.php:85 +#, php-format +msgid "%s was already indexed." +msgstr "%s wurde bereits indiziert." + +#: scripts/indexer.php:47 +msgid "Can't be both verbose and quiet" +msgstr "Ausführlich und Leise ist nicht gleichzeitig möglich" + +#: lib/Tagger.php:49 lib/Tagger.php:96 +#, php-format +msgid "Can't create copy of file %s." +msgstr "Kopie von %s konnte nicht erstellt werden." + +#: lib/Files/plain.php:85 +#, php-format +msgid "Can't open directory %s" +msgstr "Verzeichnis %s konnte nicht geöffnet werden" + +#: lib/Lang/Generic.php:117 +#, php-format +msgid "Can't open file %s." +msgstr "Datei %s konnte nicht geöffnet werden." + +#: lib/Lang/Generic.php:75 +msgid "Can't run ectags." +msgstr "ectags konnte nicht ausgeführt werden." + +#: source.php:90 +#, php-format +msgid "Could not markup file %s." +msgstr "Die Datei %s konnte nicht ausgezeichnet werden." + +#: scripts/indexer.php:88 +msgid "DONE" +msgstr "FERTIG" + +#: templates/directory.html.php:6 +msgid "Date (GMT)" +msgstr "Datum (GMT)" + +#: templates/symbol.html.php:8 +msgid "Declarations" +msgstr "Definitionen" + +#: search.php:57 +msgid "Declared as " +msgstr "Definiert als " + +#: symbol.php:38 +#, php-format +msgid "Declared as a %s" +msgstr "Definiert als ein(e) %s" + +#: templates/directory.html.php:7 +msgid "Description" +msgstr "Beschreibung" + +#: source.php:143 +#, php-format +msgid "Directory Listing :: %s" +msgstr "Verzeichnis :: %s" + +#: lib/Lang/Generic.php:65 +#, php-format +msgid "Exuberant ctags version 5 or above required, found version %s" +msgstr "Exuberant ctags Version 5 oder höher wird benötigt, %s wurde gefunden" + +#: scripts/indexer.php:69 +#, php-format +msgid "Indexing %s" +msgstr "Indiziere %s" + +#: symbol.php:44 symbol.php:68 +#, php-format +msgid "Line %s" +msgstr "Zeile %s" + +#: templates/headerbar.inc:3 +msgid "Location:" +msgstr "Position:" + +#: source.php:146 +#, php-format +msgid "Markup of %s" +msgstr "Auszeichnung von %s" + +#: templates/directory.html.php:4 +msgid "Name" +msgstr "Name" + +#: lib/Luxor.php:60 +msgid "Other Sources" +msgstr "Andere Quellen" + +#: lib/Luxor.php:138 +msgid "Parent Directory" +msgstr "Verzeichnis hoch" + +#: templates/symbol.html.php:20 +msgid "Referenced in" +msgstr "Referenziert in" + +#: scripts/indexer.php:74 +#, php-format +msgid "Referencing %s" +msgstr "Referenziere %s" + +#: templates/directory.html.php:5 +msgid "Size" +msgstr "Größe" + +#: scripts/indexer.php:81 +msgid "Skipped files:" +msgstr "Übersprungene Dateien:" + +#: templates/menu.inc:13 +msgid "Symbol Search" +msgstr "Symbolsuche" + +#: search.php:32 +#, php-format +msgid "Symbol Search for \"%s\"" +msgstr "Symbolsuche nach \"%s\"" + +#: symbol.php:21 +msgid "Symbol not found" +msgstr "Symbol nicht gefunden" + +#: source.php:84 +#, php-format +msgid "The file %s can't be opened or doesn't exist." +msgstr "Die Datei %s konnte nicht geöffnet werden oder existiert nicht." + +#: templates/headerbar.inc:10 +msgid "Tracking Branch" +msgstr "Branch beobachten" + +#: lib/Luxor.php:137 +msgid "Up to parent" +msgstr "Ein Verzeichnis höher" + +#: source.php:34 +#, php-format +msgid "You do not have permission to view %s." +msgstr "Sie haben nicht genügend Rechte, um %s anzuzeigen." + +#: lib/Luxor.php:448 +msgid "_Browse" +msgstr "_Liste" + +#: lib/Luxor.php:149 +msgid "bytes" +msgstr "Bytes" + +#: lib/Luxor.php:151 +msgid "kbytes" +msgstr "kBytes" diff --git a/luxor/po/es_ES.po b/luxor/po/es_ES.po new file mode 100644 index 000000000..a841462b8 --- /dev/null +++ b/luxor/po/es_ES.po @@ -0,0 +1,169 @@ +# Spanish translations for luxor package +# Traducciones al español para el paquete luxor. +# Copyright 2008-2009 The Horde Project +# This file is distributed under the same license as the luxor package. +# Automatically generated, 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: Luxor 1.0-cvs\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2007-11-22 17:11+0100\n" +"PO-Revision-Date: 2008-03-18 20:18+0100\n" +"Last-Translator: Manuel P. Ayala \n" +"Language-Team: i18n@lists.horde.org\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ident.php:73 +#, php-format +msgid "%s :: Symbol \"%s\"" +msgstr "%s :: Símbolo \"%s\"" + +#: lib/Tagger.php:46 lib/Tagger.php:101 +#, php-format +msgid "%s was already indexed." +msgstr "%s ya estaba indexado." + +#: lib/Tagger.php:30 lib/Tagger.php:84 +#, php-format +msgid "Can't build language class for file %s." +msgstr "No se puede contruir la clase idioma del archivo %s." + +#: lib/Tagger.php:57 lib/Tagger.php:112 +#, php-format +msgid "Can't create copy of file %s." +msgstr "No se puede crear una copia del archivo %s." + +#: lib/Files/plain.php:85 +#, php-format +msgid "Can't open directory %s" +msgstr "No se puede abrir el directorio %s" + +#: lib/Lang/Generic.php:117 +#, php-format +msgid "Can't open file %s." +msgstr "No se puede abrir el archivo %s." + +#: lib/Lang/Generic.php:75 +msgid "Can't run ectags." +msgstr "No se puede ejecutar ectags." + +#: source.php:95 +#, php-format +msgid "Could not markup file %s." +msgstr "No se puede marcar el archivo %s." + +#: source.php:18 +msgid "Date (GMT)" +msgstr "Fecha (GMT)" + +#: templates/ident/ident.html:7 +msgid "Declarations" +msgstr "Declaraciones" + +#: search.php:60 +msgid "Declared as " +msgstr "Declarada como " + +#: ident.php:40 +#, php-format +msgid "Declared as a %s" +msgstr "Declarada como una %s" + +#: source.php:19 +msgid "Description" +msgstr "Descripción" + +#: source.php:150 +#, php-format +msgid "Directory Listing :: %s" +msgstr "Listado del directorio :: %s" + +#: lib/Lang/Generic.php:65 +#, php-format +msgid "Exuberant ctags version 5 or above required, found version %s" +msgstr "" +"Se necesita exuberant ctags versión 5 o superior, se ha encontrado la " +"versión %s" + +#: scripts/genxref.php:60 +#, php-format +msgid "Indexing %s" +msgstr "Indexando %s" + +#: ident.php:46 ident.php:69 +#, php-format +msgid "Line %s" +msgstr "Línea %s" + +#: templates/headerbar.inc:2 +msgid "Location:" +msgstr "Ubicación:" + +#: source.php:153 +#, php-format +msgid "Markup of %s" +msgstr "Marcador de %s" + +#: source.php:16 +msgid "Name" +msgstr "Nombre" + +#: lib/Luxor.php:60 +msgid "Other Sources" +msgstr "Otros orígenes" + +#: lib/Luxor.php:138 +msgid "Parent Directory" +msgstr "Directorio anterior" + +#: templates/ident/ident.html:8 +msgid "Referenced in" +msgstr "Referenciado en" + +#: scripts/genxref.php:65 +#, php-format +msgid "Referencing %s" +msgstr "Remitiendo a %s" + +#: source.php:17 +msgid "Size" +msgstr "Tamaño" + +#: search.php:35 +#, php-format +msgid "Symbol Search for \"%s\"" +msgstr "Búsqueda simbólica de \"%s\"" + +#: source.php:89 +#, php-format +msgid "The file %s can't be opened or doesn't exist." +msgstr "No se puede abrir el archivo %s o no existe." + +#: templates/headerbar.inc:9 +msgid "Tracking Branch" +msgstr "Rama de seguimiento" + +#: lib/Luxor.php:137 +msgid "Up to parent" +msgstr "Nivel anterior" + +#: source.php:39 +#, php-format +msgid "You do not have permission to view %s." +msgstr "No dispone de privilegios para ver %s." + +#: lib/Luxor.php:448 +msgid "_Browse" +msgstr "_Examinar" + +#: lib/Luxor.php:149 +msgid "bytes" +msgstr "bytes" + +#: lib/Luxor.php:151 +msgid "kbytes" +msgstr "kbytes" diff --git a/luxor/po/luxor.pot b/luxor/po/luxor.pot new file mode 100644 index 000000000..585b28912 --- /dev/null +++ b/luxor/po/luxor.pot @@ -0,0 +1,170 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright YEAR Horde Project +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: dev@lists.horde.org\n" +"POT-Creation-Date: 2008-08-01 10:44+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ident.php:79 +#, php-format +msgid "%s :: Symbol \"%s\"" +msgstr "" + +#: lib/Tagger.php:46 lib/Tagger.php:101 +#, php-format +msgid "%s was already indexed." +msgstr "" + +#: lib/Tagger.php:30 lib/Tagger.php:84 +#, php-format +msgid "Can't build language class for file %s." +msgstr "" + +#: lib/Tagger.php:57 lib/Tagger.php:112 +#, php-format +msgid "Can't create copy of file %s." +msgstr "" + +#: lib/Files/plain.php:85 +#, php-format +msgid "Can't open directory %s" +msgstr "" + +#: lib/Lang/Generic.php:117 +#, php-format +msgid "Can't open file %s." +msgstr "" + +#: lib/Lang/Generic.php:75 +msgid "Can't run ectags." +msgstr "" + +#: source.php:95 +#, php-format +msgid "Could not markup file %s." +msgstr "" + +#: source.php:18 +msgid "Date (GMT)" +msgstr "" + +#: templates/ident/ident.html:7 +msgid "Declarations" +msgstr "" + +#: search.php:60 +msgid "Declared as " +msgstr "" + +#: ident.php:43 +#, php-format +msgid "Declared as a %s" +msgstr "" + +#: source.php:19 +msgid "Description" +msgstr "" + +#: source.php:150 +#, php-format +msgid "Directory Listing :: %s" +msgstr "" + +#: lib/Lang/Generic.php:65 +#, php-format +msgid "Exuberant ctags version 5 or above required, found version %s" +msgstr "" + +#: scripts/genxref.php:56 +#, php-format +msgid "Indexing %s" +msgstr "" + +#: ident.php:49 ident.php:73 +#, php-format +msgid "Line %s" +msgstr "" + +#: templates/headerbar.inc:2 +msgid "Location:" +msgstr "" + +#: source.php:153 +#, php-format +msgid "Markup of %s" +msgstr "" + +#: source.php:16 +msgid "Name" +msgstr "" + +#: lib/Luxor.php:60 +msgid "Other Sources" +msgstr "" + +#: lib/Luxor.php:138 +msgid "Parent Directory" +msgstr "" + +#: templates/ident/ident.html:8 +msgid "Referenced in" +msgstr "" + +#: scripts/genxref.php:61 +#, php-format +msgid "Referencing %s" +msgstr "" + +#: source.php:17 +msgid "Size" +msgstr "" + +#: search.php:35 +#, php-format +msgid "Symbol Search for \"%s\"" +msgstr "" + +#: ident.php:26 +msgid "Symbol not found" +msgstr "" + +#: source.php:89 +#, php-format +msgid "The file %s can't be opened or doesn't exist." +msgstr "" + +#: templates/headerbar.inc:9 +msgid "Tracking Branch" +msgstr "" + +#: lib/Luxor.php:137 +msgid "Up to parent" +msgstr "" + +#: source.php:39 +#, php-format +msgid "You do not have permission to view %s." +msgstr "" + +#: lib/Luxor.php:448 +msgid "_Browse" +msgstr "" + +#: lib/Luxor.php:149 +msgid "bytes" +msgstr "" + +#: lib/Luxor.php:151 +msgid "kbytes" +msgstr "" diff --git a/luxor/po/ro_RO.po b/luxor/po/ro_RO.po new file mode 100644 index 000000000..0e1418695 --- /dev/null +++ b/luxor/po/ro_RO.po @@ -0,0 +1,215 @@ +# Romanian translations for luxor package. +# Copyright 2003-2009 The Horde Project +# This file is distributed under the same license as the luxor package. +# Eugen Hoanca , 2003. +# +msgid "" +msgstr "" +"Project-Id-Version: Luxor 0.1\n" +"POT-Creation-Date: 2003-03-04 13:46+0100\n" +"PO-Revision-Date: 2003-03-25 11:29+0200\n" +"Last-Translator: Eugen Hoanca \n" +"Language-Team: Romanian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: lib/Tagger.php:48 lib/Tagger.php:103 +msgid "%s was already indexed." +msgstr "%s a fost deja indexat." + +#: lib/Tagger.php:31 lib/Tagger.php:86 +msgid "Can't build language class for file %s." +msgstr "Imposibil de cladit o clasa de limba pentru fisierul %s." + +#: lib/Tagger.php:59 lib/Tagger.php:115 +msgid "Can't create copy of file %s." +msgstr "Imposibil de creat copie a fisierului %s." + +#: lib/Files/plain.php:82 +msgid "Can't open directory %s" +msgstr "Nu se poate deschide directorul %s" + +#: lib/Lang/Generic.php:125 +msgid "Can't open file %s." +msgstr "Nu se poate deschite fisierul %s." + +#: lib/Lang/Generic.php:83 +msgid "Can't run ectags." +msgstr "Nu se poate rula ectags." + +#: source.php:78 +msgid "Could not markup file %s." +msgstr "Nu se poate marca fisierul %s." + +#: source.php:130 +msgid "Cross Reference" +msgstr "Referinta in cruce" + +#: source.php:18 +msgid "Date (GMT)" +msgstr "Data (GMT)" + +#: ident.php:49 +msgid "Declared as " +msgstr "Declarat ca" + +#: source.php:19 +msgid "Description" +msgstr "Descriere" + +#: lib/Lang/Generic.php:50 +msgid "Exuberant ctags version 5 or above required, found %s" +msgstr "Ctags versiunea 5 sau mai mare necesara, s-a gasit %s" + +#: templates/menu/menu.inc:17 +msgid "Help" +msgstr "Ajutor" + +#: templates/menu/menu.inc:6 +msgid "Home" +msgstr "Acasa" + +#: ident.php:29 +msgid "Identifier" +msgstr "Identificator" + +#: genxref.php:110 +msgid "Indexing %s" +msgstr "Indexare %s" + +#: templates/genxref/genxref.inc:13 +msgid "Just build the symbol index" +msgstr "Cladire index simboluri" + +#: templates/genxref/genxref.inc:14 +msgid "Just build the symbol references" +msgstr "Cladire referinte simboluri" + +#: templates/headerbar.inc:26 +msgid "Location:" +msgstr "Locatie:" + +#: templates/genxref/genxref.inc:4 +msgid "Luxor Backend" +msgstr "Suport Luxor" + +#: templates/headerbar.inc:11 +msgid "Luxor Homepage" +msgstr "Pagina Luxor" + +#: templates/index/notconfigured.inc:4 +msgid "Luxor is not properly configured" +msgstr "Luxor nu este corect configurat" + +#: source.php:16 +msgid "Name" +msgstr "Nume" + +#: lib/Driver/sql.php:477 +msgid "No configuration information specified for SQL Tasks." +msgstr "Nici o configurare specificata pentru sarcinile SQL." + +#: lib/Luxor.php:85 +msgid "Other Sources" +msgstr "Alte surse" + +#: lib/Luxor.php:156 +msgid "Parent Directory" +msgstr "Director parinte" + +#: ident.php:57 +msgid "Referenced in" +msgstr "Referinta in" + +#: genxref.php:128 +msgid "Referencing %s" +msgstr "Referinta %s" + +#: lib/Driver/sql.php:495 +msgid "Required 'charset' not specified in tasks configuration." +msgstr "'charset' nespecificat in configurarea taskurilor." + +#: lib/Driver/sql.php:492 +msgid "Required 'database' not specified in tasks configuration." +msgstr "'database' nespecificat in configurarea taskurilor." + +#: lib/Driver/sql.php:483 +msgid "Required 'hostspec' not specified in tasks configuration." +msgstr "'hostspec' nespecificat in configurarea taskurilor." + +#: lib/Driver/sql.php:489 +msgid "Required 'password' not specified in tasks configuration." +msgstr "'password' nespecificat in configurarea taskurilor." + +#: lib/Driver/sql.php:480 +msgid "Required 'phptype' not specified in tasks configuration." +msgstr "'phptype' nespecificat in configurarea taskurilor." + +#: lib/Driver/sql.php:486 +msgid "Required 'username' not specified in tasks configuration." +msgstr "'username' nespecificat in configurarea taskurilor." + +#: source.php:17 +msgid "Size" +msgstr "Marime" + +#: templates/index/notconfigured.inc:39 +msgid "Some of Luxor's configuration files are missing:" +msgstr "Anumite fisiere de configurare Luxor lipsesc:" + +#: ident.php:36 +msgid "Source" +msgstr "Sursa" + +#: source.php:55 +msgid "The file %s can't be opened or doesn't exist." +msgstr "Fisierul %s nu poate fi deschis sau nu exista." + +#: templates/index/notconfigured.inc:51 +msgid "This file contains preferences for Luxor." +msgstr "Acest fisier contine preferintele Luxor." + +#: templates/index/notconfigured.inc:58 +msgid "" +"This file controls the stylesheet that is used to set colors and fonts in " +"addition to or overriding Horde defaults." +msgstr "" +"Acest fisier controleaza schema de culori si fonturi diferite de cele " +"implicite Horde." + +#: templates/index/notconfigured.inc:44 +msgid "" +"This is the main Luxor configuration file. It contains options for all Luxor " +"scripts." +msgstr "" +"Acesta este principalul fisier de configurare Luxor. Contine optiuni pentru " +"toate scripturile Luxor." + +#: templates/headerbar.inc:30 +msgid "Tracking Branch" +msgstr "Ramura de urmarire" + +#: lib/Luxor.php:145 lib/Luxor.php:155 +msgid "Up to parent" +msgstr "Inapoi la parinte" + +#: templates/menu/menu.inc:9 +msgid "Update" +msgstr "Improspatare" + +#: templates/genxref/genxref.inc:10 +msgid "Update the Cross Reference" +msgstr "Improspatare referinta in cruce" + +#: source.php:49 +msgid "You do not have permission to view file %s." +msgstr "Nu aveti permisiunea sa vizualizati fisierul %s." + +#: lib/Luxor.php:176 +msgid "bytes" +msgstr "octeti" + +#: lib/Luxor.php:178 +msgid "kbytes" +msgstr "kocteti" diff --git a/luxor/scripts/.htaccess b/luxor/scripts/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/luxor/scripts/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/luxor/scripts/sql/luxor.sql b/luxor/scripts/sql/luxor.sql new file mode 100644 index 000000000..9b876f37a --- /dev/null +++ b/luxor/scripts/sql/luxor.sql @@ -0,0 +1,57 @@ +-- $Horde: luxor/scripts/sql/luxor.sql,v 1.4 2006/03/21 01:57:37 selsky Exp $ + +CREATE TABLE luxor_declarations ( + declid SMALLINT NOT NULL, + langid SMALLINT DEFAULT 0 NOT NULL, + declaration char(255) DEFAULT '' NOT NULL, + PRIMARY KEY (declid) +); + +CREATE TABLE luxor_files ( + fileid INT NOT NULL, + source VARCHAR(255) DEFAULT '' NOT NULL, + filename VARCHAR(255) DEFAULT '' NOT NULL, + tag VARCHAR(255) DEFAULT '' NOT NULL, + lastmodified INT DEFAULT 0 NOT NULL, + PRIMARY KEY (fileid) +); + +CREATE INDEX luxor_files_source ON luxor_files (source); +CREATE INDEX luxor_files_tag ON luxor_files (tag); +CREATE INDEX luxor_files_filename ON luxor_files (filename); + +CREATE TABLE luxor_indexes ( + symid INT DEFAULT 0 NOT NULL, + fileid INT DEFAULT 0 NOT NULL, + line INT DEFAULT 0 NOT NULL, + declid SMALLINT DEFAULT 0 NOT NULL +); + +CREATE INDEX luxor_indexes_symid ON luxor_indexes (symid); +CREATE INDEX luxor_indexes_fileid ON luxor_indexes (fileid); +CREATE INDEX luxor_indexes_declid ON luxor_indexes (declid); + +CREATE TABLE luxor_status ( + fileid INT DEFAULT 0 NOT NULL, + status SMALLINT DEFAULT 0 NOT NULL, + PRIMARY KEY (fileid) +); + +CREATE TABLE luxor_symbols ( + symid INT NOT NULL, + symname VARCHAR(255) DEFAULT '' NOT NULL, + source VARCHAR(255) DEFAULT '' NOT NULL, + PRIMARY KEY (symid) +); + +CREATE INDEX luxor_symbols_symname ON luxor_symbols (symname); +CREATE INDEX luxor_symbols_source ON luxor_symbols (source); + +CREATE TABLE luxor_usage ( + symid INT DEFAULT 0 NOT NULL, + fileid INT DEFAULT 0 NOT NULL, + line INT DEFAULT 0 NOT NULL +); + +CREATE INDEX luxor_usage_symid ON luxor_usage (symid); +CREATE INDEX luxor_usage_fileid ON luxor_usage (fileid); diff --git a/luxor/search.php b/luxor/search.php new file mode 100644 index 000000000..707e53bc1 --- /dev/null +++ b/luxor/search.php @@ -0,0 +1,64 @@ + + * @author Mike Cochrane + */ + +require_once dirname(__FILE__) . '/lib/Application.php'; +Horde_Registry::appInit('luxor'); + +$symbol = Horde_Util::getFormData('s'); +if (!$symbol) { + header('Location: ' . Horde::applicationUrl('source.php', true)); + exit; +} + +$ids = $index->searchSymbols($symbol); +if (count($ids) == 1) { + $id = current($ids); + header('Location: ' . Horde::applicationUrl('symbol.php?i=' . $id, true)); + exit; +} + +// If there are multiple search results, display some info for all of them. + +$title = sprintf(_("Symbol Search for \"%s\""), $symbol); +require LUXOR_TEMPLATES . '/common-header.inc'; +require LUXOR_TEMPLATES . '/menu.inc'; + +echo '

' . htmlspecialchars($title) . '

'; + +foreach ($ids as $ident) { + // Change source if the symbol isn't from the current source. + $symbolSource = $index->getSourceBySymbol($ident); + if ($symbolSource != $sourceid) { + $source = $sources[$symbolSource]; + $index = Luxor_Driver::factory($symbolSource); + } + + $name = $index->symname($ident); + echo '
' . Horde::link(Horde::applicationUrl('symbol.php?i=' . $ident), $name, 'header') . $name . '
'; + + $references = $index->getIndex($ident); + $sorted = array(); + foreach ($references as $ref) { + $sorted[$ref['declaration']][] = array('filename' => $ref['filename'], + 'line' => $ref['line']); + } + + foreach ($sorted as $type => $locations) { + echo _("Declared as ") . $type . "\n"; + foreach ($locations as $loc) { + $href = Luxor::url($loc['filename'], array(), 'l' . $loc['line']); + echo ' ' . $loc['filename'] . ' Line: ' . $loc['line'] . '
'; + } + echo '
'; + } +} + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/luxor/source.php b/luxor/source.php new file mode 100644 index 000000000..c81516c88 --- /dev/null +++ b/luxor/source.php @@ -0,0 +1,157 @@ + + */ + +require_once dirname(__FILE__) . '/lib/Application.php'; +Horde_Registry::appInit('luxor'); + +function printdir($dir) +{ + $view = new Horde_View(array('templatePath' => LUXOR_TEMPLATES)); + $view->addBuiltinHelpers(); + $dirlist = Luxor::dirExpand($dir); + if (is_a($dirlist, 'PEAR_Error')) { + $GLOBALS['notification']->push($dirlist, 'horde.error'); + return; + } + $view->files = $dirlist; + + return $view->render('directory.html.php') + . Luxor::dirDesc($GLOBALS['files'], $dir); +} + +function printfile($pathname, $raw = false) +{ + if (substr($pathname, -1) == '/') { + return printdir($pathname); + } + + if (Luxor::isRestricted($pathname)) { + $GLOBALS['notification']->push(sprintf(_("You do not have permission to view %s."), $pathname), 'horde.error'); + return ''; + } + + $cache = $GLOBALS['injector']->getInstance('Horde_Cache'); + $lastmod = $GLOBALS['index']->getLastModified($pathname); + $key = 'luxor_' . $pathname; + if ($raw) { + $key .= '_raw'; + } + $output = $cache->get($key, time() - $lastmod); + if (true || !$output) { + $output = $raw ? printfile_raw($pathname) : printfile_markup($pathname); + if (!empty($output)) { + $cache->set($key, $output); + } + } + + return $output; +} + +function printfile_markup($pathname) +{ + $ann = $GLOBALS['files']->getAnnotations($pathname); + /* Commented out until we have a driver that supports annotations. + this formatting should probably be done in markupFile(); + if (is_array($ann)) { + $b = null; + for ($i = 0; $i < count($ann); $i++) { + if ($ann[$i] == $b) { + $ann[$i] = str_repeat(' ', 16); + continue; + } + $b = $ann[$i]; + $ann[$i] .= str_repeat(' ', 6 - strlen($ann[$i])) . $files->getAuthor($pathname); + $ann[$i] .= str_repeat(' ', 16 - strlen($ann[$i])); + } + } + */ + + $fileh = $GLOBALS['files']->getFileHandle($pathname); + if (!$fileh) { + $GLOBALS['notification']->push(sprintf(_("The file %s can't be opened or doesn't exist."), $pathname), 'horde.error'); + return; + } + + $output = Luxor::markupFile($pathname, $fileh, $ann); + if ($output === false) { + $GLOBALS['notification']->push(sprintf(_("Could not markup file %s."), $pathname), 'horde.warning'); + return printfile_raw($pathname); + } + + return $output; +} + +function printfile_raw($pathname) +{ + global $mime_drivers, $mime_drivers_map; + + $result = Horde::loadConfiguration('mime_drivers.php', array('mime_drivers', 'mime_drivers_map'), 'horde'); + extract($result); + $result = Horde::loadConfiguration('mime_drivers.php', array('mime_drivers', 'mime_drivers_map'), 'luxor'); + if (isset($result['mime_drivers'])) { + $mime_drivers = Horde_Array::array_merge_recursive_overwrite( + $mime_drivers, $result['mime_drivers']); + } + if (isset($result['mime_drivers_map'])) { + $mime_drivers_map = Horde_Array::array_merge_recursive_overwrite( + $mime_drivers_map, $result['mime_drivers_map']); + } + + $filename = $GLOBALS['files']->toReal($pathname); + $data = file_get_contents($filename); + + $mime_part = new Horde_Mime_Part(Horde_Mime_Magic::filenameToMime($pathname), $data); + $mime_part->setName($pathname); + $viewer = Horde_Mime_Viewer::factory($mime_part); + + if ($viewer->getType() == 'text/plain') { + return '
' . htmlspecialchars($viewer->render()) . '
'; + } else { + return $viewer->render(); + } +} + +if (substr($pathname, -5) == '.html' || + substr($pathname, -4) == '.htm' || + Horde_Util::getFormData('raw')) { + echo printfile($pathname, true); + exit; +} + +$content = printfile($pathname); + +if (substr($pathname, -1) == '/') { + $title = sprintf(_("Directory Listing :: %s"), $pathname); + Horde::addScriptFile('tables.js', 'horde', true); +} else { + $title = sprintf(_("Markup of %s"), $pathname); + $lastmod = $index->getLastModified($pathname); + if ($lastmod) { + $mod_gmt = gmdate('D, d M Y H:i:s', $lastmod) . ' GMT'; + header('Last-Modified: ' . $mod_gmt); + header('Cache-Control: public, max-age=86400'); + } + + if (!empty($conf['options']['use_show_var'])) { + Horde::addScriptFile('show_var.js', 'luxor', true); + } +} + +if (is_a($content, 'PEAR_Error')) { + $notification->push($content->getMessage(), 'horde.error'); +} + +require LUXOR_TEMPLATES . '/common-header.inc'; +require LUXOR_TEMPLATES . '/menu.inc'; +require LUXOR_TEMPLATES . '/headerbar.inc'; +if (!is_a($content, 'PEAR_Error')) { + echo $content; +} +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/luxor/symbol.php b/luxor/symbol.php new file mode 100644 index 000000000..a25c09e6e --- /dev/null +++ b/luxor/symbol.php @@ -0,0 +1,86 @@ + + * @author Mike Cochrane + */ + +require_once dirname(__FILE__) . '/lib/Application.php'; +Horde_Registry::appInit('luxor'); + +$ident = Horde_Util::getFormData('i'); + +// Change source if the symbol isn't from the current source. +$symbolSource = $index->getSourceBySymbol($ident); +if (!$symbolSource) { + Horde::fatal(_("Symbol not found"), __FILE__, __LINE__); +} +if ($symbolSource != $sourceid) { + $source = $sources[$symbolSource]; + $index = Luxor_Driver::factory($symbolSource); +} + +$declarations = $index->getIndex($ident); +$sorted = array(); +foreach ($declarations as $decl) { + $sorted[$decl['declaration']][] = array('filename' => $decl['filename'], + 'line' => $decl['line']); +} + +$ds = array(); +foreach ($sorted as $type => $locations) { + $d = array(); + $d['title'] = sprintf(_("Declared as a %s"), $type); + $d['files'] = array(); + + Horde_Array::arraySort($locations, 'filename', 0, false); + foreach ($locations as $loc) { + $href = Luxor::url($loc['filename'], array(), 'l' . $loc['line']); + $d['files'][] = '' . $loc['filename'] . ' ' . sprintf(_("Line %s"), $loc['line']) . ''; + } + $ds[] = $d; +} + +$references = $index->getReference($ident); +Horde_Array::arraySort($references, 'filename', 0, false); + +$curfile = ''; +$rs = array(); +$r = array(); +foreach ($references as $info) { + if ($curfile != $info['filename']) { + if ($r) { + $rs[] = $r; + } + + $curfile = $info['filename']; + + $r = array(); + $r['file'] = '' . htmlspecialchars($info['filename']) . ''; + $r['lines'] = array(); + } + + $r['lines'][] = '' . sprintf(_("Line %s"), $info['line']) . ''; +} +if ($r) { + $rs[] = $r; +} + +$title = sprintf(_("%s :: Symbol \"%s\""), $source['name'], $index->symname($ident)); +require LUXOR_TEMPLATES . '/common-header.inc'; +require LUXOR_TEMPLATES . '/menu.inc'; + +$view = new Horde_View(array('templatePath' => LUXOR_TEMPLATES)); +$view->addBuiltinHelpers(); +$view->title = $title; +$view->declarations = $ds; +$view->references = $rs; +echo $view->render('symbol.html.php'); + +require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/luxor/templates/.htaccess b/luxor/templates/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/luxor/templates/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/luxor/templates/common-header.inc b/luxor/templates/common-header.inc new file mode 100644 index 000000000..e74d55513 --- /dev/null +++ b/luxor/templates/common-header.inc @@ -0,0 +1,29 @@ + + + + + +' : '' ?> + +get('name'); +if (!empty($title)) $page_title .= ' :: ' . $title; +if (!empty($refresh_time) && ($refresh_time > 0) && !empty($refresh_url)) { + echo "\n"; +} + +Horde::includeScriptFiles(); + +?> +<?php echo htmlspecialchars($page_title) ?> + + + + +> diff --git a/luxor/templates/directory.html.php b/luxor/templates/directory.html.php new file mode 100644 index 000000000..7ad47ecf1 --- /dev/null +++ b/luxor/templates/directory.html.php @@ -0,0 +1,20 @@ + + + + + + + + + + + files as $file): ?> + + + + + + + + +
escape($file['name']) ?>escape($file['filesize']) ?> escape($file['bytes']) ?>escape($file['modtime']) ?>
diff --git a/luxor/templates/headerbar.inc b/luxor/templates/headerbar.inc new file mode 100644 index 000000000..d51403065 --- /dev/null +++ b/luxor/templates/headerbar.inc @@ -0,0 +1,23 @@ +
+
+ +[ ] +'; + +if (!empty($onb)): ?> +    ( branches[$onb] ?>) + 1) { + echo '   '; + echo Luxor::sources(); +} ?> +
+ +
+ +
+ +
diff --git a/luxor/templates/menu.inc b/luxor/templates/menu.inc new file mode 100644 index 000000000..7cad233b0 --- /dev/null +++ b/luxor/templates/menu.inc @@ -0,0 +1,20 @@ + + +
+ + +
+ +notify(array('listeners' => 'status')) ?> diff --git a/luxor/templates/symbol.html.php b/luxor/templates/symbol.html.php new file mode 100644 index 000000000..87afb9840 --- /dev/null +++ b/luxor/templates/symbol.html.php @@ -0,0 +1,29 @@ +
+

+ escape($this->title) ?> +

+
+ +
+

+declarations as $declaration): ?> +
+
escape($declaration['title']) ?>
+ +
+ +
+ +
+ +
+

+references as $reference): ?> +
+
+ +
+ +
+ +
diff --git a/luxor/themes/graphics/favicon.ico b/luxor/themes/graphics/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..94ff92d98305607a2fa3b38b1c14308cfdb8e37d GIT binary patch literal 1150 zcma)6O-mb56n&XY5V~n95{sL_IxlLf%U+GQ#!(%&l(Xsf)U%?|AUKr z#6_ZE9Q-`P?(rqEKbja{yuie!hxvDYo!I01b;w1WThQ2ZJZydYF4#o5j8s-*JZ~ah z!i%)VT&5v<$VE=u8o?*`H`a>|cD^)abuSx8SH5Dy{d2=Vld5C-qp6e7c)8}`S+a)F zeoOk~`>c_uW`&phxqKakQVo-a^R3~he&XoIRL+y0=u6NyG33u(Rb|bWufzj#QgeK@ zDwwg=0;pxk9&YoKee4%CvXwHDuHQfXBiHodx#*aE-@t2gAMm!$gMP4&Oz}+W?73Cx zCBC4Amvf+hua>o$}CFjm-Fj|JHT^gAKP_DJY(Lv*GtZM@Jvy6 rr!(J64Ql?MZoR0~^%JE|`;=M=-F_XIABO$l-miy#@ZIKfKZyMcu2iaB literal 0 HcmV?d00001 diff --git a/luxor/themes/graphics/folder.png b/luxor/themes/graphics/folder.png new file mode 100644 index 0000000000000000000000000000000000000000..323c51b8eeb62942795a82e528b45358a11fc9fd GIT binary patch literal 479 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMf$pD`a*T0{y{QY)kQCG;XCmZ&+ zSRd-ODvMUx-(mIr_31ayZmpS?c5I5>(>tfX-<|*E*@53LcK-SHZ2hd9&lj3MJUMpv zQ02ajGoGHC^6<)rKW`5Gyj^v2_ks)iX76vcKG0?T?cKe{hnv>TuV305F~2?F`pGrl zZcck}dHwmdp@%2f+`qiHC)=bvRO#*WyC*hvtel*9u-kgqil*y35`W&V{(7zF!qK%q z9dA6r#m&CC8;1HK(BS!Wot7!mZ*?844xl zT!xBYcGO8OUm`Fo%eMDZ2#2hjoLiwn%e&d;$+ra-&F8;%u73B&ppISVWRmq_o9yJ* X?=2tDnm{r-UW|Xfhm- literal 0 HcmV?d00001 diff --git a/luxor/themes/graphics/luxor.png b/luxor/themes/graphics/luxor.png new file mode 100644 index 0000000000000000000000000000000000000000..33d9dc47d3f6686f4823cf41687bb47e3eaa83f4 GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQnS5_8QCN3r>39(a?jQ;Ji zds%O{=vmjLbA2xkMBRI|=--K=YscpOn^N&>-@04#?EY-%P-9|wdwK1%NluTJB{8w6 zy}EVk*DAMv^IXn6n)k2DY2T-1_wIH5T9x9PB@X{KMLoH(K>8L3aX8sE{-7*;i2b`OEnn?usm=)dT)b*m`ktJ%O=%GgJ1vhpEACVDckpd3$qr} z9`C}63)+7hXShBRm$_Y*T=Ve8q`FP-pUMlI@p69ph<5`2{Row>id+xw9gg3;^3vk7 z6FFRJ_Xj4QS>r#6wZp+?vUa8MyX%cw`Nd7oSVO1HJvMoVteG$Cm*%B0Rnyk4etVbq zyY&P$zPUYT^{3{Qu&N6PimyCaa@FnSXRGVye0%DSPkg-Rl<;3K?I4M1hTnmXXYh3O Kb6Mw<&;$SgC>HJj literal 0 HcmV?d00001 diff --git a/luxor/themes/graphics/parent.png b/luxor/themes/graphics/parent.png new file mode 100644 index 0000000000000000000000000000000000000000..6ee2d98ad1133ea5c704f7c692393152c7b112a1 GIT binary patch literal 428 zcmV;d0aN~oP))^(8aCS$*kqhl=IMo z;M1?+)Ue;vz4g|N>e;OM+j{xid-mCu``vxz+{^dfpZw#H_~EGV