[Feature][Modem]Update MTK MODEM V1.6 baseline version: MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6
MTK modem version: MT2735_IVT_MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6.tar.gz
RF modem version: NA
Change-Id: I45a4c2752fa9d1a618beacd5d40737fb39ab64fb
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Cell.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Cell.pm
new file mode 100644
index 0000000..2527075
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Cell.pm
@@ -0,0 +1,314 @@
+package Spreadsheet::ParseExcel::Cell;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Cell - A class for Cell data and formatting.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+our $VERSION = '0.59';
+
+###############################################################################
+#
+# new()
+#
+# Constructor.
+#
+sub new {
+ my ( $package, %properties ) = @_;
+ my $self = \%properties;
+
+ bless $self, $package;
+}
+
+###############################################################################
+#
+# value()
+#
+# Returns the formatted value of the cell.
+#
+sub value {
+
+ my $self = shift;
+
+ return $self->{_Value};
+}
+
+###############################################################################
+#
+# unformatted()
+#
+# Returns the unformatted value of the cell.
+#
+sub unformatted {
+
+ my $self = shift;
+
+ return $self->{Val};
+}
+
+###############################################################################
+#
+# get_format()
+#
+# Returns the Format object for the cell.
+#
+sub get_format {
+
+ my $self = shift;
+
+ return $self->{Format};
+}
+
+###############################################################################
+#
+# type()
+#
+# Returns the type of cell such as Text, Numeric or Date.
+#
+sub type {
+
+ my $self = shift;
+
+ return $self->{Type};
+}
+
+###############################################################################
+#
+# encoding()
+#
+# Returns the character encoding of the cell.
+#
+sub encoding {
+
+ my $self = shift;
+
+ if ( !defined $self->{Code} ) {
+ return 1;
+ }
+ elsif ( $self->{Code} eq 'ucs2' ) {
+ return 2;
+ }
+ elsif ( $self->{Code} eq '_native_' ) {
+ return 3;
+ }
+ else {
+ return 0;
+ }
+
+ return $self->{Code};
+}
+
+###############################################################################
+#
+# is_merged()
+#
+# Returns true if the cell is merged.
+#
+sub is_merged {
+
+ my $self = shift;
+
+ return $self->{Merged};
+}
+
+###############################################################################
+#
+# get_rich_text()
+#
+# Returns an array ref of font information about each string block in a "rich",
+# i.e. multi-format, string.
+#
+sub get_rich_text {
+
+ my $self = shift;
+
+ return $self->{Rich};
+}
+
+###############################################################################
+#
+# Mapping between legacy method names and new names.
+#
+{
+ no warnings; # Ignore warnings about variables used only once.
+ *Value = *value;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Cell - A class for Cell data and formatting.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 Methods
+
+The following Cell methods are available:
+
+ $cell->value()
+ $cell->unformatted()
+ $cell->get_format()
+ $cell->type()
+ $cell->encoding()
+ $cell->is_merged()
+ $cell->get_rich_text()
+
+
+=head2 value()
+
+The C<value()> method returns the formatted value of the cell.
+
+ my $value = $cell->value();
+
+Formatted in this sense refers to the numeric format of the cell value. For example a number such as 40177 might be formatted as 40,117, 40117.000 or even as the date 2009/12/30.
+
+If the cell doesn't contain a numeric format then the formatted and unformatted cell values are the same, see the C<unformatted()> method below.
+
+For a defined C<$cell> the C<value()> method will always return a value.
+
+In the case of a cell with formatting but no numeric or string contents the method will return the empty string C<''>.
+
+
+=head2 unformatted()
+
+The C<unformatted()> method returns the unformatted value of the cell.
+
+ my $unformatted = $cell->unformatted();
+
+Returns the cell value without a numeric format. See the C<value()> method above.
+
+
+=head2 get_format()
+
+The C<get_format()> method returns the L<Spreadsheet::ParseExcel::Format> object for the cell.
+
+ my $format = $cell->get_format();
+
+If a user defined format hasn't been applied to the cell then the default cell format is returned.
+
+
+=head2 type()
+
+The C<type()> method returns the type of cell such as Text, Numeric or Date. If the type was detected as Numeric, and the Cell Format matches C<m{^[dmy][-\\/dmy]*$}i>, it will be treated as a Date type.
+
+ my $type = $cell->type();
+
+See also L<Dates and Time in Excel>.
+
+
+=head2 encoding()
+
+The C<encoding()> method returns the character encoding of the cell.
+
+ my $encoding = $cell->encoding();
+
+This method is only of interest to developers. In general Spreadsheet::ParseExcel will return all character strings in UTF-8 regardless of the encoding used by Excel.
+
+The C<encoding()> method returns one of the following values:
+
+=over
+
+=item * 0: Unknown format. This shouldn't happen. In the default case the format should be 1.
+
+=item * 1: 8bit ASCII or single byte UTF-16. This indicates that the characters are encoded in a single byte. In Excel 95 and earlier This usually meant ASCII or an international variant. In Excel 97 it refers to a compressed UTF-16 character string where all of the high order bytes are 0 and are omitted to save space.
+
+=item * 2: UTF-16BE.
+
+=item * 3: Native encoding. In Excel 95 and earlier this encoding was used to represent multi-byte character encodings such as SJIS.
+
+=back
+
+
+=head2 is_merged()
+
+The C<is_merged()> method returns true if the cell is merged.
+
+ my $is_merged = $cell->is_merged();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_rich_text()
+
+The C<get_rich_text()> method returns an array ref of font information about each string block in a "rich", i.e. multi-format, string.
+
+ my $rich_text = $cell->get_rich_text();
+
+The return value is an arrayref of arrayrefs in the form:
+
+ [
+ [ $start_position, $font_object ],
+ ...,
+ ]
+
+Returns undef if the property isn't set.
+
+
+=head1 Dates and Time in Excel
+
+Dates and times in Excel are represented by real numbers, for example "Jan 1 2001 12:30 PM" is represented by the number 36892.521.
+
+The integer part of the number stores the number of days since the epoch and the fractional part stores the percentage of the day.
+
+A date or time in Excel is just like any other number. The way in which it is displayed is controlled by the number format:
+
+ Number format $cell->value() $cell->unformatted()
+ ============= ============== ==============
+ 'dd/mm/yy' '28/02/08' 39506.5
+ 'mm/dd/yy' '02/28/08' 39506.5
+ 'd-m-yyyy' '28-2-2008' 39506.5
+ 'dd/mm/yy hh:mm' '28/02/08 12:00' 39506.5
+ 'd mmm yyyy' '28 Feb 2008' 39506.5
+ 'mmm d yyyy hh:mm AM/PM' 'Feb 28 2008 12:00 PM' 39506.5
+
+
+The L<Spreadsheet::ParseExcel::Utility> module contains a function called C<ExcelLocaltime> which will convert between an unformatted Excel date/time number and a C<localtime()> like array.
+
+For date conversions using the CPAN C<DateTime> framework see L<DateTime::Format::Excel> http://search.cpan.org/search?dist=DateTime-Format-Excel
+
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Dump.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Dump.pm
new file mode 100644
index 0000000..5586db2
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Dump.pm
@@ -0,0 +1,355 @@
+package Spreadsheet::ParseExcel::Dump;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Dump - A class for dumping Excel records.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+our $VERSION = '0.59';
+
+my %NameTbl = (
+
+ #P291
+ 0x0A => 'EOF',
+ 0x0C => 'CALCCOUNT',
+ 0x0D => 'CALCMODE',
+ 0x0E => 'PRECISION',
+ 0x0F => 'REFMODE',
+ 0x10 => 'DELTA',
+ 0x11 => 'ITERATION',
+ 0x12 => 'PROTECT',
+ 0x13 => 'PASSWORD',
+ 0x14 => 'HEADER',
+
+ 0x15 => 'FOOTER',
+ 0x16 => 'EXTERNCOUNT',
+ 0x17 => 'EXTERNSHEET',
+ 0x19 => 'WINDOWPROTECT',
+ 0x1A => 'VERTICALPAGEBREAKS',
+ 0x1B => 'HORIZONTALPAGEBREAKS',
+ 0x1C => 'NOTE',
+ 0x1D => 'SELECTION',
+ 0x22 => '1904',
+ 0x26 => 'LEFTMARGIN',
+
+ 0x27 => 'RIGHTMARGIN',
+ 0x28 => 'TOPMARGIN',
+ 0x29 => 'BOTTOMMARGIN',
+ 0x2A => 'PRINTHEADERS',
+ 0x2B => 'PRINTGRIDLINES',
+ 0x2F => 'FILEPASS',
+ 0x3C => 'COUNTINUE',
+ 0x3D => 'WINDOW1',
+ 0x40 => 'BACKUP',
+ 0x41 => 'PANE',
+
+ 0x42 => 'CODEPAGE',
+ 0x4D => 'PLS',
+ 0x50 => 'DCON',
+ 0x51 => 'DCONREF',
+
+ #P292
+ 0x52 => 'DCONNAME',
+ 0x55 => 'DEFCOLWIDTH',
+ 0x59 => 'XCT',
+ 0x5A => 'CRN',
+ 0x5B => 'FILESHARING',
+ 0x5C => 'WRITEACCES',
+ 0x5D => 'OBJ',
+ 0x5E => 'UNCALCED',
+ 0x5F => 'SAVERECALC',
+ 0x60 => 'TEMPLATE',
+
+ 0x63 => 'OBJPROTECT',
+ 0x7D => 'COLINFO',
+ 0x7E => 'RK',
+ 0x7F => 'IMDATA',
+ 0x80 => 'GUTS',
+ 0x81 => 'WSBOOL',
+ 0x82 => 'GRIDSET',
+ 0x83 => 'HCENTER',
+ 0x84 => 'VCENTER',
+ 0x85 => 'BOUNDSHEET',
+
+ 0x86 => 'WRITEPROT',
+ 0x87 => 'ADDIN',
+ 0x88 => 'EDG',
+ 0x89 => 'PUB',
+ 0x8C => 'COUNTRY',
+ 0x8D => 'HIDEOBJ',
+ 0x90 => 'SORT',
+ 0x91 => 'SUB',
+ 0x92 => 'PALETTE',
+ 0x94 => 'LHRECORD',
+
+ 0x95 => 'LHNGRAPH',
+ 0x96 => 'SOUND',
+ 0x98 => 'LPR',
+ 0x99 => 'STANDARDWIDTH',
+ 0x9A => 'FNGROUPNAME',
+ 0x9B => 'FILTERMODE',
+ 0x9C => 'FNGROUPCOUNT',
+
+ #P293
+ 0x9D => 'AUTOFILTERINFO',
+ 0x9E => 'AUTOFILTER',
+ 0xA0 => 'SCL',
+ 0xA1 => 'SETUP',
+ 0xA9 => 'COORDLIST',
+ 0xAB => 'GCW',
+ 0xAE => 'SCENMAN',
+ 0xAF => 'SCENARIO',
+ 0xB0 => 'SXVIEW',
+ 0xB1 => 'SXVD',
+
+ 0xB2 => 'SXV',
+ 0xB4 => 'SXIVD',
+ 0xB5 => 'SXLI',
+ 0xB6 => 'SXPI',
+ 0xB8 => 'DOCROUTE',
+ 0xB9 => 'RECIPNAME',
+ 0xBC => 'SHRFMLA',
+ 0xBD => 'MULRK',
+ 0xBE => 'MULBLANK',
+ 0xBF => 'TOOLBARHDR',
+ 0xC0 => 'TOOLBAREND',
+ 0xC1 => 'MMS',
+
+ 0xC2 => 'ADDMENU',
+ 0xC3 => 'DELMENU',
+ 0xC5 => 'SXDI',
+ 0xC6 => 'SXDB',
+ 0xCD => 'SXSTRING',
+ 0xD0 => 'SXTBL',
+ 0xD1 => 'SXTBRGIITM',
+ 0xD2 => 'SXTBPG',
+ 0xD3 => 'OBPROJ',
+ 0xD5 => 'SXISDTM',
+
+ 0xD6 => 'RSTRING',
+ 0xD7 => 'DBCELL',
+ 0xDA => 'BOOKBOOL',
+ 0xDC => 'PARAMQRY',
+ 0xDC => 'SXEXT',
+ 0xDD => 'SCENPROTECT',
+ 0xDE => 'OLESIZE',
+
+ #P294
+ 0xDF => 'UDDESC',
+ 0xE0 => 'XF',
+ 0xE1 => 'INTERFACEHDR',
+ 0xE2 => 'INTERFACEEND',
+ 0xE3 => 'SXVS',
+ 0xEA => 'TABIDCONF',
+ 0xEB => 'MSODRAWINGGROUP',
+ 0xEC => 'MSODRAWING',
+ 0xED => 'MSODRAWINGSELECTION',
+ 0xEF => 'PHONETICINFO',
+ 0xF0 => 'SXRULE',
+
+ 0xF1 => 'SXEXT',
+ 0xF2 => 'SXFILT',
+ 0xF6 => 'SXNAME',
+ 0xF7 => 'SXSELECT',
+ 0xF8 => 'SXPAIR',
+ 0xF9 => 'SXFMLA',
+ 0xFB => 'SXFORMAT',
+ 0xFC => 'SST',
+ 0xFD => 'LABELSST',
+ 0xFF => 'EXTSST',
+
+ 0x100 => 'SXVDEX',
+ 0x103 => 'SXFORMULA',
+ 0x122 => 'SXDBEX',
+ 0x13D => 'TABID',
+ 0x160 => 'USESELFS',
+ 0x161 => 'DSF',
+ 0x162 => 'XL5MODIFY',
+ 0x1A5 => 'FILESHARING2',
+ 0x1A9 => 'USERBVIEW',
+ 0x1AA => 'USERVIEWBEGIN',
+
+ 0x1AB => 'USERSVIEWEND',
+ 0x1AD => 'QSI',
+ 0x1AE => 'SUPBOOK',
+ 0x1AF => 'PROT4REV',
+ 0x1B0 => 'CONDFMT',
+ 0x1B1 => 'CF',
+ 0x1B2 => 'DVAL',
+
+ #P295
+ 0x1B5 => 'DCONBIN',
+ 0x1B6 => 'TXO',
+ 0x1B7 => 'REFRESHALL',
+ 0x1B8 => 'HLINK',
+ 0x1BA => 'CODENAME',
+ 0x1BB => 'SXFDBTYPE',
+ 0x1BC => 'PROT4REVPASS',
+ 0x1BE => 'DV',
+ 0x200 => 'DIMENSIONS',
+ 0x201 => 'BLANK',
+
+ 0x202 => 'Integer', #Not Documented
+ 0x203 => 'NUMBER',
+ 0x204 => 'LABEL',
+ 0x205 => 'BOOLERR',
+ 0x207 => 'STRING',
+ 0x208 => 'ROW',
+ 0x20B => 'INDEX',
+ 0x218 => 'NAME',
+ 0x221 => 'ARRAY',
+ 0x223 => 'EXTERNNAME',
+ 0x225 => 'DEFAULTROWHEIGHT',
+
+ 0x231 => 'FONT',
+ 0x236 => 'TABLE',
+ 0x23E => 'WINDOW2',
+ 0x293 => 'STYLE',
+ 0x406 => 'FORMULA',
+ 0x41E => 'FORMAT',
+
+ 0x18 => 'NAME',
+
+ 0x06 => 'FORMULA',
+
+ 0x09 => 'BOF(BIFF2)',
+ 0x209 => 'BOF(BIFF3)',
+ 0x409 => 'BOF(BIFF4)',
+ 0x809 => 'BOF(BIFF5-7)',
+
+ 0x31 => 'FONT', 0x27E => 'RK',
+
+ #Chart/Graph
+ 0x1001 => 'UNITS',
+ 0x1002 => 'CHART',
+ 0x1003 => 'SERISES',
+ 0x1006 => 'DATAFORMAT',
+ 0x1007 => 'LINEFORMAT',
+ 0x1009 => 'MAKERFORMAT',
+ 0x100A => 'AREAFORMAT',
+ 0x100B => 'PIEFORMAT',
+ 0x100C => 'ATTACHEDLABEL',
+ 0x100D => 'SERIESTEXT',
+ 0x1014 => 'CHARTFORMAT',
+ 0x1015 => 'LEGEND',
+ 0x1016 => 'SERIESLIST',
+ 0x1017 => 'BAR',
+ 0x1018 => 'LINE',
+ 0x1019 => 'PIE',
+ 0x101A => 'AREA',
+ 0x101B => 'SCATTER',
+ 0x101C => 'CHARTLINE',
+ 0x101D => 'AXIS',
+ 0x101E => 'TICK',
+ 0x101F => 'VALUERANGE',
+ 0x1020 => 'CATSERRANGE',
+ 0x1021 => 'AXISLINEFORMAT',
+ 0x1022 => 'CHARTFORMATLINK',
+ 0x1024 => 'DEFAULTTEXT',
+ 0x1025 => 'TEXT',
+ 0x1026 => 'FONTX',
+ 0x1027 => 'OBJECTLINK',
+ 0x1032 => 'FRAME',
+ 0x1033 => 'BEGIN',
+ 0x1034 => 'END',
+ 0x1035 => 'PLOTAREA',
+ 0x103A => '3D',
+ 0x103C => 'PICF',
+ 0x103D => 'DROPBAR',
+ 0x103E => 'RADAR',
+ 0x103F => 'SURFACE',
+ 0x1040 => 'RADARAREA',
+ 0x1041 => 'AXISPARENT',
+ 0x1043 => 'LEGENDXN',
+ 0x1044 => 'SHTPROPS',
+ 0x1045 => 'SERTOCRT',
+ 0x1046 => 'AXESUSED',
+ 0x1048 => 'SBASEREF',
+ 0x104A => 'SERPARENT',
+ 0x104B => 'SERAUXTREND',
+ 0x104E => 'IFMT',
+ 0x104F => 'POS',
+ 0x1050 => 'ALRUNS',
+ 0x1051 => 'AI',
+ 0x105B => 'SERAUXERRBAR',
+ 0x105D => 'SERFMT',
+ 0x1060 => 'FBI',
+ 0x1061 => 'BOPPOP',
+ 0x1062 => 'AXCEXT',
+ 0x1063 => 'DAT',
+ 0x1064 => 'PLOTGROWTH',
+ 0x1065 => 'SINDEX',
+ 0x1066 => 'GELFRAME',
+ 0x1067 => 'BPOPPOPCUSTOM',
+);
+
+#------------------------------------------------------------------------------
+# subDUMP (for Spreadsheet::ParseExcel)
+#------------------------------------------------------------------------------
+sub subDUMP {
+ my ( $oBook, $bOp, $bLen, $sWk ) = @_;
+ printf "%04X:%-23s (Len:%3d) : %s\n",
+ $bOp, OpName($bOp), $bLen, unpack( "H40", $sWk );
+}
+
+#------------------------------------------------------------------------------
+# Spreadsheet::ParseExcel->OpName
+#------------------------------------------------------------------------------
+sub OpName {
+ my ($bOp) = @_;
+ return ( defined $NameTbl{$bOp} ) ? $NameTbl{$bOp} : 'undef';
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Dump - A class for dumping Excel records.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
+
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/FmtDefault.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtDefault.pm
new file mode 100644
index 0000000..416866f
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtDefault.pm
@@ -0,0 +1,221 @@
+package Spreadsheet::ParseExcel::FmtDefault;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::FmtDefault - A class for Cell formats.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+use Spreadsheet::ParseExcel::Utility qw(ExcelFmt);
+our $VERSION = '0.59';
+
+my %hFmtDefault = (
+ 0x00 => '@',
+ 0x01 => '0',
+ 0x02 => '0.00',
+ 0x03 => '#,##0',
+ 0x04 => '#,##0.00',
+ 0x05 => '($#,##0_);($#,##0)',
+ 0x06 => '($#,##0_);[RED]($#,##0)',
+ 0x07 => '($#,##0.00_);($#,##0.00_)',
+ 0x08 => '($#,##0.00_);[RED]($#,##0.00_)',
+ 0x09 => '0%',
+ 0x0A => '0.00%',
+ 0x0B => '0.00E+00',
+ 0x0C => '# ?/?',
+ 0x0D => '# ??/??',
+ 0x0E => 'yyyy-mm-dd', # Was 'm-d-yy', which is bad as system default
+ 0x0F => 'd-mmm-yy',
+ 0x10 => 'd-mmm',
+ 0x11 => 'mmm-yy',
+ 0x12 => 'h:mm AM/PM',
+ 0x13 => 'h:mm:ss AM/PM',
+ 0x14 => 'h:mm',
+ 0x15 => 'h:mm:ss',
+ 0x16 => 'm-d-yy h:mm',
+
+ #0x17-0x24 -- Differs in Natinal
+ 0x25 => '(#,##0_);(#,##0)',
+ 0x26 => '(#,##0_);[RED](#,##0)',
+ 0x27 => '(#,##0.00);(#,##0.00)',
+ 0x28 => '(#,##0.00);[RED](#,##0.00)',
+ 0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
+ 0x2A => '_($*#,##0_);_($*(#,##0);_(*"-"_);_(@_)',
+ 0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
+ 0x2C => '_($*#,##0.00_);_($*(#,##0.00);_(*"-"??_);_(@_)',
+ 0x2D => 'mm:ss',
+ 0x2E => '[h]:mm:ss',
+ 0x2F => 'mm:ss.0',
+ 0x30 => '##0.0E+0',
+ 0x31 => '@',
+);
+
+#------------------------------------------------------------------------------
+# new (for Spreadsheet::ParseExcel::FmtDefault)
+#------------------------------------------------------------------------------
+sub new {
+ my ( $sPkg, %hKey ) = @_;
+ my $oThis = {};
+ bless $oThis;
+ return $oThis;
+}
+
+#------------------------------------------------------------------------------
+# TextFmt (for Spreadsheet::ParseExcel::FmtDefault)
+#------------------------------------------------------------------------------
+sub TextFmt {
+ my ( $oThis, $sTxt, $sCode ) = @_;
+ return $sTxt if ( ( !defined($sCode) ) || ( $sCode eq '_native_' ) );
+ return pack( 'U*', unpack( 'n*', $sTxt ) );
+}
+
+#------------------------------------------------------------------------------
+# FmtStringDef (for Spreadsheet::ParseExcel::FmtDefault)
+#------------------------------------------------------------------------------
+sub FmtStringDef {
+ my ( $oThis, $iFmtIdx, $oBook, $rhFmt ) = @_;
+ my $sFmtStr = $oBook->{FormatStr}->{$iFmtIdx};
+
+ if ( !( defined($sFmtStr) ) && defined($rhFmt) ) {
+ $sFmtStr = $rhFmt->{$iFmtIdx};
+ }
+ $sFmtStr = $hFmtDefault{$iFmtIdx} unless ($sFmtStr);
+ return $sFmtStr;
+}
+
+#------------------------------------------------------------------------------
+# FmtString (for Spreadsheet::ParseExcel::FmtDefault)
+#------------------------------------------------------------------------------
+sub FmtString {
+ my ( $oThis, $oCell, $oBook ) = @_;
+
+ my $sFmtStr =
+ $oThis->FmtStringDef( $oBook->{Format}[ $oCell->{FormatNo} ]->{FmtIdx},
+ $oBook );
+
+ # Special case for cells that use Lotus123 style leading
+ # apostrophe to designate text formatting.
+ if ( $oBook->{Format}[ $oCell->{FormatNo} ]->{Key123} ) {
+ $sFmtStr = '@';
+ }
+
+ unless ( defined($sFmtStr) ) {
+ if ( $oCell->{Type} eq 'Numeric' ) {
+ if ( int( $oCell->{Val} ) != $oCell->{Val} ) {
+ $sFmtStr = '0.00';
+ }
+ else {
+ $sFmtStr = '0';
+ }
+ }
+ elsif ( $oCell->{Type} eq 'Date' ) {
+ if ( int( $oCell->{Val} ) <= 0 ) {
+ $sFmtStr = 'h:mm:ss';
+ }
+ else {
+ $sFmtStr = 'yyyy-mm-dd';
+ }
+ }
+ else {
+ $sFmtStr = '@';
+ }
+ }
+ return $sFmtStr;
+}
+
+#------------------------------------------------------------------------------
+# ValFmt (for Spreadsheet::ParseExcel::FmtDefault)
+#------------------------------------------------------------------------------
+sub ValFmt {
+ my ( $oThis, $oCell, $oBook ) = @_;
+
+ my ( $Dt, $iFmtIdx, $iNumeric, $Flg1904 );
+
+ if ( $oCell->{Type} eq 'Text' ) {
+ $Dt =
+ ( ( defined $oCell->{Val} ) && ( $oCell->{Val} ne '' ) )
+ ? $oThis->TextFmt( $oCell->{Val}, $oCell->{Code} )
+ : '';
+
+ return $Dt;
+ }
+ else {
+ $Dt = $oCell->{Val};
+ $Flg1904 = $oBook->{Flg1904};
+ my $sFmtStr = $oThis->FmtString( $oCell, $oBook );
+
+ return ExcelFmt( $sFmtStr, $Dt, $Flg1904, $oCell->{Type} );
+ }
+}
+
+#------------------------------------------------------------------------------
+# ChkType (for Spreadsheet::ParseExcel::FmtDefault)
+#------------------------------------------------------------------------------
+sub ChkType {
+ my ( $oPkg, $iNumeric, $iFmtIdx ) = @_;
+ if ($iNumeric) {
+ if ( ( ( $iFmtIdx >= 0x0E ) && ( $iFmtIdx <= 0x16 ) )
+ || ( ( $iFmtIdx >= 0x2D ) && ( $iFmtIdx <= 0x2F ) ) )
+ {
+ return "Date";
+ }
+ else {
+ return "Numeric";
+ }
+ }
+ else {
+ return "Text";
+ }
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::FmtDefault - A class for Cell formats.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/FmtJapan.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtJapan.pm
new file mode 100644
index 0000000..71f2b16
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtJapan.pm
@@ -0,0 +1,210 @@
+package Spreadsheet::ParseExcel::FmtJapan;
+use utf8;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::FmtJapan - A class for Cell formats.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+use Encode qw(find_encoding decode);
+use base 'Spreadsheet::ParseExcel::FmtDefault';
+our $VERSION = '0.59';
+
+my %FormatTable = (
+ 0x00 => '@',
+ 0x01 => '0',
+ 0x02 => '0.00',
+ 0x03 => '#,##0',
+ 0x04 => '#,##0.00',
+ 0x05 => '(\\#,##0_);(\\#,##0)',
+ 0x06 => '(\\#,##0_);[RED](\\#,##0)',
+ 0x07 => '(\\#,##0.00_);(\\#,##0.00_)',
+ 0x08 => '(\\#,##0.00_);[RED](\\#,##0.00_)',
+ 0x09 => '0%',
+ 0x0A => '0.00%',
+ 0x0B => '0.00E+00',
+ 0x0C => '# ?/?',
+ 0x0D => '# ??/??',
+
+ # 0x0E => 'm/d/yy',
+ 0x0E => 'yyyy/m/d',
+ 0x0F => 'd-mmm-yy',
+ 0x10 => 'd-mmm',
+ 0x11 => 'mmm-yy',
+ 0x12 => 'h:mm AM/PM',
+ 0x13 => 'h:mm:ss AM/PM',
+ 0x14 => 'h:mm',
+ 0x15 => 'h:mm:ss',
+
+ # 0x16 => 'm/d/yy h:mm',
+ 0x16 => 'yyyy/m/d h:mm',
+
+ #0x17-0x24 -- Differs in Natinal
+ 0x1E => 'm/d/yy',
+ 0x1F => 'yyyy"年"m"月"d"日"',
+ 0x20 => 'h"時"mm"分"',
+ 0x21 => 'h"時"mm"分"ss"秒"',
+
+ #0x17-0x24 -- Differs in Natinal
+ 0x25 => '(#,##0_);(#,##0)',
+ 0x26 => '(#,##0_);[RED](#,##0)',
+ 0x27 => '(#,##0.00);(#,##0.00)',
+ 0x28 => '(#,##0.00);[RED](#,##0.00)',
+ 0x29 => '_(*#,##0_);_(*(#,##0);_(*"-"_);_(@_)',
+ 0x2A => '_(\\*#,##0_);_(\\*(#,##0);_(*"-"_);_(@_)',
+ 0x2B => '_(*#,##0.00_);_(*(#,##0.00);_(*"-"??_);_(@_)',
+ 0x2C => '_(\\*#,##0.00_);_(\\*(#,##0.00);_(*"-"??_);_(@_)',
+ 0x2D => 'mm:ss',
+ 0x2E => '[h]:mm:ss',
+ 0x2F => 'mm:ss.0',
+ 0x30 => '##0.0E+0',
+ 0x31 => '@',
+
+ 0x37 => 'yyyy"年"m"月"',
+ 0x38 => 'm"月"d"日"',
+ 0x39 => 'ge.m.d',
+ 0x3A => 'ggge"年"m"月"d"日"',
+);
+
+#------------------------------------------------------------------------------
+# new (for Spreadsheet::ParseExcel::FmtJapan)
+#------------------------------------------------------------------------------
+sub new {
+ my ( $class, %args ) = @_;
+ my $encoding = $args{Code} || $args{encoding};
+ my $self = { Code => $encoding };
+ if($encoding){
+ $self->{encoding} = find_encoding($encoding eq 'sjis' ? 'cp932' : $encoding)
+ or do{
+ require Carp;
+ Carp::croak(qq{Unknown encoding '$encoding'});
+ };
+ }
+ return bless $self, $class;
+}
+
+#------------------------------------------------------------------------------
+# TextFmt (for Spreadsheet::ParseExcel::FmtJapan)
+#------------------------------------------------------------------------------
+sub TextFmt {
+ my ( $self, $text, $input_encoding ) = @_;
+ if(!defined $input_encoding){
+ $input_encoding = 'utf8';
+ }
+ elsif($input_encoding eq '_native_'){
+ $input_encoding = 'cp932'; # Shift_JIS in Microsoft products
+ }
+ $text = decode($input_encoding, $text);
+ return $self->{Code} ? $self->{encoding}->encode($text) : $text;
+}
+#------------------------------------------------------------------------------
+# FmtStringDef (for Spreadsheet::ParseExcel::FmtJapan)
+#------------------------------------------------------------------------------
+sub FmtStringDef {
+ my ( $self, $format_index, $book ) = @_;
+ return $self->SUPER::FmtStringDef( $format_index, $book, \%FormatTable );
+}
+
+#------------------------------------------------------------------------------
+# CnvNengo (for Spreadsheet::ParseExcel::FmtJapan)
+#------------------------------------------------------------------------------
+
+# Convert A.D. into Japanese Nengo (aka Gengo)
+
+my @Nengo = (
+ {
+ name => '平成', # Heisei
+ abbr_name => 'H',
+
+ base => 1988,
+ start => 19890108,
+ },
+ {
+ name => '昭和', # Showa
+ abbr_name => 'S',
+
+ base => 1925,
+ start => 19261225,
+ },
+ {
+ name => '大正', # Taisho
+ abbr_name => 'T',
+
+ base => 1911,
+ start => 19120730,
+ },
+ {
+ name => '明治', # Meiji
+ abbr_name => 'M',
+
+ base => 1867,
+ start => 18680908,
+ },
+);
+
+# Usage: CnvNengo(name => @tm) or CnvNeng(abbr_name => @tm)
+sub CnvNengo {
+ my ( $kind, @tm ) = @_;
+ my $year = $tm[5] + 1900;
+ my $wk = ($year * 10000) + ($tm[4] * 100) + ($tm[3] * 1);
+ #my $wk = sprintf( '%04d%02d%02d', $year, $tm[4], $tm[3] );
+ foreach my $nengo(@Nengo){
+ if( $wk >= $nengo->{start} ){
+ return $nengo->{$kind} . ($year - $nengo->{base});
+ }
+ }
+ return $year;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::FmtJapan - A class for Cell formats.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/FmtJapan2.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtJapan2.pm
new file mode 100644
index 0000000..318cb01
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtJapan2.pm
@@ -0,0 +1,103 @@
+package Spreadsheet::ParseExcel::FmtJapan2;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::FmtJapan2 - A class for Cell formats.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+use Jcode;
+use Unicode::Map;
+use base 'Spreadsheet::ParseExcel::FmtJapan';
+our $VERSION = '0.59';
+
+#------------------------------------------------------------------------------
+# new (for Spreadsheet::ParseExcel::FmtJapan2)
+#------------------------------------------------------------------------------
+sub new {
+ my ( $sPkg, %hKey ) = @_;
+ my $oMap = Unicode::Map->new('CP932Excel');
+ die "NO MAP FILE CP932Excel!!"
+ unless ( -r Unicode::Map->mapping("CP932Excel") );
+
+ my $oThis = {
+ Code => $hKey{Code},
+ _UniMap => $oMap,
+ };
+ bless $oThis;
+ $oThis->SUPER::new(%hKey);
+ return $oThis;
+}
+
+#------------------------------------------------------------------------------
+# TextFmt (for Spreadsheet::ParseExcel::FmtJapan2)
+#------------------------------------------------------------------------------
+sub TextFmt {
+ my ( $oThis, $sTxt, $sCode ) = @_;
+
+ # $sCode = 'sjis' if((! defined($sCode)) || ($sCode eq '_native_'));
+ if ( $oThis->{Code} ) {
+ if ( !defined($sCode) ) {
+ $sTxt =~ s/(.)/\x00$1/sg;
+ $sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
+ }
+ elsif ( $sCode eq 'ucs2' ) {
+ $sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
+ }
+ return Jcode::convert( $sTxt, $oThis->{Code}, 'sjis' );
+ }
+ else {
+ return $sTxt;
+ }
+}
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::FmtJapan2 - A class for Cell formats.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/FmtUnicode.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtUnicode.pm
new file mode 100644
index 0000000..f0368bc
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/FmtUnicode.pm
@@ -0,0 +1,104 @@
+package Spreadsheet::ParseExcel::FmtUnicode;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::FmtUnicode - A class for Cell formats.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+use Unicode::Map;
+use base 'Spreadsheet::ParseExcel::FmtDefault';
+
+our $VERSION = '0.59';
+
+#------------------------------------------------------------------------------
+# new (for Spreadsheet::ParseExcel::FmtUnicode)
+#------------------------------------------------------------------------------
+sub new {
+ my ( $sPkg, %hKey ) = @_;
+ my $sMap = $hKey{Unicode_Map};
+ my $oMap;
+ $oMap = Unicode::Map->new($sMap) if $sMap;
+ my $oThis = {
+ Unicode_Map => $sMap,
+ _UniMap => $oMap,
+ };
+ bless $oThis;
+ return $oThis;
+}
+
+#------------------------------------------------------------------------------
+# TextFmt (for Spreadsheet::ParseExcel::FmtUnicode)
+#------------------------------------------------------------------------------
+sub TextFmt {
+ my ( $oThis, $sTxt, $sCode ) = @_;
+ if ( $oThis->{_UniMap} ) {
+ if ( !defined($sCode) ) {
+ my $sSv = $sTxt;
+ $sTxt =~ s/(.)/\x00$1/sg;
+ $sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
+ $sTxt = $sSv unless ($sTxt);
+ }
+ elsif ( $sCode eq 'ucs2' ) {
+ $sTxt = $oThis->{_UniMap}->from_unicode($sTxt);
+ }
+
+ # $sTxt = $oThis->{_UniMap}->from_unicode($sTxt)
+ # if(defined($sCode) && $sCode eq 'ucs2');
+ return $sTxt;
+ }
+ else {
+ return $sTxt;
+ }
+}
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::FmtUnicode - A class for Cell formats.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Font.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Font.pm
new file mode 100644
index 0000000..eb3b1fd
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Font.pm
@@ -0,0 +1,69 @@
+package Spreadsheet::ParseExcel::Font;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Font - A class for Cell fonts.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+our $VERSION = '0.59';
+
+sub new {
+ my ( $class, %rhIni ) = @_;
+ my $self = \%rhIni;
+
+ bless $self, $class;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Font - A class for Cell fonts.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
+
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Format.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Format.pm
new file mode 100644
index 0000000..18b762f
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Format.pm
@@ -0,0 +1,68 @@
+package Spreadsheet::ParseExcel::Format;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Format - A class for Cell formats.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+our $VERSION = '0.59';
+
+sub new {
+ my ( $class, %rhIni ) = @_;
+ my $self = \%rhIni;
+
+ bless $self, $class;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Format - A class for Cell formats.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser.pm
new file mode 100644
index 0000000..3d2cf9c
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser.pm
@@ -0,0 +1,310 @@
+package Spreadsheet::ParseExcel::SaveParser;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::SaveParser - Rewrite an existing Excel file.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+use Spreadsheet::ParseExcel;
+use Spreadsheet::ParseExcel::SaveParser::Workbook;
+use Spreadsheet::ParseExcel::SaveParser::Worksheet;
+use Spreadsheet::WriteExcel;
+use base 'Spreadsheet::ParseExcel';
+
+our $VERSION = '0.59';
+
+###############################################################################
+#
+# new()
+#
+sub new {
+
+ my ( $package, %params ) = @_;
+ $package->SUPER::new(%params);
+}
+
+###############################################################################
+#
+# Create()
+#
+sub Create {
+
+ my ( $self, $formatter ) = @_;
+
+ #0. New $workbook
+ my $workbook = Spreadsheet::ParseExcel::Workbook->new();
+ $workbook->{SheetCount} = 0;
+
+ # User specified formater class.
+ if ($formatter) {
+ $workbook->{FmtClass} = $formatter;
+ }
+ else {
+ $workbook->{FmtClass} = Spreadsheet::ParseExcel::FmtDefault->new();
+ }
+
+ return Spreadsheet::ParseExcel::SaveParser::Workbook->new($workbook);
+}
+
+###############################################################################
+#
+# Parse()
+#
+sub Parse {
+
+ my ( $self, $sFile, $formatter ) = @_;
+
+ my $workbook = $self->SUPER::Parse( $sFile, $formatter );
+
+ return undef unless defined $workbook;
+ return Spreadsheet::ParseExcel::SaveParser::Workbook->new($workbook);
+}
+
+###############################################################################
+#
+# SaveAs()
+#
+sub SaveAs {
+
+ my ( $self, $workbook, $filename ) = @_;
+
+ $workbook->SaveAs($filename);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::SaveParser - Rewrite an existing Excel file.
+
+=head1 SYNOPSIS
+
+
+
+Say we start with an Excel file that looks like this:
+
+ -----------------------------------------------------
+ | | A | B | C |
+ -----------------------------------------------------
+ | 1 | Hello | ... | ... | ...
+ | 2 | World | ... | ... | ...
+ | 3 | *Bold text* | ... | ... | ...
+ | 4 | ... | ... | ... | ...
+ | 5 | ... | ... | ... | ...
+
+
+Then we process it with the following program:
+
+ #!/usr/bin/perl
+
+ use strict;
+ use warnings;
+
+ use Spreadsheet::ParseExcel;
+ use Spreadsheet::ParseExcel::SaveParser;
+
+
+ # Open an existing file with SaveParser
+ my $parser = Spreadsheet::ParseExcel::SaveParser->new();
+ my $template = $parser->Parse('template.xls');
+
+
+ # Get the first worksheet.
+ my $worksheet = $template->worksheet(0);
+ my $row = 0;
+ my $col = 0;
+
+
+ # Overwrite the string in cell A1
+ $worksheet->AddCell( $row, $col, 'New string' );
+
+
+ # Add a new string in cell B1
+ $worksheet->AddCell( $row, $col + 1, 'Newer' );
+
+
+ # Add a new string in cell C1 with the format from cell A3.
+ my $cell = $worksheet->get_cell( $row + 2, $col );
+ my $format_number = $cell->{FormatNo};
+
+ $worksheet->AddCell( $row, $col + 2, 'Newest', $format_number );
+
+
+ # Write over the existing file or write a new file.
+ $template->SaveAs('newfile.xls');
+
+
+We should now have an Excel file that looks like this:
+
+ -----------------------------------------------------
+ | | A | B | C |
+ -----------------------------------------------------
+ | 1 | New string | Newer | *Newest* | ...
+ | 2 | World | ... | ... | ...
+ | 3 | *Bold text* | ... | ... | ...
+ | 4 | ... | ... | ... | ...
+ | 5 | ... | ... | ... | ...
+
+
+
+=head1 DESCRIPTION
+
+The C<Spreadsheet::ParseExcel::SaveParser> module rewrite an existing Excel file by reading it with C<Spreadsheet::ParseExcel> and rewriting it with C<Spreadsheet::WriteExcel>.
+
+=head1 METHODS
+
+=head1 Parser
+
+=head2 new()
+
+ $parse = new Spreadsheet::ParseExcel::SaveParser();
+
+Constructor.
+
+=head2 Parse()
+
+ $workbook = $parse->Parse($sFileName);
+
+ $workbook = $parse->Parse($sFileName , $formatter);
+
+Returns a L</Workbook> object. If an error occurs, returns undef.
+
+The optional C<$formatter> is a Formatter Class to format the value of cells.
+
+
+=head1 Workbook
+
+The C<Parse()> method returns a C<Spreadsheet::ParseExcel::SaveParser::Workbook> object.
+
+This is a subclass of the L<Spreadsheet::ParseExcel::Workbook> and has the following methods:
+
+=head2 worksheets()
+
+Returns an array of L</Worksheet> objects. This was most commonly used to iterate over the worksheets in a workbook:
+
+ for my $worksheet ( $workbook->worksheets() ) {
+ ...
+ }
+
+=head2 worksheet()
+
+The C<worksheet()> method returns a single C<Worksheet> object using either its name or index:
+
+ $worksheet = $workbook->worksheet('Sheet1');
+ $worksheet = $workbook->worksheet(0);
+
+Returns C<undef> if the sheet name or index doesn't exist.
+
+
+=head2 AddWorksheet()
+
+ $workbook = $workbook->AddWorksheet($name, %properties);
+
+Create a new Worksheet object of type C<Spreadsheet::ParseExcel::Worksheet>.
+
+The C<%properties> hash contains the properties of new Worksheet.
+
+
+=head2 AddFont
+
+ $workbook = $workbook->AddFont(%properties);
+
+Create new Font object of type C<Spreadsheet::ParseExcel::Font>.
+
+The C<%properties> hash contains the properties of new Font.
+
+
+=head2 AddFormat
+
+ $workbook = $workbook->AddFormat(%properties);
+
+The C<%properties> hash contains the properties of new Font.
+
+
+=head1 Worksheet
+
+Spreadsheet::ParseExcel::SaveParser::Worksheet
+
+Worksheet is a subclass of Spreadsheet::ParseExcel::Worksheet.
+And has these methods :
+
+
+The C<Worksbook::worksheet()> method returns a C<Spreadsheet::ParseExcel::SaveParser::Worksheet> object.
+
+This is a subclass of the L<Spreadsheet::ParseExcel::Worksheet> and has the following methods:
+
+
+=head1 AddCell
+
+ $workbook = $worksheet->AddCell($row, $col, $value, $format [$encoding]);
+
+Create new Cell object of type C<Spreadsheet::ParseExcel::Cell>.
+
+The C<$format> parameter is the format number rather than a full format object.
+
+To specify just same as another cell,
+you can set it like below:
+
+ $row = 0;
+ $col = 0;
+ $worksheet = $template->worksheet(0);
+ $cell = $worksheet->get_cell( $row, $col );
+ $format_number = $cell->{FormatNo};
+
+ $worksheet->AddCell($row +1, $coll, 'New data', $format_number);
+
+
+
+
+=head1 TODO
+
+Please note that this module is currently (versions 0.50-0.60) undergoing a major
+restructuring and rewriting.
+
+=head1 Known Problems
+
+
+You can only rewrite the features that Spreadsheet::WriteExcel supports so
+macros, graphs and some other features in the original Excel file will be lost.
+Also, formulas aren't rewritten, only the result of a formula is written.
+
+Only last print area will remain. (Others will be removed)
+
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2002 Kawai Takanori and Nippon-RAD Co. OP Division
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser/Workbook.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser/Workbook.pm
new file mode 100644
index 0000000..7011563
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser/Workbook.pm
@@ -0,0 +1,436 @@
+package Spreadsheet::ParseExcel::SaveParser::Workbook;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::SaveParser::Workbook - A class for SaveParser Workbooks.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+use base 'Spreadsheet::ParseExcel::Workbook';
+our $VERSION = '0.59';
+
+#==============================================================================
+# Spreadsheet::ParseExcel::SaveParser::Workbook
+#==============================================================================
+
+sub new {
+ my ( $sPkg, $oBook ) = @_;
+ return undef unless ( defined $oBook );
+ my %oThis = %$oBook;
+ bless \%oThis, $sPkg;
+
+ # re-bless worksheets (and set their _Book properties !!!)
+ my $sWkP = ref($sPkg) || "$sPkg";
+ $sWkP =~ s/Workbook$/Worksheet/;
+ map { bless( $_, $sWkP ); } @{ $oThis{Worksheet} };
+ map { $_->{_Book} = \%oThis; } @{ $oThis{Worksheet} };
+ return \%oThis;
+}
+
+#------------------------------------------------------------------------------
+# Parse (for Spreadsheet::ParseExcel::SaveParser::Workbook)
+#------------------------------------------------------------------------------
+sub Parse {
+ my ( $sClass, $sFile, $oWkFmt ) = @_;
+ my $oBook = Spreadsheet::ParseExcel::Workbook->Parse( $sFile, $oWkFmt );
+ bless $oBook, $sClass;
+
+ # re-bless worksheets (and set their _Book properties !!!)
+ my $sWkP = ref($sClass) || "$sClass";
+ $sWkP =~ s/Workbook$/Worksheet/;
+ map { bless( $_, $sWkP ); } @{ $oBook->{Worksheet} };
+ map { $_->{_Book} = $oBook; } @{ $oBook->{Worksheet} };
+ return $oBook;
+}
+
+#------------------------------------------------------------------------------
+# SaveAs (for Spreadsheet::ParseExcel::SaveParser::Workbook)
+#------------------------------------------------------------------------------
+sub SaveAs {
+ my ( $oBook, $sName ) = @_;
+
+ # Create a new Excel workbook
+ my $oWrEx = Spreadsheet::WriteExcel->new($sName);
+ $oWrEx->compatibility_mode();
+ my %hFmt;
+
+ my $iNo = 0;
+ my @aAlH = (
+ 'left', 'left', 'center', 'right',
+ 'fill', 'justify', 'merge', 'equal_space'
+ );
+ my @aAlV = ( 'top', 'vcenter', 'bottom', 'vjustify', 'vequal_space' );
+
+ foreach my $pFmt ( @{ $oBook->{Format} } ) {
+ my $oFmt = $oWrEx->addformat(); # Add Formats
+ unless ( $pFmt->{Style} ) {
+ $hFmt{$iNo} = $oFmt;
+ my $rFont = $pFmt->{Font};
+
+ $oFmt->set_font( $rFont->{Name} );
+ $oFmt->set_size( $rFont->{Height} );
+ $oFmt->set_color( $rFont->{Color} );
+ $oFmt->set_bold( $rFont->{Bold} );
+ $oFmt->set_italic( $rFont->{Italic} );
+ $oFmt->set_underline( $rFont->{Underline} );
+ $oFmt->set_font_strikeout( $rFont->{Strikeout} );
+ $oFmt->set_font_script( $rFont->{Super} );
+
+ $oFmt->set_hidden( $rFont->{Hidden} ); #Add
+
+ $oFmt->set_locked( $pFmt->{Lock} );
+
+ $oFmt->set_align( $aAlH[ $pFmt->{AlignH} ] );
+ $oFmt->set_align( $aAlV[ $pFmt->{AlignV} ] );
+
+ $oFmt->set_rotation( $pFmt->{Rotate} );
+
+ $oFmt->set_num_format(
+ $oBook->{FmtClass}->FmtStringDef( $pFmt->{FmtIdx}, $oBook ) );
+
+ $oFmt->set_text_wrap( $pFmt->{Wrap} );
+
+ $oFmt->set_pattern( $pFmt->{Fill}->[0] );
+ $oFmt->set_fg_color( $pFmt->{Fill}->[1] )
+ if ( ( $pFmt->{Fill}->[1] >= 8 )
+ && ( $pFmt->{Fill}->[1] <= 63 ) );
+ $oFmt->set_bg_color( $pFmt->{Fill}->[2] )
+ if ( ( $pFmt->{Fill}->[2] >= 8 )
+ && ( $pFmt->{Fill}->[2] <= 63 ) );
+
+ $oFmt->set_left(
+ ( $pFmt->{BdrStyle}->[0] > 7 ) ? 3 : $pFmt->{BdrStyle}->[0] );
+ $oFmt->set_right(
+ ( $pFmt->{BdrStyle}->[1] > 7 ) ? 3 : $pFmt->{BdrStyle}->[1] );
+ $oFmt->set_top(
+ ( $pFmt->{BdrStyle}->[2] > 7 ) ? 3 : $pFmt->{BdrStyle}->[2] );
+ $oFmt->set_bottom(
+ ( $pFmt->{BdrStyle}->[3] > 7 ) ? 3 : $pFmt->{BdrStyle}->[3] );
+
+ $oFmt->set_left_color( $pFmt->{BdrColor}->[0] )
+ if ( ( $pFmt->{BdrColor}->[0] >= 8 )
+ && ( $pFmt->{BdrColor}->[0] <= 63 ) );
+ $oFmt->set_right_color( $pFmt->{BdrColor}->[1] )
+ if ( ( $pFmt->{BdrColor}->[1] >= 8 )
+ && ( $pFmt->{BdrColor}->[1] <= 63 ) );
+ $oFmt->set_top_color( $pFmt->{BdrColor}->[2] )
+ if ( ( $pFmt->{BdrColor}->[2] >= 8 )
+ && ( $pFmt->{BdrColor}->[2] <= 63 ) );
+ $oFmt->set_bottom_color( $pFmt->{BdrColor}->[3] )
+ if ( ( $pFmt->{BdrColor}->[3] >= 8 )
+ && ( $pFmt->{BdrColor}->[3] <= 63 ) );
+ }
+ $iNo++;
+ }
+ for ( my $iSheet = 0 ; $iSheet < $oBook->{SheetCount} ; $iSheet++ ) {
+ my $oWkS = $oBook->{Worksheet}[$iSheet];
+ my $oWrS = $oWrEx->addworksheet( $oWkS->{Name} );
+
+ #Landscape
+ if ( !$oWkS->{Landscape} ) { # Landscape (0:Horizontal, 1:Vertical)
+ $oWrS->set_landscape();
+ }
+ else {
+ $oWrS->set_portrait();
+ }
+
+ #Protect
+ if ( defined $oWkS->{Protect} )
+ { # Protect ('':NoPassword, Password:Password)
+ if ( $oWkS->{Protect} ne '' ) {
+ $oWrS->protect( $oWkS->{Protect} );
+ }
+ else {
+ $oWrS->protect();
+ }
+ }
+ if ( ( $oWkS->{FitWidth} == 1 ) and ( $oWkS->{FitHeight} == 1 ) ) {
+
+ # Pages on fit with width and Heigt
+ $oWrS->fit_to_pages( $oWkS->{FitWidth}, $oWkS->{FitHeight} );
+
+ #Print Scale
+ $oWrS->set_print_scale( $oWkS->{Scale} );
+ }
+ else {
+
+ #Print Scale
+ $oWrS->set_print_scale( $oWkS->{Scale} );
+
+ # Pages on fit with width and Heigt
+ $oWrS->fit_to_pages( $oWkS->{FitWidth}, $oWkS->{FitHeight} );
+ }
+
+ # Paper Size
+ $oWrS->set_paper( $oWkS->{PaperSize} );
+
+ # Margin
+ $oWrS->set_margin_left( $oWkS->{LeftMargin} );
+ $oWrS->set_margin_right( $oWkS->{RightMargin} );
+ $oWrS->set_margin_top( $oWkS->{TopMargin} );
+ $oWrS->set_margin_bottom( $oWkS->{BottomMargin} );
+
+ # HCenter
+ $oWrS->center_horizontally() if ( $oWkS->{HCenter} );
+
+ # VCenter
+ $oWrS->center_vertically() if ( $oWkS->{VCenter} );
+
+ # Header, Footer
+ $oWrS->set_header( $oWkS->{Header}, $oWkS->{HeaderMargin} );
+ $oWrS->set_footer( $oWkS->{Footer}, $oWkS->{FooterMargin} );
+
+ # Print Area
+ if ( ref( $oBook->{PrintArea}[$iSheet] ) eq 'ARRAY' ) {
+ my $raP;
+ for $raP ( @{ $oBook->{PrintArea}[$iSheet] } ) {
+ $oWrS->print_area(@$raP);
+ }
+ }
+
+ # Print Title
+ my $raW;
+ foreach $raW ( @{ $oBook->{PrintTitle}[$iSheet]->{Row} } ) {
+ $oWrS->repeat_rows(@$raW);
+ }
+ foreach $raW ( @{ $oBook->{PrintTitle}[$iSheet]->{Column} } ) {
+ $oWrS->repeat_columns(@$raW);
+ }
+
+ # Print Gridlines
+ if ( $oWkS->{PrintGrid} == 1 ) {
+ $oWrS->hide_gridlines(0);
+ }
+ else {
+ $oWrS->hide_gridlines(1);
+ }
+
+ # Print Headings
+ if ( $oWkS->{PrintHeaders} ) {
+ $oWrS->print_row_col_headers();
+ }
+
+ # Horizontal Page Breaks
+ $oWrS->set_h_pagebreaks( @{ $oWkS->{HPageBreak} } );
+
+ # Veritical Page Breaks
+ $oWrS->set_v_pagebreaks( @{ $oWkS->{VPageBreak} } );
+
+
+
+# PageStart => $oWkS->{PageStart}, # Page number for start
+# UsePage => $oWkS->{UsePage}, # Use own start page number
+# NoColor => $oWkS->{NoColor}, # Print in blcak-white
+# Draft => $oWkS->{Draft}, # Print in draft mode
+# Notes => $oWkS->{Notes}, # Print notes
+# LeftToRight => $oWkS->{LeftToRight}, # Left to Right
+
+
+ for (
+ my $iC = $oWkS->{MinCol} ;
+ defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ;
+ $iC++
+ )
+ {
+ if ( defined $oWkS->{ColWidth}[$iC] ) {
+ if ( $oWkS->{ColWidth}[$iC] > 0 ) {
+ $oWrS->set_column( $iC, $iC, $oWkS->{ColWidth}[$iC] )
+ ; #, undef, 1) ;
+ }
+ else {
+ $oWrS->set_column( $iC, $iC, 0, undef, 1 );
+ }
+ }
+ }
+ for (
+ my $iR = $oWkS->{MinRow} ;
+ defined $oWkS->{MaxRow} && $iR <= $oWkS->{MaxRow} ;
+ $iR++
+ )
+ {
+ $oWrS->set_row( $iR, $oWkS->{RowHeight}[$iR] );
+ for (
+ my $iC = $oWkS->{MinCol} ;
+ defined $oWkS->{MaxCol} && $iC <= $oWkS->{MaxCol} ;
+ $iC++
+ )
+ {
+
+ my $oWkC = $oWkS->{Cells}[$iR][$iC];
+ if ($oWkC) {
+ if ( $oWkC->{Merged} ) {
+ my $oFmtN = $oWrEx->addformat();
+ $oFmtN->copy( $hFmt{ $oWkC->{FormatNo} } );
+ $oFmtN->set_merge(1);
+ $oWrS->write(
+ $iR,
+ $iC,
+ $oBook->{FmtClass}
+ ->TextFmt( $oWkC->{Val}, $oWkC->{Code} ),
+ $oFmtN
+ );
+ }
+ else {
+ $oWrS->write(
+ $iR,
+ $iC,
+ $oBook->{FmtClass}
+ ->TextFmt( $oWkC->{Val}, $oWkC->{Code} ),
+ $hFmt{ $oWkC->{FormatNo} }
+ );
+ }
+ }
+ }
+ }
+ }
+ return $oWrEx;
+}
+
+#------------------------------------------------------------------------------
+# AddWorksheet (for Spreadsheet::ParseExcel::SaveParser::Workbook)
+#------------------------------------------------------------------------------
+sub AddWorksheet {
+ my ( $oBook, $sName, %hAttr ) = @_;
+ $oBook->AddFormat if ( $#{ $oBook->{Format} } < 0 );
+ $hAttr{Name} ||= $sName;
+ $hAttr{LeftMargin} ||= 0;
+ $hAttr{RightMargin} ||= 0;
+ $hAttr{TopMargin} ||= 0;
+ $hAttr{BottomMargin} ||= 0;
+ $hAttr{HeaderMargin} ||= 0;
+ $hAttr{FooterMargin} ||= 0;
+ $hAttr{FitWidth} ||= 0;
+ $hAttr{FitHeight} ||= 0;
+ $hAttr{PrintGrid} ||= 0;
+ my $oWkS = Spreadsheet::ParseExcel::SaveParser::Worksheet->new(%hAttr);
+ $oWkS->{_Book} = $oBook;
+ $oWkS->{_SheetNo} = $oBook->{SheetCount};
+ $oBook->{Worksheet}[ $oBook->{SheetCount} ] = $oWkS;
+ $oBook->{SheetCount}++;
+ return $oWkS; #$oBook->{SheetCount} - 1;
+}
+
+#------------------------------------------------------------------------------
+# AddFont (for Spreadsheet::ParseExcel::SaveParser::Workbook)
+#------------------------------------------------------------------------------
+sub AddFont {
+ my ( $oBook, %hAttr ) = @_;
+ $hAttr{Name} ||= 'Arial';
+ $hAttr{Height} ||= 10;
+ $hAttr{Bold} ||= 0;
+ $hAttr{Italic} ||= 0;
+ $hAttr{Underline} ||= 0;
+ $hAttr{Strikeout} ||= 0;
+ $hAttr{Super} ||= 0;
+ push @{ $oBook->{Font} }, Spreadsheet::ParseExcel::Font->new(%hAttr);
+ return $#{ $oBook->{Font} };
+}
+
+#------------------------------------------------------------------------------
+# AddFormat (for Spreadsheet::ParseExcel::SaveParser::Workbook)
+#------------------------------------------------------------------------------
+sub AddFormat {
+ my ( $oBook, %hAttr ) = @_;
+ $hAttr{Fill} ||= [ 0, 0, 0 ];
+ $hAttr{BdrStyle} ||= [ 0, 0, 0, 0 ];
+ $hAttr{BdrColor} ||= [ 0, 0, 0, 0 ];
+ $hAttr{AlignH} ||= 0;
+ $hAttr{AlignV} ||= 0;
+ $hAttr{Rotate} ||= 0;
+ $hAttr{Landscape} ||= 0;
+ $hAttr{FmtIdx} ||= 0;
+
+ if ( !defined( $hAttr{Font} ) ) {
+ my $oFont;
+ if ( defined $hAttr{FontNo} ) {
+ $oFont = $oBook->{Font}[ $hAttr{FontNo} ];
+ }
+ elsif ( !defined $oFont ) {
+ if ( $#{ $oBook->{Font} } >= 0 ) {
+ $oFont = $oBook->{Font}[0];
+ }
+ else {
+ my $iNo = $oBook->AddFont;
+ $oFont = $oBook->{Font}[$iNo];
+ }
+ }
+ $hAttr{Font} = $oFont;
+ }
+ push @{ $oBook->{Format} }, Spreadsheet::ParseExcel::Format->new(%hAttr);
+ return $#{ $oBook->{Format} };
+}
+
+#------------------------------------------------------------------------------
+# AddCell (for Spreadsheet::ParseExcel::SaveParser::Workbook)
+#------------------------------------------------------------------------------
+sub AddCell {
+ my ( $oBook, $iSheet, $iR, $iC, $sVal, $oCell, $sCode ) = @_;
+ my %rhKey;
+ $oCell ||= 0;
+ my $iFmt =
+ ( UNIVERSAL::isa( $oCell, 'Spreadsheet::ParseExcel::Cell' ) )
+ ? $oCell->{FormatNo}
+ : ( ref($oCell) ) ? 0
+ : $oCell + 0;
+ $rhKey{FormatNo} = $iFmt;
+ $rhKey{Format} = $oBook->{Format}[$iFmt];
+ $rhKey{Val} = $sVal;
+ $rhKey{Code} = $sCode || '_native_';
+ $oBook->{_CurSheet} = $iSheet;
+ my $oNewCell =
+ Spreadsheet::ParseExcel::_NewCell( $oBook, $iR, $iC, %rhKey );
+ Spreadsheet::ParseExcel::_SetDimension( $oBook, $iR, $iC, $iC );
+ return $oNewCell;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::SaveParser::Workbook - A class for SaveParser Workbooks.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm
new file mode 100644
index 0000000..12e8fa4
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/SaveParser/Worksheet.pm
@@ -0,0 +1,91 @@
+package Spreadsheet::ParseExcel::SaveParser::Worksheet;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::SaveParser::Worksheet - A class for SaveParser Worksheets.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+#==============================================================================
+# Spreadsheet::ParseExcel::SaveParser::Worksheet
+#==============================================================================
+
+use base 'Spreadsheet::ParseExcel::Worksheet';
+our $VERSION = '0.59';
+
+sub new {
+ my ( $sClass, %rhIni ) = @_;
+ $sClass->SUPER::new(%rhIni); # returns object
+}
+
+#------------------------------------------------------------------------------
+# AddCell (for Spreadsheet::ParseExcel::SaveParser::Worksheet)
+#------------------------------------------------------------------------------
+sub AddCell {
+ my ( $oSelf, $iR, $iC, $sVal, $oCell, $sCode ) = @_;
+ $oSelf->{_Book}
+ ->AddCell( $oSelf->{_SheetNo}, $iR, $iC, $sVal, $oCell, $sCode );
+}
+
+#------------------------------------------------------------------------------
+# Protect (for Spreadsheet::ParseExcel::SaveParser::Worksheet)
+# - Password = undef -> No protect
+# - Password = '' -> Protected. No password
+# - Password = $pwd -> Protected. Password = $pwd
+#------------------------------------------------------------------------------
+sub Protect {
+ my ( $oSelf, $sPassword ) = @_;
+ $oSelf->{Protect} = $sPassword;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::SaveParser::Worksheet - A class for SaveParser Worksheets.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Utility.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Utility.pm
new file mode 100644
index 0000000..2eb09e7
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Utility.pm
@@ -0,0 +1,1615 @@
+package Spreadsheet::ParseExcel::Utility;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Utility - Utility functions for ParseExcel.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+require Exporter;
+use vars qw(@ISA @EXPORT_OK);
+@ISA = qw(Exporter);
+@EXPORT_OK = qw(ExcelFmt LocaltimeExcel ExcelLocaltime
+ col2int int2col sheetRef xls2csv);
+
+our $VERSION = '0.59';
+
+my $qrNUMBER = qr/(^[+-]?\d+(\.\d+)?$)|(^[+-]?\d+\.?(\d*)[eE][+-](\d+))$/;
+
+###############################################################################
+#
+# ExcelFmt()
+#
+# This function takes an Excel style number format and converts a number into
+# that format. for example: 'hh:mm:ss AM/PM' + 0.01023148 = '12:14:44 AM'.
+#
+# It does this with a type of templating mechanism. The format string is parsed
+# to identify tokens that need to be replaced and their position within the
+# string is recorded. These can be thought of as placeholders. The number is
+# then converted to the required formats and substituted into the placeholders.
+#
+# Interested parties should refer to the Excel documentation on cell formats for
+# more information: http://office.microsoft.com/en-us/excel/HP051995001033.aspx
+# The Microsoft documentation for the Excel Binary File Format, [MS-XLS].pdf,
+# also contains a ABNF grammar for number format strings.
+#
+# Maintainers notes:
+# ==================
+#
+# Note on format subsections:
+# A format string can contain 4 possible sub-sections separated by semi-colons:
+# Positive numbers, negative numbers, zero values, and text.
+# For example: _(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)
+#
+# Note on conditional formats.
+# A number format in Excel can have a conditional expression such as:
+# [>9999999](000)000-0000;000-0000
+# This is equivalent to the following in Perl:
+# $format = $number > 9999999 ? '(000)000-0000' : '000-0000';
+# Nested conditionals are also possible but we don't support them.
+#
+# Efficiency: The excessive use of substr() isn't very efficient. However,
+# it probably doesn't merit rewriting this function with a parser or regular
+# expressions and \G.
+#
+# TODO: I think the single quote handling may not be required. Check.
+#
+sub ExcelFmt {
+
+ my ( $format_str, $number, $is_1904, $number_type, $want_subformats ) = @_;
+
+ # Return text strings without further formatting.
+ return $number unless $number =~ $qrNUMBER;
+
+ # Handle OpenOffice.org GENERAL format.
+ $format_str = '@' if uc($format_str) eq "GENERAL";
+
+ # Check for a conditional at the start of the format. See notes above.
+ my $conditional;
+ if ( $format_str =~ /^\[([<>=][^\]]+)\](.*)$/ ) {
+ $conditional = $1;
+ $format_str = $2;
+ }
+
+ # Ignore the underscore token which is used to indicate a padding space.
+ $format_str =~ s/_/ /g;
+
+ # Split the format string into 4 possible sub-sections: positive numbers,
+ # negative numbers, zero values, and text. See notes above.
+ my @formats;
+ my $section = 0;
+ my $double_quote = 0;
+ my $single_quote = 0;
+
+ # Initial parsing of the format string to remove escape characters. This
+ # also handles quoted strings. See note about single quotes above.
+ CHARACTER:
+ for my $char ( split //, $format_str ) {
+
+ if ( $double_quote or $single_quote ) {
+ $formats[$section] .= $char;
+ $double_quote = 0 if $char eq '"';
+ $single_quote = 0;
+ next CHARACTER;
+ }
+
+ if ( $char eq ';' ) {
+ $section++;
+ next CHARACTER;
+ }
+ elsif ( $char eq '"' ) {
+ $double_quote = 1;
+ }
+ elsif ( $char eq '!' ) {
+ $single_quote = 1;
+ }
+ elsif ( $char eq '\\' ) {
+ $single_quote = 1;
+ }
+ elsif ( $char eq '(' ) {
+ next CHARACTER; # Ignore.
+ }
+ elsif ( $char eq ')' ) {
+ next CHARACTER; # Ignore.
+ }
+
+ # Convert upper case OpenOffice.org date/time formats to lowercase..
+ $char = lc($char) if $char =~ /[DMYHS]/;
+
+ $formats[$section] .= $char;
+ }
+
+ # Select the appropriate format from the 4 possible sub-sections:
+ # positive numbers, negative numbers, zero values, and text.
+ # We ignore the Text section since non-numeric values are returned
+ # unformatted at the start of the function.
+ my $format;
+ $section = 0;
+
+ if ( @formats == 1 ) {
+ $section = 0;
+ }
+ elsif ( @formats == 2 ) {
+ if ( $number < 0 ) {
+ $section = 1;
+ }
+ else {
+ $section = 0;
+ }
+ }
+ elsif ( @formats == 3 ) {
+ if ( $number == 0 ) {
+ $section = 2;
+ }
+ elsif ( $number < 0 ) {
+ $section = 1;
+ }
+ else {
+ $section = 0;
+ }
+ }
+ else {
+ $section = 0;
+ }
+
+ # Override the previous choice if the format is conditional.
+ if ($conditional) {
+
+ # TODO. Replace string eval with a function.
+ $section = eval "$number $conditional" ? 0 : 1;
+ }
+
+ # We now have the required format.
+ $format = $formats[$section];
+
+ # The format string can contain one of the following colours:
+ # [Black] [Blue] [Cyan] [Green] [Magenta] [Red] [White] [Yellow]
+ # or the string [ColorX] where x is a colour index from 1 to 56.
+ # We don't use the colour but we return it to the caller.
+ #
+ my $color = '';
+ if ( $format =~ s/^(\[[A-Z][a-z]{2,}(\d{1,2})?\])// ) {
+ $color = $1;
+ }
+
+ # Remove the locale, such as [$-409], from the format string.
+ my $locale = '';
+ if ( $format =~ s/^(\[\$?-\d+\])// ) {
+ $locale = $1;
+ }
+
+ # Replace currency locale, such as [$$-409], with $ in the format string.
+ # See the RT#60547 test cases in 21_number_format_user.t.
+ if ( $format =~ s/(\[\$([^-]+)(-\d+)?\])/$2/s ) {
+ $locale = $1;
+ }
+
+
+ # Remove leading # from '# ?/?', '# ??/??' fraction formats.
+ $format =~ s{# \?}{?}g;
+
+ # Parse the format string and create an AoA of placeholders that contain
+ # the parts of the string to be replaced. The format of the information
+ # stored is: [ $token, $start_pos, $end_pos, $option_info ].
+ #
+ my $format_mode = ''; # Either: '', 'number', 'date'
+ my $pos = 0; # Character position within format string.
+ my @placeholders = (); # Arefs with parts of the format to be replaced.
+ my $token = ''; # The actual format extracted from the total str.
+ my $start_pos; # A position variable. Initial parser position.
+ my $token_start = -1; # A position variable.
+ my $decimal_pos = -1; # Position of the punctuation char "." or ",".
+ my $comma_count = 0; # Count of the commas in the format.
+ my $is_fraction = 0; # Number format is a fraction.
+ my $is_currency = 0; # Number format is a currency.
+ my $is_percent = 0; # Number format is a percentage.
+ my $is_12_hour = 0; # Time format is using 12 hour clock.
+ my $seen_dot = 0; # Treat only the first "." as the decimal point.
+
+ # Parse the format.
+ PARSER:
+ while ( $pos < length $format ) {
+ $start_pos = $pos;
+ my $char = substr( $format, $pos, 1 );
+
+ # Ignore control format characters such as '#0+-.?eE,%'. However,
+ # only ignore '.' if it is the first one encountered. RT 45502.
+ if ( ( !$seen_dot && $char !~ /[#0\+\-\.\?eE\,\%]/ )
+ || $char !~ /[#0\+\-\?eE\,\%]/ )
+ {
+
+ if ( $token_start != -1 ) {
+ push @placeholders,
+ [
+ substr( $format, $token_start, $pos - $token_start ),
+ $decimal_pos, $pos - $token_start
+ ];
+ $token_start = -1;
+ }
+ }
+
+ # Processing for quoted strings within the format. See notes above.
+ if ( $char eq '"' ) {
+ $double_quote = $double_quote ? 0 : 1;
+ $pos++;
+ next PARSER;
+ }
+ elsif ( $char eq '!' ) {
+ $single_quote = 1;
+ $pos++;
+ next PARSER;
+ }
+ elsif ( $char eq '\\' ) {
+ if ( $single_quote != 1 ) {
+ $single_quote = 1;
+ $pos++;
+ next PARSER;
+ }
+ }
+
+ if ( ( defined($double_quote) and ($double_quote) )
+ or ( defined($single_quote) and ($single_quote) )
+ or ( $seen_dot && $char eq '.' ) )
+ {
+ $single_quote = 0;
+ if (
+ ( $format_mode ne 'date' )
+ and ( ( substr( $format, $pos, 2 ) eq "\x81\xA2" )
+ || ( substr( $format, $pos, 2 ) eq "\x81\xA3" )
+ || ( substr( $format, $pos, 2 ) eq "\xA2\xA4" )
+ || ( substr( $format, $pos, 2 ) eq "\xA2\xA5" ) )
+ )
+ {
+
+ # The above matches are currency symbols.
+ push @placeholders,
+ [ substr( $format, $pos, 2 ), length($token), 2 ];
+ $is_currency = 1;
+ $pos += 2;
+ }
+ else {
+ $pos++;
+ }
+ }
+ elsif (
+ ( $char =~ /[#0\+\.\?eE\,\%]/ )
+ || ( ( $format_mode ne 'date' )
+ and ( ( $char eq '-' ) || ( $char eq '(' ) || ( $char eq ')' ) )
+ )
+ )
+ {
+ $format_mode = 'number' unless $format_mode;
+ if ( substr( $format, $pos, 1 ) =~ /[#0]/ ) {
+ if (
+ substr( $format, $pos ) =~
+ /^([#0]+[\.]?[0#]*[eE][\+\-][0#]+)/ )
+ {
+ push @placeholders, [ $1, $pos, length($1) ];
+ $pos += length($1);
+ }
+ else {
+ if ( $token_start == -1 ) {
+ $token_start = $pos;
+ $decimal_pos = length($token);
+ }
+ }
+ }
+ elsif ( substr( $format, $pos, 1 ) eq '?' ) {
+
+ # Look for a fraction format like ?/? or ??/??
+ if ( $token_start != -1 ) {
+ push @placeholders,
+ [
+ substr(
+ $format, $token_start, $pos - $token_start + 1
+ ),
+ $decimal_pos,
+ $pos - $token_start + 1
+ ];
+ }
+ $token_start = $pos;
+
+ # Find the end of the fraction format.
+ FRACTION:
+ while ( $pos < length($format) ) {
+ if ( substr( $format, $pos, 1 ) eq '/' ) {
+ $is_fraction = 1;
+ }
+ elsif ( substr( $format, $pos, 1 ) eq '?' ) {
+ $pos++;
+ next FRACTION;
+ }
+ else {
+ if ( $is_fraction
+ && ( substr( $format, $pos, 1 ) =~ /[0-9]/ ) )
+ {
+
+ # TODO: Could invert if() logic and remove this.
+ $pos++;
+ next FRACTION;
+ }
+ else {
+ last FRACTION;
+ }
+ }
+ $pos++;
+ }
+ $pos--;
+
+ push @placeholders,
+ [
+ substr( $format, $token_start, $pos - $token_start + 1 ),
+ length($token), $pos - $token_start + 1
+ ];
+ $token_start = -1;
+ }
+ elsif ( substr( $format, $pos, 3 ) =~ /^[eE][\+\-][0#]$/ ) {
+ if ( substr( $format, $pos ) =~ /([eE][\+\-][0#]+)/ ) {
+ push @placeholders, [ $1, $pos, length($1) ];
+ $pos += length($1);
+ }
+ $token_start = -1;
+ }
+ else {
+ if ( $token_start != -1 ) {
+ push @placeholders,
+ [
+ substr( $format, $token_start, $pos - $token_start ),
+ $decimal_pos, $pos - $token_start
+ ];
+ $token_start = -1;
+ }
+ if ( substr( $format, $pos, 1 ) =~ /[\+\-]/ ) {
+ push @placeholders,
+ [ substr( $format, $pos, 1 ), length($token), 1 ];
+ $is_currency = 1;
+ }
+ elsif ( substr( $format, $pos, 1 ) eq '.' ) {
+ push @placeholders,
+ [ substr( $format, $pos, 1 ), length($token), 1 ];
+ $seen_dot = 1;
+ }
+ elsif ( substr( $format, $pos, 1 ) eq ',' ) {
+ $comma_count++;
+ push @placeholders,
+ [ substr( $format, $pos, 1 ), length($token), 1 ];
+ }
+ elsif ( substr( $format, $pos, 1 ) eq '%' ) {
+ $is_percent = 1;
+ }
+ elsif (( substr( $format, $pos, 1 ) eq '(' )
+ || ( substr( $format, $pos, 1 ) eq ')' ) )
+ {
+ push @placeholders,
+ [ substr( $format, $pos, 1 ), length($token), 1 ];
+ $is_currency = 1;
+ }
+ }
+ $pos++;
+ }
+ elsif ( $char =~ /[ymdhsapg]/i ) {
+ $format_mode = 'date' unless $format_mode;
+ if ( substr( $format, $pos, 5 ) =~ /am\/pm/i ) {
+ push @placeholders, [ 'am/pm', length($token), 5 ];
+ $is_12_hour = 1;
+ $pos += 5;
+ }
+ elsif ( substr( $format, $pos, 3 ) =~ /a\/p/i ) {
+ push @placeholders, [ 'a/p', length($token), 3 ];
+ $is_12_hour = 1;
+ $pos += 3;
+ }
+ elsif ( substr( $format, $pos, 5 ) eq 'mmmmm' ) {
+ push @placeholders, [ 'mmmmm', length($token), 5 ];
+ $pos += 5;
+ }
+ elsif (( substr( $format, $pos, 4 ) eq 'mmmm' )
+ || ( substr( $format, $pos, 4 ) eq 'dddd' )
+ || ( substr( $format, $pos, 4 ) eq 'yyyy' )
+ || ( substr( $format, $pos, 4 ) eq 'ggge' ) )
+ {
+ push @placeholders,
+ [ substr( $format, $pos, 4 ), length($token), 4 ];
+ $pos += 4;
+ }
+ elsif (( substr( $format, $pos, 3 ) eq 'ddd' )
+ || ( substr( $format, $pos, 3 ) eq 'mmm' )
+ || ( substr( $format, $pos, 3 ) eq 'yyy' ) )
+ {
+ push @placeholders,
+ [ substr( $format, $pos, 3 ), length($token), 3 ];
+ $pos += 3;
+ }
+ elsif (( substr( $format, $pos, 2 ) eq 'yy' )
+ || ( substr( $format, $pos, 2 ) eq 'mm' )
+ || ( substr( $format, $pos, 2 ) eq 'dd' )
+ || ( substr( $format, $pos, 2 ) eq 'hh' )
+ || ( substr( $format, $pos, 2 ) eq 'ss' )
+ || ( substr( $format, $pos, 2 ) eq 'ge' ) )
+ {
+ if (
+ ( substr( $format, $pos, 2 ) eq 'mm' )
+ && (@placeholders)
+ && ( ( $placeholders[-1]->[0] eq 'h' )
+ or ( $placeholders[-1]->[0] eq 'hh' ) )
+ )
+ {
+
+ # For this case 'm' is minutes not months.
+ push @placeholders, [ 'mm', length($token), 2, 'minutes' ];
+ }
+ else {
+ push @placeholders,
+ [ substr( $format, $pos, 2 ), length($token), 2 ];
+ }
+ if ( ( substr( $format, $pos, 2 ) eq 'ss' )
+ && ( @placeholders > 1 ) )
+ {
+ if ( ( $placeholders[-2]->[0] eq 'm' )
+ || ( $placeholders[-2]->[0] eq 'mm' ) )
+ {
+
+ # For this case 'm' is minutes not months.
+ push( @{ $placeholders[-2] }, 'minutes' );
+ }
+ }
+ $pos += 2;
+ }
+ elsif (( substr( $format, $pos, 1 ) eq 'm' )
+ || ( substr( $format, $pos, 1 ) eq 'd' )
+ || ( substr( $format, $pos, 1 ) eq 'h' )
+ || ( substr( $format, $pos, 1 ) eq 's' ) )
+ {
+ if (
+ ( substr( $format, $pos, 1 ) eq 'm' )
+ && (@placeholders)
+ && ( ( $placeholders[-1]->[0] eq 'h' )
+ or ( $placeholders[-1]->[0] eq 'hh' ) )
+ )
+ {
+
+ # For this case 'm' is minutes not months.
+ push @placeholders, [ 'm', length($token), 1, 'minutes' ];
+ }
+ else {
+ push @placeholders,
+ [ substr( $format, $pos, 1 ), length($token), 1 ];
+ }
+ if ( ( substr( $format, $pos, 1 ) eq 's' )
+ && ( @placeholders > 1 ) )
+ {
+ if ( ( $placeholders[-2]->[0] eq 'm' )
+ || ( $placeholders[-2]->[0] eq 'mm' ) )
+ {
+
+ # For this case 'm' is minutes not months.
+ push( @{ $placeholders[-2] }, 'minutes' );
+ }
+ }
+ $pos += 1;
+ }
+ }
+ elsif ( ( substr( $format, $pos, 3 ) eq '[h]' ) ) {
+ $format_mode = 'date' unless $format_mode;
+ push @placeholders, [ '[h]', length($token), 3 ];
+ $pos += 3;
+ }
+ elsif ( ( substr( $format, $pos, 4 ) eq '[mm]' ) ) {
+ $format_mode = 'date' unless $format_mode;
+ push @placeholders, [ '[mm]', length($token), 4 ];
+ $pos += 4;
+ }
+ elsif ( $char eq '@' ) {
+ push @placeholders, [ '@', length($token), 1 ];
+ $pos++;
+ }
+ elsif ( $char eq '*' ) {
+ push @placeholders,
+ [ substr( $format, $pos, 1 ), length($token), 1 ];
+ }
+ else {
+ $pos++;
+ }
+ $pos++ if ( $pos == $start_pos ); #No Format match
+ $token .= substr( $format, $start_pos, $pos - $start_pos );
+
+ } # End of parsing.
+
+ # Copy the located format string to a result string that we will perform
+ # the substitutions on and return to the user.
+ my $result = $token;
+
+ # Add a placeholder between the decimal/comma and end of the token, if any.
+ if ( $token_start != -1 ) {
+ push @placeholders,
+ [
+ substr( $format, $token_start, $pos - $token_start + 1 ),
+ $decimal_pos, $pos - $token_start + 1
+ ];
+ }
+
+ #
+ # In the next sections we process date, number and text formats. We take a
+ # format such as yyyy/mm/dd and replace it with something like 2008/12/25.
+ #
+ if ( ( $format_mode eq 'date' ) && ( $number =~ $qrNUMBER ) ) {
+
+ # The maximum allowable date in Excel is 9999-12-31T23:59:59.000 which
+ # equates to 2958465.999+ in the 1900 epoch and 2957003.999+ in the
+ # 1904 epoch. We use 0 as the minimum in both epochs. The 1904 system
+ # actually supports negative numbers but that isn't worth the effort.
+ my $min_date = 0;
+ my $max_date = 2958466;
+ $max_date = 2957004 if $is_1904;
+
+ if ( $number < $min_date || $number >= $max_date ) {
+ return $number; # Return unformatted number.
+ }
+
+ # Process date formats.
+ my @time = ExcelLocaltime( $number, $is_1904 );
+
+ # 0 1 2 3 4 5 6 7
+ my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @time;
+
+ $month++; # localtime() zero indexed month.
+ $year += 1900; # localtime() year.
+
+ my @full_month_name = qw(
+ None January February March April May June July
+ August September October November December
+ );
+ my @short_month_name = qw(
+ None Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
+ );
+ my @full_day_name = qw(
+ Sunday Monday Tuesday Wednesday Thursday Friday Saturday
+ );
+ my @short_day_name = qw(
+ Sun Mon Tue Wed Thu Fri Sat
+ );
+
+ # Replace the placeholders in the template such as yyyy mm dd with
+ # actual numbers or strings.
+ my $replacement;
+ for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) {
+ my $placeholder = $placeholders[$i];
+
+ if ( $placeholder->[-1] eq 'minutes' ) {
+
+ # For this case 'm/mm' is minutes not months.
+ if ( $placeholder->[0] eq 'mm' ) {
+ $replacement = sprintf( "%02d", $min );
+ }
+ else {
+ $replacement = sprintf( "%d", $min );
+ }
+ }
+ elsif ( $placeholder->[0] eq 'yyyy' ) {
+
+ # 4 digit Year. 2000 -> 2000.
+ $replacement = sprintf( '%04d', $year );
+ }
+ elsif ( $placeholder->[0] eq 'yy' ) {
+
+ # 2 digit Year. 2000 -> 00.
+ $replacement = sprintf( '%02d', $year % 100 );
+ }
+ elsif ( $placeholder->[0] eq 'mmmmm' ) {
+
+ # First character of the month name. 1 -> J.
+ $replacement = substr( $short_month_name[$month], 0, 1 );
+ }
+ elsif ( $placeholder->[0] eq 'mmmm' ) {
+
+ # Full month name. 1 -> January.
+ $replacement = $full_month_name[$month];
+ }
+ elsif ( $placeholder->[0] eq 'mmm' ) {
+
+ # Short month name. 1 -> Jan.
+ $replacement = $short_month_name[$month];
+ }
+ elsif ( $placeholder->[0] eq 'mm' ) {
+
+ # 2 digit month. 1 -> 01.
+ $replacement = sprintf( '%02d', $month );
+ }
+ elsif ( $placeholder->[0] eq 'm' ) {
+
+ # 1 digit month. 1 -> 1.
+ $replacement = sprintf( '%d', $month );
+ }
+ elsif ( $placeholder->[0] eq 'dddd' ) {
+
+ # Full day name. Wednesday (for example.)
+ $replacement = $full_day_name[$wday];
+ }
+ elsif ( $placeholder->[0] eq 'ddd' ) {
+
+ # Short day name. Wed (for example.)
+ $replacement = $short_day_name[$wday];
+ }
+ elsif ( $placeholder->[0] eq 'dd' ) {
+
+ # 2 digit day. 1 -> 01.
+ $replacement = sprintf( '%02d', $day );
+ }
+ elsif ( $placeholder->[0] eq 'd' ) {
+
+ # 1 digit day. 1 -> 1.
+ $replacement = sprintf( '%d', $day );
+ }
+ elsif ( $placeholder->[0] eq 'hh' ) {
+
+ # 2 digit hour.
+ if ($is_12_hour) {
+ my $hour_tmp = $hour % 12;
+ $hour_tmp = 12 if $hour % 12 == 0;
+ $replacement = sprintf( '%d', $hour_tmp );
+ }
+ else {
+ $replacement = sprintf( '%02d', $hour );
+ }
+ }
+ elsif ( $placeholder->[0] eq 'h' ) {
+
+ # 1 digit hour.
+ if ($is_12_hour) {
+ my $hour_tmp = $hour % 12;
+ $hour_tmp = 12 if $hour % 12 == 0;
+ $replacement = sprintf( '%2d', $hour_tmp );
+ }
+ else {
+ $replacement = sprintf( '%d', $hour );
+ }
+ }
+ elsif ( $placeholder->[0] eq 'ss' ) {
+
+ # 2 digit seconds.
+ $replacement = sprintf( '%02d', $sec );
+ }
+ elsif ( $placeholder->[0] eq 's' ) {
+
+ # 1 digit seconds.
+ $replacement = sprintf( '%d', $sec );
+ }
+ elsif ( $placeholder->[0] eq 'am/pm' ) {
+
+ # AM/PM.
+ $replacement = ( $hour >= 12 ) ? 'PM' : 'AM';
+ }
+ elsif ( $placeholder->[0] eq 'a/p' ) {
+
+ # AM/PM.
+ $replacement = ( $hour >= 12 ) ? 'P' : 'A';
+ }
+ elsif ( $placeholder->[0] eq '.' ) {
+
+ # Decimal point for seconds.
+ $replacement = '.';
+ }
+ elsif ( $placeholder->[0] =~ /(^0+$)/ ) {
+
+ # Milliseconds. For example h:ss.000.
+ my $length = length($1);
+ $replacement =
+ substr( sprintf( "%.${length}f", $msec / 1000 ), 2, $length );
+ }
+ elsif ( $placeholder->[0] eq '[h]' ) {
+
+ # Hours modulus 24. 25 displays as 25 not as 1.
+ $replacement = sprintf( '%d', int($number) * 24 + $hour );
+ }
+ elsif ( $placeholder->[0] eq '[mm]' ) {
+
+ # Mins modulus 60. 72 displays as 72 not as 12.
+ $replacement =
+ sprintf( '%d', ( int($number) * 24 + $hour ) * 60 + $min );
+ }
+ elsif ( $placeholder->[0] eq 'ge' ) {
+ require Spreadsheet::ParseExcel::FmtJapan;
+ # Japanese Nengo (aka Gengo) in initialism (abbr. name)
+ $replacement =
+ Spreadsheet::ParseExcel::FmtJapan::CnvNengo( abbr_name => @time );
+ }
+ elsif ( $placeholder->[0] eq 'ggge' ) {
+ require Spreadsheet::ParseExcel::FmtJapan;
+ # Japanese Nengo (aka Gengo) in Kanji (full name)
+ $replacement =
+ Spreadsheet::ParseExcel::FmtJapan::CnvNengo( name => @time );
+ }
+ elsif ( $placeholder->[0] eq '@' ) {
+
+ # Text format.
+ $replacement = $number;
+ }
+
+ # Substitute the replacement string back into the template.
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ $replacement );
+ }
+ }
+ elsif ( ( $format_mode eq 'number' ) && ( $number =~ $qrNUMBER ) ) {
+
+ # Process non date formats.
+ if (@placeholders) {
+ while ( $placeholders[-1]->[0] eq ',' ) {
+ $comma_count--;
+ substr(
+ $result,
+ $placeholders[-1]->[1],
+ $placeholders[-1]->[2], ''
+ );
+ $number /= 1000;
+ pop @placeholders;
+ }
+
+ my $number_format = join( '', map { $_->[0] } @placeholders );
+ my $number_result;
+ my $str_length = 0;
+ my $engineering = 0;
+ my $is_decimal = 0;
+ my $is_integer = 0;
+ my $after_decimal = undef;
+
+ for my $token ( split //, $number_format ) {
+ if ( $token eq '.' ) {
+ $str_length++;
+ $is_decimal = 1;
+ }
+ elsif ( ( $token eq 'E' ) || ( $token eq 'e' ) ) {
+ $engineering = 1;
+ }
+ elsif ( $token eq '0' ) {
+ $str_length++;
+ $after_decimal++ if $is_decimal;
+ $is_integer = 1;
+ }
+ elsif ( $token eq '#' ) {
+ $after_decimal++ if $is_decimal;
+ $is_integer = 1;
+ }
+ elsif ( $token eq '?' ) {
+ $after_decimal++ if $is_decimal;
+ }
+ }
+
+ $number *= 100.0 if $is_percent;
+
+ my $data = ($is_currency) ? abs($number) : $number + 0;
+
+ if ($is_fraction) {
+ $number_result = sprintf( "%0${str_length}d", int($data) );
+ }
+ else {
+ if ($is_decimal) {
+
+ if ( defined $after_decimal ) {
+ $number_result =
+ sprintf "%0${str_length}.${after_decimal}f", $data;
+ }
+ else {
+ $number_result = sprintf "%0${str_length}f", $data;
+ }
+
+ # Fix for Perl and sprintf not rounding up like Excel.
+ # http://rt.cpan.org/Public/Bug/Display.html?id=45626
+ if ( $data =~ /^${number_result}5/ ) {
+ $number_result =
+ sprintf "%0${str_length}.${after_decimal}f",
+ $data . '1';
+ }
+ }
+ else {
+ $number_result = sprintf( "%0${str_length}.0f", $data );
+ }
+ }
+
+ $number_result = AddComma($number_result) if $comma_count > 0;
+
+ my $number_length = length($number_result);
+ my $decimal_pos = -1;
+ my $replacement;
+
+ for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) {
+ my $placeholder = $placeholders[$i];
+
+ if ( $placeholder->[0] =~
+ /([#0]*)([\.]?)([0#]*)([eE])([\+\-])([0#]+)/ )
+ {
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ MakeE( $placeholder->[0], $number ) );
+ }
+ elsif ( $placeholder->[0] =~ /\// ) {
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ MakeFraction( $placeholder->[0], $number, $is_integer )
+ );
+ }
+ elsif ( $placeholder->[0] eq '.' ) {
+ $number_length--;
+ $decimal_pos = $number_length;
+ }
+ elsif ( $placeholder->[0] eq '+' ) {
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ ( $number > 0 )
+ ? '+'
+ : ( ( $number == 0 ) ? '+' : '-' ) );
+ }
+ elsif ( $placeholder->[0] eq '-' ) {
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ ( $number > 0 )
+ ? ''
+ : ( ( $number == 0 ) ? '' : '-' ) );
+ }
+ elsif ( $placeholder->[0] eq '@' ) {
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ $number );
+ }
+ elsif ( $placeholder->[0] eq '*' ) {
+ substr( $result, $placeholder->[1], $placeholder->[2], '' );
+ }
+ elsif (( $placeholder->[0] eq "\xA2\xA4" )
+ or ( $placeholder->[0] eq "\xA2\xA5" )
+ or ( $placeholder->[0] eq "\x81\xA2" )
+ or ( $placeholder->[0] eq "\x81\xA3" ) )
+ {
+ substr(
+ $result, $placeholder->[1],
+ $placeholder->[2], $placeholder->[0]
+ );
+ }
+ elsif (( $placeholder->[0] eq '(' )
+ or ( $placeholder->[0] eq ')' ) )
+ {
+ substr(
+ $result, $placeholder->[1],
+ $placeholder->[2], $placeholder->[0]
+ );
+ }
+ else {
+ if ( $number_length > 0 ) {
+ if ( $i <= 0 ) {
+ $replacement =
+ substr( $number_result, 0, $number_length );
+ $number_length = 0;
+ }
+ else {
+ my $real_part_length = length( $placeholder->[0] );
+ if ( $decimal_pos >= 0 ) {
+ my $format = $placeholder->[0];
+ $format =~ s/^#+//;
+ $real_part_length = length $format;
+ $real_part_length =
+ ( $number_length <= $real_part_length )
+ ? $number_length
+ : $real_part_length;
+ }
+ else {
+ $real_part_length =
+ ( $number_length <= $real_part_length )
+ ? $number_length
+ : $real_part_length;
+ }
+ $replacement =
+ substr( $number_result,
+ $number_length - $real_part_length,
+ $real_part_length );
+ $number_length -= $real_part_length;
+ }
+ }
+ else {
+ $replacement = '';
+ }
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ "\x00" . $replacement );
+ }
+ }
+ $replacement =
+ ( $number_length > 0 )
+ ? substr( $number_result, 0, $number_length )
+ : '';
+ $result =~ s/\x00/$replacement/;
+ $result =~ s/\x00//g;
+ }
+ }
+ else {
+
+ # Process text formats
+ my $is_text = 0;
+ for ( my $i = @placeholders - 1 ; $i >= 0 ; $i-- ) {
+ my $placeholder = $placeholders[$i];
+ if ( $placeholder->[0] eq '@' ) {
+ substr( $result, $placeholder->[1], $placeholder->[2],
+ $number );
+ $is_text++;
+ }
+ else {
+ substr( $result, $placeholder->[1], $placeholder->[2], '' );
+ }
+ }
+
+ $result = $number unless $is_text;
+
+ } # End of placeholder substitutions.
+
+ # Trim the leading and trailing whitespace from the results.
+ $result =~ s/^\s+//;
+ $result =~ s/\s+$//;
+
+ # Fix for negative currency.
+ $result =~ s/^\$\-/\-\$/;
+ $result =~ s/^\$ \-/\-\$ /;
+
+ # Return color and locale strings if required.
+ if ($want_subformats) {
+ return ( $result, $color, $locale );
+ }
+ else {
+ return $result;
+ }
+}
+
+#------------------------------------------------------------------------------
+# AddComma (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+sub AddComma {
+ my ($sNum) = @_;
+
+ if ( $sNum =~ /^([^\d]*)(\d\d\d\d+)(\.*.*)$/ ) {
+ my ( $sPre, $sObj, $sAft ) = ( $1, $2, $3 );
+ for ( my $i = length($sObj) - 3 ; $i > 0 ; $i -= 3 ) {
+ substr( $sObj, $i, 0, ',' );
+ }
+ return $sPre . $sObj . $sAft;
+ }
+ else {
+ return $sNum;
+ }
+}
+
+#------------------------------------------------------------------------------
+# MakeFraction (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+sub MakeFraction {
+ my ( $sFmt, $iData, $iFlg ) = @_;
+ my $iBunbo;
+ my $iShou;
+
+ #1. Init
+ # print "FLG: $iFlg\n";
+ if ($iFlg) {
+ $iShou = $iData - int($iData);
+ return '' if ( $iShou == 0 );
+ }
+ else {
+ $iShou = $iData;
+ }
+ $iShou = abs($iShou);
+ my $sSWk;
+
+ #2.Calc BUNBO
+ #2.1 BUNBO defined
+ if ( $sFmt =~ /\/(\d+)$/ ) {
+ $iBunbo = $1;
+ return sprintf( "%d/%d", $iShou * $iBunbo, $iBunbo );
+ }
+ else {
+
+ #2.2 Calc BUNBO
+ $sFmt =~ /\/(\?+)$/;
+ my $iKeta = length($1);
+ my $iSWk = 1;
+ my $sSWk = '';
+ my $iBunsi;
+ for ( my $iBunbo = 2 ; $iBunbo < 10**$iKeta ; $iBunbo++ ) {
+ $iBunsi = int( $iShou * $iBunbo + 0.5 );
+ my $iCmp = abs( $iShou - ( $iBunsi / $iBunbo ) );
+ if ( $iCmp < $iSWk ) {
+ $iSWk = $iCmp;
+ $sSWk = sprintf( "%d/%d", $iBunsi, $iBunbo );
+ last if ( $iSWk == 0 );
+ }
+ }
+ return $sSWk;
+ }
+}
+
+#------------------------------------------------------------------------------
+# MakeE (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+sub MakeE {
+ my ( $sFmt, $iData ) = @_;
+
+ $sFmt =~ /(([#0]*)[\.]?[#0]*)([eE])([\+\-][0#]+)/;
+ my ( $sKari, $iKeta, $sE, $sSisu ) = ( $1, length($2), $3, $4 );
+ $iKeta = 1 if ( $iKeta <= 0 );
+
+ my $iLog10 = 0;
+ $iLog10 = ( $iData == 0 ) ? 0 : ( log( abs($iData) ) / log(10) );
+ $iLog10 = (
+ int( $iLog10 / $iKeta ) +
+ ( ( ( $iLog10 - int( $iLog10 / $iKeta ) ) < 0 ) ? -1 : 0 ) ) * $iKeta;
+
+ my $sUe = ExcelFmt( $sKari, $iData * ( 10**( $iLog10 * -1 ) ), 0 );
+ my $sShita = ExcelFmt( $sSisu, $iLog10, 0 );
+ return $sUe . $sE . $sShita;
+}
+
+#------------------------------------------------------------------------------
+# LeapYear (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+sub LeapYear {
+ my ($iYear) = @_;
+ return 1 if ( $iYear == 1900 ); #Special for Excel
+ return ( ( ( $iYear % 4 ) == 0 )
+ && ( ( $iYear % 100 ) || ( $iYear % 400 ) == 0 ) )
+ ? 1
+ : 0;
+}
+
+#------------------------------------------------------------------------------
+# LocaltimeExcel (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+sub LocaltimeExcel {
+ my ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec, $flg1904 )
+ = @_;
+
+ #0. Init
+ $iMon++;
+ $iYear += 1900;
+
+ #1. Calc Time
+ my $iTime;
+ $iTime = $iHour;
+ $iTime *= 60;
+ $iTime += $iMin;
+ $iTime *= 60;
+ $iTime += $iSec;
+ $iTime += $iMSec / 1000.0 if ( defined($iMSec) );
+ $iTime /= 86400.0; #3600*24(1day in seconds)
+ my $iY;
+ my $iYDays;
+
+ #2. Calc Days
+ if ($flg1904) {
+ $iY = 1904;
+ $iTime--; #Start from Jan 1st
+ $iYDays = 366;
+ }
+ else {
+ $iY = 1900;
+ $iYDays = 366; #In Excel 1900 is leap year (That's not TRUE!)
+ }
+ while ( $iY < $iYear ) {
+ $iTime += $iYDays;
+ $iY++;
+ $iYDays = ( LeapYear($iY) ) ? 366 : 365;
+ }
+ for ( my $iM = 1 ; $iM < $iMon ; $iM++ ) {
+ if ( $iM == 1
+ || $iM == 3
+ || $iM == 5
+ || $iM == 7
+ || $iM == 8
+ || $iM == 10
+ || $iM == 12 )
+ {
+ $iTime += 31;
+ }
+ elsif ( $iM == 4 || $iM == 6 || $iM == 9 || $iM == 11 ) {
+ $iTime += 30;
+ }
+ elsif ( $iM == 2 ) {
+ $iTime += ( LeapYear($iYear) ) ? 29 : 28;
+ }
+ }
+ $iTime += $iDay;
+ return $iTime;
+}
+
+#------------------------------------------------------------------------------
+# ExcelLocaltime (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+sub ExcelLocaltime {
+
+ my ( $dObj, $flg1904 ) = @_;
+ my ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec );
+ my ( $iDt, $iTime, $iYDays );
+
+ $iDt = int($dObj);
+ $iTime = $dObj - $iDt;
+
+ #1. Calc Days
+ if ($flg1904) {
+ $iYear = 1904;
+ $iDt++; #Start from Jan 1st
+ $iYDays = 366;
+ $iwDay = ( ( $iDt + 4 ) % 7 );
+ }
+ else {
+ $iYear = 1900;
+ $iYDays = 366; #In Excel 1900 is leap year (That's not TRUE!)
+ $iwDay = ( ( $iDt + 6 ) % 7 );
+ }
+ while ( $iDt > $iYDays ) {
+ $iDt -= $iYDays;
+ $iYear++;
+ $iYDays =
+ ( ( ( $iYear % 4 ) == 0 )
+ && ( ( $iYear % 100 ) || ( $iYear % 400 ) == 0 ) ) ? 366 : 365;
+ }
+ $iYear -= 1900; # Localtime year is relative to 1900.
+
+ for ( $iMon = 1 ; $iMon < 12 ; $iMon++ ) {
+ my $iMD;
+ if ( $iMon == 1
+ || $iMon == 3
+ || $iMon == 5
+ || $iMon == 7
+ || $iMon == 8
+ || $iMon == 10
+ || $iMon == 12 )
+ {
+ $iMD = 31;
+ }
+ elsif ( $iMon == 4 || $iMon == 6 || $iMon == 9 || $iMon == 11 ) {
+ $iMD = 30;
+ }
+ elsif ( $iMon == 2 ) {
+ $iMD = ( ( $iYear % 4 ) == 0 ) ? 29 : 28;
+ }
+ last if ( $iDt <= $iMD );
+ $iDt -= $iMD;
+ }
+
+ $iMon -= 1; # Localtime month is 0 based.
+
+ #2. Calc Time
+ $iDay = $iDt;
+ $iTime += ( 0.0005 / 86400.0 );
+ $iTime *= 24.0;
+ $iHour = int($iTime);
+ $iTime -= $iHour;
+ $iTime *= 60.0;
+ $iMin = int($iTime);
+ $iTime -= $iMin;
+ $iTime *= 60.0;
+ $iSec = int($iTime);
+ $iTime -= $iSec;
+ $iTime *= 1000.0;
+ $iMSec = int($iTime);
+
+ return ( $iSec, $iMin, $iHour, $iDay, $iMon, $iYear, $iwDay, $iMSec );
+}
+
+# -----------------------------------------------------------------------------
+# col2int (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+# converts a excel row letter into an int for use in an array
+sub col2int {
+ my $result = 0;
+ my $str = shift;
+ my $incr = 0;
+
+ for ( my $i = length($str) ; $i > 0 ; $i-- ) {
+ my $char = substr( $str, $i - 1 );
+ my $curr += ord( lc($char) ) - ord('a') + 1;
+ $curr *= $incr if ($incr);
+ $result += $curr;
+ $incr += 26;
+ }
+
+ # this is one out as we range 0..x-1 not 1..x
+ $result--;
+
+ return $result;
+}
+
+# -----------------------------------------------------------------------------
+# int2col (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+### int2col
+# convert a column number into column letters
+# @note this is quite a brute force coarse method
+# does not manage values over 701 (ZZ)
+# @arg number, to convert
+# @returns string, column name
+#
+sub int2col {
+ my $out = "";
+ my $val = shift;
+
+ do {
+ $out .= chr( ( $val % 26 ) + ord('A') );
+ $val = int( $val / 26 ) - 1;
+ } while ( $val >= 0 );
+
+ return scalar reverse $out;
+}
+
+# -----------------------------------------------------------------------------
+# sheetRef (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
+### sheetRef
+# convert an excel letter-number address into a useful array address
+# @note that also Excel uses X-Y notation, we normally use Y-X in arrays
+# @args $str, excel coord eg. A2
+# @returns an array - 2 elements - column, row, or undefined
+#
+sub sheetRef {
+ my $str = shift;
+ my @ret;
+
+ $str =~ m/^(\D+)(\d+)$/;
+
+ if ( $1 && $2 ) {
+ push( @ret, $2 - 1, col2int($1) );
+ }
+ if ( $ret[0] < 0 ) {
+ undef @ret;
+ }
+
+ return @ret;
+}
+
+# -----------------------------------------------------------------------------
+# xls2csv (for Spreadsheet::ParseExcel::Utility)
+#------------------------------------------------------------------------------
+### xls2csv
+# convert a chunk of an excel file into csv text chunk
+# @args $param, sheet-colrow:colrow (1-A1:B2 or A1:B2 for sheet 1
+# @args $rotate, 0 or 1 decides if output should be rotated or not
+# @returns string containing a chunk of csv
+#
+sub xls2csv {
+ my ( $filename, $regions, $rotate ) = @_;
+ my $sheet = 0;
+
+ # We need Text::CSV_XS for proper CSV handling.
+ require Text::CSV_XS;
+
+ # extract any sheet number from the region string
+ $regions =~ m/^(\d+)-(.*)/;
+
+ if ($2) {
+ $sheet = $1 - 1;
+ $regions = $2;
+ }
+
+ # now extract the start and end regions
+ $regions =~ m/(.*):(.*)/;
+
+ if ( !$1 || !$2 ) {
+ print STDERR "Bad Params";
+ return "";
+ }
+
+ my @start = sheetRef($1);
+ my @end = sheetRef($2);
+ if ( !@start ) {
+ print STDERR "Bad coorinates - $1";
+ return "";
+ }
+ if ( !@end ) {
+ print STDERR "Bad coorinates - $2";
+ return "";
+ }
+
+ if ( $start[1] > $end[1] ) {
+ print STDERR "Bad COLUMN ordering\n";
+ print STDERR "Start column " . int2col( $start[1] );
+ print STDERR " after end column " . int2col( $end[1] ) . "\n";
+ return "";
+ }
+ if ( $start[0] > $end[0] ) {
+ print STDERR "Bad ROW ordering\n";
+ print STDERR "Start row " . ( $start[0] + 1 );
+ print STDERR " after end row " . ( $end[0] + 1 ) . "\n";
+ exit;
+ }
+
+ # start the excel object now
+ my $oExcel = new Spreadsheet::ParseExcel;
+ my $oBook = $oExcel->Parse($filename);
+
+ # open the sheet
+ my $oWkS = $oBook->{Worksheet}[$sheet];
+
+ # now check that the region exists in the file
+ # if not truncate to the possible region
+ # output a warning msg
+ if ( $start[1] < $oWkS->{MinCol} ) {
+ print STDERR int2col( $start[1] )
+ . " < min col "
+ . int2col( $oWkS->{MinCol} )
+ . " Resetting\n";
+ $start[1] = $oWkS->{MinCol};
+ }
+ if ( $end[1] > $oWkS->{MaxCol} ) {
+ print STDERR int2col( $end[1] )
+ . " > max col "
+ . int2col( $oWkS->{MaxCol} )
+ . " Resetting\n";
+ $end[1] = $oWkS->{MaxCol};
+ }
+ if ( $start[0] < $oWkS->{MinRow} ) {
+ print STDERR ""
+ . ( $start[0] + 1 )
+ . " < min row "
+ . ( $oWkS->{MinRow} + 1 )
+ . " Resetting\n";
+ $start[0] = $oWkS->{MinCol};
+ }
+ if ( $end[0] > $oWkS->{MaxRow} ) {
+ print STDERR ""
+ . ( $end[0] + 1 )
+ . " > max row "
+ . ( $oWkS->{MaxRow} + 1 )
+ . " Resetting\n";
+ $end[0] = $oWkS->{MaxRow};
+
+ }
+
+ my $x1 = $start[1];
+ my $y1 = $start[0];
+ my $x2 = $end[1];
+ my $y2 = $end[0];
+
+ my @cell_data;
+ my $row = 0;
+
+ if ( !$rotate ) {
+ for ( my $y = $y1 ; $y <= $y2 ; $y++ ) {
+ for ( my $x = $x1 ; $x <= $x2 ; $x++ ) {
+ my $cell = $oWkS->{Cells}[$y][$x];
+
+ my $value;
+ if ( defined $cell ) {
+ $value .= $cell->value();
+ }
+ else {
+ $value = '';
+ }
+
+ push @{ $cell_data[$row] }, $value;
+ }
+ $row++;
+ }
+ }
+ else {
+ for ( my $x = $x1 ; $x <= $x2 ; $x++ ) {
+ for ( my $y = $y1 ; $y <= $y2 ; $y++ ) {
+ my $cell = $oWkS->{Cells}[$y][$x];
+
+ my $value;
+ if ( defined $cell ) {
+ $value .= $cell->value();
+ }
+ else {
+ $value = '';
+ }
+
+ push @{ $cell_data[$row] }, $value;
+ }
+ $row++;
+ }
+ }
+
+ # Create the CSV output string.
+ my $csv = Text::CSV_XS->new( { binary => 1, eol => $/ } );
+ my $output = "";
+
+ for my $row (@cell_data) {
+ $csv->combine(@$row);
+ $output .= $csv->string();
+ }
+
+ return $output;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Utility - Utility functions for Spreadsheet::ParseExcel.
+
+=head1 SYNOPSIS
+
+ use Spreadsheet::ParseExcel::Utility qw(ExcelFmt ExcelLocaltime LocaltimeExcel);
+
+ # Convert localtime to Excel time
+ my $datetime = LocaltimeExcel(11, 10, 12, 23, 2, 64); # 1964-3-23 12:10:11
+
+ print $datetime, "\n"; # 23459.5070717593 (Excel date/time format)
+
+ # Convert Excel Time to localtime
+ my @time = ExcelLocaltime($datetime);
+ print join(":", @time), "\n"; # 11:10:12:23:2:64:1:0
+
+ # Formatting
+ print ExcelFmt('yyyy-mm-dd', $datetime), "\n"; # 1964-3-23
+ print ExcelFmt('m-d-yy', $datetime), "\n"; # 3-23-64
+ print ExcelFmt('#,##0', $datetime), "\n"; # 23,460
+ print ExcelFmt('#,##0.00', $datetime), "\n"; # 23,459.51
+
+=head1 DESCRIPTION
+
+The C<Spreadsheet::ParseExcel::Utility> module provides utility functions for working with ParseExcel and Excel data.
+
+=head1 Functions
+
+C<Spreadsheet::ParseExcel::Utility> can export the following functions:
+
+ ExcelFmt
+ ExcelLocaltime
+ LocaltimeExcel
+ col2int
+ int2col
+ sheetRef
+ xls2csv
+
+These functions must be imported implicitly:
+
+ # Just one function.
+ use Spreadsheet::ParseExcel::Utility 'col2int';
+
+ # More than one.
+ use Spreadsheet::ParseExcel::Utility qw(ExcelFmt ExcelLocaltime LocaltimeExcel);
+
+
+=head2 ExcelFmt($format_string, $number, $is_1904)
+
+Excel stores data such as dates and currency values as numbers. The way these numbers are displayed is controlled by the number format string for the cell. For example a cell with a number format of C<'$#,##0.00'> for currency and a value of 1234.567 would be displayed as follows:
+
+ '$#,##0.00' + 1234.567 = '$1,234.57'.
+
+The C<ExcelFmt()> function tries to emulate this formatting so that the user can convert raw numbers returned by C<Spreadsheet::ParseExel> to a desired format. For example:
+
+ print ExcelFmt('$#,##0.00', 1234.567); # $1,234.57.
+
+The syntax of the function is:
+
+ my $text = ExcelFmt($format_string, $number, $is_1904);
+
+Where C<$format_string> is an Excel number format string, C<$number> is a real or integer number and C<is_1904> is an optional flag to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch.
+
+C<ExcelFmt()> is also used internally to convert numbers returned by the C<Cell::unformatted()> method to the formatted value returned by the C<Cell::value()> method:
+
+
+ my $cell = $worksheet->get_cell( 0, 0 );
+
+ print $cell->unformatted(), "\n"; # 1234.567
+ print $cell->value(), "\n"; # $1,234.57
+
+The most common usage for C<ExcelFmt> is to convert numbers to dates. Dates and times in Excel are represented by real numbers, for example "1 Jan 2001 12:30 PM" is represented by the number 36892.521. The integer part of the number stores the number of days since the epoch and the fractional part stores the percentage of the day. By applying an Excel number format the number is converted to the desired string representation:
+
+ print ExcelFmt('d mmm yyyy h:mm AM/PM', 36892.521); # 1 Jan 2001 12:30 PM
+
+C<$is_1904> is an optional flag to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch. Excel for Windows generally uses 1900 and Excel for Mac OS uses 1904. The C<$is1904> flag isn't required very often by a casual user and can usually be ignored.
+
+
+=head2 ExcelLocaltime($excel_datetime, $is_1904)
+
+The C<ExcelLocaltime()> function converts from an Excel date/time number to a C<localtime()>-like array of values:
+
+ my @time = ExcelLocaltime($excel_datetime);
+
+ # 0 1 2 3 4 5 6 7
+ my ( $sec, $min, $hour, $day, $month, $year, $wday, $msec ) = @time;
+
+The array elements from C<(0 .. 6)> are the same as Perl's C<localtime()>. The last element C<$msec> is milliseconds. In particular it should be noted that, in common with C<localtime()>, the month is zero indexed and the year is the number of years since 1900. This means that you will usually need to do the following:
+
+ $month++;
+ $year += 1900;
+
+See also Perl's documentation for L<localtime()|perlfunc>:
+
+The C<$is_1904> flag is an optional. It is used to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch.
+
+=head2 LocaltimeExcel($sec, $min, $hour, $day, $month, $year, $wday, $msec, $is_1904)
+
+The C<LocaltimeExcel()> function converts from a C<localtime()>-like array of values to an Excel date/time number:
+
+ $excel_datetime = LocaltimeExcel($sec, $min, $hour, $day, $month, $year, $wday, $msec);
+
+The array elements from C<(0 .. 6)> are the same as Perl's C<localtime()>. The last element C<$msec> is milliseconds. In particular it should be noted that, in common with C<localtime()>, the month is zero indexed and the year is the number of years since 1900. See also Perl's documentation for L<localtime()|perlfunc>:
+
+The C<$wday> and C<$msec> elements are usually optional. This time elements can also be zeroed if they aren't of interest:
+
+ # sec, min, hour, day, month, year
+ $excel_datetime = LocaltimeExcel( 0, 0, 0, 1, 0, 101 );
+
+ print ExcelFmt('d mmm yyyy', $excel_datetime); # 1 Jan 2001
+
+The C<$is_1904> flag is also optional. It is used to indicate that dates should use Excel's 1904 epoch instead of the default 1900 epoch.
+
+
+=head2 col2int($column)
+
+The C<col2int()> function converts an Excel column letter to an zero-indexed column number:
+
+ print col2int('A'); # 0
+ print col2int('AA'); # 26
+
+This function was contributed by Kevin Mulholland.
+
+
+=head2 int2col($column_number)
+
+The C<int2col()> function converts an zero-indexed Excel column number to a column letter:
+
+ print int2col(0); # 'A'
+ print int2col(26); # 'AA'
+
+This function was contributed by Kevin Mulholland.
+
+
+=head2 sheetRef($cell_string)
+
+The C<sheetRef()> function converts an Excel cell reference in 'A1' notation to a zero-indexed C<(row, col)> pair.
+
+ my ($row, $col) = sheetRef('A1'); # ( 0, 0 )
+ my ($row, $col) = sheetRef('C2'); # ( 1, 2 )
+
+This function was contributed by Kevin Mulholland.
+
+
+=head2 xls2csv($filename, $region, $rotate)
+
+The C<xls2csv()> function converts a section of an Excel file into a CSV text string.
+
+ $csv_text = xls2csv($filename, $region, $rotate);
+
+Where:
+
+ $region = "sheet-colrow:colrow"
+ For example '1-A1:B2' means 'A1:B2' for sheet 1.
+
+ and
+
+ $rotate = 0 or 1 (output is rotated/transposed or not)
+
+This function requires C<Text::CSV_XS> to be installed. It was contributed by Kevin Mulholland along with the C<xls2csv> script in the C<sample> directory of the distro.
+
+See also the following xls2csv utilities: Ken Prows' C<xls2csv>: http://search.cpan.org/~ken/xls2csv/script/xls2csv and H.Merijn Brand's C<xls2csv> (which is part of Spreadsheet::Read): http://search.cpan.org/~hmbrand/Spreadsheet-Read/
+
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Workbook.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Workbook.pm
new file mode 100644
index 0000000..d8a03c0
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Workbook.pm
@@ -0,0 +1,297 @@
+package Spreadsheet::ParseExcel::Workbook;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Workbook - A class for Workbooks.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+
+our $VERSION = '0.59';
+
+###############################################################################
+#
+# new()
+#
+# Constructor.
+#
+sub new {
+ my ($class) = @_;
+ my $self = {};
+ bless $self, $class;
+}
+
+###############################################################################
+#
+# worksheet()
+#
+# This method returns a single Worksheet object using either its name or index.
+#
+sub worksheet {
+ my ( $oBook, $sName ) = @_;
+ my $oWkS;
+ foreach $oWkS ( @{ $oBook->{Worksheet} } ) {
+ return $oWkS if ( $oWkS->{Name} eq $sName );
+ }
+ if ( $sName =~ /^\d+$/ ) {
+ return $oBook->{Worksheet}->[$sName];
+ }
+ return undef;
+}
+
+###############################################################################
+#
+# worksheets()
+#
+# Returns an array ofWorksheet objects.
+#
+sub worksheets {
+ my $self = shift;
+
+ return @{ $self->{Worksheet} };
+}
+
+###############################################################################
+#
+# worksheet_count()
+#
+# Returns the number Woksheet objects in the Workbook.
+#
+sub worksheet_count {
+
+ my $self = shift;
+
+ return $self->{SheetCount};
+}
+
+###############################################################################
+#
+# get_filename()
+#
+# Returns the name of the Excel file of C<undef> if the data was read from a filehandle rather than a file.
+#
+sub get_filename {
+
+ my $self = shift;
+
+ return $self->{File};
+}
+
+###############################################################################
+#
+# get_print_areas()
+#
+# Returns an array ref of print areas.
+#
+# TODO. This should really be a Worksheet method.
+#
+sub get_print_areas {
+
+ my $self = shift;
+
+ return $self->{PrintArea};
+}
+
+###############################################################################
+#
+# get_print_titles()
+#
+# Returns an array ref of print title hash refs.
+#
+# TODO. This should really be a Worksheet method.
+#
+sub get_print_titles {
+
+ my $self = shift;
+
+ return $self->{PrintTitle};
+}
+
+###############################################################################
+#
+# using_1904_date()
+#
+# Returns true if the Excel file is using the 1904 date epoch.
+#
+sub using_1904_date {
+
+ my $self = shift;
+
+ return $self->{Flg1904};
+}
+
+###############################################################################
+#
+# ParseAbort()
+#
+# Todo
+#
+sub ParseAbort {
+ my ( $self, $val ) = @_;
+ $self->{_ParseAbort} = $val;
+}
+
+###############################################################################
+#
+# Parse(). Deprecated.
+#
+# Syntactic wrapper around Spreadsheet::ParseExcel::Parse().
+# This method is *deprecated* since it doesn't conform to the the current
+# error handling in the S::PE Parse() method.
+#
+sub Parse {
+
+ my ( $class, $source, $formatter ) = @_;
+ my $excel = Spreadsheet::ParseExcel->new();
+ my $workbook = $excel->Parse( $source, $formatter );
+ $workbook->{_Excel} = $excel;
+ return $workbook;
+}
+
+###############################################################################
+#
+# Mapping between legacy method names and new names.
+#
+{
+ no warnings; # Ignore warnings about variables used only once.
+ *Worksheet = *worksheet;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Workbook - A class for Workbooks.
+
+=head1 SYNOPSIS
+
+See the documentation for Spreadsheet::ParseExcel.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for L<Spreadsheet::ParseExcel>.
+
+
+=head1 Methods
+
+The following Workbook methods are available:
+
+ $workbook->worksheets()
+ $workbook->worksheet()
+ $workbook->worksheet_count()
+ $workbook->get_filename()
+ $workbook->get_print_areas()
+ $workbook->get_print_titles()
+ $workbook->using_1904_date()
+
+
+=head2 worksheets()
+
+The C<worksheets()> method returns an array of Worksheet objects. This was most commonly used to iterate over the worksheets in a workbook:
+
+ for my $worksheet ( $workbook->worksheets() ) {
+ ...
+ }
+
+
+=head2 worksheet()
+
+The C<worksheet()> method returns a single C<Worksheet> object using either its name or index:
+
+ $worksheet = $workbook->worksheet('Sheet1');
+ $worksheet = $workbook->worksheet(0);
+
+Returns C<undef> if the sheet name or index doesn't exist.
+
+
+=head2 worksheet_count()
+
+The C<worksheet_count()> method returns the number of Woksheet objects in the Workbook.
+
+ my $worksheet_count = $workbook->worksheet_count();
+
+
+=head2 get_filename()
+
+The C<get_filename()> method returns the name of the Excel file of C<undef> if the data was read from a filehandle rather than a file.
+
+ my $filename = $workbook->get_filename();
+
+
+=head2 get_print_areas()
+
+The C<get_print_areas()> method returns an array ref of print areas.
+
+ my $print_areas = $workbook->get_print_areas();
+
+Each print area is as follows:
+
+ [ $start_row, $start_col, $end_row, $end_col ]
+
+Returns undef if there are no print areas.
+
+
+=head2 get_print_titles()
+
+The C<get_print_titles()> method returns an array ref of print title hash refs.
+
+ my $print_titles = $workbook->get_print_titles();
+
+Each print title array ref is as follows:
+
+ {
+ Row => [ $start_row, $end_row ],
+ Column => [ $start_col, $end_col ],
+ }
+
+
+Returns undef if there are no print titles.
+
+
+=head2 using_1904_date()
+
+The C<using_1904_date()> method returns true if the Excel file is using the 1904 date epoch instead of the 1900 epoch.
+
+ my $using_1904_date = $workbook->using_1904_date();
+
+ The Windows version of Excel generally uses the 1900 epoch while the Mac version of Excel generally uses the 1904 epoch.
+
+Returns 0 if the 1900 epoch is in use.
+
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut
diff --git a/mcu/tools/perl/Spreadsheet/ParseExcel/Worksheet.pm b/mcu/tools/perl/Spreadsheet/ParseExcel/Worksheet.pm
new file mode 100644
index 0000000..b9d32d7
--- /dev/null
+++ b/mcu/tools/perl/Spreadsheet/ParseExcel/Worksheet.pm
@@ -0,0 +1,955 @@
+package Spreadsheet::ParseExcel::Worksheet;
+
+###############################################################################
+#
+# Spreadsheet::ParseExcel::Worksheet - A class for Worksheets.
+#
+# Used in conjunction with Spreadsheet::ParseExcel.
+#
+# Copyright (c) 2009 John McNamara
+# Copyright (c) 2006-2008 Gabor Szabo
+# Copyright (c) 2000-2006 Kawai Takanori
+#
+# perltidy with standard settings.
+#
+# Documentation after __END__
+#
+
+use strict;
+use warnings;
+use Scalar::Util qw(weaken);
+
+our $VERSION = '0.59';
+
+###############################################################################
+#
+# new()
+#
+sub new {
+
+ my ( $class, %properties ) = @_;
+
+ my $self = \%properties;
+
+ weaken $self->{_Book};
+
+ $self->{Cells} = undef;
+ $self->{DefColWidth} = 8.43;
+
+ return bless $self, $class;
+}
+
+###############################################################################
+#
+# get_cell( $row, $col )
+#
+# Returns the Cell object at row $row and column $col, if defined.
+#
+sub get_cell {
+
+ my ( $self, $row, $col ) = @_;
+
+ if ( !defined $row
+ || !defined $col
+ || !defined $self->{MaxRow}
+ || !defined $self->{MaxCol} )
+ {
+
+ # Return undef if no arguments are given or if no cells are defined.
+ return undef;
+ }
+ elsif ($row < $self->{MinRow}
+ || $row > $self->{MaxRow}
+ || $col < $self->{MinCol}
+ || $col > $self->{MaxCol} )
+ {
+
+ # Return undef if outside allowable row/col range.
+ return undef;
+ }
+ else {
+
+ # Return the Cell object.
+ return $self->{Cells}->[$row]->[$col];
+ }
+}
+
+###############################################################################
+#
+# row_range()
+#
+# Returns a two-element list ($min, $max) containing the minimum and maximum
+# defined rows in the worksheet.
+#
+# If there is no row defined $max is smaller than $min.
+#
+sub row_range {
+
+ my $self = shift;
+
+ my $min = $self->{MinRow} || 0;
+ my $max = defined( $self->{MaxRow} ) ? $self->{MaxRow} : ( $min - 1 );
+
+ return ( $min, $max );
+}
+
+###############################################################################
+#
+# col_range()
+#
+# Returns a two-element list ($min, $max) containing the minimum and maximum
+# defined cols in the worksheet.
+#
+# If there is no column defined $max is smaller than $min.
+#
+sub col_range {
+
+ my $self = shift;
+
+ my $min = $self->{MinCol} || 0;
+ my $max = defined( $self->{MaxCol} ) ? $self->{MaxCol} : ( $min - 1 );
+
+ return ( $min, $max );
+}
+
+###############################################################################
+#
+# get_name()
+#
+# Returns the name of the worksheet.
+#
+sub get_name {
+
+ my $self = shift;
+
+ return $self->{Name};
+}
+
+###############################################################################
+#
+# sheet_num()
+#
+sub sheet_num {
+
+ my $self = shift;
+
+ return $self->{_SheetNo};
+}
+
+###############################################################################
+#
+# get_h_pagebreaks()
+#
+# Returns an array ref of row numbers where a horizontal page break occurs.
+#
+sub get_h_pagebreaks {
+
+ my $self = shift;
+
+ return $self->{HPageBreak};
+}
+
+###############################################################################
+#
+# get_v_pagebreaks()
+#
+# Returns an array ref of column numbers where a vertical page break occurs.
+#
+sub get_v_pagebreaks {
+
+ my $self = shift;
+
+ return $self->{VPageBreak};
+}
+
+###############################################################################
+#
+# get_merged_areas()
+#
+# Returns an array ref of cells that are merged.
+#
+sub get_merged_areas {
+
+ my $self = shift;
+
+ return $self->{MergedArea};
+}
+
+###############################################################################
+#
+# get_row_heights()
+#
+# Returns an array_ref of row heights.
+#
+sub get_row_heights {
+
+ my $self = shift;
+
+ return @{ $self->{RowHeight} };
+}
+
+###############################################################################
+#
+# get_col_widths()
+#
+# Returns an array_ref of column widths.
+#
+sub get_col_widths {
+
+ my $self = shift;
+
+ return @{ $self->{ColWidth} };
+}
+
+###############################################################################
+#
+# get_default_row_height()
+#
+# Returns the default row height for the worksheet. Generally 12.75.
+#
+sub get_default_row_height {
+
+ my $self = shift;
+
+ return $self->{DefRowHeight};
+}
+
+###############################################################################
+#
+# get_default_col_width()
+#
+# Returns the default column width for the worksheet. Generally 8.43.
+#
+sub get_default_col_width {
+
+ my $self = shift;
+
+ return $self->{DefColWidth};
+}
+
+###############################################################################
+#
+# _get_row_properties()
+#
+# Returns an array_ref of row properties.
+# TODO. This is a placeholder for a future method.
+#
+sub _get_row_properties {
+
+ my $self = shift;
+
+ return $self->{RowProperties};
+}
+
+###############################################################################
+#
+# _get_col_properties()
+#
+# Returns an array_ref of column properties.
+# TODO. This is a placeholder for a future method.
+#
+sub _get_col_properties {
+
+ my $self = shift;
+
+ return $self->{ColProperties};
+}
+
+###############################################################################
+#
+# get_header()
+#
+# Returns the worksheet header string.
+#
+sub get_header {
+
+ my $self = shift;
+
+ return $self->{Header};
+}
+
+###############################################################################
+#
+# get_footer()
+#
+# Returns the worksheet footer string.
+#
+sub get_footer {
+
+ my $self = shift;
+
+ return $self->{Footer};
+}
+
+###############################################################################
+#
+# get_margin_left()
+#
+# Returns the left margin of the worksheet in inches.
+#
+sub get_margin_left {
+
+ my $self = shift;
+
+ return $self->{LeftMargin};
+}
+
+###############################################################################
+#
+# get_margin_right()
+#
+# Returns the right margin of the worksheet in inches.
+#
+sub get_margin_right {
+
+ my $self = shift;
+
+ return $self->{RightMargin};
+}
+
+###############################################################################
+#
+# get_margin_top()
+#
+# Returns the top margin of the worksheet in inches.
+#
+sub get_margin_top {
+
+ my $self = shift;
+
+ return $self->{TopMargin};
+}
+
+###############################################################################
+#
+# get_margin_bottom()
+#
+# Returns the bottom margin of the worksheet in inches.
+#
+sub get_margin_bottom {
+
+ my $self = shift;
+
+ return $self->{BottomMargin};
+}
+
+###############################################################################
+#
+# get_margin_header()
+#
+# Returns the header margin of the worksheet in inches.
+#
+sub get_margin_header {
+
+ my $self = shift;
+
+ return $self->{HeaderMargin};
+}
+
+###############################################################################
+#
+# get_margin_footer()
+#
+# Returns the footer margin of the worksheet in inches.
+#
+sub get_margin_footer {
+
+ my $self = shift;
+
+ return $self->{FooterMargin};
+}
+
+###############################################################################
+#
+# get_paper()
+#
+# Returns the printer paper size.
+#
+sub get_paper {
+
+ my $self = shift;
+
+ return $self->{PaperSize};
+}
+
+###############################################################################
+#
+# get_start_page()
+#
+# Returns the page number that printing will start from.
+#
+sub get_start_page {
+
+ my $self = shift;
+
+ # Only return the page number if the "First page number" option is set.
+ if ( $self->{UsePage} ) {
+ return $self->{PageStart};
+ }
+ else {
+ return 0;
+ }
+}
+
+###############################################################################
+#
+# get_print_order()
+#
+# Returns the Worksheet page printing order.
+#
+sub get_print_order {
+
+ my $self = shift;
+
+ return $self->{LeftToRight};
+}
+
+###############################################################################
+#
+# get_print_scale()
+#
+# Returns the workbook scale for printing.
+#
+sub get_print_scale {
+
+ my $self = shift;
+
+ return $self->{Scale};
+}
+
+###############################################################################
+#
+# get_fit_to_pages()
+#
+# Returns the number of pages wide and high that the printed worksheet page
+# will fit to.
+#
+sub get_fit_to_pages {
+
+ my $self = shift;
+
+ if ( !$self->{PageFit} ) {
+ return ( 0, 0 );
+ }
+ else {
+ return ( $self->{FitWidth}, $self->{FitHeight} );
+ }
+}
+
+###############################################################################
+#
+# is_portrait()
+#
+# Returns true if the worksheet has been set for printing in portrait mode.
+#
+sub is_portrait {
+
+ my $self = shift;
+
+ return $self->{Landscape};
+}
+
+###############################################################################
+#
+# is_centered_horizontally()
+#
+# Returns true if the worksheet has been centered horizontally for printing.
+#
+sub is_centered_horizontally {
+
+ my $self = shift;
+
+ return $self->{HCenter};
+}
+
+###############################################################################
+#
+# is_centered_vertically()
+#
+# Returns true if the worksheet has been centered vertically for printing.
+#
+sub is_centered_vertically {
+
+ my $self = shift;
+
+ return $self->{HCenter};
+}
+
+###############################################################################
+#
+# is_print_gridlines()
+#
+# Returns true if the worksheet print "gridlines" option is turned on.
+#
+sub is_print_gridlines {
+
+ my $self = shift;
+
+ return $self->{PrintGrid};
+}
+
+###############################################################################
+#
+# is_print_row_col_headers()
+#
+# Returns true if the worksheet print "row and column headings" option is on.
+#
+sub is_print_row_col_headers {
+
+ my $self = shift;
+
+ return $self->{PrintHeaders};
+}
+
+###############################################################################
+#
+# is_print_black_and_white()
+#
+# Returns true if the worksheet print "black and white" option is turned on.
+#
+sub is_print_black_and_white {
+
+ my $self = shift;
+
+ return $self->{NoColor};
+}
+
+###############################################################################
+#
+# is_print_draft()
+#
+# Returns true if the worksheet print "draft" option is turned on.
+#
+sub is_print_draft {
+
+ my $self = shift;
+
+ return $self->{Draft};
+}
+
+###############################################################################
+#
+# is_print_comments()
+#
+# Returns true if the worksheet print "comments" option is turned on.
+#
+sub is_print_comments {
+
+ my $self = shift;
+
+ return $self->{Notes};
+}
+
+###############################################################################
+#
+# Mapping between legacy method names and new names.
+#
+{
+ no warnings; # Ignore warnings about variables used only once.
+ *sheetNo = *sheet_num;
+ *Cell = *get_cell;
+ *RowRange = *row_range;
+ *ColRange = *col_range;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+Spreadsheet::ParseExcel::Worksheet - A class for Worksheets.
+
+=head1 SYNOPSIS
+
+See the documentation for L<Spreadsheet::ParseExcel>.
+
+=head1 DESCRIPTION
+
+This module is used in conjunction with Spreadsheet::ParseExcel. See the documentation for Spreadsheet::ParseExcel.
+
+=head1 Methods
+
+The C<Spreadsheet::ParseExcel::Worksheet> class encapsulates the properties of an Excel worksheet. It has the following methods:
+
+ $worksheet->get_cell()
+ $worksheet->row_range()
+ $worksheet->col_range()
+ $worksheet->get_name()
+ $worksheet->get_h_pagebreaks()
+ $worksheet->get_v_pagebreaks()
+ $worksheet->get_merged_areas()
+ $worksheet->get_row_heights()
+ $worksheet->get_col_widths()
+ $worksheet->get_default_row_height()
+ $worksheet->get_default_col_width()
+ $worksheet->get_header()
+ $worksheet->get_footer()
+ $worksheet->get_margin_left()
+ $worksheet->get_margin_right()
+ $worksheet->get_margin_top()
+ $worksheet->get_margin_bottom()
+ $worksheet->get_margin_header()
+ $worksheet->get_margin_footer()
+ $worksheet->get_paper()
+ $worksheet->get_start_page()
+ $worksheet->get_print_order()
+ $worksheet->get_print_scale()
+ $worksheet->get_fit_to_pages()
+ $worksheet->is_portrait()
+ $worksheet->is_centered_horizontally()
+ $worksheet->is_centered_vertically()
+ $worksheet->is_print_gridlines()
+ $worksheet->is_print_row_col_headers()
+ $worksheet->is_print_black_and_white()
+ $worksheet->is_print_draft()
+ $worksheet->is_print_comments()
+
+
+=head2 get_cell($row, $col)
+
+Return the L</Cell> object at row C<$row> and column C<$col> if it is defined. Otherwise returns undef.
+
+ my $cell = $worksheet->get_cell($row, $col);
+
+=head2 row_range()
+
+Returns a two-element list C<($min, $max)> containing the minimum and maximum defined rows in the worksheet. If there is no row defined C<$max> is smaller than C<$min>.
+
+ my ( $row_min, $row_max ) = $worksheet->row_range();
+
+=head2 col_range()
+
+Returns a two-element list C<($min, $max)> containing the minimum and maximum of defined columns in the worksheet. If there is no column defined C<$max> is smaller than C<$min>.
+
+ my ( $col_min, $col_max ) = $worksheet->col_range();
+
+
+=head2 get_name()
+
+The C<get_name()> method returns the name of the worksheet.
+
+ my $name = $worksheet->get_name();
+
+
+=head2 get_h_pagebreaks()
+
+The C<get_h_pagebreaks()> method returns an array ref of row numbers where a horizontal page break occurs.
+
+ my $h_pagebreaks = $worksheet->get_h_pagebreaks();
+
+Returns C<undef> if there are no pagebreaks.
+
+
+=head2 get_v_pagebreaks()
+
+The C<get_v_pagebreaks()> method returns an array ref of column numbers where a vertical page break occurs.
+
+ my $v_pagebreaks = $worksheet->get_v_pagebreaks();
+
+Returns C<undef> if there are no pagebreaks.
+
+
+=head2 get_merged_areas()
+
+The C<get_merged_areas()> method returns an array ref of cells that are merged.
+
+ my $merged_areas = $worksheet->get_merged_areas();
+
+Each merged area is represented as follows:
+
+ [ $start_row, $start_col, $end_row, $end_col]
+
+Returns C<undef> if there are no merged areas.
+
+
+=head2 get_row_heights()
+
+The C<get_row_heights()> method returns an array_ref of row heights.
+
+ my $row_heights = $worksheet->get_row_heights();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_col_widths()
+
+The C<get_col_widths()> method returns an array_ref of column widths.
+
+ my $col_widths = $worksheet->get_col_widths();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_default_row_height()
+
+The C<get_default_row_height()> method returns the default row height for the worksheet. Generally 12.75.
+
+ my $default_row_height = $worksheet->get_default_row_height();
+
+
+=head2 get_default_col_width()
+
+The C<get_default_col_width()> method returns the default column width for the worksheet. Generally 8.43.
+
+ my $default_col_width = $worksheet->get_default_col_width();
+
+
+=head2 get_header()
+
+The C<get_header()> method returns the worksheet header string. This string can contain control codes for alignment and font properties. Refer to the Excel on-line help on headers and footers or to the Spreadsheet::WriteExcel documentation for set_header().
+
+ my $header = $worksheet->get_header();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_footer()
+
+The C<get_footer()> method returns the worksheet footer string. This string can contain control codes for alignment and font properties. Refer to the Excel on-line help on headers and footers or to the Spreadsheet::WriteExcel documentation for set_header().
+
+ my $footer = $worksheet->get_footer();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_margin_left()
+
+The C<get_margin_left()> method returns the left margin of the worksheet in inches.
+
+ my $margin_left = $worksheet->get_margin_left();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_margin_right()
+
+The C<get_margin_right()> method returns the right margin of the worksheet in inches.
+
+ my $margin_right = $worksheet->get_margin_right();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_margin_top()
+
+The C<get_margin_top()> method returns the top margin of the worksheet in inches.
+
+ my $margin_top = $worksheet->get_margin_top();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_margin_bottom()
+
+The C<get_margin_bottom()> method returns the bottom margin of the worksheet in inches.
+
+ my $margin_bottom = $worksheet->get_margin_bottom();
+
+Returns C<undef> if the property isn't set.
+
+
+=head2 get_margin_header()
+
+The C<get_margin_header()> method returns the header margin of the worksheet in inches.
+
+ my $margin_header = $worksheet->get_margin_header();
+
+Returns a default value of 0.5 if not set.
+
+
+=head2 get_margin_footer()
+
+The C<get_margin_footer()> method returns the footer margin of the worksheet in inches.
+
+ my $margin_footer = $worksheet->get_margin_footer();
+
+Returns a default value of 0.5 if not set.
+
+
+=head2 get_paper()
+
+The C<get_paper()> method returns the printer paper size.
+
+ my $paper = $worksheet->get_paper();
+
+The value corresponds to the formats shown below:
+
+ Index Paper format Paper size
+ ===== ============ ==========
+ 0 Printer default -
+ 1 Letter 8 1/2 x 11 in
+ 2 Letter Small 8 1/2 x 11 in
+ 3 Tabloid 11 x 17 in
+ 4 Ledger 17 x 11 in
+ 5 Legal 8 1/2 x 14 in
+ 6 Statement 5 1/2 x 8 1/2 in
+ 7 Executive 7 1/4 x 10 1/2 in
+ 8 A3 297 x 420 mm
+ 9 A4 210 x 297 mm
+ 10 A4 Small 210 x 297 mm
+ 11 A5 148 x 210 mm
+ 12 B4 250 x 354 mm
+ 13 B5 182 x 257 mm
+ 14 Folio 8 1/2 x 13 in
+ 15 Quarto 215 x 275 mm
+ 16 - 10x14 in
+ 17 - 11x17 in
+ 18 Note 8 1/2 x 11 in
+ 19 Envelope 9 3 7/8 x 8 7/8
+ 20 Envelope 10 4 1/8 x 9 1/2
+ 21 Envelope 11 4 1/2 x 10 3/8
+ 22 Envelope 12 4 3/4 x 11
+ 23 Envelope 14 5 x 11 1/2
+ 24 C size sheet -
+ 25 D size sheet -
+ 26 E size sheet -
+ 27 Envelope DL 110 x 220 mm
+ 28 Envelope C3 324 x 458 mm
+ 29 Envelope C4 229 x 324 mm
+ 30 Envelope C5 162 x 229 mm
+ 31 Envelope C6 114 x 162 mm
+ 32 Envelope C65 114 x 229 mm
+ 33 Envelope B4 250 x 353 mm
+ 34 Envelope B5 176 x 250 mm
+ 35 Envelope B6 176 x 125 mm
+ 36 Envelope 110 x 230 mm
+ 37 Monarch 3.875 x 7.5 in
+ 38 Envelope 3 5/8 x 6 1/2 in
+ 39 Fanfold 14 7/8 x 11 in
+ 40 German Std Fanfold 8 1/2 x 12 in
+ 41 German Legal Fanfold 8 1/2 x 13 in
+ 256 User defined
+
+The two most common paper sizes are C<1 = "US Letter"> and C<9 = A4>. Returns 9 by default.
+
+
+=head2 get_start_page()
+
+The C<get_start_page()> method returns the page number that printing will start from.
+
+ my $start_page = $worksheet->get_start_page();
+
+Returns 0 if the property isn't set.
+
+
+=head2 get_print_order()
+
+The C<get_print_order()> method returns 0 if the worksheet print "page order" is "Down then over" (the default) or 1 if it is "Over then down".
+
+ my $print_order = $worksheet->get_print_order();
+
+
+=head2 get_print_scale()
+
+The C<get_print_scale()> method returns the workbook scale for printing. The print scale fctor can be in the range 10 .. 400.
+
+ my $print_scale = $worksheet->get_print_scale();
+
+Returns 100 by default.
+
+
+=head2 get_fit_to_pages()
+
+The C<get_fit_to_pages()> method returns the number of pages wide and high that the printed worksheet page will fit to.
+
+ my ($pages_wide, $pages_high) = $worksheet->get_fit_to_pages();
+
+Returns (0, 0) if the property isn't set.
+
+
+=head2 is_portrait()
+
+The C<is_portrait()> method returns true if the worksheet has been set for printing in portrait mode.
+
+ my $is_portrait = $worksheet->is_portrait();
+
+Returns 0 if the worksheet has been set for printing in horizontal mode.
+
+
+=head2 is_centered_horizontally()
+
+The C<is_centered_horizontally()> method returns true if the worksheet has been centered horizontally for printing.
+
+ my $is_centered_horizontally = $worksheet->is_centered_horizontally();
+
+Returns 0 if the property isn't set.
+
+
+=head2 is_centered_vertically()
+
+The C<is_centered_vertically()> method returns true if the worksheet has been centered vertically for printing.
+
+ my $is_centered_vertically = $worksheet->is_centered_vertically();
+
+Returns 0 if the property isn't set.
+
+
+=head2 is_print_gridlines()
+
+The C<is_print_gridlines()> method returns true if the worksheet print "gridlines" option is turned on.
+
+ my $is_print_gridlines = $worksheet->is_print_gridlines();
+
+Returns 0 if the property isn't set.
+
+
+=head2 is_print_row_col_headers()
+
+The C<is_print_row_col_headers()> method returns true if the worksheet print "row and column headings" option is turned on.
+
+ my $is_print_row_col_headers = $worksheet->is_print_row_col_headers();
+
+Returns 0 if the property isn't set.
+
+
+=head2 is_print_black_and_white()
+
+The C<is_print_black_and_white()> method returns true if the worksheet print "black and white" option is turned on.
+
+ my $is_print_black_and_white = $worksheet->is_print_black_and_white();
+
+Returns 0 if the property isn't set.
+
+
+=head2 is_print_draft()
+
+The C<is_print_draft()> method returns true if the worksheet print "draft" option is turned on.
+
+ my $is_print_draft = $worksheet->is_print_draft();
+
+Returns 0 if the property isn't set.
+
+
+=head2 is_print_comments()
+
+The C<is_print_comments()> method returns true if the worksheet print "comments" option is turned on.
+
+ my $is_print_comments = $worksheet->is_print_comments();
+
+Returns 0 if the property isn't set.
+
+
+=head1 AUTHOR
+
+Maintainer 0.40+: John McNamara jmcnamara@cpan.org
+
+Maintainer 0.27-0.33: Gabor Szabo szabgab@cpan.org
+
+Original author: Kawai Takanori kwitknr@cpan.org
+
+=head1 COPYRIGHT
+
+Copyright (c) 2009-2010 John McNamara
+
+Copyright (c) 2006-2008 Gabor Szabo
+
+Copyright (c) 2000-2006 Kawai Takanori
+
+All rights reserved.
+
+You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.
+
+=cut