adding support for external references in formulas

git-svn-id: https://svn.php.net/repository/pear/packages/Spreadsheet_Excel_Writer/trunk@116261 c90b9560-bf6c-de11-be94-00142212c4b1
This commit is contained in:
Xavier Noguer Gallego 2003-02-13 18:45:14 +00:00
parent 5244cffc68
commit 5cdea13592
2 changed files with 149 additions and 5 deletions

View File

@ -116,6 +116,12 @@ class Parser extends PEAR
*/ */
var $_func_args; var $_func_args;
/**
* Array of external sheets
* @var array
*/
var $_ext_sheets;
/** /**
* The class constructor * The class constructor
* *
@ -132,6 +138,7 @@ class Parser extends PEAR
$this->_initializeHashes(); // Initialize the hashes: ptg's and function's ptg's $this->_initializeHashes(); // Initialize the hashes: ptg's and function's ptg's
$this->_byte_order = $byte_order; // Little Endian or Big Endian $this->_byte_order = $byte_order; // Little Endian or Big Endian
$this->_func_args = 0; // Number of arguments for the current function $this->_func_args = 0; // Number of arguments for the current function
$this->_ext_sheets = array();
} }
/** /**
@ -500,6 +507,11 @@ class Parser extends PEAR
{ {
return($this->_convertRef2d($token)); return($this->_convertRef2d($token));
} }
// match external references like Sheet1!A1
elseif(preg_match("/^([A-Za-z0-9]+\![A-I]?[A-Z])(\d+)$/",$token))
{
return($this->_convertRef3d($token));
}
// match ranges like A1:B2 // match ranges like A1:B2
elseif(preg_match("/^([A-I]?[A-Z])(\d+)\:([A-I]?[A-Z])(\d+)$/",$token)) elseif(preg_match("/^([A-I]?[A-Z])(\d+)\:([A-I]?[A-Z])(\d+)$/",$token))
{ {
@ -641,7 +653,7 @@ class Parser extends PEAR
if($this->isError($cell_array)) { if($this->isError($cell_array)) {
return($cell_array); return($cell_array);
} }
list($row, $col) = $cell_array; //$this->_cellToPackedRowcol($cell); list($row, $col) = $cell_array;
// The ptg value depends on the class of the ptg. // The ptg value depends on the class of the ptg.
if ($class == 0) { if ($class == 0) {
@ -660,6 +672,124 @@ class Parser extends PEAR
return($ptgRef.$row.$col); return($ptgRef.$row.$col);
} }
/**
* Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a
* ptgRef3dV.
*
* @access private
* @param string $cell An Excel cell reference
* @return string The cell in packed() format with the corresponding ptg
*/
function _convertRef3d($cell)
{
$class = 2; // as far as I know, this is magick.
// Split the ref at the ! symbol
list($ext_ref, $cell) = split('!', $cell);
// Convert the external reference part
$ext_ref = $this->_packExtRef($ext_ref);
if ($this->isError($ext_ref)) {
return $ext_ref;
}
// Convert the cell reference part
list($row, $col) = $this->_cellToPackedRowcol($cell);
// The ptg value depends on the class of the ptg.
if ($class == 0) {
$ptgRef = pack("C", $this->ptg['ptgRef3d']);
}
elseif ($class == 1) {
$ptgRef = pack("C", $this->ptg['ptgRef3dV']);
}
elseif ($class == 2) {
$ptgRef = pack("C", $this->ptg['ptgRef3dA']);
}
else {
$this->raiseError("Unknown class $class", 0, PEAR_ERROR_DIE);
}
return $ptgRef . $ext_ref. $row . $col;
}
/**
* Convert the sheet name part of an external reference, for example "Sheet1" or
* "Sheet1:Sheet2", to a packed structure.
*
* @access private
* @param string $ext_ref The name of the external reference
* @return string The reference index in packed() format
*/
function _packExtRef($ext_ref)
{
$ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any.
$ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any.
// Check if there is a sheet range eg., Sheet1:Sheet2.
if (preg_match("/:/", $ext_ref))
{
list($sheet_name1, $sheet_name2) = split(':', $ext_ref);
$sheet1 = $this->_getSheetIndex($sheet_name1);
if ($sheet1 == -1) {
return $this->raiseError("Unknown sheet name $sheet_name1 in formula");
}
$sheet2 = $this->_getSheetIndex($sheet_name2);
if ($sheet2 == -1) {
return $this->raiseError("Unknown sheet name $sheet_name2 in formula");
}
// Reverse max and min sheet numbers if necessary
if ($sheet1 > $sheet2) {
list($sheet1, $sheet2) = array($sheet2, $sheet1);
}
}
else // Single sheet name only.
{
$sheet1 = $this->_getSheetIndex($ext_ref);
if ($sheet1 == -1) {
return $this->raiseError("Unknown sheet name $ext_ref in formula");
}
$sheet2 = $sheet1;
}
// References are stored relative to 0xFFFF.
$offset = -1 - $sheet1;
return pack('vdvv', $offset, 0x00, $sheet1, $sheet2);
}
/**
* Look up the index that corresponds to an external sheet name. The hash of
* sheet names is updated by the addworksheet() method of the Workbook class.
*
* @access private
* @return integer
*/
function _getSheetIndex($sheet_name)
{
if (!isset($this->_ext_sheets[$sheet_name])) {
return -1;
}
else {
return $this->_ext_sheets[$sheet_name];
}
}
/**
* This method is used to update the array of sheet names. It is
* called by the addWorksheet() method of the Workbook class.
*
* @access private
* @param string $name The name of the worksheet being added
* @param integer $index The index of the worksheet being added
*/
function setExtSheet($name, $index)
{
$this->_ext_sheets[$name] = $index;
}
/** /**
* pack() row and column into the required 3 byte format. * pack() row and column into the required 3 byte format.
* *
@ -795,6 +925,13 @@ class Parser extends PEAR
{ {
return($token); return($token);
} }
// If it's an external reference (Sheet1!A1)
elseif(eregi("^[A-Za-z0-9]+\![A-I]?[A-Z][0-9]+$",$token) and
!ereg("[0-9]",$this->_lookahead) and
($this->_lookahead != ':') and ($this->_lookahead != '.'))
{
return($token);
}
// if it's a range (A1:A2) // if it's a range (A1:A2)
elseif(eregi("^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$",$token) and elseif(eregi("^[A-I]?[A-Z][0-9]+:[A-I]?[A-Z][0-9]+$",$token) and
!ereg("[0-9]",$this->_lookahead)) !ereg("[0-9]",$this->_lookahead))
@ -958,9 +1095,16 @@ class Parser extends PEAR
$this->_advance(); $this->_advance();
return($result); return($result);
} }
// If it's an external reference (Sheet1!A1)
elseif(eregi("^[A-Za-z0-9]+\![A-I]?[A-Z][0-9]+$",$this->_current_token))
{
$result = $this->_current_token;
$this->_advance();
return($result);
}
// if it's a range // if it's a range
elseif (eregi("^[A-Z]?[A-Z][0-9]+:[A-Z]?[A-Z][0-9]+$",$this->_current_token) or elseif (eregi("^[A-Z]?[A-Z][0-9]+:[A-Z]?[A-Z][0-9]+$",$this->_current_token) or
eregi("^[A-Z]?[A-Z][0-9]+\.\.[A-Z]?[A-Z][0-9]+$",$this->_current_token)) eregi("^[A-Z]?[A-Z][0-9]+\.\.[A-Z]?[A-Z][0-9]+$",$this->_current_token))
{ {
$result = $this->_current_token; $result = $this->_current_token;
$this->_advance(); $this->_advance();

View File

@ -249,9 +249,9 @@ class Workbook extends BIFFwriter
$this->_firstsheet,$this->_url_format, $this->_firstsheet,$this->_url_format,
$this->_parser); $this->_parser);
$this->_worksheets[$index] = &$worksheet; // Store ref for iterator $this->_worksheets[$index] = &$worksheet; // Store ref for iterator
$this->_sheetnames[$index] = $name; // Store EXTERNSHEET names $this->_sheetnames[$index] = $name; // Store EXTERNSHEET names
//$this->parser->set_ext_sheet($name,$index); // Store names in Formula.php $this->_parser->setExtSheet($name, $index); // Register worksheet name with parser
return($worksheet); return($worksheet);
} }