From: Chuck Hagenbuch Date: Sat, 24 Apr 2010 16:00:04 +0000 (-0400) Subject: First try converting Luxor to H4-git X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=a6e50ed6d17f606444e6bb7d4130628d36005d52;p=horde.git First try converting Luxor to H4-git --- 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 000000000..ca6a29ced Binary files /dev/null and b/luxor/locale/de_DE/LC_MESSAGES/luxor.mo differ diff --git a/luxor/locale/es_ES/LC_MESSAGES/luxor.mo b/luxor/locale/es_ES/LC_MESSAGES/luxor.mo new file mode 100644 index 000000000..91fea880e Binary files /dev/null and b/luxor/locale/es_ES/LC_MESSAGES/luxor.mo differ 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 000000000..474bd4230 Binary files /dev/null and b/luxor/locale/ro_RO/LC_MESSAGES/luxor.mo differ diff --git a/luxor/po/.htaccess b/luxor/po/.htaccess new file mode 100644 index 000000000..3a4288278 --- /dev/null +++ b/luxor/po/.htaccess @@ -0,0 +1 @@ +Deny from all diff --git a/luxor/po/README b/luxor/po/README new file mode 100644 index 000000000..a985e94aa --- /dev/null +++ b/luxor/po/README @@ -0,0 +1 @@ +see horde/po/README diff --git a/luxor/po/de_DE.po b/luxor/po/de_DE.po new file mode 100644 index 000000000..3b2824df6 --- /dev/null +++ b/luxor/po/de_DE.po @@ -0,0 +1,181 @@ +# German translations for Luxor. +# Copyright 2003-2009 The Horde Project +# This file is distributed under the same license as the Luxor package. +# Jan Schneider , 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 000000000..94ff92d98 Binary files /dev/null and b/luxor/themes/graphics/favicon.ico differ diff --git a/luxor/themes/graphics/folder.png b/luxor/themes/graphics/folder.png new file mode 100644 index 000000000..323c51b8e Binary files /dev/null and b/luxor/themes/graphics/folder.png differ diff --git a/luxor/themes/graphics/luxor.png b/luxor/themes/graphics/luxor.png new file mode 100644 index 000000000..33d9dc47d Binary files /dev/null and b/luxor/themes/graphics/luxor.png differ diff --git a/luxor/themes/graphics/parent.png b/luxor/themes/graphics/parent.png new file mode 100644 index 000000000..6ee2d98ad Binary files /dev/null and b/luxor/themes/graphics/parent.png differ diff --git a/luxor/themes/screen.css b/luxor/themes/screen.css new file mode 100644 index 000000000..8ea099a7e --- /dev/null +++ b/luxor/themes/screen.css @@ -0,0 +1,60 @@ +/** + * $Horde: luxor/themes/screen.css,v 1.7 2008/08/06 16:10:00 chuck Exp $ + */ + +th { + border-bottom: 1px solid #999; +} +.title { + font-size: 120%; + font-weight: bold; +} +.comment { + color: #008000; +} +.string { + color: #d00; +} +.variable { + color: #ff8000; +} +.variable-highlight { + background: yellow; +} +.reserved { + color: #007f7f; +} +.symbol { + color: #00b; +} + +dl { + margin: 5px; +} +dt { + font-weight: bold; +} +dd { + margin-left: 10px; +} + +#headerbar { + margin-bottom: .5em; +} + +#filelist { + text-align: left; + white-space: nowrap; +} +#filelist td, #filelist tr { + padding: 1px 4px; +} + +#symbol-declarations, #symbol-references { + width: 48%; + float: left; +} +#symbol-declarations h2, #symbol-references h2 { + margin-left: .3em; + font-size: 1.2em; +}