Overview

Packages

  • Luxor
  • None

Classes

  • Luxor
  • Luxor_Driver
  • Luxor_Driver_sql
  • Luxor_Files
  • Luxor_Files_plain
  • Luxor_Lang
  • Luxor_Lang_Generic
  • Luxor_SimpleParse
  • Luxor_Tagger
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * A generic implementation of the Luxor_Lang API to handle all programming
  4:  * languages that don't have a specific driver.
  5:  *
  6:  * @author  Jan Schneider <jan@horde.org>
  7:  * @since   Luxor 0.1
  8:  * @package Luxor
  9:  */
 10: class Luxor_Lang_Generic extends Luxor_Lang
 11: {
 12:     /**
 13:      * The current language.
 14:      *
 15:      * @var string
 16:      */
 17:     var $_language;
 18: 
 19:     /**
 20:      * This language's copy of the 'langmap' hash from the $languages array.
 21:      *
 22:      * @var array
 23:      */
 24:     var $_langmap;
 25: 
 26:     /**
 27:      * Constructs a new generic language parser.
 28:      *
 29:      * @param array  $params    A hash containing necessary parameters.
 30:      */
 31:     public function __construct($params)
 32:     {
 33:         global $languages;
 34: 
 35:         $this->_language = $params[0];
 36:         $this->_langmap = $languages['langmap'][$this->_language];
 37:     }
 38: 
 39:     /**
 40:      * Indexes a file.
 41:      *
 42:      * @param string $path  The full path name of the file to index.
 43:      * @param int $fileId   The file's unique ID.
 44:      *
 45:      * @return mixed        A PEAR_Error on error.
 46:      */
 47:     function indexFile($path, $fileId)
 48:     {
 49:         global $conf, $index;
 50: 
 51:         $typemap = $this->_langmap['typemap'];
 52:         $languages = Horde::loadConfiguration('languages.php', 'languages', 'luxor');
 53: 
 54:         if (isset($languages['eclangnamemapping'][$this->_language])) {
 55:             $langforce = $languages['eclangnamemapping'][$this->_language];
 56:         } else {
 57:             $langforce = $this->_language;
 58:         }
 59: 
 60:         $version = shell_exec($conf['paths']['ectags'] . ' --version');
 61:         if (!preg_match('/Exuberant ctags +(\d+)/i', $version, $match) ||
 62:             $match[1] < 5) {
 63:             return PEAR::raiseError(sprintf(_("Exuberant ctags version 5 or above required, found version %s"), $version));
 64:         }
 65: 
 66:         if (file_exists($conf['paths']['ectags'])) {
 67:             /* Call excuberant ctags. */
 68:             $ectags = @popen($conf['paths']['ectags'] . ' ' . $languages['ectagsopts'] .
 69:                              ' --excmd=number --language-force=' . $langforce . ' -f - ' .
 70:                              $path, 'r');
 71: 
 72:             if (!$ectags) {
 73:                 return PEAR::raiseError(_("Can't run ectags."));
 74:             }
 75:             while ($fgets = trim(fgets($ectags))) {
 76:                 @list($sym, $file, $line, $type, $ext) = explode("\t", $fgets);
 77:                 $line = preg_replace('/;"$/', '', $line);
 78:                 preg_match('/language:(\w+)/', $ext, $match);
 79:                 $ext = @$match[1];
 80:                 if (!isset($typemap[$type])) {
 81:                     continue;
 82:                 }
 83:                 $type = $typemap[$type];
 84:                 if (!empty($ext) && preg_match('/^(struct|union|class|enum):(.*)/', $ext, $match)) {
 85:                     $ext = str_replace('::<anonymous>', '', $match[2]);
 86:                 } else {
 87:                     $ext = '';
 88:                 }
 89: 
 90:                 /* Build index. */
 91:                 $result = $index->index($sym, $fileId, $line, $this->_langmap['langid'], $type);
 92:                 if (is_a($result, 'PEAR_Error')) {
 93:                     pclose($ectags);
 94:                     return $result;
 95:                 }
 96:             }
 97:             pclose($ectags);
 98:         }
 99:     }
100: 
101:     /**
102:      * References a file.
103:      *
104:      * @param string $path  The full path name of the file to reference.
105:      * @param int $fileId   The file's unique ID.
106:      *
107:      * @return mixed        A PEAR_Error on error.
108:      */
109:     function referenceFile($path, $fileId)
110:     {
111:         global $conf, $index;
112: 
113:         $fp = @fopen($path, 'r');
114:         if (!$fp) {
115:             return PEAR::raiseError(sprintf(_("Can't open file %s."), $path));
116:         }
117: 
118:         /* Instantiate parser. */
119:         $parser = new Luxor_SimpleParse($fp, 1, $this->_langmap['spec']);
120: 
121:         $linenum = 1;
122:         list($btype, $frag) = $parser->nextFrag();
123:         while ($frag) {
124:             $lines = array();
125:             if (preg_match_all('/(.*?\\n)/', $frag, $match)) {
126:                 $lines = $match[1];
127:             }
128:             if (preg_match('/([^\\n]*)$/', $frag, $match)) {
129:                 $lines[] = $match[1];
130:             }
131: 
132:             if ($btype) {
133:                 /* Skip comments, strings and includes. */
134:                 if ($btype == 'comment' || $btype == 'string' || $btype == 'include') {
135:                     $linenum += count($lines) - 1;
136:                 }
137:             } else {
138:                 foreach ($lines as $l) {
139:                     /* Strip symbol name. */
140:                     preg_match_all('/(?:^|[^a-zA-Z_\#])(\\~?_*[a-zA-Z][a-zA-Z0-9_]*)\b/x', $l, $match);
141:                     foreach ($match[1] as $string) {
142:                         /* Create references only for known symbols and not reserved words. */
143:                         if (!in_array($string, $this->_langmap['reserved']) &&
144:                             $index->isSymbol($string)) {
145:                             $result = $index->reference($string, $fileId, $linenum);
146:                             if (is_a($result, 'PEAR_Error')) {
147:                                 return $result;
148:                             }
149:                         }
150:                     }
151:                     $linenum++;
152:                 }
153:                 $linenum--;
154:             }
155:             list($btype, $frag) = $parser->nextFrag();
156:         }
157:     }
158: 
159:     /**
160:      * Process a chunk of code
161:      *
162:      * Basically, look for anything that looks like a symbol, and if
163:      * it is then make it a hyperlink, unless it's a reserved word in this
164:      * language.
165:      *
166:      * @param string $code Reference to the code to markup.
167:      */
168:     function processCode($code, $altsources = array())
169:     {
170:         global $index, $sourceid;
171: 
172:         // Make sure spacing is correct.
173:         $code = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter')->filter($code, 'space2html', array('encode' => true, 'encode_all' => true));
174: 
175:         // Split all the symbols.
176:         preg_match_all('/(^|[^\w\#&])([\w~][\w]*)\b/', $code, $match);
177: 
178:         // Replace symbol by link unless it's a reserved word.
179:         $replaced = array();
180:         foreach ($match[2] as $id => $string) {
181:             if (!in_array($string, $this->_langmap['reserved']) &&
182:                 !in_array($match[0][$id], $replaced) && $idx = $index->isSymbol($string, $altsources)) {
183: 
184:                 $link = Horde::url(Horde_Util::addParameter('symbol.php', 'i', $idx));
185:                 $link = Horde_Util::addParameter($link, 'source', $sourceid);
186:                 $match0 = str_replace($string, '<a href="' . $link . '" class="fixed"><span class="symbol">' . $string . "</span></a>", $match[0][$id]);
187:                 $code = str_replace($match[0][$id], $match0, $code);
188:                 $replaced[] = $match[0][$id];
189:             } elseif (in_array($string, $this->_langmap['reserved']) && !in_array($match[0][$id], $replaced)) {
190:                 $match0 = str_replace($string, '<span class="reserved">' . $string . "</span>", $match[0][$id]);
191:                 $code = str_replace($match[0][$id], $match0, $code);
192:                 $replaced[] = $match[0][$id];
193:             }
194:         }
195: 
196:         return $code;
197:     }
198: }
199: 
API documentation generated by ApiGen