set_conf($conf); } /** * Setter for the conf array */ function set_conf($conf) { $this->conf = $conf; } /** * Makes the parser to parse the code. * When no complaint is made ($this->error is then set to true), * this function returns the $goban_data array with: * $attributes, $caption, $board, $width, $height, $source * for the render() function to work. * Returns nothing if an error has occured. */ function parse($str) { $lines = explode("\n", $str); // init of attributes, caption and bi-dimensional array of chars $attributes_str = ''; $caption = ''; $board = array(); // first pass for some checks, caption and attributes foreach ($lines as $line) { if ($line!='') { // check if this is the attributes line // maybe preg_match is better if (substr($line, 0, strlen($this->conf['attributes_key'])) == $this->conf['attributes_key']) { $attributes_str.= ' '.substr($line, strlen($this->conf['attributes_key'])); // check if this is the caption line } elseif (substr($line, 0, strlen($this->conf['caption_key'])) == $this->conf['caption_key']) { if ($caption!='') { $this->error = true; $this->error_code = WEIQI_ERROR_ONE_CAPTION; return; } $caption = trim(substr($line, strlen($this->conf['caption_key']))); } else { // check length of our lines // first store the one of the first line if (empty($line_length)) $line_length = strlen($line); if (strlen($line) != $line_length) { $this->error = true; $this->error_code = WEIQI_ERROR_RECTANGULAR; return; } } } } $attributes = $this->parse_goban_attributes($attributes_str);//echo 'att:<';print_r($attributes);echo '>'; if ($this->error) return; // second pass for parsing the board code foreach ($lines as $line) { if ($line!='') { // check if this is the attributes or caption line $att = substr($line, 0, strlen($this->conf['attributes_key'])) == $this->conf['attributes_key']; $cap = substr($line, 0, strlen($this->conf['caption_key'])) == $this->conf['caption_key']; if ( !$att AND !$cap) { $tmp_array_line = array(); // map the string to an array // one by one for standard code, // two by two for advanced code if (!array_key_exists('advanced', $attributes)) { for($i=0;$iconf['default_attributes'] as $key => $val) $$key = $val; // import user-defined attributes // quite dangerous, but controlled by $allowed_keys // in the parse_goban_attributes() function foreach ($attributes as $key => $val) $$key = $val; // some adjustments $goban = 'images/wood'.$goban; $w1 = $grid_size; $w2 = $edges_width; $wout = ''; // weiqi output, appended to $renderer->doc at the end // should we output the source too (demo purpose) if ($demo) { $wout.= '
';
            $wout.= $source;
            $wout.= '
'; } // hardcoded style (I mean not CSSed) to be able to change the goban color $wout.= ''; if ($caption!='') $wout .= ''; // top coordinates if ($coords) { $wout .= ''; $wout .= '';// blank for left coordinates $wout .= '';// blank for left edge for($x=1;$x<=$width;$x++) { if ($reverse_letters) $row_letter = $this->letter($width - ($x - ($start_letter - 1)) + 1); else $row_letter = $this->letter($x + ($start_letter - 1)); $wout .= '';// top coordinates } $wout .= '';// blank for right edge $wout .= '';// blank for right coordinates $wout .= ''; } // top edge $wout .= ''; if ($coords) $wout .= '';// blank for left coordinates $wout .= '';// top left goban corner $wout .= '';// top corner $wout .= '';// top right goban corner if ($coords) $wout .= '';// blank for right coordinates $wout .= ''; // body $y=0; foreach ($board as $line) { $y++; $x=0; $wout .= ''; if ($reverse_numbers) $line_number = $y + ($start_number - 1); else $line_number = $height - $y + 1 + ($start_number - 1); if ($coords) $wout .= '';// left coordinates if ($y==1) $wout .= '';// left edge // board foreach ($line as $char) { $x++; $wout .= ''; } if ($y==1) $wout .= '';// right edge if ($coords) $wout .= '';// left coordinates $wout .= ''; } // bottom edge $wout .= ''; if ($coords) $wout .= '';// blank for left coordinates $wout .= '';// bottom left goban corner $wout .= ''; $wout .= '';// bottom right goban corner if ($coords) $wout .= '';// blank for right coordinates $wout .= ''; // bottom coordinates if ($coords) { $wout .= ''; $wout .= '';// blank for left coordinates $wout .= '';// blank for left edge for($x=1;$x<=$width;$x++) { if ($reverse_letters) $row_letter = $this->letter($width - ($x - ($start_letter - 1)) + 1); else $row_letter = $this->letter($x + ($start_letter - 1)); $wout .= '';// bottom coordinates } $wout .= '';// blank for right edge $wout .= '';// blank for right coordinates $wout .= ''; } $wout.= '
'.$caption.'
'.$this->img('images/blank',' ',$w1,$w1).''.$this->img('images/blank',' ',$w2,$w1).''.$this->img($w1.'/c'.$row_letter, $row_letter).''.$this->img('images/blank',' ',$w2,$w1).''.$this->img('images/blank',' ',$w1,$w1).'
'.$this->img('images/blank',' ',$w1,$w2).''.$this->img($goban.'_ul', ' ').''.$this->img($goban.'_u', ' ', $w1*$width, $w2).''.$this->img($goban.'_ur', ' ').''.$this->img('images/blank',' ',$w1,$w2).'
'.$this->img($w1.'/c'.$line_number, $line_number).''.$this->img($goban.'_l', ' ', $w2, $w1*$height).''.$this->img($w1.'/'.$this->weiqi_code($char, $x, $y, $width, $height), $char, $w1).''.$this->img($goban.'_r', ' ', $w2, $w1*$height).''.$this->img($w1.'/c'.$line_number, $line_number).'
'.$this->img('images/blank',' ',$w1,$w2).''.$this->img($goban.'_dl', ' ').''.$this->img($goban.'_d', ' ', $w1*$width, $w2).''.$this->img($goban.'_dr', ' ').''.$this->img('images/blank',' ',$w1,$w2).'
'.$this->img('images/blank',' ',$w1,$w1).''.$this->img('images/blank',' ',$w2,$w1).''.$this->img($w1.'/c'.$row_letter, $row_letter).''.$this->img('images/blank',' ',$w2,$w1).''.$this->img('images/blank',' ',$w1,$w1).'
'; return $wout; } /** * A character (or two in advanced mode) is translated to * the relevant image file for the img() function to work. * If ends with a #, img() will display text. */ function weiqi_code($str, $x, $y, $width, $height) { $str = trim($str); if (strlen($str) == 1) { // normal code switch ($str) { // goban case '.': return 'e'; case ',': return 'h'; case '+': if ( $x==$width && $y==1 ) return 'ur'; if ( $x==1 && $y==1 ) return 'ul'; if ( $x==1 && $y==$height ) return 'dl'; if ( $x==$width && $y==$height ) return 'dr'; case '-': if ( $y==1 ) return 'u'; if ( $y==$height ) return 'd'; case '|': if ( $x==1 ) return 'el'; if ( $x==$width ) return 'er'; // stones case 'x': return 'b'; case 'X': return 'bm'; case 'o': return 'w'; case 'O': return 'wm'; // for letters or numbers, we append an '#' // for them to appear as plain text // letters and numbers case '1': return '1#'; case '2': return '2#'; case '3': return '3#'; case '4': return '4#'; case '5': return '5#'; case '6': return '6#'; case '7': return '7#'; case '8': return '8#'; case '9': return '9#'; case 'a': return 'a#'; case 'b': return 'b#'; case 'c': return 'c#'; case 'd': return 'd#'; case 'e': return 'e#'; case 'f': return 'f#'; case 'g': return 'g#'; case 'h': return 'h#'; case 'i': return 'i#'; case 'j': return 'j#'; case 'k': return 'k#'; case 'l': return 'l#'; case 'm': return 'm#'; case 'n': return 'n#'; case 'p': return 'p#'; case 'q': return 'q#'; case 'r': return 'r#'; case 's': return 's#'; case 't': return 't#'; case 'u': return 'u#'; case 'v': return 'v#'; case 'w': return 'w#'; case 'y': return 'y#'; case 'z': return 'z#'; case 'A': return 'A#'; case 'B': return 'B#'; case 'C': return 'C#'; case 'D': return 'D#'; case 'E': return 'E#'; case 'F': return 'F#'; case 'G': return 'G#'; case 'H': return 'H#'; case 'I': return 'I#'; case 'J': return 'J#'; case 'K': return 'K#'; case 'L': return 'L#'; case 'M': return 'M#'; case 'N': return 'N#'; case 'P': return 'P#'; case 'Q': return 'Q#'; case 'R': return 'R#'; case 'S': return 'S#'; case 'T': return 'T#'; case 'U': return 'U#'; case 'V': return 'V#'; case 'W': return 'W#'; case 'Y': return 'Y#'; case 'Z': return 'Z#'; } } else { // advanced code // for letters or numbers, we append an '#' // for them to appear as plain text // the rest of the numbers if (is_numeric($str)) return $str.'#'; else { // the rest of the available symbols $ch1 = substr($str, 0, 1); $ch2 = substr($str, 1, 1); // first, the rest of the letters if ($ch2 == 'l') return $ch1.'#'; // now the goban marks and stones // ok it's a simple map, but DGS files for red squares have a d $ch2 = ($ch2=='r')?'d':$ch2; // some checks now // if nothing found, let's return nothing // so the img() function can report a mistake $available_second_chars = 'cstbwxdg1234567890'; if (strpos($available_second_chars, $ch2) === false) return ''; // no black stone with a black square, same for white if ($ch1.$ch2=='bb' OR $ch1.$ch2=='ww') return ''; switch ($ch1) { // goban and marks case '.': return 'e'.$ch2; case ',': return 'h'.$ch2; case '+': if ( $x==$width && $y==1 ) return 'ur'.$ch2; if ( $x==1 && $y==1 ) return 'ul'.$ch2; if ( $x==1 && $y==$height ) return 'dl'.$ch2; if ( $x==$width && $y==$height ) return 'dr'.$ch2; case '-': if ( $y==1 ) return 'u'.$ch2; if ( $y==$height ) return 'd'.$ch2; case '|': if ( $x==1 ) return 'el'.$ch2; if ( $x==$width ) return 'er'.$ch2; // stones case 'x': ; case 'X': return 'b'.($ch2=='0'?'10':$ch2); case 'o': ; case 'O': return 'w'.($ch2=='0'?'10':$ch2); } } } // if nothing found, let's return nothing, // so the img() function can report a mistake return ''; } /** * Number to letter using $this->conf['letter_sequence']) */ function letter($n) { $n--; if ($n >= 0 AND $n < strlen($this->conf['letter_sequence'])) return substr($this->conf['letter_sequence'], $n, 1); // this can help debugging the wiki code else return $n; } /** * Returns an img tag or text to fille the table. */ function img($src, $alt=false, $w=false, $h=false) { $text_px = floor($this->conf['plain_text_coeff']*$w); // '/' at the end means we have to report a mistake if (preg_match('@/$@', $src)) return '@'; // '#' at the end means we have a number or a letter // numbers and letters are displayed with simple text if (preg_match('@/(.+)#$@', $src, $match)) return ''.$match[1].''; // the rest is done with the usual img html tag $html = ''; $html.= 'conf['img_path_web'].$src.'.gif"'; if($alt) $html.= ' alt="'.$alt.'"'; $html.= ' />'; return $html; } /** * Parses the attribute lines. * Returns an array that will be used by the render() function if everything * is correct. * Returns nothing and sets the error vars correctly if not. */ function parse_goban_attributes($str) { $str = trim($str); if ($str=='') return array(); $ret = array(); $attributes = explode(' ', $str); $errors = array(); foreach ($attributes as $attribute) { list($key,$value) = preg_split('/=/',$attribute,2); // report non allowed keys if (!in_array($key, $this->conf['allowed_attribute_keys'])) $errors[$key] = ''; if ($key == 'demo') $ret[$key] = true; if ($key == 'goban') { if (!is_file(realpath($this->conf['img_path_fs'].'images/wood'.$value.'.gif'))) { $errors[$key] = $value; } $ret['goban'] = $value; } if ($key == 'coords') $ret[$key] = true; if ($key == 'grid_size') { if (!is_dir(realpath($this->conf['img_path_fs'].$value))) { $errors[$key] = $value; } $ret['grid_size'] = $value; } if ($key == 'reverse_numbers') $ret[$key] = true; if ($key == 'reverse_letters') $ret[$key] = true; if ($key == 'start_number') { if ($value<1 OR $value>25) { $errors[$key] = $value; } $ret['start_number'] = $value; } if ($key == 'start_letter') { $strpos = strpos($this->conf['letter_sequence'], strtolower($value)); if ($strpos===false) { $errors[$key] = $value; } $ret['start_letter'] = $strpos + 1; } if ($key == 'advanced') $ret[$key] = true; } if (!empty($errors)) { $this->error = true; $this->error_code = WEIQI_ERROR_BAD_ATTRIBUTES; $this->error_data = array('attributes_str' => $str, 'errors' => $errors); return; } return $ret; } }