      1: <?php
      2:
      3: /**
      4:  * Default language strategy tries to load TeX files from a relative path
      5:  * to the class sourcefile.
      6:  */
      7: class Syllable_Source_File implements Syllable_Source_Interface
      8: {
      9:
     10:     private static $minHyphens = null;
     11:     private $path = null;
     12:     private $language = null;
     13:     private $loaded = false;
     14:     private $patterns = null;
     15:     private $max_pattern_length = null;
     16:     private $hyphenations = null;
     17:
     18:     public function __construct($language, $path)
     19:     {
     20:         $this->setLanguage($language);
     21:         $this->setPath($path);
     22:         $this->loaded = false;
     23:     }
     24:
     25:     public function setPath($path)
     26:     {
     27:         $this->path = $path;
     28:         $this->loaded = false;
     29:     }
     30:
     31:     public function setLanguage($language)
     32:     {
     33:         $this->language = strtolower($language);
     34:         $this->loaded = false;
     35:     }
     36:
     37:     public function getMinHyphens()
     38:     {
     39:         if (!self::$minHyphens) {
     40:             self::$minHyphens = json_decode(file_get_contents("{$this->path}/min.json"), true);
     41:         }
     42:
     43:         return isset(self::$minHyphens[$this->language]) ? self::$minHyphens[$this->language] : null;
     44:     }
     45:
     46:     private function loadLanguage()
     47:     {
     48:         if (!$this->loaded) {
     49:             $this->patterns = array();
     50:             $this->max_pattern_length = 0;
     51:             $this->hyphenations = array();
     52:
     53:             // parser state
     54:             $command = FALSE;
     55:             $braces = FALSE;
     56:
     57:             // parse .tex file
     58:             foreach (file("{$this->path}/hyph-{$this->language}.tex") as $line) {
     59:                 $offset = 0;
     60:                 $strlen_line = mb_strlen($line);
     61:                 while ($offset < $strlen_line) {
     62:                     $char = $line{$offset};
     63:
     64:                     // %comment
     65:                     if ($char === '%') {
     66:                         break; // ignore rest of line
     67:                     }
     68:
     69:                     // \command
     70:                     if ($char === '\\' && preg_match('~^\\\\([[:alpha:]]+)~', mb_substr($line, $offset), $m) === 1) {
     71:                         $command = $m[1];
     72:                         $offset += mb_strlen($m[0]);
     73:                         continue; // next token
     74:                     }
     75:
     76:                     // {
     77:                     if ($char === '{') {
     78:                         $braces = TRUE;
     79:                         ++$offset;
     80:                         continue; // next token
     81:                     }
     82:
     83:                     // content
     84:                     if ($braces) {
     85:                         switch ($command) {
     86:                             case 'patterns':
     87:                                 if (preg_match('~^\S+~u', mb_substr($line, $offset), $m) === 1) {
     88:                                     $numbers = '';
     89:                                     $pattern = '';
     90:                                     $strlen = 0;
     91:                                     $expect_number = true;
     92:                                     foreach (preg_split('/(?<!^)(?!$)/u', $m[0]) as $char) {
     93:                                         if (is_numeric($char)) {
     94:                                             $numbers .= $char;
     95:                                             $expect_number = false;
     96:                                         } else {
     97:                                             if ($expect_number) {
     98:                                                 $numbers .= '0';
     99:                                             }
    100:                                             $pattern .= $char;
    101:                                             ++$strlen;
    102:                                             $expect_number = true;
    103:                                         }
    104:                                         ++$offset;
    105:                                     }
    106:                                     if ($expect_number) {
    107:                                         $numbers .= '0';
    108:                                     }
    109:
    110:                                     $this->patterns[$pattern] = $numbers;
    111:                                     if ($strlen > $this->max_pattern_length) {
    112:                                         $this->max_pattern_length = $strlen;
    113:                                     }
    114:                                 }
    115:                                 continue; // next token
    116:                                 break;
    117:
    118:                             case 'hyphenation':
    119:                                 if (preg_match('~^\S+~u', substr($line, $offset), $m) === 1) {
    120:                                     $hyphenation = preg_replace('~\-~', '', $m[0]);
    121:                                     $this->hyphenations[$hyphenation] = $m[0];
    122:                                     $offset += strlen($m[0]);
    123:                                 }
    124:                                 continue; // next token
    125:                                 break;
    126:                         }
    127:                     }
    128:
    129:                     // }
    130:                     if ($char === '}') {
    131:                         $braces = FALSE;
    132:                         $command = FALSE;
    133:                         ++$offset;
    134:                         continue; // next token
    135:                     }
    136:
    137:                     // ignorable content, skip one char
    138:                     ++$offset;
    139:                 }
    140:             }
    141:
    142:             $this->loaded = true;
    143:         }
    144:     }
    145:
    146:     public function getHyphentations()
    147:     {
    148:         $this->loadLanguage();
    149:         return $this->hyphenations;
    150:     }
    151:
    152:     public function getMaxPattern()
    153:     {
    154:         $this->loadLanguage();
    155:         return $this->max_pattern_length;
    156:     }
    157:
    158:     public function getPatterns()
    159:     {
    160:         $this->loadLanguage();
    161:         return $this->patterns;
    162:     }
    163:
    164: }
    165: