File Coverage

blib/lib/GDS2.pm
Criterion Covered Total %
statement 833 1865 44.6
branch 267 864 30.9
condition 78 234 33.3
subroutine 105 252 41.6
pod 130 172 75.5
total 1413 3387 41.7


line stmt bran cond sub pod time code
1             package GDS2;
2             {
3             require 5.010001;
4             $GDS2::VERSION = '3.35';
5             ## Note: '@ ( # )' used by the what command E.g. what GDS2.pm
6             $GDS2::revision = '@(#) $Id: GDS2.pm,v $ $Revision: 3.35 $ $Date: 2017-10-04 03:27:57-06 $';
7             #
8              
9             =pod
10              
11             =head1 NAME
12              
13             GDS2 - GDS2 stream module
14              
15             =head1 SYNOPSIS
16              
17             This is GDS2, a module for creating programs to read and/or write GDS2 files.
18              
19             Send feedback/suggestions to
20             perl -le '$_=q(Zpbhgnpe@pvnt.uxa);$_=~tr/n-sa-gt-zh-mZ/a-zS/;print;'
21              
22             =head1 COPYRIGHT
23              
24             Author: Ken Schumack (c) 1999-2017. All rights reserved.
25             This module is free software. It may be used, redistributed
26             and/or modified under the terms of the Perl Artistic License.
27             ( see http://www.perl.com/pub/a/language/misc/Artistic.html )
28             Have fun, Ken
29              
30             Schumack@cpan.org
31              
32             =head1 DESCRIPTION
33              
34             GDS2 allows you to read and write GDS2 files record by record in a
35             stream fashion which inherently uses little memory. It is capable but
36             not fast. If you have large files you may be happier using the C/C++
37             http://sourceforge.net/projects/gds2/ which can easily be used by Perl.
38              
39             =cut
40              
41             #
42             # Contributor Modification: Toby Schaffer 2004-01-21
43             # returnUnitsAsArray() added which returns user units and database
44             # units as a 2 element array.
45             #
46             # Contributor Modification: Peter Baumbach 2002-01-11
47             # returnRecordAsPerl() was created to facilitate the creation of
48             # parameterized gds2 data with perl. -Years later Andreas Pawlak
49             # pointed out a endian problem that needed to be addressed.
50             #
51             # POD documentation is sprinkled throughout the file in an
52             # attempt at Literate Programming style (which Perl partly supports ...
53             # see http://www.literateprogramming.com/ )
54             # Search for the strings '=head' or run perldoc on this file.
55              
56             # You can run this file through either pod2man or pod2html to produce
57             # documentation in manual or html file format
58              
59 6     6   6618 use strict;
  6         59  
  6         243  
60 6     6   45 use warnings;
  6         16  
  6         436  
61             BEGIN
62             {
63 6     6   46 use constant TRUE => 1;
  6         13  
  6         589  
64 6     6   43 use constant FALSE => 0;
  6         18  
  6         366  
65 6     6   44 use constant UNKNOWN => -1;
  6         19  
  6         471  
66              
67 6     6   45 use constant HAVE_FLOCK => TRUE; ## some systems still may not have this...manually change
  6         14  
  6         393  
68 6     6   49 use Config;
  6         13  
  6         374  
69 6     6   2772 use IO::File;
  6         59763  
  6         933  
70             }
71              
72             if (HAVE_FLOCK)
73             {
74 6     6   64 use Fcntl q(:flock); # import LOCK_* constants
  6         18  
  6         998  
75             }
76              
77 6     6   48 no strict qw( refs );
  6         19  
  6         603  
78              
79             my $isLittleEndian = FALSE; #default - was developed on a BigEndian machine
80             $isLittleEndian = TRUE if ($Config{'byteorder'} =~ m/^1/); ## Linux mswin32 cygwin vms
81              
82             ################################################################################
83             ## GDS2 STREAM RECORD DATATYPES
84 6     6   53 use constant NO_REC_DATA => 0;
  6         21  
  6         623  
85 6     6   50 use constant BIT_ARRAY => 1;
  6         16  
  6         364  
86 6     6   65 use constant INTEGER_2 => 2;
  6         18  
  6         342  
87 6     6   41 use constant INTEGER_4 => 3;
  6         17  
  6         313  
88 6     6   41 use constant REAL_4 => 4; ## NOT supported, should not be found in any GDS2
  6         12  
  6         352  
89 6     6   46 use constant REAL_8 => 5;
  6         19  
  6         334  
90 6     6   46 use constant ACSII_STRING => 6;
  6         14  
  6         483  
91             ################################################################################
92              
93             ################################################################################
94             ## GDS2 STREAM RECORD TYPES
95 6     6   41 use constant HEADER => 0; ## 2-byte Signed Integer
  6         14  
  6         323  
96 6     6   44 use constant BGNLIB => 1; ## 2-byte Signed Integer
  6         14  
  6         303  
97 6     6   39 use constant LIBNAME => 2; ## ASCII String
  6         15  
  6         452  
98 6     6   63 use constant UNITS => 3; ## 8-byte Real
  6         15  
  6         313  
99 6     6   40 use constant ENDLIB => 4; ## no data present
  6         13  
  6         444  
100 6     6   41 use constant BGNSTR => 5; ## 2-byte Signed Integer
  6         14  
  6         336  
101 6     6   40 use constant STRNAME => 6; ## ASCII String
  6         13  
  6         314  
102 6     6   39 use constant ENDSTR => 7; ## no data present
  6         15  
  6         312  
103 6     6   42 use constant BOUNDARY => 8; ## no data present
  6         15  
  6         334  
104 6     6   45 use constant PATH => 9; ## no data present
  6         15  
  6         328  
105 6     6   42 use constant SREF => 10; ## no data present
  6         13  
  6         347  
106 6     6   63 use constant AREF => 11; ## no data present
  6         23  
  6         401  
107 6     6   42 use constant TEXT => 12; ## no data present
  6         15  
  6         339  
108 6     6   42 use constant LAYER => 13; ## 2-byte Signed Integer
  6         17  
  6         447  
109 6     6   39 use constant DATATYPE => 14; ## 2-byte Signed Integer
  6         13  
  6         311  
110 6     6   40 use constant WIDTH => 15; ## 4-byte Signed Integer
  6         14  
  6         293  
111 6     6   40 use constant XY => 16; ## 2-byte Signed Integer
  6         14  
  6         337  
112 6     6   41 use constant ENDEL => 17; ## no data present
  6         20  
  6         314  
113 6     6   42 use constant SNAME => 18; ## ASCII String
  6         14  
  6         342  
114 6     6   52 use constant COLROW => 19; ## 2 2-byte Signed Integer
  6         30  
  6         302  
115 6     6   39 use constant TEXTNODE => 20; ## no data present
  6         14  
  6         365  
116 6     6   40 use constant NODE => 21; ## no data present
  6         14  
  6         310  
117 6     6   39 use constant TEXTTYPE => 22; ## 2-byte Signed Integer
  6         13  
  6         361  
118 6     6   37 use constant PRESENTATION => 23; ## Bit Array
  6         16  
  6         318  
119 6     6   42 use constant SPACING => 24; ## discontinued
  6         15  
  6         342  
120 6     6   76 use constant STRING => 25; ## ASCII String
  6         126  
  6         361  
121 6     6   41 use constant STRANS => 26; ## Bit Array
  6         17  
  6         352  
122 6     6   40 use constant MAG => 27; ## 8-byte Real
  6         39  
  6         334  
123 6     6   43 use constant ANGLE => 28; ## 8-byte Real
  6         12  
  6         327  
124 6     6   41 use constant UINTEGER => 29; ## UNKNOWN User int, used only in Calma V2.0
  6         14  
  6         511  
125 6     6   42 use constant USTRING => 30; ## UNKNOWN User string, used only in Calma V2.0
  6         16  
  6         314  
126 6     6   41 use constant REFLIBS => 31; ## ASCII String
  6         14  
  6         393  
127 6     6   45 use constant FONTS => 32; ## ASCII String
  6         14  
  6         312  
128 6     6   42 use constant PATHTYPE => 33; ## 2-byte Signed Integer
  6         14  
  6         321  
129 6     6   69 use constant GENERATIONS => 34; ## 2-byte Signed Integer
  6         14  
  6         456  
130 6     6   48 use constant ATTRTABLE => 35; ## ASCII String
  6         20  
  6         325  
131 6     6   38 use constant STYPTABLE => 36; ## ASCII String "Unreleased feature"
  6         19  
  6         1209  
132 6     6   1054 use constant STRTYPE => 37; ## 2-byte Signed Integer "Unreleased feature"
  6         1013  
  6         3189  
133 6     6   46 use constant EFLAGS => 38; ## BIT_ARRAY Flags for template and exterior data. bits 15 to 0, l to r 0=template,
  6         12  
  6         277  
134             ## 1=external data, others unused
135 6     6   38 use constant ELKEY => 39; ## INTEGER_4 "Unreleased feature"
  6         14  
  6         273  
136 6     6   38 use constant LINKTYPE => 40; ## UNKNOWN "Unreleased feature"
  6         12  
  6         274  
137 6     6   37 use constant LINKKEYS => 41; ## UNKNOWN "Unreleased feature"
  6         12  
  6         261  
138 6     6   36 use constant NODETYPE => 42; ## INTEGER_2 Nodetype specification. On Calma this could be 0 to 63, GDSII allows 0 to 255.
  6         10  
  6         255  
139             ## Of course a 2 byte integer allows up to 65535...
140 6     6   41 use constant PROPATTR => 43; ## INTEGER_2 Property number.
  6         12  
  6         309  
141 6     6   106 use constant PROPVALUE => 44; ## STRING Property value. On GDSII, 128 characters max, unless an SREF, AREF, or NODE,
  6         13  
  6         296  
142             ## which may have 512 characters.
143 6     6   38 use constant BOX => 45; ## NO_DATA The beginning of a BOX element.
  6         14  
  6         293  
144 6     6   34 use constant BOXTYPE => 46; ## INTEGER_2 Boxtype specification.
  6         12  
  6         413  
145 6     6   40 use constant PLEX => 47; ## INTEGER_4 Plex number and plexhead flag. The least significant bit of the most significant
  6         193  
  6         293  
146             ## byte is the plexhead flag.
147 6     6   40 use constant BGNEXTN => 48; ## INTEGER_4 Path extension beginning for pathtype 4 in Calma CustomPlus. In database units,
  6         12  
  6         305  
148             ## may be negative.
149 6     6   40 use constant ENDEXTN => 49; ## INTEGER_4 Path extension end for pathtype 4 in Calma CustomPlus. In database units, may be negative.
  6         11  
  6         350  
150 6     6   321 use constant TAPENUM => 50; ## INTEGER_2 Tape number for multi-reel stream file.
  6         12  
  6         341  
151 6     6   47 use constant TAPECODE => 51; ## INTEGER_2 Tape code to verify that the reel is from the proper set. 12 bytes that are
  6         14  
  6         362  
152             ## supposed to form a unique tape code.
153 6     6   40 use constant STRCLASS => 52; ## BIT_ARRAY Calma use only.
  6         15  
  6         459  
154 6     6   34 use constant RESERVED => 53; ## INTEGER_4 Used to be NUMTYPES per Calma GDSII Stream Format Manual, v6.0.
  6         13  
  6         275  
155 6     6   36 use constant FORMAT => 54; ## INTEGER_2 Archive or Filtered flag. 0: Archive 1: filtered
  6         11  
  6         351  
156 6     6   47 use constant MASK => 55; ## STRING Only in filtered streams. Layers and datatypes used for mask in a filtered
  6         74  
  6         313  
157             ## stream file. A string giving ranges of layers and datatypes separated by a semicolon.
158             ## There may be more than one mask in a stream file.
159 6     6   39 use constant ENDMASKS => 56; ## NO_DATA The end of mask descriptions.
  6         11  
  6         281  
160 6     6   37 use constant LIBDIRSIZE => 57; ## INTEGER_2 Number of pages in library director, a GDSII thing, it seems to have only been
  6         10  
  6         383  
161             ## used when Calma INFORM was creating a new library.
162 6     6   35 use constant SRFNAME => 58; ## STRING Calma "Sticks"(c) rule file name.
  6         10  
  6         285  
163 6     6   40 use constant LIBSECUR => 59; ## INTEGER_2 Access control list stuff for CalmaDOS, ancient. INFORM used this when creating
  6         12  
  6         403  
164             ## a new library. Had 1 to 32 entries with group numbers, user numbers and access rights.
165             #################################################################################################
166 6     6   39 use vars '$StrSpace';
  6         11  
  6         369  
167 6     6   52 use vars '$ElmSpace';
  6         10  
  6         126929  
168             $StrSpace='';
169             $ElmSpace='';
170              
171             my %RecordTypeNumbers=(
172             'HEADER' => HEADER,
173             'BGNLIB' => BGNLIB,
174             'LIBNAME' => LIBNAME,
175             'UNITS' => UNITS,
176             'ENDLIB' => ENDLIB,
177             'BGNSTR' => BGNSTR,
178             'STRNAME' => STRNAME,
179             'ENDSTR' => ENDSTR,
180             'BOUNDARY' => BOUNDARY,
181             'PATH' => PATH,
182             'SREF' => SREF,
183             'AREF' => AREF,
184             'TEXT' => TEXT,
185             'LAYER' => LAYER,
186             'DATATYPE' => DATATYPE,
187             'WIDTH' => WIDTH,
188             'XY' => XY,
189             'ENDEL' => ENDEL,
190             'SNAME' => SNAME,
191             'COLROW' => COLROW,
192             'TEXTNODE' => TEXTNODE,
193             'NODE' => NODE,
194             'TEXTTYPE' => TEXTTYPE,
195             'PRESENTATION'=> PRESENTATION,
196             'SPACING' => SPACING,
197             'STRING' => STRING,
198             'STRANS' => STRANS,
199             'MAG' => MAG,
200             'ANGLE' => ANGLE,
201             'UINTEGER' => UINTEGER,
202             'USTRING' => USTRING,
203             'REFLIBS' => REFLIBS,
204             'FONTS' => FONTS,
205             'PATHTYPE' => PATHTYPE,
206             'GENERATIONS' => GENERATIONS,
207             'ATTRTABLE' => ATTRTABLE,
208             'STYPTABLE' => STYPTABLE,
209             'STRTYPE' => STRTYPE,
210             'EFLAGS' => EFLAGS,
211             'ELKEY' => ELKEY,
212             'LINKTYPE' => LINKTYPE,
213             'LINKKEYS' => LINKKEYS,
214             'NODETYPE' => NODETYPE,
215             'PROPATTR' => PROPATTR,
216             'PROPVALUE' => PROPVALUE,
217             'BOX' => BOX,
218             'BOXTYPE' => BOXTYPE,
219             'PLEX' => PLEX,
220             'BGNEXTN' => BGNEXTN,
221             'ENDEXTN' => ENDEXTN,
222             'TAPENUM' => TAPENUM,
223             'TAPECODE' => TAPECODE,
224             'STRCLASS' => STRCLASS,
225             'RESERVED' => RESERVED,
226             'FORMAT' => FORMAT,
227             'MASK' => MASK,
228             'ENDMASKS' => ENDMASKS,
229             'LIBDIRSIZE' => LIBDIRSIZE,
230             'SRFNAME' => SRFNAME,
231             'LIBSECUR' => LIBSECUR,
232             );
233              
234             my @RecordTypeStrings=( ## for ascii print of GDS
235             'HEADER',
236             'BGNLIB',
237             'LIBNAME',
238             'UNITS',
239             'ENDLIB',
240             'BGNSTR',
241             'STRNAME',
242             'ENDSTR',
243             'BOUNDARY',
244             'PATH',
245             'SREF',
246             'AREF',
247             'TEXT',
248             'LAYER',
249             'DATATYPE',
250             'WIDTH',
251             'XY',
252             'ENDEL',
253             'SNAME',
254             'COLROW',
255             'TEXTNODE',
256             'NODE',
257             'TEXTTYPE',
258             'PRESENTATION',
259             'SPACING',
260             'STRING',
261             'STRANS',
262             'MAG',
263             'ANGLE',
264             'UINTEGER',
265             'USTRING',
266             'REFLIBS',
267             'FONTS',
268             'PATHTYPE',
269             'GENERATIONS',
270             'ATTRTABLE',
271             'STYPTABLE',
272             'STRTYPE',
273             'EFLAGS',
274             'ELKEY',
275             'LINKTYPE',
276             'LINKKEYS',
277             'NODETYPE',
278             'PROPATTR',
279             'PROPVALUE',
280             'BOX',
281             'BOXTYPE',
282             'PLEX',
283             'BGNEXTN',
284             'ENDEXTN',
285             'TAPENUM',
286             'TAPECODE',
287             'STRCLASS',
288             'RESERVED',
289             'FORMAT',
290             'MASK',
291             'ENDMASKS',
292             'LIBDIRSIZE',
293             'SRFNAME',
294             'LIBSECUR',
295             );
296             my @CompactRecordTypeStrings=( ## for compact ascii print of GDS (GDT format) see http://sourceforge.net/projects/gds2/
297             'gds2{', #HEADER
298             '', #BGNLIB
299             'lib', #LIBNAME
300             '', #UNITS
301             '}', #ENDLIB
302             'cell{', #BGNSTR
303             '', #STRNAME
304             '}', #ENDSTR
305             'b{', #BOUNDARY
306             'p{', #PATH
307             's{', #SREF
308             'a{', #AREF
309             't{', #TEXT
310             '', #LAYER
311             ' dt', #DATATYPE
312             ' w', #WIDTH
313             ' xy(', #XY #)
314             '}', #ENDEL
315             '', #SNAME
316             ' cr', #COLROW
317             ' tn', #TEXTNODE
318             ' no', #NODE
319             ' tt', #TEXTTYPE
320             '', #PRESENTATION'
321             ' sp', #SPACING
322             '', #STRING
323             '', #STRANS
324             ' m', #MAG
325             ' a', #ANGLE
326             ' ui', #UINTEGER
327             ' us', #USTRING
328             ' rl', #REFLIBS
329             ' f', #FONTS
330             ' pt', #PATHTYPE
331             ' gen', #GENERATIONS
332             ' at', #ATTRTABLE
333             ' st', #STYPTABLE
334             ' strt', #STRTYPE
335             ' ef', #EFLAGS
336             ' ek', #ELKEY
337             ' lt', #LINKTYPE
338             ' lk', #LINKKEYS
339             ' nt', #NODETYPE
340             ' ptr', #PROPATTR
341             ' pv', #PROPVALUE
342             ' bx', #BOX
343             ' bt', #BOXTYPE
344             ' px', #PLEX
345             ' bx', #BGNEXTN
346             ' ex', #ENDEXTN
347             ' tnum', #TAPENUM
348             ' tcode', #TAPECODE
349             ' strc', #STRCLASS
350             ' resv', #RESERVED
351             ' fmt', #FORMAT
352             ' msk', #MASK
353             ' emsk', #ENDMASKS
354             ' lds', #LIBDIRSIZE
355             ' srfn', #SRFNAME
356             ' libs', #LIBSECUR
357             );
358              
359             ###################################################
360             my %RecordTypeData=(
361             'HEADER' => INTEGER_2,
362             'BGNLIB' => INTEGER_2,
363             'LIBNAME' => ACSII_STRING,
364             'UNITS' => REAL_8,
365             'ENDLIB' => NO_REC_DATA,
366             'BGNSTR' => INTEGER_2,
367             'STRNAME' => ACSII_STRING,
368             'ENDSTR' => NO_REC_DATA,
369             'BOUNDARY' => NO_REC_DATA,
370             'PATH' => NO_REC_DATA,
371             'SREF' => NO_REC_DATA,
372             'AREF' => NO_REC_DATA,
373             'TEXT' => NO_REC_DATA,
374             'LAYER' => INTEGER_2,
375             'DATATYPE' => INTEGER_2,
376             'WIDTH' => INTEGER_4,
377             'XY' => INTEGER_4,
378             'ENDEL' => NO_REC_DATA,
379             'SNAME' => ACSII_STRING,
380             'COLROW' => INTEGER_2,
381             'TEXTNODE' => NO_REC_DATA,
382             'NODE' => NO_REC_DATA,
383             'TEXTTYPE' => INTEGER_2,
384             'PRESENTATION' => BIT_ARRAY,
385             'SPACING' => UNKNOWN, #INTEGER_4, discontinued
386             'STRING' => ACSII_STRING,
387             'STRANS' => BIT_ARRAY,
388             'MAG' => REAL_8,
389             'ANGLE' => REAL_8,
390             'UINTEGER' => UNKNOWN, #INTEGER_4, no longer used
391             'USTRING' => UNKNOWN, #ACSII_STRING, no longer used
392             'REFLIBS' => ACSII_STRING,
393             'FONTS' => ACSII_STRING,
394             'PATHTYPE' => INTEGER_2,
395             'GENERATIONS' => INTEGER_2,
396             'ATTRTABLE' => ACSII_STRING,
397             'STYPTABLE' => ACSII_STRING, # unreleased feature
398             'STRTYPE' => INTEGER_2, #INTEGER_2, unreleased feature
399             'EFLAGS' => BIT_ARRAY,
400             'ELKEY' => INTEGER_4, #INTEGER_4, unreleased feature
401             'LINKTYPE' => INTEGER_2, #unreleased feature
402             'LINKKEYS' => INTEGER_4, #unreleased feature
403             'NODETYPE' => INTEGER_2,
404             'PROPATTR' => INTEGER_2,
405             'PROPVALUE' => ACSII_STRING,
406             'BOX' => NO_REC_DATA,
407             'BOXTYPE' => INTEGER_2,
408             'PLEX' => INTEGER_4,
409             'BGNEXTN' => INTEGER_4,
410             'ENDEXTN' => INTEGER_4,
411             'TAPENUM' => INTEGER_2,
412             'TAPECODE' => INTEGER_2,
413             'STRCLASS' => UNKNOWN,
414             'RESERVED' => INTEGER_4,
415             'FORMAT' => INTEGER_2,
416             'MASK' => ACSII_STRING,
417             'ENDMASKS' => NO_REC_DATA,
418             'LIBDIRSIZE' => UNKNOWN, #INTEGER_2
419             'SRFNAME' => ACSII_STRING,
420             'LIBSECUR' => UNKNOWN, #INTEGER_2,
421             );
422              
423             # This is the default class for the GDS2 object to use when all else fails.
424             $GDS2::DefaultClass = 'GDS2' unless defined $GDS2::DefaultClass;
425              
426             my $G_gdtString="";
427             my $G_epsilon="0.001"; ## to take care of floating point representation problems
428             my $G_fltLen=3;
429             { #it's own name space...
430             my $fltLenTmp = sprintf("%0.99f",(1.0/3.0)); $fltLenTmp=~s/^0.(3+).*/$1/; $fltLenTmp = length($fltLenTmp) - 10;
431             if ($fltLenTmp > length($G_epsilon)) # try to make smaller if we can...
432             {
433             $G_epsilon = sprintf("%0.${fltLenTmp}f1",0);
434             $G_fltLen = $fltLenTmp;
435             }
436             }
437             $G_epsilon *= 1; #ensure it's a number
438              
439             ################################################################################
440              
441             =head1 Examples
442              
443             Layer change:
444             here's a bare bones script to change all layer 59 to 66 given a file to
445             read and a new file to create.
446             #!/usr/bin/perl -w
447             use strict;
448             use GDS2;
449             my $fileName1 = $ARGV[0];
450             my $fileName2 = $ARGV[1];
451             my $gds2File1 = new GDS2(-fileName => $fileName1);
452             my $gds2File2 = new GDS2(-fileName => ">$fileName2");
453             while (my $record = $gds2File1 -> readGds2Record)
454             {
455             if ($gds2File1 -> returnLayer == 59)
456             {
457             $gds2File2 -> printLayer(-num=>66);
458             }
459             else
460             {
461             $gds2File2 -> printRecord(-data=>$record);
462             }
463             }
464              
465              
466             Gds2 dump:
467             here's a complete program to dump the contents of a stream file.
468             #!/usr/bin/perl -w
469             use GDS2;
470             $\="\n";
471             my $gds2File = new GDS2(-fileName=>$ARGV[0]);
472             while ($gds2File -> readGds2Record)
473             {
474             print $gds2File -> returnRecordAsString;
475             }
476              
477              
478             Gds2 dump in GDT format: which is smaller and easier to parse - http://sourceforge.net/projects/gds2/
479             #!/usr/bin/perl -w
480             use GDS2;
481             my $gds2File = new GDS2(-fileName=>$ARGV[0]);
482             while ($gds2File -> readGds2Record)
483             {
484             print $gds2File -> returnRecordAsString(-compact=>1);
485             }
486              
487             Dump from the command line of a bzip2 compressed file:
488             perl -MGDS2 -MFileHandle -MIPC::Open3 -e '$f1=new FileHandle;$f0=new FileHandle;open3($f0,$f1,$f1,"bzcat test.gds.bz2");$gds=new GDS2(-fileHandle=>$f1);while($gds->readGds2Record){print $gds->returnRecordAsString(-compact=>1)}'
489              
490             Create a complete GDS2 stream file from scratch:
491             #!/usr/bin/perl -w
492             use GDS2;
493             my $gds2File = new GDS2(-fileName=>'>test.gds');
494             $gds2File -> printInitLib(-name=>'testlib');
495             $gds2File -> printBgnstr(-name=>'test');
496             $gds2File -> printPath(
497             -layer=>6,
498             -pathType=>0,
499             -width=>2.4,
500             -xy=>[0,0, 10.5,0, 10.5,3.3],
501             );
502             $gds2File -> printSref(
503             -name=>'contact',
504             -xy=>[4,5.5],
505             );
506             $gds2File -> printAref(
507             -name=>'contact',
508             -columns=>2,
509             -rows=>3,
510             -xy=>[0,0, 10,0, 0,15],
511             );
512             $gds2File -> printEndstr;
513             $gds2File -> printBgnstr(-name => 'contact');
514             $gds2File -> printBoundary(
515             -layer=>10,
516             -xy=>[0,0, 1,0, 1,1, 0,1],
517             );
518             $gds2File -> printEndstr;
519             $gds2File -> printEndlib();
520              
521             ################################################################################
522              
523             =head1 METHODS
524              
525             =head2 new - open gds2 file
526              
527             usage:
528             my $gds2File = new GDS2(-fileName => "filename.gds2"); ## to read
529             my $gds2File2 = new GDS2(-fileName => ">filename.gds2"); ## to write
530              
531             -or- provide your own fileHandle:
532              
533             my $gds2File = new GDS2(-fileHandle => $fh); ## e.g. to attach to a compression/decompression pipe
534              
535             =cut
536              
537             sub new
538             {
539 8     8 1 4001580 my($class,%arg) = @_;
540 8         33 my $self = {};
541 8   33     60 bless $self,$class || ref $class || $GDS2::DefaultClass;
542              
543 8         27 my $fileName = $arg{'-fileName'};
544 8 50       35 $fileName = "" unless (defined $fileName);
545              
546 8         25 my $fileHandle = $arg{'-fileHandle'};
547 8 50       44 $fileHandle = "" unless (defined $fileHandle);
548              
549 8 50 33     65 if ($fileName && $fileHandle)
550             {
551 0         0 die "new expects a gds2 file name -OR- a file handle. Do not give both.";
552             }
553 8 50 33     53 unless ($fileName || $fileHandle)
554             {
555 0         0 die "new expects a -fileName => 'name' OR and -fileHandle => fh $!";
556             }
557 8         25 my $lockMode = LOCK_SH; ## default
558 8 50       31 if ($fileName)
559             {
560 8         36 my $openModStr = substr($fileName,0,2); ### looking for > or >>
561 8         45 $openModStr =~ s|^\s+||;
562 8         72 $openModStr =~ s|[^\+>]+||g;
563 8         23 my $openModeNum = O_RDONLY;
564 8 50       44 if ($openModStr =~ m|^\+|)
565             {
566 0         0 warn("Ignoring '+' in open mode"); ## not handling this yet...
567 0         0 $openModStr =~ s|\++||;
568             }
569 8 100       51 if ($openModStr eq '>')
    50          
570             {
571 5         16 $openModeNum = O_WRONLY|O_CREAT;
572 5         15 $lockMode = LOCK_EX;
573 5         82 $fileName =~ s|^$openModStr||;
574             }
575             elsif ($openModStr eq '>>')
576             {
577 0         0 $openModeNum = O_WRONLY|O_APPEND;
578 0         0 $lockMode = LOCK_EX;
579 0         0 $fileName =~ s|^$openModStr||;
580             }
581 8         95 $fileHandle = new IO::File;
582 8 50       558 $fileHandle -> open("$fileName",$openModeNum) or die "Unable to open $fileName because $!";
583 8         900 if (HAVE_FLOCK)
584             {
585 8 50       94 flock($fileHandle,$lockMode) or die "File lock on $fileName failed because $!";
586             }
587             }
588 8         34 my $resolution = $arg{'-resolution'};
589 8 50       31 unless (defined $resolution)
590             {
591 8         21 $resolution=1000;
592             }
593 8 50 33     101 die "new expects a positive integer resolution. ($resolution) $!" if (($resolution <= 0) || ($resolution !~ m|^\d+$|));
594 8         59 binmode $fileHandle,':raw';
595 8         77 $self -> {'Fd'} = $fileHandle -> fileno;
596 8         104 $self -> {'FileHandle'} = $fileHandle;
597 8         28 $self -> {'FileName'} = $fileName; ## the gds2 filename
598 8         28 $self -> {'BytesDone'} = 0; ## total file size so far
599 8         25 $self -> {'EOLIB'} = FALSE; ## end of library flag
600 8         25 $self -> {'INHEADER'} = UNKNOWN; ## in header? flag TRUE | FALSE | UNKNOWN
601 8         25 $self -> {'INDATA'} = FALSE; ## in data? flag TRUE | FALSE
602 8         38 $self -> {'Length'} = 0; ## length of data
603 8         66 $self -> {'DataType'} = UNKNOWN; ## one of 7 gds datatypes
604 8         28 $self -> {'UUnits'} = -1.0; ## for gds2 file e.g. 0.001
605 8         27 $self -> {'DBUnits'} = -1.0; ## for gds2 file e.g. 1e-9
606 8         24 $self -> {'Record'} = ''; ## the whole record as found in gds2 file
607 8         26 $self -> {'RecordType'} = UNKNOWN;
608 8         22 $self -> {'DataIndex'} = 0;
609 8         25 $self -> {'RecordData'} = ();
610 8         35 $self -> {'CurrentDataList'} = '';
611 8         24 $self -> {'InBoundary'} = FALSE; ##
612 8         22 $self -> {'InTxt'} = FALSE; ##
613 8         32 $self -> {'DateFld'} = 0; ##
614 8         25 $self -> {'Resolution'} = $resolution;
615 8         22 $self -> {'UsingPrettyPrint'} = FALSE; ## print as string ...
616 8         42 $self;
617             }
618             ################################################################################
619              
620             #######
621             #private method to check how accurately users perl can do math
622             sub getG_epsilon
623             {
624 4     4 0 37 my($self,%arg) = @_;
625 4         15 $G_epsilon;
626             }
627             ################################################################################
628              
629             #######
630             #private method to check how accurately users perl can do math
631             sub getG_fltLen
632             {
633 4     4 0 32 my($self,%arg) = @_;
634 4         19 $G_fltLen;
635             }
636             ################################################################################
637              
638             #######
639             #private method to report Endianness
640             sub endianness
641             {
642 2     2 0 69 my($self,%arg) = @_;
643 2         9 $isLittleEndian;
644             }
645             ################################################################################
646              
647             #######
648             #private method to clean up number
649             sub cleanExpNum($)
650             {
651 3     3 0 10 my $num = shift;
652 3         40 $num = sprintf("%0.${G_fltLen}e",$num);
653 3         16 $num =~ s/([1-9])0+e/$1e/;
654 3         38 $num =~ s/(\d)\.0+e/$1e/;
655 3         15 $num;
656             }
657             ################################################################################
658              
659             #######
660             #private method to clean up number
661             sub cleanFloatNum($)
662             {
663 189     189 0 354 my $num = shift;
664 189         1119 $num = sprintf("%0.${G_fltLen}f",$num);
665 189         1070 $num =~ s/([1-9])0+$/$1/;
666 189         542 $num =~ s/(\d)\.0+$/$1/;
667 189         521 $num;
668             }
669             ################################################################################
670              
671             =head2 fileNum - file number...
672              
673             usage:
674              
675             =cut
676              
677             sub fileNum
678             {
679 0     0 1 0 my($self,%arg) = @_;
680 0         0 int($self -> {'Fd'});
681             }
682             ################################################################################
683              
684             =head2 close - close gds2 file
685              
686             usage:
687             $gds2File -> close;
688             -or-
689             $gds2File -> close(-markEnd=>1); ## -- some systems have trouble closing files
690             $gds2File -> close(-pad=>2048); ## -- pad end with \0's till file size is a
691             ## multiple of number. Note: old reel to reel tapes on Calma
692             ## systems used 2048 byte blocks
693              
694             =cut
695              
696             sub close
697             {
698 5     5 1 57 my($self,%arg) = @_;
699 5         18 my $markEnd = $arg{'-markEnd'};
700 5         19 my $pad = $arg{'-pad'};
701 5 50 33     36 if ((defined $markEnd)&&($markEnd))
702             {
703 0         0 my $fh = $self -> {'FileHandle'};
704 0         0 print $fh "\x1a\x04"; # a ^Z and a ^D
705 0         0 $self -> {'BytesDone'} += 2;
706             }
707 5 100 66     40 if ((defined $pad)&&($pad > 0))
708             {
709 1         4 my $fh = $self -> {'FileHandle'};
710 1         2074 $fh -> flush;
711 1         12 seek($fh,0,SEEK_END);
712 1         4 my $fileSize = tell($fh);
713 1         3 my $padSize = $pad - ($fileSize % $pad);
714 1 50       6 $padSize=0 if ($padSize == $pad);
715 1         5 for (my $i=0; $i < $padSize; $i++)
716             {
717 1702         2380 print $fh "\0"; ## a null
718             }
719             }
720 5         96 $self -> {'FileHandle'} -> close;
721             }
722             ################################################################################
723              
724             ################################################################################
725              
726             =head1 High Level Write Methods
727              
728             =cut
729              
730             ################################################################################
731              
732             =head2 printInitLib() - Does all the things needed to start a library, writes HEADER,BGNLIB,LIBNAME,and UNITS records
733              
734             The default is to create a library with a default unit of 1 micron that has a resolution of 1000. To get this set uUnit to 0.001 (1/1000) and the dbUnit to 1/1000th of a micron (1e-9).
735             usage:
736             $gds2File -> printInitLib(-name => "testlib", ## required
737             -isoDate => 0|1 ## (optional) use ISO 4 digit date 2001 vs 101
738             -uUnit => real number ## (optional) default is 0.001
739             -dbUnit => real number ## (optional) default is 1e-9
740             );
741              
742             ## defaults to current date for library date
743              
744             note:
745             remember to close library with printEndlib()
746              
747             =cut
748              
749             sub printInitLib
750             {
751 2     2 1 35 my($self,%arg) = @_;
752 2         10 my $libName = $arg{'-name'};
753 2 50       13 unless (defined $libName)
754             {
755 0         0 die "printInitLib expects a library name. Missing -name => 'name' $!";
756             }
757             #################################################
758 2         7 my $isoDate = $arg{'-isoDate'};
759 2 50       11 if (! defined $isoDate)
    0          
760             {
761 2         7 $isoDate = FALSE;
762             }
763             elsif ($isoDate != 0)
764             {
765 0         0 $isoDate = TRUE;
766             }
767              
768             #################################################
769 2         8 my $uUnit = $arg{'-uUnit'};
770 2 50       10 if (! defined $uUnit)
771             {
772 2         7 $uUnit = 0.001;
773             }
774             else
775             {
776 0         0 $self -> {'Resolution'} = cleanFloatNum(1 / $uUnit); ## default is 1000 - already set in new()
777             }
778 2         8 $self -> {'UUnits'} = $uUnit;
779              
780             #################################################
781 2         6 my $dbUnit = $arg{'-dbUnit'};
782 2 50       13 $dbUnit = 1e-9 unless (defined $dbUnit);
783 2         8 $self -> {'DBUnits'} = $dbUnit;
784             #################################################
785              
786 2         108 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
787 2         9 $mon++;
788 2 50       13 $year += 1900 if ($isoDate); ## Cadence likes year left "as is". GDS format supports year number up to 65535 -- 101 vs 2001
789 2         22 $self -> printGds2Record(-type => 'HEADER',-data => 3); ## GDS2 HEADER
790 2         19 $self -> printGds2Record(-type => 'BGNLIB',-data => [$year,$mon,$mday,$hour,$min,$sec,$year,$mon,$mday,$hour,$min,$sec]);
791 2         16 $self -> printGds2Record(-type => 'LIBNAME',-data => $libName);
792 2         14 $self -> printGds2Record(-type => 'UNITS',-data => [$uUnit,$dbUnit]);
793             }
794             ################################################################################
795              
796             =head2 printBgnstr - Does all the things needed to start a structure definition
797              
798             usage:
799             $gds2File -> printBgnstr(-name => "nand3" ## writes BGNSTR and STRNAME records
800             -isoDate => 1|0 ## (optional) use ISO 4 digit date 2001 vs 101
801             );
802              
803             note:
804             remember to close with printEndstr()
805              
806             =cut
807              
808             sub printBgnstr
809             {
810 4     4 1 47 my($self,%arg) = @_;
811              
812 4         15 my $strName = $arg{'-name'};
813 4 50       22 unless (defined $strName)
814             {
815 0         0 die "bgnStr expects a structure name. Missing -name => 'name' $!";
816             }
817 4         11 my $createTime = $arg{'-createTime'};
818 4         11 my $isoDate = $arg{'-isoDate'};
819 4 50       98 if (! defined $isoDate)
    0          
820             {
821 4         14 $isoDate = FALSE;
822             }
823             elsif ($isoDate != 0)
824             {
825 0         0 $isoDate = TRUE;
826             }
827 4         12 my ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst);
828 4 50       16 if (defined $createTime)
829             {
830 0         0 ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = localtime($createTime);
831             }
832             else
833             {
834 4         120 ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = localtime(time);
835             }
836 4         16 $cmon++;
837              
838 4         12 my $modTime = $arg{'-modTime'};
839 4         12 my ($msec,$mmin,$mhour,$mmday,$mmon,$myear,$mwday,$myday,$misdst);
840 4 50       16 if (defined $modTime)
841             {
842 0         0 ($msec,$mmin,$mhour,$mmday,$mmon,$myear,$mwday,$myday,$misdst) = localtime($modTime);
843             }
844             else
845             {
846 4         61 ($msec,$mmin,$mhour,$mmday,$mmon,$myear,$mwday,$myday,$misdst) = localtime(time);
847             }
848 4         13 $mmon++;
849              
850 4 50       17 if ($isoDate)
851             {
852 0         0 $cyear += 1900; ## 2001 vs 101
853 0         0 $myear += 1900;
854             }
855 4         31 $self -> printGds2Record(-type => 'BGNSTR',-data => [$cyear,$cmon,$cmday,$chour,$cmin,$csec,$myear,$mmon,$mmday,$mhour,$mmin,$msec]);
856 4         27 $self -> printGds2Record(-type => 'STRNAME',-data => $strName);
857             }
858             ################################################################################
859              
860             =head2 printPath - prints a gds2 path
861              
862             usage:
863             $gds2File -> printPath(
864             -layer=>#,
865             -dataType=>#, ##optional
866             -pathType=>#,
867             -width=>#.#,
868             -unitWidth=>#, ## (optional) directly specify width in data base units (vs -width which is multipled by resolution)
869              
870             -xy=>\@array, ## array of reals
871             # -or-
872             -xyInt=>\@array, ## array of internal ints (optional -wks better if you are modifying an existing GDS2 file)
873             );
874              
875             note:
876             layer defaults to 0 if -layer not used
877             pathType defaults to 0 if -pathType not used
878             pathType 0 = square end
879             1 = round end
880             2 = square - extended 1/2 width
881             4 = custom plus variable path extension...
882             width defaults to 0.0 if -width not used
883              
884             =cut
885              
886             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
887             # ::= PATH [ELFLAGS] [PLEX] LAYER DATATYPE [PATHTYPE] [WIDTH] XY
888             sub printPath
889             {
890 2     2 1 38 my($self,%arg) = @_;
891 2         10 my $resolution = $self -> {'Resolution'};
892 2         7 my $layer = $arg{'-layer'};
893 2 50       10 $layer=0 unless ( defined $layer);
894              
895 2         4 my $dataType = $arg{'-dataType'};
896 2 50       10 $dataType=0 unless (defined $dataType);
897              
898 2         5 my $pathType = $arg{'-pathType'};
899 2 50       16 $pathType=0 unless (defined $pathType);
900              
901 2         6 my $bgnExtn = $arg{'-bgnExtn'};
902 2 50       9 $bgnExtn=0 unless (defined $bgnExtn);
903              
904 2         8 my $endExtn = $arg{'-endExtn'};
905 2 50       8 $endExtn=0 unless (defined $endExtn);
906              
907 2         6 my $unitWidth = $arg{'-unitWidth'};
908 2         4 my $widthReal = $arg{'-width'};
909 2         7 my $width = 0;
910 2 50 33     10 if ((defined $unitWidth)&&($unitWidth >= 0))
911             {
912 0         0 $width=int($unitWidth);
913             }
914 2 50 33     19 if ((defined $widthReal)&&($widthReal >= 0.0))
915             {
916 2         15 $width = int(($widthReal*$resolution)+$G_epsilon);
917             }
918             #### -xyInt most useful if reading and modifying... -xy if creating from scratch
919 2         7 my $xyInt = $arg{'-xyInt'}; ## $xyInt should be a reference to an array of internal GDS2 format integers
920 2         5 my $xy = $arg{'-xy'}; ## $xy should be a reference to an array of reals
921 2         8 my @xyTmp=(); ##don't pollute array passed in
922 2 50 33     12 if (! ((defined $xy) || (defined $xyInt)))
923             {
924 0         0 die "printPath expects an xy array reference. Missing -xy => \\\@array $!";
925             }
926 2 50       22 if (defined $xyInt)
927             {
928 0         0 $xy = $xyInt;
929 0         0 $resolution=1;
930             }
931 2         12 $self -> printGds2Record(-type => 'PATH');
932 2         13 $self -> printGds2Record(-type => 'LAYER',-data => $layer);
933 2         14 $self -> printGds2Record(-type => 'DATATYPE',-data => $dataType);
934 2 50       9 $self -> printGds2Record(-type => 'PATHTYPE',-data => $pathType) if ($pathType);
935 2 50       17 $self -> printGds2Record(-type => 'WIDTH',-data => $width) if ($width);
936 2 50       12 if ($pathType == 4)
937             {
938 0         0 $self -> printGds2Record(-type => 'BGNEXTN',-data => $bgnExtn); ## int used with resolution
939 0         0 $self -> printGds2Record(-type => 'ENDEXTN',-data => $endExtn); ## int used with resolution
940             }
941 2         14 for(my $i=0;$i<=$#$xy;$i++) ## e.g. 3.4 in -> 3400 out
942             {
943 12 50       42 if ($xy -> [$i] >= 0) { push @xyTmp,int((($xy -> [$i])*$resolution)+$G_epsilon);}
  12         51  
944 0         0 else { push @xyTmp,int((($xy -> [$i])*$resolution)-$G_epsilon);}
945             }
946 2 50 33     23 if ($bgnExtn || $endExtn) ## we have to convert
947             {
948 0         0 my $bgnX1 = $xyTmp[0];
949 0         0 my $bgnY1 = $xyTmp[1];
950 0         0 my $bgnX2 = $xyTmp[2];
951 0         0 my $bgnY2 = $xyTmp[3];
952 0         0 my $endX1 = $xyTmp[$#xyTmp - 1];
953 0         0 my $endY1 = $xyTmp[$#xyTmp];
954 0         0 my $endX2 = $xyTmp[$#xyTmp - 3];
955 0         0 my $endY2 = $xyTmp[$#xyTmp - 2];
956 0 0       0 if ($bgnExtn)
957             {
958 0 0       0 if ($bgnX1 == $bgnX2) #vertical ...modify 1st Y
    0          
959             {
960 0 0       0 if ($bgnY1 < $bgnY2) ## points down
961             {
962 0         0 $xyTmp[1] -= $bgnExtn;
963 0 0       0 $xyTmp[1] += int($width/2) if ($pathType != 0);
964             }
965             else ## points up
966             {
967 0         0 $xyTmp[1] += $bgnExtn;
968 0 0       0 $xyTmp[1] -= int($width/2) if ($pathType != 0);
969             }
970             }
971             elsif ($bgnY1 == $bgnY2) #horizontal ...modify 1st X
972             {
973 0 0       0 if ($bgnX1 < $bgnX2) ## points left
974             {
975 0         0 $xyTmp[0] -= $bgnExtn;
976 0 0       0 $xyTmp[0] += int($width/2) if ($pathType != 0);
977             }
978             else ## points up
979             {
980 0         0 $xyTmp[0] += $bgnExtn;
981 0 0       0 $xyTmp[0] -= int($width/2) if ($pathType != 0);
982             }
983             }
984             }
985              
986 0 0       0 if ($endExtn)
987             {
988 0 0       0 if ($endX1 == $endX2) #vertical ...modify last Y
    0          
989             {
990 0 0       0 if ($endY1 < $endY2) ## points down
991             {
992 0         0 $xyTmp[$#xyTmp] -= $endExtn;
993 0 0       0 $xyTmp[$#xyTmp] += int($width/2) if ($pathType != 0);
994             }
995             else ## points up
996             {
997 0         0 $xyTmp[$#xyTmp] += $endExtn;
998 0 0       0 $xyTmp[$#xyTmp] -= int($width/2) if ($pathType != 0);
999             }
1000             }
1001             elsif ($endY1 == $endY2) #horizontal ...modify last X
1002             {
1003 0 0       0 if ($endX1 < $endX2) ## points left
1004             {
1005 0         0 $xyTmp[$#xyTmp - 1] -= $endExtn;
1006 0 0       0 $xyTmp[$#xyTmp - 1] += int($width/2) if ($pathType != 0);
1007             }
1008             else ## points up
1009             {
1010 0         0 $xyTmp[$#xyTmp - 1] += $endExtn;
1011 0 0       0 $xyTmp[$#xyTmp - 1] -= int($width/2) if ($pathType != 0);
1012             }
1013             }
1014             }
1015             }
1016 2         17 $self -> printGds2Record(-type => 'XY',-data => \@xyTmp);
1017 2         15 $self -> printGds2Record(-type => 'ENDEL');
1018             }
1019             ################################################################################
1020              
1021             =head2 printBoundary - prints a gds2 boundary
1022              
1023             usage:
1024             $gds2File -> printBoundary(
1025             -layer=>#,
1026             -dataType=>#,
1027              
1028             -xy=>\@array, ## ref to array of reals
1029             # -or-
1030             -xyInt=>\@array, ## ref to array of internal ints (optional -wks better if you are modifying an existing GDS2 file)
1031             );
1032              
1033             note:
1034             layer defaults to 0 if -layer not used
1035             dataType defaults to 0 if -dataType not used
1036              
1037             =cut
1038              
1039             # ::= BOUNDARY [ELFLAGS] [PLEX] LAYER DATATYPE XY
1040             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1041             sub printBoundary
1042             {
1043 2     2 1 30 my($self,%arg) = @_;
1044 2         10 my $resolution = $self -> {'Resolution'};
1045 2         6 my $layer = $arg{'-layer'};
1046 2 50       10 $layer = 0 unless (defined $layer);
1047 2         6 my $dataType = $arg{'-dataType'};
1048 2 50       12 $dataType=0 unless (defined $dataType);
1049             #### -xyInt most useful if reading and modifying... -xy if creating from scratch
1050 2         7 my $xyInt = $arg{'-xyInt'}; ## $xyInt should be a reference to an array of internal GDS2 format integers
1051 2         7 my $xy = $arg{'-xy'}; ## $xy should be a reference to an array of reals
1052 2         18 my @xyTmp = (); ##don't pollute array passed in
1053 2 50 33     12 unless (defined($xy) || defined($xyInt))
1054             {
1055 0         0 die "printBoundary expects an xy array reference. Missing -xy => \\\@array $!";
1056             }
1057 2 50       10 if (defined $xyInt)
1058             {
1059 0         0 $xy = $xyInt;
1060 0         0 $resolution=1;
1061             }
1062 2         14 $self -> printGds2Record(-type => 'BOUNDARY');
1063 2         16 $self -> printGds2Record(-type => 'LAYER',-data => $layer);
1064 2         16 $self -> printGds2Record(-type => 'DATATYPE',-data => $dataType);
1065 2 50       17 if (my $numPoints=$#$xy+1 < 6)
1066             {
1067 0         0 die "printBoundary expects an xy array of at leasts 3 coordinates $!";
1068             }
1069 2         14 for(my $i=0;$i<=$#$xy;$i++) ## e.g. 3.4 in -> 3400 out
1070             {
1071 16 50       49 if ($xy -> [$i] >= 0) {push @xyTmp,int((($xy -> [$i])*$resolution)+$G_epsilon);}
  16         70  
1072 0         0 else {push @xyTmp,int((($xy -> [$i])*$resolution)-$G_epsilon);}
1073             }
1074             ## gds expects square to have 5 coords (closure)
1075 2 50 33     40 if (($xy -> [0] != ($xy -> [($#$xy - 1)])) || ($xy -> [1] != ($xy -> [$#$xy])))
1076             {
1077 2 50       9 if ($xy -> [0] >= 0) {push @xyTmp,int((($xy -> [0])*$resolution)+$G_epsilon);}
  2         14  
1078 0         0 else {push @xyTmp,int((($xy -> [0])*$resolution)-$G_epsilon);}
1079 2 50       11 if ($xy -> [1] >= 0) {push @xyTmp,int((($xy -> [1])*$resolution)+$G_epsilon);}
  2         11  
1080 0         0 else {push @xyTmp,int((($xy -> [1])*$resolution)-$G_epsilon);}
1081             }
1082 2         14 $self -> printGds2Record(-type => 'XY',-data => \@xyTmp);
1083 2         21 $self -> printGds2Record(-type => 'ENDEL');
1084             }
1085             ################################################################################
1086              
1087             =head2 printSref - prints a gds2 Structure REFerence
1088              
1089             usage:
1090             $gds2File -> printSref(
1091             -name=>string, ## Name of structure
1092              
1093             -xy=>\@array, ## ref to array of reals
1094             # -or-
1095             -xyInt=>\@array, ## ref to array of internal ints (optional -wks better than -xy if you are modifying an existing GDS2 file)
1096              
1097             -angle=>#.#, ## (optional) Default is 0.0
1098             -mag=>#.#, ## (optional) Default is 1.0
1099             -reflect=>0|1 ## (optional)
1100             );
1101              
1102             note:
1103             best not to specify angle or mag if not needed
1104              
1105             =cut
1106              
1107             #::= SREF [ELFLAGS] [PLEX] SNAME [] XY
1108             # ::= STRANS [MAG] [ANGLE]
1109             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1110             sub printSref
1111             {
1112 2     2 1 34 my($self,%arg) = @_;
1113 2         9 my $useSTRANS=FALSE;
1114 2         7 my $resolution = $self -> {'Resolution'};
1115 2         8 my $sname = $arg{'-name'};
1116 2 50       12 unless (defined $sname)
1117             {
1118 0         0 die "printSref expects a name string. Missing -name => 'text' $!";
1119             }
1120             #### -xyInt most useful if reading and modifying... -xy if creating from scratch
1121 2         6 my $xyInt = $arg{'-xyInt'}; ## $xyInt should be a reference to an array of internal GDS2 format integers
1122 2         6 my $xy = $arg{'-xy'}; ## $xy should be a reference to an array of reals
1123 2 50 33     11 unless (defined($xy) || defined($xyInt))
1124             {
1125 0         0 die "printSref expects an xy array reference. Missing -xy => \\\@array $!";
1126             }
1127 2 50       16 if (defined $xyInt)
1128             {
1129 0         0 $xy = $xyInt;
1130 0         0 $resolution=1;
1131             }
1132 2         14 $self -> printGds2Record(-type => 'SREF');
1133 2         17 $self -> printGds2Record(-type => 'SNAME',-data => $sname);
1134 2         6 my $reflect = $arg{'-reflect'};
1135 2 50 33     21 if ((! defined $reflect)||($reflect <= 0))
1136             {
1137 2         8 $reflect = 0;
1138             }
1139             else
1140             {
1141 0         0 $reflect = 1;
1142 0         0 $useSTRANS = TRUE;
1143             }
1144 2         8 my $mag = $arg{'-mag'};
1145 2 50 33     24 if ((! defined $mag)||($mag <= 0))
1146             {
1147 2         7 $mag=0;
1148             }
1149             else
1150             {
1151 0         0 $mag = cleanFloatNum($mag);
1152 0         0 $useSTRANS=TRUE;
1153             }
1154 2         6 my $angle = $arg{'-angle'};
1155 2 50       10 if (! defined $angle)
1156             {
1157 2         5 $angle = -1; #not really... just means not specified
1158             }
1159             else
1160             {
1161 0         0 $angle = posAngle($angle);
1162 0         0 $useSTRANS = TRUE;
1163             }
1164 2 50       11 if ($useSTRANS)
1165             {
1166 0         0 my $data = $reflect.'0'x15; ## 16 'bit' string
1167 0         0 $self -> printGds2Record(-type => 'STRANS',-data => $data);
1168 0 0       0 $self -> printGds2Record(-type => 'MAG',-data => $mag) if ($mag);
1169 0 0       0 $self -> printGds2Record(-type => 'ANGLE',-data => $angle) if ($angle >= 0);
1170             }
1171 2         7 my @xyTmp=(); ##don't pollute array passed in
1172 2         14 for(my $i=0;$i<=$#$xy;$i++) ## e.g. 3.4 in -> 3400 out
1173             {
1174 4 50       16 if ($xy -> [$i] >= 0) {push @xyTmp,int((($xy -> [$i])*$resolution)+$G_epsilon);}
  4         26  
1175 0         0 else {push @xyTmp,int((($xy -> [$i])*$resolution)-$G_epsilon);}
1176             }
1177 2         13 $self -> printGds2Record(-type => 'XY',-data => \@xyTmp);
1178 2         13 $self -> printGds2Record(-type => 'ENDEL');
1179             }
1180             ################################################################################
1181              
1182             =head2 printAref - prints a gds2 Array REFerence
1183              
1184             usage:
1185             $gds2File -> printAref(
1186             -name=>string, ## Name of structure
1187             -columns=>#, ## Default is 1
1188             -rows=>#, ## Default is 1
1189              
1190             -xy=>\@array, ## ref to array of reals
1191             # -or-
1192             -xyInt=>\@array, ## ref to array of internal ints (optional -wks better if you are modifying an existing GDS2 file)
1193              
1194             -angle=>#.#, ## (optional) Default is 0.0
1195             -mag=>#.#, ## (optional) Default is 1.0
1196             -reflect=>0|1 ## (optional)
1197             );
1198              
1199             note:
1200             best not to specify angle or mag if not needed
1201             xyList: 1st coord: origin, 2nd coord: X of col * xSpacing + origin, 3rd coord: Y of row * ySpacing + origin
1202              
1203             =cut
1204              
1205             #::= AREF [ELFLAGS] [PLEX] SNAME [] COLROW XY
1206             # ::= STRANS [MAG] [ANGLE]
1207             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
1208             sub printAref
1209             {
1210 2     2 1 37 my($self,%arg) = @_;
1211 2         14 my $useSTRANS=FALSE;
1212 2         22 my $resolution = $self -> {'Resolution'};
1213 2         8 my $sname = $arg{'-name'};
1214 2 50       10 unless (defined $sname)
1215             {
1216 0         0 die "printAref expects a sname string. Missing -name => 'text' $!";
1217             }
1218             #### -xyInt most useful if reading and modifying... -xy if creating from scratch
1219 2         7 my $xyInt = $arg{'-xyInt'}; ## $xyInt should be a reference to an array of internal GDS2 format integers
1220 2         7 my $xy = $arg{'-xy'}; ## $xy should be a reference to an array of reals
1221 2 50 33     18 unless (defined($xy) || defined($xyInt))
1222             {
1223 0         0 die "printAref expects an xy array reference. Missing -xy => \\\@array $!";
1224             }
1225 2 50       11 if (defined $xyInt)
1226             {
1227 0         0 $xy = $xyInt;
1228 0         0 $resolution=1;
1229             }
1230 2         16 $self -> printGds2Record(-type => 'AREF');
1231 2         14 $self -> printGds2Record(-type => 'SNAME',-data => $sname);
1232 2         8 my $reflect = $arg{'-reflect'};
1233 2 50 33     15 if ((! defined $reflect)||($reflect <= 0))
1234             {
1235 2         6 $reflect = 0;
1236             }
1237             else
1238             {
1239 0         0 $reflect = 1;
1240 0         0 $useSTRANS=TRUE;
1241             }
1242 2         6 my $mag = $arg{'-mag'};
1243 2 50 33     12 if ((! defined $mag)||($mag <= 0))
1244             {
1245 2         7 $mag = 0;
1246             }
1247             else
1248             {
1249 0         0 $mag = cleanFloatNum($mag);
1250 0         0 $useSTRANS=TRUE;
1251             }
1252 2         7 my $angle = $arg{'-angle'};
1253 2 50       8 if (! defined $angle)
1254             {
1255 2         6 $angle = -1; #not really... just means not specified
1256             }
1257             else
1258             {
1259 0         0 $angle = posAngle($angle);
1260 0         0 $useSTRANS = TRUE;
1261             }
1262 2 50       8 if ($useSTRANS)
1263             {
1264 0         0 my $data=$reflect.'0'x15; ## 16 'bit' string
1265 0         0 $self -> printGds2Record(-type => 'STRANS',-data => $data);
1266 0 0       0 $self -> printGds2Record(-type => 'MAG',-data => $mag) if ($mag);
1267 0 0       0 $self -> printGds2Record(-type => 'ANGLE',-data => $angle) if ($angle >= 0);
1268             }
1269 2         8 my $columns = $arg{'-columns'};
1270 2 50 33     20 if ((! defined $columns)||($columns <= 0))
1271             {
1272 0         0 $columns=1;
1273             }
1274             else
1275             {
1276 2         7 $columns = int($columns);
1277             }
1278 2         6 my $rows = $arg{'-rows'};
1279 2 50 33     20 if ((! defined $rows)||($rows <= 0))
1280             {
1281 0         0 $rows=1;
1282             }
1283             else
1284             {
1285 2         8 $rows = int($rows);
1286             }
1287 2         15 $self -> printGds2Record(-type => 'COLROW',-data => [$columns,$rows]);
1288 2         8 my @xyTmp=(); ##don't pollute array passed in
1289 2         15 for(my $i=0;$i<=$#$xy;$i++) ## e.g. 3.4 in -> 3400 out
1290             {
1291 8 50       30 if ($xy -> [$i] >= 0) {push @xyTmp,int((($xy -> [$i])*$resolution)+$G_epsilon);}
  8         39  
1292 0         0 else {push @xyTmp,int((($xy -> [$i])*$resolution)-$G_epsilon);}
1293             }
1294 2         21 $self -> printGds2Record(-type => 'XY',-data => \@xyTmp);
1295 2         14 $self -> printGds2Record(-type => 'ENDEL');
1296             }
1297             ################################################################################
1298              
1299             =head2 printText - prints a gds2 Text
1300              
1301             usage:
1302             $gds2File -> printText(
1303             -string=>string,
1304             -layer=>#, ## Default is 0
1305             -textType=>#, ## Default is 0
1306             -font=>#, ## 0-3
1307             -top, or -middle, -bottom, ##optional vertical presentation
1308             -left, or -center, or -right, ##optional horizontal presentation
1309              
1310             -xy=>\@array, ## ref to array of reals
1311             # -or-
1312             -xyInt=>\@array, ## ref to array of internal ints (optional -wks better if you are modifying an existing GDS2 file)
1313              
1314             -x=>#.#, ## optional way of passing in x value
1315             -y=>#.#, ## optional way of passing in y value
1316             -angle=>#.#, ## (optional) Default is 0.0
1317             -mag=>#.#, ## (optional) Default is 1.0
1318             -reflect=>#, ## (optional) Default is 0
1319             );
1320              
1321             note:
1322             best not to specify reflect, angle or mag if not needed
1323              
1324             =cut
1325              
1326             #::= TEXT [ELFLAGS] [PLEX] LAYER
1327             # ::= TEXTTYPE [PRESENTATION] [PATHTYPE] [WIDTH] [] XY STRING
1328             # ::= STRANS [MAG] [ANGLE]
1329             ################################################################################
1330             sub printText
1331             {
1332 0     0 1 0 my($self,%arg) = @_;
1333 0         0 my $useSTRANS = FALSE;
1334 0         0 my $string = $arg{'-string'};
1335 0 0       0 unless (defined $string)
1336             {
1337 0         0 die "printText expects a string. Missing -string => 'text' $!";
1338             }
1339 0         0 my $resolution = $self -> {'Resolution'};
1340 0         0 my $x = $arg{'-x'};
1341 0         0 my $y = $arg{'-y'};
1342             #### -xyInt most useful if reading and modifying... -xy if creating from scratch
1343 0         0 my $xyInt = $arg{'-xyInt'}; ## $xyInt should be a reference to an array of internal GDS2 format integers
1344 0         0 my $xy = $arg{'-xy'}; ## $xy should be a reference to an array of reals
1345 0 0       0 if (defined $xyInt)
1346             {
1347 0         0 $xy = $xyInt;
1348 0         0 $resolution=1;
1349             }
1350 0 0       0 if (defined $xy)
1351             {
1352 0         0 $x = $xy -> [0];
1353 0         0 $y = $xy -> [1];
1354             }
1355              
1356 0         0 my $x2 = $arg{'-x'};
1357 0 0       0 if (defined $x2)
1358             {
1359 0         0 $x = $x2;
1360             }
1361 0 0       0 unless (defined $x)
1362             {
1363 0         0 die "printText expects a x coord. Missing -xy=>\@array or -x => 'num' $!";
1364             }
1365 0 0       0 if ($x>=0) {$x = int(($x*$resolution)+$G_epsilon);}
  0         0  
1366 0         0 else {$x = int(($x*$resolution)-$G_epsilon);}
1367              
1368 0         0 my $y2 = $arg{'-y'};
1369 0 0       0 if (defined $y2)
1370             {
1371 0         0 $y = $y2;
1372             }
1373 0 0       0 unless (defined $y)
1374             {
1375 0         0 die "printText expects a y coord. Missing -xy=>\@array or -y => 'num' $!";
1376             }
1377 0 0       0 if ($y>=0) {$y = int(($y*$resolution)+$G_epsilon);}
  0         0  
1378 0         0 else {$y = int(($y*$resolution)-$G_epsilon);}
1379              
1380 0         0 my $layer = $arg{'-layer'};
1381 0 0       0 $layer = 0 unless (defined $layer);
1382 0         0 my $textType = $arg{'-textType'};
1383 0 0       0 $textType=0 unless (defined $textType);
1384 0         0 my $reflect = $arg{'-reflect'};
1385 0 0 0     0 if ((! defined $reflect)||($reflect <= 0))
1386             {
1387 0         0 $reflect = 0;
1388             }
1389             else
1390             {
1391 0         0 $reflect = 1;
1392 0         0 $useSTRANS = TRUE;
1393             }
1394              
1395 0         0 my $font = $arg{'-font'};
1396 0 0 0     0 if ((! defined $font) || ($font < 0) || ($font > 3))
      0        
1397             {
1398 0         0 $font = 0;
1399             }
1400 0         0 $font = sprintf("%02d",$font);
1401              
1402 0         0 my $vertical;
1403 0         0 my $top = $arg{'-top'};
1404 0         0 my $middle = $arg{'-middle'};
1405 0         0 my $bottom = $arg{'-bottom'};
1406 0 0       0 if (defined $top) {$vertical = '00';}
  0 0       0  
1407 0         0 elsif (defined $bottom) {$vertical = '10';}
1408 0         0 else {$vertical = '01';} ## middle
1409 0         0 my $horizontal;
1410 0         0 my $left = $arg{'-left'};
1411 0         0 my $center = $arg{'-center'};
1412 0         0 my $right = $arg{'-right'};
1413 0 0       0 if (defined $left) {$horizontal = '00';}
  0 0       0  
1414 0         0 elsif (defined $right) {$horizontal = '10';}
1415 0         0 else {$horizontal = '01';} ## center
1416 0         0 my $presString = '0'x10;
1417 0         0 $presString .= "$font$vertical$horizontal";
1418              
1419 0         0 my $mag = $arg{'-mag'};
1420 0 0 0     0 if ((! defined $mag)||($mag <= 0))
1421             {
1422 0         0 $mag=0;
1423             }
1424             else
1425             {
1426 0         0 $mag = cleanFloatNum($mag);
1427             }
1428 0         0 my $angle = $arg{'-angle'};
1429 0 0       0 if (! defined $angle)
1430             {
1431 0         0 $angle = -1; #not really... just means not specified
1432             }
1433             else
1434             {
1435 0         0 $angle=posAngle($angle);
1436             }
1437 0         0 $self -> printGds2Record(-type=>'TEXT');
1438 0         0 $self -> printGds2Record(-type=>'LAYER',-data=>$layer);
1439 0         0 $self -> printGds2Record(-type=>'TEXTTYPE',-data=>$textType);
1440 0 0 0     0 $self -> printGds2Record(-type => 'PRESENTATION',-data => $presString) if (defined $font || defined $top || defined $middle || defined $bottom || defined $bottom || defined $left || defined $center || defined $right);
      0        
      0        
      0        
      0        
      0        
      0        
1441 0 0       0 if ($useSTRANS)
1442             {
1443 0         0 my $data=$reflect.'0'x15; ## 16 'bit' string
1444 0         0 $self -> printGds2Record(-type=>'STRANS',-data=>$data);
1445             }
1446 0 0       0 $self -> printGds2Record(-type=>'MAG',-data=>$mag) if ($mag);
1447 0 0       0 $self -> printGds2Record(-type=>'ANGLE',-data=>$angle) if ($angle >= 0);
1448 0         0 $self -> printGds2Record(-type=>'XY',-data=>[$x,$y]);
1449 0         0 $self -> printGds2Record(-type=>'STRING',-data=>$string);
1450 0         0 $self -> printGds2Record(-type=>'ENDEL');
1451             }
1452             ################################################################################
1453              
1454             =head1 Low Level Generic Write Methods
1455              
1456             =cut
1457              
1458             ################################################################################
1459              
1460             =head2 saveGds2Record() - low level method to create a gds2 record given record type
1461             and data (if required). Data of more than one item should be given as a list.
1462              
1463             NOTE: THIS ONLY USES GDS2 OBJECT TO GET RESOLUTION
1464              
1465             usage:
1466             saveGds2Record(
1467             -type=>string,
1468             -data=>data_If_Needed, ##optional for some types
1469             -scale=>#.#, ##optional number to scale data to. I.E -scale=>0.5 #default is NOT to scale
1470             -snap=>#.#, ##optional number to snap data to I.E. -snap=>0.005 #default is 1 resolution unit, typically 0.001
1471             );
1472              
1473             examples:
1474             my $gds2File = new GDS2(-fileName => ">$fileName");
1475             my $record = $gds2File -> saveGds2Record(-type=>'header',-data=>3);
1476             $gds2FileOut -> printGds2Record(-type=>'record',-data=>$record);
1477              
1478              
1479             =cut
1480              
1481             sub saveGds2Record
1482             {
1483 0     0 1 0 my ($self,%arg) = @_;
1484 0         0 my $record = '';
1485              
1486 0         0 my $type = $arg{'-type'};
1487 0 0       0 if (! defined $type)
1488             {
1489 0         0 die "saveGds2Record expects a type name. Missing -type => 'name' $!";
1490             }
1491             else
1492             {
1493 0         0 $type = uc $type;
1494             }
1495              
1496 0         0 my $saveEnd = $\;
1497 0         0 $\ = '';
1498              
1499 0         0 my @data = $arg{'-data'};
1500 0         0 my $dataString = $arg{'-asciiData'};
1501 0 0 0     0 die "saveGds2Record can not handle both -data and -asciiData options $!" if ((defined $dataString)&&((defined $data[0])&&($data[0] ne '')));
      0        
1502              
1503 0         0 my $data = '';
1504 0 0       0 if ($type eq 'RECORD') ## special case...
1505             {
1506 0         0 return $data[0];
1507             }
1508             else
1509             {
1510 0         0 my $numDataElements = 0;
1511 0         0 my $resolution = $self -> {'Resolution'};
1512              
1513 0         0 my $scale = $arg{'-scale'};
1514 0 0       0 if (! defined $scale)
1515             {
1516 0         0 $scale = 1;
1517             }
1518 0 0       0 if ($scale <= 0)
1519             {
1520 0         0 die "saveGds2Record expects a positive scale -scale => $scale $!";
1521             }
1522              
1523 0         0 my $snap = $arg{'-snap'};
1524 0 0       0 if (! defined $snap) ## default is one resolution unit
1525             {
1526 0         0 $snap = 1;
1527             }
1528             else
1529             {
1530 0         0 $snap = $snap*$resolution; ## i.e. 0.001 -> 1
1531             }
1532 0 0       0 if ($snap < 1)
1533             {
1534 0         0 die "saveGds2Record expects a snap >= 1/resolution -snap => $snap $!";
1535             }
1536              
1537 0 0 0     0 if ((defined $data[0])&&($data[0] ne ''))
1538             {
1539 0         0 $data = $data[0];
1540 0         0 $numDataElements = @$data;
1541 0 0       0 if ($numDataElements) ## passed in anonymous array
1542             {
1543 0         0 @data = @$data; ## deref
1544             }
1545             else
1546             {
1547 0         0 $numDataElements = @data;
1548             }
1549             }
1550              
1551 0         0 my $recordDataType = $RecordTypeData{$type};
1552 0 0       0 if (defined $dataString)
1553             {
1554 0         0 $dataString =~ s|^\s+||; ## clean-up
1555 0         0 $dataString =~ s|\s+$||;
1556 0 0       0 $dataString =~ s|\s+| |g if ($dataString !~ m|'|); ## don't compress spaces in strings...
1557 0         0 $dataString =~ s|'$||; #'for strings
1558 0         0 $dataString =~ s|^'||; #'for strings
1559 0 0 0     0 if (($recordDataType == BIT_ARRAY)||($recordDataType == ACSII_STRING))
1560             {
1561 0         0 $data = $dataString;
1562             }
1563             else
1564             {
1565 0         0 $dataString =~ s|\s*[\s,;:/\\]+\s*| |g; ## incase commas etc... (non-std) were added by hand
1566 0         0 @data = split(' ',$dataString);
1567 0         0 $numDataElements = @data;
1568 0 0       0 if ($recordDataType == INTEGER_4)
1569             {
1570 0         0 my @xyTmp = ();
1571 0         0 for(my $i=0;$i<$numDataElements;$i++) ## e.g. 3.4 in -> 3400 out
1572             {
1573 0 0       0 if ($data[$i]>=0) {push @xyTmp,int((($data[$i])*$resolution)+$G_epsilon);}
  0         0  
1574 0         0 else {push @xyTmp,int((($data[$i])*$resolution)-$G_epsilon);}
1575             }
1576 0         0 @data=@xyTmp;
1577             }
1578             }
1579             }
1580 0         0 my $byte;
1581 0         0 my $length = 0;
1582 0 0       0 if ($recordDataType == BIT_ARRAY)
    0          
    0          
    0          
    0          
1583             {
1584 0         0 $length = 2;
1585             }
1586             elsif ($recordDataType == INTEGER_2)
1587             {
1588 0         0 $length = 2 * $numDataElements;
1589             }
1590             elsif ($recordDataType == INTEGER_4)
1591             {
1592 0         0 $length = 4 * $numDataElements;
1593             }
1594             elsif ($recordDataType == REAL_8)
1595             {
1596 0         0 $length = 8 * $numDataElements;
1597             }
1598             elsif ($recordDataType == ACSII_STRING)
1599             {
1600 0         0 my $slen = length $data;
1601 0         0 $length = $slen + ($slen % 2); ## needs to be an even number
1602             }
1603              
1604 0         0 my $recordLength = pack 'S',($length + 4); #1 2 bytes for length 3rd for recordType 4th for dataType
1605 0         0 $record .= $recordLength;
1606 0         0 my $recordType = pack 'C',$RecordTypeNumbers{$type};
1607 0         0 $record .= $recordType;
1608              
1609 0         0 my $dataType = pack 'C',$RecordTypeData{$type};
1610 0         0 $record .= $dataType;
1611              
1612 0 0       0 if ($recordDataType == BIT_ARRAY) ## bit array
    0          
    0          
    0          
    0          
1613             {
1614 0         0 my $bitLength = $length * 8;
1615 0         0 $record .= pack("B$bitLength",$data);
1616             }
1617             elsif ($recordDataType == INTEGER_2) ## 2 byte signed integer
1618             {
1619 0         0 foreach my $num (@data)
1620             {
1621 0         0 $record .= pack('s',$num);
1622             }
1623             }
1624             elsif ($recordDataType == INTEGER_4) ## 4 byte signed integer
1625             {
1626 0         0 foreach my $num (@data)
1627             {
1628 0 0       0 $num = scaleNum($num,$scale) if ($scale != 1);
1629 0 0       0 $num = snapNum($num,$snap) if ($snap != 1);
1630 0         0 $record .= pack('i',$num);
1631             }
1632             }
1633             elsif ($recordDataType == REAL_8) ## 8 byte real
1634             {
1635 0         0 foreach my $num (@data)
1636             {
1637 0         0 my $real = $num;
1638 0         0 my $negative = FALSE;
1639 0 0       0 if($num < 0.0)
1640             {
1641 0         0 $negative = TRUE;
1642 0         0 $real = 0 - $num;
1643             }
1644              
1645 0         0 my $exponent = 0;
1646 0         0 while($real >= 1.0)
1647             {
1648 0         0 $exponent++;
1649 0         0 $real = ($real / 16.0);
1650             }
1651              
1652 0 0       0 if ($real != 0)
1653             {
1654 0         0 while($real < 0.0625)
1655             {
1656 0         0 --$exponent;
1657 0         0 $real = ($real * 16.0);
1658             }
1659             }
1660              
1661 0 0       0 if($negative) { $exponent += 192; }
  0         0  
1662 0         0 else { $exponent += 64; }
1663 0         0 $record .= pack('C',$exponent);
1664              
1665 0         0 for (my $i=1; $i<=7; $i++)
1666             {
1667 0 0       0 if ($real>=0) {$byte = int(($real*256.0)+$G_epsilon);}
  0         0  
1668 0         0 else {$byte = int(($real*256.0)-$G_epsilon);}
1669 0         0 $record .= pack('C',$byte);
1670 0         0 $real = $real * 256.0 - ($byte + 0.0);
1671             }
1672             }
1673             }
1674             elsif ($recordDataType == ACSII_STRING) ## ascii string (null padded)
1675             {
1676 0         0 $record .= pack("a$length",$data);
1677             }
1678             }
1679 0         0 $\=$saveEnd;
1680 0         0 $record;
1681             }
1682             ################################################################################
1683              
1684             =head2 printGds2Record() - low level method to print a gds2 record given record type
1685             and data (if required). Data of more than one item should be given as a list.
1686              
1687             usage:
1688             printGds2Record(
1689             -type=>string,
1690             -data=>data_If_Needed, ##optional for some types
1691             -scale=>#.#, ##optional number to scale data to. I.E -scale=>0.5 #default is NOT to scale
1692             -snap=>#.#, ##optional number to snap data to I.E. -snap=>0.005 #default is 1 resolution unit, typically 0.001
1693             );
1694              
1695             examples:
1696             my $gds2File = new GDS2(-fileName => ">$fileName");
1697              
1698             $gds2File -> printGds2Record(-type=>'header',-data=>3);
1699             $gds2File -> printGds2Record(-type=>'bgnlib',-data=>[99,12,1,22,33,0,99,12,1,22,33,9]);
1700             $gds2File -> printGds2Record(-type=>'libname',-data=>"testlib");
1701             $gds2File -> printGds2Record(-type=>'units',-data=>[0.001, 1e-9]);
1702             $gds2File -> printGds2Record(-type=>'bgnstr',-data=>[99,12,1,22,33,0,99,12,1,22,33,9]);
1703             ...
1704             $gds2File -> printGds2Record(-type=>'endstr');
1705             $gds2File -> printGds2Record(-type=>'endlib');
1706              
1707             Note: the special record type of 'record' can be used to copy a complete record
1708             just read in:
1709             while (my $record = $gds2FileIn -> readGds2Record())
1710             {
1711             $gds2FileOut -> printGds2Record(-type=>'record',-data=>$record);
1712             }
1713              
1714             =cut
1715              
1716             sub printGds2Record
1717             {
1718 317     317 1 6275 my ($self,%arg) = @_;
1719              
1720 317         591 my $type = $arg{'-type'};
1721 317 50       636 unless (defined $type)
1722             {
1723 0         0 die "printGds2Record expects a type name. Missing -type => 'name' $!";
1724             }
1725             else
1726             {
1727 317         574 $type = uc $type;
1728             }
1729 317         590 my @data = $arg{'-data'};
1730 317         535 my $dataString = $arg{'-asciiData'};
1731 317 50 33     896 die "printGds2Record can not handle both -data and -asciiData options $!" if ((defined $dataString)&&((defined $data[0])&&($data[0] ne '')));
      66        
1732              
1733 317         513 my $fh = $self -> {'FileHandle'};
1734 317         594 my $saveEnd=$\;
1735 317         617 $\='';
1736              
1737 317         444 my $data = '';
1738 317 100       708 @data = () unless (defined $data[0]);
1739 317         421 my $recordLength; ## 1st 2 bytes for length 3rd for recordType 4th for dataType
1740 317 50       575 if ($type eq 'RECORD') ## special case...
1741             {
1742 0 0       0 if ($isLittleEndian)
1743             {
1744 0         0 my $length = substr($data[0],0,2);
1745 0         0 $recordLength = unpack 'v',$length;
1746 0         0 $self -> {'BytesDone'} += $recordLength;
1747 0         0 $length = reverse $length;
1748 0         0 print($fh $length);
1749              
1750 0         0 my $recordType = substr($data[0],2,1);
1751 0         0 print($fh $recordType);
1752 0         0 $recordType = unpack 'C',$recordType;
1753 0         0 $type = $RecordTypeStrings[$recordType]; ## will use code below.....
1754              
1755 0         0 my $dataType = substr($data[0],3,1);
1756 0         0 print($fh $dataType);
1757 0         0 $dataType = unpack 'C',$dataType;
1758 0 0       0 if ($recordLength > 4)
1759             {
1760 0         0 my $lengthLeft = $recordLength - 4; ## length left
1761 0         0 my $recordDataType = $RecordTypeData{$type};
1762              
1763 0 0 0     0 if (($recordDataType == INTEGER_2) || ($recordDataType == BIT_ARRAY))
    0          
    0          
    0          
    0          
1764             {
1765 0         0 my $binData = unpack 'b*',$data[0];
1766 0         0 my $intData = substr($binData,32); #skip 1st 4 bytes (length, recordType dataType)
1767              
1768 0         0 my ($byteInt2String,$byte2);
1769 0         0 for(my $i=0; $i<($lengthLeft/2); $i++)
1770             {
1771 0         0 $byteInt2String = reverse(substr($intData,0,16,''));
1772 0         0 $byte2=pack 'B16',reverse($byteInt2String);
1773 0         0 print($fh $byte2);
1774             }
1775             }
1776             elsif ($recordDataType == INTEGER_4)
1777             {
1778 0         0 my $binData = unpack 'b*',$data[0];
1779 0         0 my $intData = substr($binData,32); #skip 1st 4 bytes (length, recordType dataType)
1780 0         0 my ($byteInt4String,$byte4);
1781 0         0 for(my $i=0; $i<($lengthLeft/4); $i++)
1782             {
1783 0         0 $byteInt4String = reverse(substr($intData,0,32,''));
1784 0         0 $byte4=pack 'B32',reverse($byteInt4String);
1785 0         0 print($fh $byte4);
1786             }
1787             }
1788             elsif ($recordDataType == REAL_8)
1789             {
1790 0         0 my $binData = unpack 'b*',$data[0];
1791 0         0 my $realData = substr($binData,32); #skip 1st 4 bytes (length, recordType dataType)
1792 0         0 my ($bit64String,$mantissa,$byteString,$byte);
1793 0         0 for(my $i=0; $i<($lengthLeft/8); $i++)
1794             {
1795 0         0 $bit64String = substr($realData,($i*64),64);
1796 0         0 print($fh pack 'b8',$bit64String);
1797 0         0 $mantissa = substr($bit64String,8,56);
1798 0         0 for(my $j=0; $j<7; $j++)
1799             {
1800 0         0 $byteString = substr($mantissa,($j*8),8);
1801 0         0 $byte=pack 'b8',$byteString;
1802 0         0 print($fh $byte);
1803             }
1804             }
1805             }
1806             elsif ($recordDataType == ACSII_STRING) ## ascii string (null padded)
1807             {
1808 0         0 print($fh pack("a$lengthLeft",substr($data[0],4)));
1809             }
1810             elsif ($recordDataType == REAL_4) ## 4 byte real
1811             {
1812 0         0 die "4-byte reals are not supported $!";
1813             }
1814             }
1815             }
1816             else
1817             {
1818 0         0 print($fh $data[0]);
1819 0         0 $recordLength = length $data[0];
1820 0         0 $self -> {'BytesDone'} += $recordLength;
1821             }
1822             }
1823             else #if ($type ne 'RECORD')
1824             {
1825 317         404 my $numDataElements = 0;
1826 317         480 my $resolution = $self -> {'Resolution'};
1827 317         454 my $uUnits = $self -> {'UUnits'};
1828              
1829 317         441 my $scale = $arg{'-scale'};
1830 317 50       605 if (! defined $scale)
1831             {
1832 317         418 $scale = 1;
1833             }
1834 317 50       585 if ($scale <= 0)
1835             {
1836 0         0 die "printGds2Record expects a positive scale -scale => $scale $!";
1837             }
1838              
1839 317         435 my $snap = $arg{'-snap'};
1840 317 50       521 if (! defined $snap) ## default is one resolution unit
1841             {
1842 317         413 $snap = 1;
1843             }
1844             else
1845             {
1846 0         0 $snap = int(($snap*$resolution)+$G_epsilon); ## i.e. 0.001 -> 1
1847             }
1848 317 50       530 if ($snap < 1)
1849             {
1850 0         0 die "printGds2Record expects a snap >= 1/resolution -snap => $snap $!";
1851             }
1852              
1853 317 100 66     739 if ((defined $data[0])&&($data[0] ne ''))
1854             {
1855 40         96 $data = $data[0];
1856 40         180 $numDataElements = @$data;
1857 40 100       108 if ($numDataElements) ## passed in anonymous array
1858             {
1859 18         75 @data = @$data; ## deref
1860             }
1861             else
1862             {
1863 22         49 $numDataElements = @data;
1864             }
1865             }
1866              
1867 317         589 my $recordDataType = $RecordTypeData{$type};
1868              
1869 317 100       610 if (defined $dataString)
1870             {
1871 255         765 $dataString=~s|^\s+||; ## clean-up
1872 255         762 $dataString=~s|\s+$||;
1873 255 100       739 $dataString=~s|\s+| |g if ($dataString !~ m|'|); ## don't compress spaces in strings...
1874 255         373 $dataString=~s|'$||; #'# for strings
1875 255         344 $dataString=~s|^'||; #'# for strings
1876 255 100 100     721 if (($recordDataType == BIT_ARRAY)||($recordDataType == ACSII_STRING))
1877             {
1878 57         92 $data = $dataString;
1879             }
1880             else
1881             {
1882 198         681 $dataString=~s|\s*[\s,;:/\\]+\s*| |g; ## in case commas etc... (non-std) were added by hand
1883 198         466 @data = split(' ',$dataString);
1884 198         288 $numDataElements = @data;
1885 198 100       376 if ($recordDataType == INTEGER_4)
1886             {
1887 33         54 my @xyTmp=();
1888 33         75 for(my $i=0;$i<$numDataElements;$i++) ## e.g. 3.4 in -> 3400 out
1889             {
1890 165 100       370 if ($data[$i]>=0) {push @xyTmp,int((($data[$i])*$resolution)+$G_epsilon);}
  126         318  
1891 39         326 else {push @xyTmp,int((($data[$i])*$resolution)-$G_epsilon);}
1892             }
1893 33         103 @data=@xyTmp;
1894             }
1895             }
1896             }
1897 317         429 my $byte;
1898 317         415 my $length = 0;
1899 317 100       869 if ($recordDataType == BIT_ARRAY)
    100          
    100          
    100          
    100          
1900             {
1901 27         91 $length = 2;
1902             }
1903             elsif ($recordDataType == INTEGER_2)
1904             {
1905 87         133 $length = 2 * $numDataElements;
1906             }
1907             elsif ($recordDataType == INTEGER_4)
1908             {
1909 43         80 $length = 4 * $numDataElements;
1910             }
1911             elsif ($recordDataType == REAL_8)
1912             {
1913 26         43 $length = 8 * $numDataElements;
1914             }
1915             elsif ($recordDataType == ACSII_STRING)
1916             {
1917 40         69 my $slen = length $data;
1918 40         88 $length = $slen + ($slen % 2); ## needs to be an even number
1919             }
1920 317         522 $self -> {'BytesDone'} += $length;
1921 317 50       498 if ($isLittleEndian)
1922             {
1923 317         809 $recordLength = pack 'v',($length + 4);
1924 317         517 $recordLength = reverse $recordLength;
1925             }
1926             else
1927             {
1928 0         0 $recordLength = pack 'S',($length + 4);
1929             }
1930 317         742 print($fh $recordLength);
1931              
1932 317         871 my $recordType = pack 'C',$RecordTypeNumbers{$type};
1933 317 50       690 $recordType = reverse $recordType if ($isLittleEndian);
1934 317         568 print($fh $recordType);
1935              
1936 317         596 my $dataType = pack 'C',$RecordTypeData{$type};
1937 317 50       637 $dataType = reverse $dataType if ($isLittleEndian);
1938 317         489 print($fh $dataType);
1939              
1940 317 100       925 if ($recordDataType == BIT_ARRAY) ## bit array
    100          
    100          
    100          
    100          
1941             {
1942 27         43 my $bitLength = $length * 8;
1943 27         88 my $value = pack("B$bitLength",$data);
1944 27         56 print($fh $value);
1945             }
1946             elsif ($recordDataType == INTEGER_2) ## 2 byte signed integer
1947             {
1948 87         115 my $value;
1949 87         154 foreach my $num (@data)
1950             {
1951 287         555 $value = pack('s',$num);
1952 287 50       560 $value = reverse $value if ($isLittleEndian);
1953 287         568 print($fh $value);
1954             }
1955             }
1956             elsif ($recordDataType == INTEGER_4) ## 4 byte signed integer
1957             {
1958 43         67 my $value;
1959 43         85 foreach my $num (@data)
1960             {
1961 211 50       387 $num = scaleNum($num,$scale) if ($scale != 1);
1962 211 50       483 $num = snapNum($num,$snap) if ($snap != 1);
1963 211         374 $value = pack('i',$num);
1964 211 50       419 $value = reverse $value if ($isLittleEndian);
1965 211         402 print($fh $value);
1966             }
1967             }
1968             elsif ($recordDataType == REAL_8) ## 8 byte real
1969             {
1970 26         51 my ($real,$negative,$exponent,$value);
1971 26         54 foreach my $num (@data)
1972             {
1973 31         52 $real = $num;
1974 31         47 $negative = FALSE;
1975 31 50       103 if($num < 0.0)
1976             {
1977 0         0 $negative = TRUE;
1978 0         0 $real = 0 - $num;
1979             }
1980              
1981 31         42 $exponent = 0;
1982 31         97 while($real >= 1.0)
1983             {
1984 15         21 $exponent++;
1985 15         35 $real = ($real / 16.0);
1986             }
1987              
1988 31 50       82 if ($real != 0)
1989             {
1990 31         70 while($real < 0.0625)
1991             {
1992 45         64 --$exponent;
1993 45         85 $real = ($real * 16.0);
1994             }
1995             }
1996 31 50       72 if($negative) { $exponent += 192; }
  0         0  
1997 31         46 else { $exponent += 64; }
1998 31         73 $value = pack('C',$exponent);
1999 31 50       75 $value = reverse $value if ($isLittleEndian);
2000 31         66 print($fh $value);
2001              
2002 31         82 for (my $i=1; $i<=7; $i++)
2003             {
2004 217 50       352 if ($real>=0) {$byte = int(($real*256.0)+$G_epsilon);}
  217         353  
2005 0         0 else {$byte = int(($real*256.0)-$G_epsilon);}
2006 217         363 my $value = pack('C',$byte);
2007 217 50       406 $value = reverse $value if ($isLittleEndian);
2008 217         333 print($fh $value);
2009 217         723 $real = $real * 256.0 - ($byte + 0.0);
2010             }
2011             }
2012             }
2013             elsif ($recordDataType == ACSII_STRING) ## ascii string (null padded)
2014             {
2015 40         168 print($fh pack("a$length",$data));
2016             }
2017             }
2018 317         1692 $\=$saveEnd;
2019             }
2020             ################################################################################
2021              
2022             =head2 printRecord - prints a record just read
2023              
2024             usage:
2025             $gds2File -> printRecord(
2026             -data => $record
2027             );
2028              
2029             =cut
2030              
2031             sub printRecord
2032             {
2033 0     0 1 0 my ($self,%arg) = @_;
2034 0         0 my $record = $arg{'-data'};
2035 0 0       0 if (! defined $record)
2036             {
2037 0         0 die "printGds2Record expects a data record. Missing -data => \$record $!";
2038             }
2039 0         0 my $type = $arg{'-type'};
2040 0 0       0 if (defined $type)
2041             {
2042 0         0 die "printRecord does not take -type. Perhaps you meant to use printGds2Record? $!";
2043             }
2044 0         0 $self -> printGds2Record(-type=>'record',-data=>$record);
2045             }
2046             ################################################################################
2047              
2048             ################################################################################
2049              
2050             =head1 Low Level Generic Read Methods
2051              
2052             =cut
2053              
2054             ################################################################################
2055              
2056             =head2 readGds2Record - reads record header and data section
2057              
2058             usage:
2059             while ($gds2File -> readGds2Record)
2060             {
2061             if ($gds2File -> returnRecordTypeString eq 'LAYER')
2062             {
2063             $layersFound[$gds2File -> layer] = 1;
2064             }
2065             }
2066              
2067             =cut
2068              
2069             sub readGds2Record
2070             {
2071 172     172 1 943 my $self = shift;
2072 172 100       468 return "" if ($self -> {'EOLIB'});
2073 170         476 $self -> readGds2RecordHeader();
2074 170         540 $self -> readGds2RecordData();
2075 170         309 $self -> {'INHEADER'} = FALSE;
2076 170         295 $self -> {'INDATA'} = TRUE; ## actually just done w/ it
2077 170         535 $self -> {'Record'};
2078             }
2079             ################################################################################
2080              
2081             =head2 readGds2RecordHeader - only reads gds2 record header section (2 bytes)
2082              
2083             slightly faster if you just want a certain thing...
2084             usage:
2085             while ($gds2File -> readGds2RecordHeader)
2086             {
2087             if ($gds2File -> returnRecordTypeString eq 'LAYER')
2088             {
2089             $gds2File -> readGds2RecordData;
2090             $layersFound[$gds2File -> returnLayer] = 1;
2091             }
2092             }
2093              
2094             =cut
2095              
2096             sub readGds2RecordHeader
2097             {
2098 256     256 1 573 my $self = shift;
2099              
2100 256 100 100     771 $self -> skipGds2RecordData() if ((! $self -> {'INDATA'}) && ($self -> {'INHEADER'} != UNKNOWN)) ; # need to read record data before header unless 1st time
2101 256         484 $self -> {'Record'} = '';
2102 256         430 $self -> {'RecordType'} = UNKNOWN;
2103 256         409 $self -> {'INHEADER'} = TRUE; ## will actually be just just done with it by the time we can check this ...
2104 256         388 $self -> {'INDATA'} = FALSE;
2105 256 100       552 return '' if ($self -> {'EOLIB'}); ## no sense reading null padding..
2106              
2107 255         424 my $buffer = '';
2108 255 50       1011 return 0 if (! read($self -> {'FileHandle'},$buffer,4));
2109 255         460 my $data;
2110             #if (read($self -> {'FileHandle'},$data,2)) ### length
2111 255         521 $data = substr($buffer,0,2);
2112             {
2113 255 50       401 $data = reverse $data if ($isLittleEndian);
  255         658  
2114 255         474 $self -> {'Record'} = $data;
2115 255         703 $self -> {'Length'} = unpack 'S',$data;
2116 255         543 $self -> {'BytesDone'} += $self -> {'Length'};
2117             }
2118              
2119             #if (read($self -> {'FileHandle'},$data,1)) ## record type
2120 255         495 $data = substr($buffer,2,1);
2121             {
2122 255 50       408 $data = reverse $data if ($isLittleEndian);
  255         575  
2123 255         476 $self -> {'Record'} .= $data;
2124 255         559 $self -> {'RecordType'} = unpack 'C',$data;
2125 255 100       656 $self -> {'EOLIB'} = TRUE if (($self -> {'RecordType'}) == ENDLIB);
2126              
2127 255 100       587 if ($self -> {'UsingPrettyPrint'})
2128             {
2129 252 100       563 putStrSpace('') if (($self -> {'RecordType'}) == ENDSTR);
2130 252 100       608 putStrSpace(' ') if (($self -> {'RecordType'}) == BGNSTR);
2131              
2132             putElmSpace(' ') if ((($self -> {'RecordType'}) == TEXT) || (($self -> {'RecordType'}) == PATH) ||
2133             (($self -> {'RecordType'}) == BOUNDARY) || (($self -> {'RecordType'}) == SREF) ||
2134 252 100 100     1962 (($self -> {'RecordType'}) == AREF));
      100        
      100        
      66        
2135 252 100       585 if (($self -> {'RecordType'}) == ENDEL)
2136             {
2137 30         103 putElmSpace('');
2138 30         60 $self -> {'InTxt'} = FALSE;
2139 30         55 $self -> {'InBoundary'} = FALSE;
2140             }
2141 252 100       581 $self -> {'InTxt'} = TRUE if (($self -> {'RecordType'}) == TEXT);
2142 252 100       571 $self -> {'InBoundary'} = TRUE if (($self -> {'RecordType'}) == BOUNDARY);
2143 252 100 100     988 if ((($self -> {'RecordType'}) == LIBNAME) || (($self -> {'RecordType'}) == STRNAME))
2144              
2145             {
2146 12         29 $self -> {'DateFld'} = 0;
2147             }
2148 252 100 100     969 $self -> {'DateFld'} = 1 if ((($self -> {'RecordType'}) == BGNLIB) || (($self -> {'RecordType'}) == BGNSTR));
2149             }
2150             }
2151              
2152             #if (read($self -> {'FileHandle'},$data,1)) ## data type
2153 255         586 $data = substr($buffer,3,1);
2154             {
2155 255 50       400 $data = reverse $data if ($isLittleEndian);
  255         610  
2156 255         485 $self -> {'Record'} .= $data;
2157 255         585 $self -> {'DataType'} = unpack 'C',$data;
2158             }
2159             #printf("P:Length=%-5d RecordType=%-2d DataType=%-2d\n",$self -> {'Length'},$self -> {'RecordType'},$self -> {'DataType'}); ##DEBUG
2160 255         582 return 1;
2161             }
2162             ################################################################################
2163              
2164             =head2 readGds2RecordData - only reads record data section
2165              
2166             slightly faster if you just want a certain thing...
2167             usage:
2168             while ($gds2File -> readGds2RecordHeader)
2169             {
2170             if ($gds2File -> returnRecordTypeString eq 'LAYER')
2171             {
2172             $gds2File -> readGds2RecordData;
2173             $layersFound[$gds2File -> returnLayer] = 1;
2174             }
2175             }
2176              
2177             =cut
2178              
2179             sub readGds2RecordData
2180             {
2181 255     255 1 429 my $self = shift;
2182              
2183 255 50       626 $self -> readGds2RecordHeader() if ($self -> {'INHEADER'} != TRUE); # program did not read HEADER - needs to...
2184 255 100       638 return $self -> {'Record'} if ($self -> {'DataType'} == NO_REC_DATA); # no sense going on...
2185 183         309 $self -> {'INHEADER'} = FALSE; # not in HEADER - need to read HEADER next time around...
2186 183         301 $self -> {'INDATA'} = TRUE; # rather in DATA - actually will be at the end of data by the time we test this...
2187 183         381 $self -> {'RecordData'} = '';
2188 183         481 $self -> {'RecordData'} = ();
2189 183         376 $self -> {'CurrentDataList'} = '';
2190 183         367 my $bytesLeft = $self -> {'Length'} - 4; ## 4 should have been just read by readGds2RecordHeader
2191 183         284 my $data;
2192 183 100       706 if ($self -> {'DataType'} == BIT_ARRAY) ## bit array
    100          
    100          
    50          
    100          
    50          
2193             {
2194 27         58 $self -> {'DataIndex'}=0;
2195 27         94 read($self -> {'FileHandle'},$data,$bytesLeft);
2196 27 50       90 $data = reverse $data if ($isLittleEndian);
2197 27         60 my $bitsLeft = $bytesLeft * 8;
2198 27         57 $self -> {'Record'} .= $data;
2199 27         137 $self -> {'RecordData'}[0] = unpack "B$bitsLeft",$data;
2200 27         86 $self -> {'CurrentDataList'} = ($self -> {'RecordData'}[0]);
2201             }
2202             elsif ($self -> {'DataType'} == INTEGER_2) ## 2 byte signed integer
2203             {
2204 69         117 my $tmpListString = '';
2205 69         121 my $i = 0;
2206 69         158 while ($bytesLeft)
2207             {
2208 201         476 read($self -> {'FileHandle'},$data,2);
2209 201 50       454 $data = reverse $data if ($isLittleEndian);
2210 201         331 $self -> {'Record'} .= $data;
2211 201         532 $self -> {'RecordData'}[$i] = unpack 's',$data;
2212 201         367 $tmpListString .= ',';
2213 201         429 $tmpListString .= $self -> {'RecordData'}[$i];
2214 201         274 $i++;
2215 201         441 $bytesLeft -= 2;
2216             }
2217 69         139 $self -> {'DataIndex'} = $i - 1;
2218 69         142 $self -> {'CurrentDataList'} = $tmpListString;
2219             }
2220             elsif ($self -> {'DataType'} == INTEGER_4) ## 4 byte signed integer
2221             {
2222 33         71 my $tmpListString = '';
2223 33         60 my $i = 0;
2224 33         58 my $buffer = '';
2225 33         107 read($self -> {'FileHandle'},$buffer,$bytesLeft); ## try fewer reads
2226 33         109 for(my $start=0; $start < $bytesLeft; $start += 4)
2227             {
2228 165         317 $data = substr($buffer,$start,4);
2229 165 50       376 $data = reverse $data if ($isLittleEndian);
2230 165         357 $self -> {'Record'} .= $data;
2231 165         413 $self -> {'RecordData'}[$i] = unpack 'i',$data;
2232 165         308 $tmpListString .= ',';
2233 165         359 $tmpListString .= $self -> {'RecordData'}[$i];
2234 165         388 $i++;
2235             }
2236 33         72 $self -> {'DataIndex'} = $i - 1;
2237 33         78 $self -> {'CurrentDataList'} = $tmpListString;
2238             }
2239             elsif ($self -> {'DataType'} == REAL_4) ## 4 byte real
2240             {
2241 0         0 die "4-byte reals are not supported $!";
2242             }
2243             elsif ($self -> {'DataType'} == REAL_8) ## 8 byte real - UNITS, MAG, ANGLE
2244             {
2245 24         68 my $resolution = $self -> {'Resolution'};
2246 24         56 my $tmpListString = '';
2247 24         46 my $i = 0;
2248 24         60 my ($negative,$exponent,$mantdata,$byteString,$byte,$mantissa,$real);
2249 24         63 while ($bytesLeft)
2250             {
2251 27         91 read($self -> {'FileHandle'},$data,1); ## sign bit and 7 exponent bits
2252 27         63 $self -> {'Record'} .= $data;
2253 27         89 $negative = unpack 'B',$data; ## sign bit
2254 27         77 $exponent = unpack 'C',$data;
2255 27 50       73 if ($negative)
2256             {
2257 0         0 $exponent -= 192; ## 128 + 64
2258             }
2259             else
2260             {
2261 27         56 $exponent -= 64;
2262             }
2263 27         71 read($self -> {'FileHandle'},$data,7); ## mantissa bits
2264 27         101 $mantdata = unpack 'b*',$data;
2265 27         71 $self -> {'Record'} .= $data;
2266 27         57 $mantissa = 0.0;
2267 27         95 for(my $j=0; $j<7; $j++)
2268             {
2269 189         405 $byteString = substr($mantdata,0,8,'');
2270 189         470 $byte = pack 'b*',$byteString;
2271 189         376 $byte = unpack 'C',$byte;
2272 189         546 $mantissa += $byte / (256.0**($j+1));
2273             }
2274 27         76 $real = $mantissa * (16**$exponent);
2275 27 50       73 $real = (0 - $real) if ($negative);
2276 27 100       98 if ($RecordTypeStrings[$self -> {'RecordType'}] eq 'UNITS')
2277             {
2278 6 100       35 if ($self -> {'UUnits'} == -1.0)
    50          
2279             {
2280 3         9 $self -> {'UUnits'} = $real;
2281             }
2282             elsif ($self -> {'DBUnits'} == -1.0)
2283             {
2284 3         10 $self -> {'DBUnits'} = $real;
2285             }
2286             }
2287             else
2288             {
2289             ### this works because UUnits and DBUnits are 1st reals in GDS2 file
2290 21 50       133 $real = int(($real+($self -> {'UUnits'}/$resolution))/$self -> {'UUnits'})*$self -> {'UUnits'} if ($self -> {'UUnits'} != 0); ## "rounds" off
2291             }
2292 27         80 $self -> {'RecordData'}[$i] = $real;
2293 27         68 $tmpListString .= ',';
2294 27         277 $tmpListString .= $self -> {'RecordData'}[$i];
2295 27         60 $i++;
2296 27         83 $bytesLeft -= 8;
2297             }
2298 24         54 $self -> {'DataIndex'} = $i - 1;
2299 24         66 $self -> {'CurrentDataList'} = $tmpListString;
2300             }
2301             elsif ($self -> {'DataType'} == ACSII_STRING) ## ascii string (null padded)
2302             {
2303 30         75 $self -> {'DataIndex'} = 0;
2304 30         97 read($self -> {'FileHandle'},$data,$bytesLeft);
2305 30         77 $self -> {'Record'} .= $data;
2306 30         158 $self -> {'RecordData'}[0] = unpack "a$bytesLeft",$data;
2307 30         144 $self -> {'RecordData'}[0] =~ s|\0||g; ## take off ending nulls
2308 30         80 $self -> {'CurrentDataList'} = ($self -> {'RecordData'}[0]);
2309             }
2310 183         393 return 1;
2311             }
2312             ################################################################################
2313              
2314             =head1 Low Level Generic Evaluation Methods
2315              
2316             =cut
2317              
2318             ################################################################################
2319              
2320             =head2 returnRecordType - returns current (read) record type as integer
2321              
2322             usage:
2323             if ($gds2File -> returnRecordType == 6)
2324             {
2325             print "found STRNAME";
2326             }
2327              
2328             =cut
2329              
2330             sub returnRecordType
2331             {
2332 0     0 1 0 my $self = shift;
2333 0         0 $self -> {'RecordType'};
2334             }
2335             ################################################################################
2336              
2337             =head2 returnRecordTypeString - returns current (read) record type as string
2338              
2339             usage:
2340             if ($gds2File -> returnRecordTypeString eq 'LAYER')
2341             {
2342             code goes here...
2343             }
2344              
2345             =cut
2346              
2347             sub returnRecordTypeString
2348             {
2349 0     0 1 0 my $self = shift;
2350 0         0 $RecordTypeStrings[($self -> {'RecordType'})];
2351             }
2352             ################################################################################
2353              
2354             =head2 returnRecordAsString - returns current (read) record as a string
2355              
2356             usage:
2357             while ($gds2File -> readGds2Record)
2358             {
2359             print $gds2File -> returnRecordAsString(-compact=>1);
2360             }
2361              
2362             =cut
2363              
2364             sub returnRecordAsString()
2365             {
2366 255     255 1 1068 my($self,%arg) = @_;
2367 255         498 my $compact = $arg{'-compact'};
2368 255 100       613 $compact = FALSE if (! defined $compact);
2369 255         430 my $string = '';
2370 255         446 $self -> {'UsingPrettyPrint'} = TRUE;
2371 255         432 my $inText = $self -> {'InTxt'};
2372 255         453 my $inBoundary = $self -> {'InBoundary'};
2373 255         3168 my $dateFld = $self -> {'DateFld'};
2374 255 100       551 if (! $compact)
2375             {
2376 170 100       483 $string .= getStrSpace() if ($self -> {'RecordType'} != BGNSTR);
2377             $string .= getElmSpace() if (!(
2378             ($self -> {'RecordType'} == BOUNDARY) ||
2379             ($self -> {'RecordType'} == PATH) ||
2380             ($self -> {'RecordType'} == TEXT) ||
2381             ($self -> {'RecordType'} == SREF) ||
2382 170 100 100     1617 ($self -> {'RecordType'} == AREF)
      100        
      100        
      66        
2383             ));
2384             }
2385 255         617 my $recordType = $RecordTypeStrings[$self -> {'RecordType'}];
2386 255 100       563 if ($compact)
2387             {
2388 85         218 $string .= $CompactRecordTypeStrings[$self -> {'RecordType'}];
2389             }
2390             else
2391             {
2392 170         274 $string .= $recordType;
2393             }
2394 255         413 my $i = 0;
2395 255         632 while ($i <= $self -> {'DataIndex'})
2396             {
2397 716 100       2343 if ($self -> {'DataType'} == BIT_ARRAY)
    100          
    100          
    100          
    100          
2398             {
2399 27         81 my $bitString = $self -> {'RecordData'}[$i];
2400 27 50       83 if ($isLittleEndian)
2401             {
2402 27         132 $bitString =~ m|(........)(........)|;
2403 27         130 $bitString = "$2$1";
2404             }
2405 27 100       80 if ($compact)
2406             {
2407 9 100       65 $string .= ' fx' if($bitString =~ m/^1/);
2408 9 100 100     53 if ($inText && ($self -> {'RecordType'} != STRANS))
2409             {
2410 3         9 $string .= ' f';
2411 3 50       34 $string .= '0' if ($bitString =~ m/00....$/);
2412 3 50       13 $string .= '1' if ($bitString =~ m/01....$/);
2413 3 50       11 $string .= '2' if ($bitString =~ m/10....$/);
2414 3 50       12 $string .= '3' if ($bitString =~ m/11....$/);
2415 3 50       21 $string .= ' t' if ($bitString =~ m/00..$/);
2416 3 50       14 $string .= ' m' if ($bitString =~ m/01..$/);
2417 3 50       37 $string .= ' b' if ($bitString =~ m/10..$/);
2418 3 100       23 $string .= 'l' if ($bitString =~ m/00$/);
2419 3 50       14 $string .= 'c' if ($bitString =~ m/01$/);
2420 3 100       15 $string .= 'r' if ($bitString =~ m/10$/);
2421             }
2422             }
2423             else
2424             {
2425 18         55 $string .= ' '.$bitString;
2426             }
2427             }
2428             elsif ($self -> {'DataType'} == INTEGER_2)
2429             {
2430 201 100       347 if ($compact)
2431             {
2432 67 100       130 if ($dateFld)
2433             {
2434 48         99 my $num = $self -> {'RecordData'}[$i];
2435 48 100       165 if ($dateFld =~ m/^[17]$/)
2436             {
2437 8 100       29 if ($dateFld eq '1')
    50          
2438             {
2439 4 100       13 if ($recordType eq 'BGNLIB')
2440             {
2441 1         3 $string .= 'm=';
2442             }
2443             else
2444             {
2445 3         7 $string .= 'c=';
2446             }
2447             }
2448             elsif ($dateFld eq '7')
2449             {
2450 4 100       12 if ($recordType eq 'BGNLIB')
2451             {
2452 1         5 $string .= ' a=';
2453             }
2454             else
2455             {
2456 3         8 $string .= ' m=';
2457             }
2458             }
2459 8 50       25 $num += 1900 if ($num < 1900);
2460             }
2461 48         146 $num = sprintf("%02d",$num);
2462 48 100       157 $string .= '-' if ($dateFld =~ m/^[2389]/);
2463 48 100       142 $string .= ':' if ($dateFld =~ m/^[56]/);
2464 48 100       129 $string .= ':' if ($dateFld =~ m/^1[12]/);
2465 48 100 100     182 $string .= ' ' if (($dateFld eq '4') || ($dateFld eq '10'));
2466 48         100 $string .= $num;
2467             }
2468             else
2469             {
2470 19 100       122 $string .= ' ' unless ($string =~ m/ (a|m|pt|dt|tt)$/i);
2471 19         58 $string .= $self -> {'RecordData'}[$i];
2472             }
2473             }
2474             else
2475             {
2476 134         207 $string .= ' ';
2477 134         219 $string .= $self -> {'RecordData'}[$i];
2478             }
2479 201 50       415 if ($recordType eq 'UNITS')
2480             {
2481 0         0 $string =~ s|(\d)\.e|$1e|; ## perl on Cygwin prints "1.e-9" others "1e-9"
2482 0         0 $string =~ s|(\d)e\-0+|$1e-|; ## different perls print 1e-9 1e-09 1e-009 etc... standardize to 1e-9
2483             }
2484             }
2485             elsif ($self -> {'DataType'} == INTEGER_4)
2486             {
2487 165 100       304 if ($compact)
2488             {
2489 55 100       137 $string .= ' ' if ($i);
2490             }
2491             else
2492             {
2493 110         182 $string .= ' ';
2494             }
2495 165         530 $string .= cleanFloatNum($self -> {'RecordData'}[$i]*($self -> {'UUnits'}));
2496 165 100 100     600 if ($compact && $i && ($i == $#{$self -> {'RecordData'}}))
  44   100     1394  
2497             {
2498 10 100       68 $string =~ s/ +[\d\.\-]+ +[\d\.\-]+$// if ($inBoundary); #remove last point
2499 10         27 $string .= ')';
2500             }
2501             }
2502             elsif ($self -> {'DataType'} == REAL_8)
2503             {
2504 27 100       92 if ($compact)
2505             {
2506 9 100       81 $string .= ' ' unless ($string =~ m/ (a|m|pt|dt|tt)$/i);
2507             }
2508             else
2509             {
2510 18         44 $string .= ' ';
2511             }
2512 27         72 my $num = $self -> {'RecordData'}[$i];
2513 27 100       199 if ($num =~ m/e/i)
2514             {
2515 3         18 $num = cleanExpNum($num);
2516             }
2517             else
2518             {
2519 24         88 $num = cleanFloatNum($num);
2520             }
2521 27         70 $string .= $num;
2522 27 100       90 if ($recordType eq 'UNITS')
2523             {
2524 6         18 $string =~ s|(\d)\.e|$1e|; ## perl on Cygwin prints "1.e-9" others "1e-9"
2525 6         37 $string =~ s|(\d)e\-0+|$1e-|; ## different perls print 1e-9 1e-09 1e-009 etc... standardize to shorter 1e-9
2526             }
2527             }
2528             elsif ($self -> {'DataType'} == ACSII_STRING)
2529             {
2530 30 100       89 $string .= ' ' if (! $compact);
2531 30         98 $string .= " '".$self -> {'RecordData'}[$i]."'";
2532             }
2533 716         1099 $i++;
2534 716 100       1879 $dateFld++ if ($dateFld);
2535             }
2536              
2537 255 100       523 if ($compact)
2538             {
2539 85         209 $G_gdtString .= $string;
2540 85 100 100     686 if (($G_gdtString =~ m/}$/ || $G_gdtString =~ m/^(gds2|lib|m).*\d$/) || ($G_gdtString =~ m/^cell.*'$/))
      100        
2541             {
2542 20         66 $string = "$G_gdtString\n";
2543 20         74 $string =~ s/{ /{/; #a little more compact
2544 20         138 $string =~ s/(dt0|pt0|tt0|m1|w0|f0) //g; #these are all default in true GDT format
2545 20         49 $G_gdtString = "";
2546             }
2547             else
2548             {
2549 65         158 $string = "";
2550             }
2551             }
2552              
2553 255         1357 $string;
2554             }
2555             ################################################################################
2556              
2557             =head2 returnXyAsArray - returns current (read) XY record as an array
2558              
2559             usage:
2560             $gds2File -> returnXyAsArray(
2561             -asInteger => 0|1 ## (optional) default is true. Return integer
2562             ## array or if false return array of reals.
2563             -withClosure => 0|1 ## (optional) default is true. Whether to
2564             ##return a rectangle with 5 or 4 points.
2565             );
2566              
2567             example:
2568             while ($gds2File -> readGds2Record)
2569             {
2570             my @xy = $gds2File -> returnXyAsArray if ($gds2File -> isXy);
2571             }
2572              
2573             =cut
2574              
2575             sub returnXyAsArray()
2576             {
2577 0     0 1 0 my($self,%arg) = @_;
2578 0         0 my $asInteger = $arg{'-asInteger'};
2579 0 0       0 $asInteger = TRUE unless (defined $asInteger);
2580 0         0 my $withClosure = $arg{'-withClosure'};
2581 0 0       0 $withClosure = TRUE unless (defined $withClosure);
2582 0         0 my @xys=();
2583 0 0       0 if ($self -> isXy)
2584             {
2585 0         0 my $i = 0;
2586 0         0 my $stopPoint = $self -> {'DataIndex'};
2587 0 0       0 if ($withClosure)
2588             {
2589 0 0       0 return @{$self -> {'RecordData'}} if ($asInteger);
  0         0  
2590             }
2591             else
2592             {
2593 0         0 $stopPoint -= 2;
2594             }
2595 0         0 my $num=0;
2596 0         0 while ($i <= $stopPoint)
2597             {
2598 0 0       0 if ($asInteger)
2599             {
2600 0         0 $num = $self -> {'RecordData'}[$i];
2601             }
2602             else
2603             {
2604 0         0 $num = cleanFloatNum($self -> {'RecordData'}[$i]*($self -> {'UUnits'}));
2605             }
2606 0         0 push @xys,$num;
2607 0         0 $i++;
2608             }
2609             }
2610 0         0 @xys;
2611             }
2612             ################################################################################
2613              
2614              
2615             =head2 returnRecordAsPerl - returns current (read) record as a perl command to facilitate the creation of parameterized gds2 data with perl.
2616              
2617             usage:
2618             #!/usr/local/bin/perl
2619             use GDS2;
2620             my $gds2File = new GDS2(-fileName=>"test.gds");
2621             while ($gds2File -> readGds2Record)
2622             {
2623             print $gds2File -> returnRecordAsPerl;
2624             }
2625              
2626             =cut
2627              
2628             sub returnRecordAsPerl()
2629             {
2630 0     0 1 0 my($self,%arg) = @_;
2631              
2632 0         0 my $gds2File = $arg{'-gds2File'};
2633 0 0       0 $gds2File = '$gds2File' unless (defined $gds2File);
2634              
2635 0         0 my $PGR = $arg{'-printGds2Record'};
2636 0 0       0 $PGR = 'printGds2Record' unless (defined $PGR);
2637              
2638 0         0 my $string = '';
2639 0         0 $self -> {'UsingPrettyPrint'} = TRUE;
2640 0 0       0 $string .= getStrSpace() if ($self -> {'RecordType'} != BGNSTR);
2641             $string .= getElmSpace() if (!(
2642             ($self -> {'RecordType'} == TEXT) ||
2643             ($self -> {'RecordType'} == PATH) ||
2644             ($self -> {'RecordType'} == BOUNDARY) ||
2645             ($self -> {'RecordType'} == SREF) ||
2646 0 0 0     0 ($self -> {'RecordType'} == AREF)
      0        
      0        
      0        
2647             ));
2648 0 0 0     0 if (
      0        
      0        
      0        
      0        
      0        
      0        
2649             ($self -> {'RecordType'} == TEXT) ||
2650             ($self -> {'RecordType'} == PATH) ||
2651             ($self -> {'RecordType'} == BOUNDARY) ||
2652             ($self -> {'RecordType'} == SREF) ||
2653             ($self -> {'RecordType'} == AREF) ||
2654             ($self -> {'RecordType'} == ENDEL) ||
2655             ($self -> {'RecordType'} == ENDSTR) ||
2656             ($self -> {'RecordType'} == ENDLIB)
2657             )
2658             {
2659 0         0 $string .= $gds2File.'->'.$PGR.'(-type=>'."'".$RecordTypeStrings[$self -> {'RecordType'}]."'".');';
2660             }
2661             else
2662             {
2663 0         0 $string .= $gds2File.'->'.$PGR.'(-type=>'."'".$RecordTypeStrings[$self -> {'RecordType'}]."',-data=>";
2664 0         0 my $i = 0;
2665 0         0 my $maxi = $self -> {'DataIndex'};
2666 0 0       0 if ($maxi >= 1) {$string .= '['}
  0         0  
2667 0         0 while ($i <= $maxi)
2668             {
2669 0 0       0 if ($self -> {'DataType'} == BIT_ARRAY)
    0          
    0          
    0          
    0          
2670             {
2671 0         0 my $bitString = $self -> {'RecordData'}[$i];
2672 0 0       0 if ($isLittleEndian)
2673             {
2674 0         0 $bitString =~ m|(........)(........)|;
2675 0         0 $bitString = "$2$1";
2676             }
2677 0         0 $string .= "'$bitString'";
2678             }
2679             elsif ($self -> {'DataType'} == INTEGER_2)
2680             {
2681 0         0 $string .= $self -> {'RecordData'}[$i];
2682             }
2683             elsif ($self -> {'DataType'} == INTEGER_4)
2684             {
2685 0         0 $string .= $self -> {'RecordData'}[$i];
2686             }
2687             elsif ($self -> {'DataType'} == REAL_8)
2688             {
2689 0         0 $string .= $self -> {'RecordData'}[$i];
2690             }
2691             elsif ($self -> {'DataType'} == ACSII_STRING)
2692             {
2693 0         0 $string .= "'".$self -> {'RecordData'}[$i]."'";
2694             }
2695 0 0       0 if ($i < $maxi) {$string .= ', '}
  0         0  
2696 0         0 $i++;
2697             }
2698 0 0       0 if ($maxi >= 1) {$string .= ']'}
  0         0  
2699 0         0 $string .= ');';
2700             }
2701 0         0 $string;
2702             }
2703             ################################################################################
2704              
2705              
2706             =head1 Low Level Specific Write Methods
2707              
2708             =cut
2709              
2710             ################################################################################
2711              
2712             =head2 printAngle - prints ANGLE record
2713              
2714             usage:
2715             $gds2File -> printAngle(-num=>#.#);
2716              
2717             =cut
2718              
2719             sub printAngle
2720             {
2721 0     0 1 0 my($self,%arg) = @_;
2722 0         0 my $angle = $arg{'-num'};
2723 0 0       0 if (defined $angle)
2724             {
2725 0         0 $angle=posAngle($angle);
2726             }
2727             else
2728             {
2729 0         0 $angle = -1; #not really... just means not specified
2730             }
2731 0 0       0 $self -> printGds2Record(-type => 'ANGLE',-data => $angle) if ($angle >= 0);
2732             }
2733             ################################################################################
2734              
2735             =head2 printAttrtable - prints ATTRTABLE record
2736              
2737             usage:
2738             $gds2File -> printAttrtable(-string=>$string);
2739              
2740             =cut
2741              
2742             sub printAttrtable
2743             {
2744 0     0 1 0 my($self,%arg) = @_;
2745 0         0 my $string = $arg{'-string'};
2746 0 0       0 unless (defined $string)
2747             {
2748 0         0 die "printAttrtable expects a string. Missing -string => 'text' $!";
2749             }
2750 0         0 $self -> printGds2Record(-type => 'ATTRTABLE',-data => $string);
2751             }
2752             ################################################################################
2753              
2754             =head2 printBgnextn - prints BGNEXTN record
2755              
2756             usage:
2757             $gds2File -> printBgnextn(-num=>#.#);
2758              
2759             =cut
2760              
2761             sub printBgnextn
2762             {
2763 0     0 1 0 my($self,%arg) = @_;
2764 0         0 my $num = $arg{'-num'};
2765 0 0       0 unless (defined $num)
2766             {
2767 0         0 die "printBgnextn expects a extension number. Missing -num => #.# $!";
2768             }
2769 0         0 my $resolution = $self -> {'Resolution'};
2770 0 0       0 if ($num >= 0) {$num = int(($num*$resolution)+$G_epsilon);}
  0         0  
2771 0         0 else {$num = int(($num*$resolution)-$G_epsilon);}
2772 0         0 $self -> printGds2Record(-type => 'BGNEXTN',-data => $num);
2773             }
2774             ################################################################################
2775              
2776             =head2 printBgnlib - prints BGNLIB record
2777              
2778             usage:
2779             $gds2File -> printBgnlib(
2780             -isoDate => 0|1 ## (optional) use ISO 4 digit date 2001 vs 101
2781             );
2782              
2783             =cut
2784              
2785             sub printBgnlib
2786             {
2787 0     0 1 0 my($self,%arg) = @_;
2788 0         0 my $isoDate = $arg{'-isoDate'};
2789 0 0       0 if (! defined $isoDate)
    0          
2790             {
2791 0         0 $isoDate = 0;
2792             }
2793             elsif ($isoDate != 0)
2794             {
2795 0         0 $isoDate = 1;
2796             }
2797 0         0 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
2798 0         0 $mon++;
2799 0 0       0 $year += 1900 if ($isoDate); ## Cadence likes year left "as is". GDS format supports year number up to 65535 -- 101 vs 2001
2800 0         0 $self -> printGds2Record(-type=>'BGNLIB',-data=>[$year,$mon,$mday,$hour,$min,$sec,$year,$mon,$mday,$hour,$min,$sec]);
2801             }
2802             ################################################################################
2803              
2804             =head2 printBox - prints BOX record
2805              
2806             usage:
2807             $gds2File -> printBox;
2808              
2809             =cut
2810              
2811             sub printBox
2812             {
2813 0     0 1 0 my $self = shift;
2814 0         0 $self -> printGds2Record(-type => 'BOX');
2815             }
2816             ################################################################################
2817              
2818             =head2 printBoxtype - prints BOXTYPE record
2819              
2820             usage:
2821             $gds2File -> printBoxtype(-num=>#);
2822              
2823             =cut
2824              
2825             sub printBoxtype
2826             {
2827 0     0 1 0 my($self,%arg) = @_;
2828 0         0 my $num = $arg{'-num'};
2829 0 0       0 unless (defined $num)
2830             {
2831 0         0 die "printBoxtype expects a number. Missing -num => # $!";
2832             }
2833 0         0 $self -> printGds2Record(-type => 'BOXTYPE',-data => $num);
2834             }
2835             ################################################################################
2836              
2837             =head2 printColrow - prints COLROW record
2838              
2839             usage:
2840             $gds2File -> printBoxtype(-columns=>#, -rows=>#);
2841              
2842             =cut
2843              
2844             sub printColrow
2845             {
2846 0     0 1 0 my($self,%arg) = @_;
2847 0         0 my $columns = $arg{'-columns'};
2848 0 0 0     0 if ((! defined $columns)||($columns <= 0))
2849             {
2850 0         0 $columns=1;
2851             }
2852             else
2853             {
2854 0         0 $columns=int($columns);
2855             }
2856 0         0 my $rows = $arg{'-rows'};
2857 0 0 0     0 if ((! defined $rows)||($rows <= 0))
2858             {
2859 0         0 $rows=1;
2860             }
2861             else
2862             {
2863 0         0 $rows=int($rows);
2864             }
2865 0         0 $self -> printGds2Record(-type => 'COLROW',-data => [$columns,$rows]);
2866             }
2867             ################################################################################
2868              
2869             =head2 printDatatype - prints DATATYPE record
2870              
2871             usage:
2872             $gds2File -> printDatatype(-num=>#);
2873              
2874             =cut
2875              
2876             sub printDatatype
2877             {
2878 0     0 1 0 my($self,%arg) = @_;
2879 0         0 my $dataType = $arg{'-num'};
2880 0 0       0 $dataType=0 unless (defined $dataType);
2881 0         0 $self -> printGds2Record(-type => 'DATATYPE',-data => $dataType);
2882             }
2883             ################################################################################
2884              
2885             sub printEflags
2886             {
2887 0     0 0 0 my $self = shift;
2888 0         0 die "EFLAGS type not supported $!";
2889             }
2890             ################################################################################
2891              
2892             =head2 printElkey - prints ELKEY record
2893              
2894             usage:
2895             $gds2File -> printElkey(-num=>#);
2896              
2897             =cut
2898              
2899             sub printElkey
2900             {
2901 0     0 1 0 my($self,%arg) = @_;
2902 0         0 my $num = $arg{'-num'};
2903 0 0       0 unless (defined $num)
2904             {
2905 0         0 die "printElkey expects a number. Missing -num => #.# $!";
2906             }
2907 0         0 $self -> printGds2Record(-type => 'ELKEY',-data => $num);
2908             }
2909             ################################################################################
2910              
2911             =head2 printEndel - closes an element definition
2912              
2913             =cut
2914              
2915             sub printEndel
2916             {
2917 0     0 1 0 my $self = shift;
2918 0         0 $self -> printGds2Record(-type => 'ENDEL');
2919             }
2920             ################################################################################
2921              
2922             =head2 printEndextn - prints path end extension record
2923              
2924             usage:
2925             $gds2File printEndextn -> (-num=>#.#);
2926              
2927             =cut
2928              
2929             sub printEndextn
2930             {
2931 0     0 1 0 my($self,%arg) = @_;
2932 0         0 my $num = $arg{'-num'};
2933 0 0       0 unless (defined $num)
2934             {
2935 0         0 die "printEndextn expects a extension number. Missing -num => #.# $!";
2936             }
2937 0         0 my $resolution = $self -> {'Resolution'};
2938 0 0       0 if ($num >= 0) {$num = int(($num*$resolution)+$G_epsilon);}
  0         0  
2939 0         0 else {$num = int(($num*$resolution)-$G_epsilon);}
2940 0         0 $self -> printGds2Record(-type => 'ENDEXTN',-data => $num);
2941             }
2942             ################################################################################
2943              
2944             =head2 printEndlib - closes a library definition
2945              
2946             =cut
2947              
2948             sub printEndlib
2949             {
2950 2     2 1 20 my $self = shift;
2951 2         11 $self -> printGds2Record(-type => 'ENDLIB');
2952             }
2953             ################################################################################
2954              
2955             =head2 printEndstr - closes a structure definition
2956              
2957             =cut
2958              
2959             sub printEndstr
2960             {
2961 4     4 1 40 my $self = shift;
2962 4         60 $self -> printGds2Record(-type => 'ENDSTR');
2963             }
2964             ################################################################################
2965              
2966             =head2 printEndmasks - prints a ENDMASKS
2967              
2968             =cut
2969              
2970             sub printEndmasks
2971             {
2972 0     0 1 0 my $self = shift;
2973 0         0 $self -> printGds2Record(-type => 'ENDMASKS');
2974             }
2975             ################################################################################
2976              
2977             =head2 printFonts - prints a FONTS record
2978              
2979             usage:
2980             $gds2File -> printFonts(-string=>'names_of_font_files');
2981              
2982             =cut
2983              
2984             sub printFonts
2985             {
2986 0     0 1 0 my($self,%arg) = @_;
2987 0         0 my $string = $arg{'-string'};
2988 0 0       0 unless (defined $string)
2989             {
2990 0         0 die "printFonts expects a string. Missing -string => 'text' $!";
2991             }
2992 0         0 $self -> printGds2Record(-type => 'FONTS',-data => $string);
2993             }
2994             ################################################################################
2995              
2996             sub printFormat
2997             {
2998 0     0 0 0 my($self,%arg) = @_;
2999 0         0 my $num = $arg{'-num'};
3000 0 0       0 unless (defined $num)
3001             {
3002 0         0 die "printFormat expects a number. Missing -num => #.# $!";
3003             }
3004 0         0 $self -> printGds2Record(-type => 'FORMAT',-data => $num);
3005             }
3006             ################################################################################
3007              
3008             sub printGenerations
3009             {
3010 0     0 0 0 my $self = shift;
3011 0         0 $self -> printGds2Record(-type => 'GENERATIONS');
3012             }
3013             ################################################################################
3014              
3015             =head2 printHeader - Prints a rev 3 header
3016              
3017             usage:
3018             $gds2File -> printHeader(
3019             -num => # ## optional, defaults to 3. valid revs are 0,3,4,5,and 600
3020             );
3021              
3022             =cut
3023              
3024             sub printHeader
3025             {
3026 0     0 1 0 my($self,%arg) = @_;
3027 0         0 my $rev = $arg{'-num'};
3028 0 0       0 unless (defined $rev)
3029             {
3030 0         0 $rev=3;
3031             }
3032 0         0 $self -> printGds2Record(-type=>'HEADER',-data=>$rev);
3033             }
3034             ################################################################################
3035              
3036             =head2 printLayer - prints a LAYER number
3037              
3038             usage:
3039             $gds2File -> printLayer(
3040             -num => # ## optional, defaults to 0.
3041             );
3042              
3043             =cut
3044              
3045             sub printLayer
3046             {
3047 0     0 1 0 my($self,%arg) = @_;
3048 0         0 my $layer = $arg{'-num'};
3049 0 0       0 $layer = 0 unless (defined $layer);
3050 0         0 $self -> printGds2Record(-type => 'LAYER',-data => $layer);
3051             }
3052             ################################################################################
3053              
3054             sub printLibdirsize
3055             {
3056 0     0 0 0 my $self = shift;
3057 0         0 $self -> printGds2Record(-type => 'LIBDIRSIZE');
3058             }
3059             ################################################################################
3060              
3061             =head2 printLibname - Prints library name
3062              
3063             usage:
3064             printLibname(-name=>$name);
3065              
3066             =cut
3067              
3068             sub printLibname
3069             {
3070 0     0 1 0 my($self,%arg) = @_;
3071 0         0 my $libName = $arg{'-name'};
3072 0 0       0 unless (defined $libName)
3073             {
3074 0         0 die "printLibname expects a library name. Missing -name => 'name' $!";
3075             }
3076 0         0 $self -> printGds2Record(-type => 'LIBNAME',-data => $libName);
3077             }
3078             ################################################################################
3079              
3080             sub printLibsecur
3081             {
3082 0     0 0 0 my $self = shift;
3083 0         0 $self -> printGds2Record(-type => 'LIBSECUR');
3084             }
3085             ################################################################################
3086              
3087             sub printLinkkeys
3088             {
3089 0     0 0 0 my($self,%arg) = @_;
3090 0         0 my $num = $arg{'-num'};
3091 0 0       0 unless (defined $num)
3092             {
3093 0         0 die "printLinkkeys expects a number. Missing -num => #.# $!";
3094             }
3095 0         0 $self -> printGds2Record(-type => 'LINKKEYS',-data => $num);
3096             }
3097             ################################################################################
3098              
3099             sub printLinktype
3100             {
3101 0     0 0 0 my($self,%arg) = @_;
3102 0         0 my $num = $arg{'-num'};
3103 0 0       0 unless (defined $num)
3104             {
3105 0         0 die "printLinktype expects a number. Missing -num => #.# $!";
3106             }
3107 0         0 $self -> printGds2Record(-type => 'LINKTYPE',-data => $num);
3108             }
3109             ################################################################################
3110              
3111             =head2 printPathtype - prints a PATHTYPE number
3112              
3113             usage:
3114             $gds2File -> printPathtype(
3115             -num => # ## optional, defaults to 0.
3116             );
3117              
3118             =cut
3119              
3120             sub printPathtype
3121             {
3122 0     0 1 0 my($self,%arg) = @_;
3123 0         0 my $pathType = $arg{'-num'};
3124 0 0       0 $pathType=0 if (! defined $pathType);
3125 0 0       0 $self -> printGds2Record(-type => 'PATHTYPE',-data => $pathType) if ($pathType);
3126             }
3127             ################################################################################
3128              
3129             =head2 printMag - prints a MAG number
3130              
3131             usage:
3132             $gds2File -> printMag(
3133             -num => #.# ## optional, defaults to 0.0
3134             );
3135              
3136             =cut
3137              
3138             sub printMag
3139             {
3140 0     0 1 0 my($self,%arg) = @_;
3141 0         0 my $mag = $arg{'-num'};
3142 0 0 0     0 $mag=0 if ((! defined $mag)||($mag <= 0));
3143 0         0 $mag = cleanFloatNum($mag);
3144 0 0       0 $self -> printGds2Record(-type => 'MAG',-data => $mag) if ($mag);
3145             }
3146             ################################################################################
3147              
3148             sub printMask
3149             {
3150 0     0 0 0 my($self,%arg) = @_;
3151 0         0 my $string = $arg{'-string'};
3152 0 0       0 unless (defined $string)
3153             {
3154 0         0 die "printMask expects a string. Missing -string => 'text' $!";
3155             }
3156 0         0 $self -> printGds2Record(-type => 'MASK',-data => $string);
3157             }
3158             ################################################################################
3159              
3160             sub printNode
3161             {
3162 0     0 0 0 my $self = shift;
3163 0         0 $self -> printGds2Record(-type => 'NODE');
3164             }
3165             ################################################################################
3166              
3167             =head2 printNodetype - prints a NODETYPE number
3168              
3169             usage:
3170             $gds2File -> printNodetype(
3171             -num => #
3172             );
3173              
3174             =cut
3175              
3176             sub printNodetype
3177             {
3178 0     0 1 0 my($self,%arg) = @_;
3179 0         0 my $num = $arg{'-num'};
3180 0 0       0 unless (defined $num)
3181             {
3182 0         0 die "printNodetype expects a number. Missing -num => # $!";
3183             }
3184 0         0 $self -> printGds2Record(-type => 'NODETYPE',-data => $num);
3185             }
3186             ################################################################################
3187              
3188             sub printPlex
3189             {
3190 0     0 0 0 my($self,%arg) = @_;
3191 0         0 my $num = $arg{'-num'};
3192 0 0       0 unless (defined $num)
3193             {
3194 0         0 die "printPlex expects a number. Missing -num => #.# $!";
3195             }
3196 0         0 $self -> printGds2Record(-type => 'PLEX',-data => $num);
3197             }
3198             ################################################################################
3199              
3200             =head2 printPresentation - prints a text presentation record
3201              
3202             usage:
3203             $gds2File -> printPresentation(
3204             -font => #, ##optional, defaults to 0, valid numbers are 0-3
3205             -top, ||-middle, || -bottom, ## vertical justification
3206             -left, ||-center, || -right, ## horizontal justification
3207             );
3208              
3209             example:
3210             gds2File -> printPresentation(-font=>0,-top,-left);
3211              
3212             =cut
3213              
3214             sub printPresentation
3215             {
3216 0     0 1 0 my($self,%arg) = @_;
3217 0         0 my $font = $arg{'-font'};
3218 0 0 0     0 if ((! defined $font) || ($font < 0) || ($font > 3))
      0        
3219             {
3220 0         0 $font=0;
3221             }
3222 0         0 $font = sprintf("%02d",$font);
3223              
3224 0         0 my $vertical;
3225 0         0 my $top = $arg{'-top'};
3226 0         0 my $middle = $arg{'-middle'};
3227 0         0 my $bottom = $arg{'-bottom'};
3228 0 0       0 if (defined $top) {$vertical = '00';}
  0 0       0  
3229 0         0 elsif (defined $bottom) {$vertical = '10';}
3230 0         0 else {$vertical = '01';} ## middle
3231 0         0 my $horizontal;
3232 0         0 my $left = $arg{'-left'};
3233 0         0 my $center = $arg{'-center'};
3234 0         0 my $right = $arg{'-right'};
3235 0 0       0 if (defined $left) {$horizontal = '00';}
  0 0       0  
3236 0         0 elsif (defined $right) {$horizontal = '10';}
3237 0         0 else {$horizontal = '01';} ## center
3238              
3239 0         0 my $bitstring = '0'x10;
3240 0         0 $bitstring .= "$font$vertical$horizontal";
3241 0         0 $self -> printGds2Record(-type => 'PRESENTATION',-data => $bitstring);
3242             }
3243             ################################################################################
3244              
3245             =head2 printPropattr - prints a property id number
3246              
3247             usage:
3248             $gds2File -> printPropattr( -num => # );
3249              
3250             =cut
3251              
3252             sub printPropattr
3253             {
3254 0     0 1 0 my($self,%arg) = @_;
3255 0         0 my $num = $arg{'-num'};
3256 0 0       0 unless (defined $num)
3257             {
3258 0         0 die "printPropattr expects a number. Missing -num => # $!";
3259             }
3260 0         0 $self -> printGds2Record(-type => 'PROPATTR',-data => $num);
3261             }
3262             ################################################################################
3263              
3264             =head2 printPropvalue - prints a property value string
3265              
3266             usage:
3267             $gds2File -> printPropvalue( -string => $string );
3268              
3269             =cut
3270              
3271             sub printPropvalue
3272             {
3273 0     0 1 0 my($self,%arg) = @_;
3274 0         0 my $string = $arg{'-string'};
3275 0 0       0 unless (defined $string)
3276             {
3277 0         0 die "printPropvalue expects a string. Missing -string => 'text' $!";
3278             }
3279 0         0 $self -> printGds2Record(-type => 'PROPVALUE',-data => $string);
3280             }
3281             ################################################################################
3282              
3283             sub printReflibs
3284             {
3285 0     0 0 0 my($self,%arg) = @_;
3286 0         0 my $string = $arg{'-string'};
3287 0 0       0 unless (defined $string)
3288             {
3289 0         0 die "printReflibs expects a string. Missing -string => 'text' $!";
3290             }
3291 0         0 $self -> printGds2Record(-type => 'REFLIBS',-data => $string);
3292             }
3293             ################################################################################
3294              
3295             sub printReserved
3296             {
3297 0     0 0 0 my($self,%arg) = @_;
3298 0         0 my $num = $arg{'-num'};
3299 0 0       0 unless (defined $num)
3300             {
3301 0         0 die "printReserved expects a number. Missing -num => #.# $!";
3302             }
3303 0         0 $self -> printGds2Record(-type => 'RESERVED',-data => $num);
3304             }
3305             ################################################################################
3306              
3307             =head2 printSname - prints a SNAME string
3308              
3309             usage:
3310             $gds2File -> printSname( -name => $cellName );
3311              
3312             =cut
3313              
3314             sub printSname
3315             {
3316 0     0 1 0 my($self,%arg) = @_;
3317 0         0 my $string = $arg{'-name'};
3318 0 0       0 if (! defined $string)
3319             {
3320 0         0 die "printSname expects a cell name. Missing -name => 'text' $!";
3321             }
3322 0         0 $self -> printGds2Record(-type => 'SNAME',-data => $string);
3323             }
3324             ################################################################################
3325              
3326             sub printSpacing
3327             {
3328 0     0 0 0 my $self = shift;
3329 0         0 die "SPACING type not supported $!";
3330             }
3331             ################################################################################
3332              
3333             sub printSrfname
3334             {
3335 0     0 0 0 my $self = shift;
3336 0         0 $self -> printGds2Record(-type => 'SRFNAME');
3337             }
3338             ################################################################################
3339              
3340             =head2 printStrans - prints a STRANS record
3341              
3342             usage:
3343             $gds2File -> printStrans( -reflect );
3344              
3345             =cut
3346              
3347             sub printStrans
3348             {
3349 0     0 1 0 my($self,%arg) = @_;
3350 0         0 my $reflect = $arg{'-reflect'};
3351 0 0 0     0 if ((! defined $reflect)||($reflect <= 0))
3352             {
3353 0         0 $reflect = 0;
3354             }
3355             else
3356             {
3357 0         0 $reflect = 1;
3358             }
3359 0         0 my $data = $reflect.'0'x15; ## 16 'bit' string
3360 0         0 $self -> printGds2Record(-type => 'STRANS',-data => $data);
3361             }
3362             ################################################################################
3363              
3364             sub printStrclass
3365             {
3366 0     0 0 0 my $self = shift;
3367 0         0 $self -> printGds2Record(-type => 'STRCLASS');
3368             }
3369             ################################################################################
3370              
3371             =head2 printString - prints a STRING record
3372              
3373             usage:
3374             $gds2File -> printSname( -string => $text );
3375              
3376             =cut
3377              
3378             sub printString
3379             {
3380 0     0 1 0 my($self,%arg) = @_;
3381 0         0 my $string = $arg{'-string'};
3382 0 0       0 unless (defined $string)
3383             {
3384 0         0 die "printString expects a string. Missing -string => 'text' $!";
3385             }
3386 0         0 $self -> printGds2Record(-type => 'STRING',-data => $string);
3387             }
3388             ################################################################################
3389              
3390             =head2 printStrname - prints a structure name string
3391              
3392             usage:
3393             $gds2File -> printStrname( -name => $cellName );
3394              
3395             =cut
3396              
3397             sub printStrname
3398             {
3399 0     0 1 0 my($self,%arg) = @_;
3400 0         0 my $strName = $arg{'-name'};
3401 0 0       0 unless (defined $strName)
3402             {
3403 0         0 die "printStrname expects a structure name. Missing -name => 'name' $!";
3404             }
3405 0         0 $self -> printGds2Record(-type => 'STRNAME',-data => $strName);
3406             }
3407             ################################################################################
3408              
3409             sub printStrtype
3410             {
3411 0     0 0 0 my $self = shift;
3412 0         0 die "STRTYPE type not supported $!";
3413             }
3414             ################################################################################
3415              
3416             sub printStyptable
3417             {
3418 0     0 0 0 my($self,%arg) = @_;
3419 0         0 my $string = $arg{'-string'};
3420 0 0       0 unless (defined $string)
3421             {
3422 0         0 die "printStyptable expects a string. Missing -string => 'text' $!";
3423             }
3424 0         0 $self -> printGds2Record(-type => 'STYPTABLE',-data => $string);
3425             }
3426             ################################################################################
3427              
3428             sub printTapecode
3429             {
3430 0     0 0 0 my($self,%arg) = @_;
3431 0         0 my $num = $arg{'-num'};
3432 0 0       0 unless (defined $num)
3433             {
3434 0         0 die "printTapecode expects a number. Missing -num => #.# $!";
3435             }
3436 0         0 $self -> printGds2Record(-type => 'TAPECODE',-data => $num);
3437             }
3438             ################################################################################
3439              
3440             sub printTapenum
3441             {
3442 0     0 0 0 my($self,%arg) = @_;
3443 0         0 my $num = $arg{'-num'};
3444 0 0       0 unless (defined $num)
3445             {
3446 0         0 die "printTapenum expects a number. Missing -num => #.# $!";
3447             }
3448 0         0 $self -> printGds2Record(-type => 'TAPENUM',-data => $num);
3449             }
3450             ################################################################################
3451              
3452             sub printTextnode
3453             {
3454 0     0 0 0 my $self = shift;
3455 0         0 $self -> printGds2Record(-type => 'TEXTNODE');
3456             }
3457             ################################################################################
3458              
3459             =head2 printTexttype - prints a text type number
3460              
3461             usage:
3462             $gds2File -> printTexttype( -num => # );
3463              
3464             =cut
3465              
3466             sub printTexttype
3467             {
3468 0     0 1 0 my($self,%arg) = @_;
3469 0         0 my $num = $arg{'-num'};
3470 0 0       0 unless (defined $num)
3471             {
3472 0         0 die "printTexttype expects a number. Missing -num => # $!";
3473             }
3474 0 0       0 $num = 0 if ($num < 0);
3475 0         0 $self -> printGds2Record(-type => 'TEXTTYPE',-data => $num);
3476             }
3477             ################################################################################
3478              
3479             sub printUinteger
3480             {
3481 0     0 0 0 my $self = shift;
3482 0         0 die "UINTEGER type not supported $!";
3483             }
3484             ################################################################################
3485              
3486             =head2 printUnits - Prints units record.
3487              
3488             options:
3489             -uUnit => real number ## (optional) default is 0.001
3490             -dbUnit => real number ## (optional) default is 1e-9
3491              
3492             =cut
3493              
3494             sub printUnits
3495             {
3496 0     0 1 0 my($self,%arg) = @_;
3497              
3498 0         0 my $uUnit = $arg{'-uUnit'};
3499 0 0       0 if (! defined $uUnit)
3500             {
3501 0         0 $uUnit = 0.001;
3502             }
3503             else
3504             {
3505 0         0 $self -> {'Resolution'} = (1 / $uUnit); ## default is 1000 - already set in new()
3506             }
3507 0         0 $self -> {'UUnits'} = $uUnit;
3508             #################################################
3509 0         0 my $dbUnit = $arg{'-dbUnit'};
3510 0 0       0 unless (defined $dbUnit)
3511             {
3512 0         0 $dbUnit = 1e-9;
3513             }
3514 0         0 $self -> {'DBUnits'} = $dbUnit;
3515             #################################################
3516              
3517 0         0 $self -> printGds2Record(-type => 'UNITS',-data => [$uUnit,$dbUnit]);
3518             }
3519             ################################################################################
3520              
3521             sub printUstring
3522             {
3523 0     0 0 0 my $self = shift;
3524 0         0 die "USTRING type not supported $!";
3525             }
3526             ################################################################################
3527              
3528             =head2 printWidth - prints a width number
3529              
3530             usage:
3531             $gds2File -> printWidth( -num => # );
3532              
3533             =cut
3534              
3535             sub printWidth
3536             {
3537 0     0 1 0 my($self,%arg) = @_;
3538 0         0 my $width = $arg{'-num'};
3539 0 0 0     0 if ((! defined $width)||($width <= 0))
3540             {
3541 0         0 $width=0;
3542             }
3543 0 0       0 $self -> printGds2Record(-type => 'WIDTH',-data => $width) if ($width);
3544             }
3545             ################################################################################
3546              
3547             =head2 printXy - prints an XY array
3548              
3549             usage:
3550             $gds2File -> printXy( -xyInt => \@arrayGds2Ints );
3551             -or-
3552             $gds2File -> printXy( -xy => \@arrayReals );
3553              
3554             -xyInt most useful if reading and modifying... -xy if creating from scratch
3555              
3556             =cut
3557              
3558             sub printXy
3559             {
3560 0     0 1 0 my($self,%arg) = @_;
3561             #### -xyInt most useful if reading and modifying... -xy if creating from scratch
3562 0         0 my $xyInt = $arg{'-xyInt'}; ## $xyInt should be a reference to an array of internal GDS2 format integers
3563 0         0 my $xy = $arg{'-xy'}; ## $xy should be a reference to an array of reals
3564 0         0 my $resolution = $self -> {'Resolution'};
3565 0 0 0     0 if (! ((defined $xy) || (defined $xyInt)))
3566             {
3567 0         0 die "printXy expects an xy array reference. Missing -xy => \\\@array $!";
3568             }
3569 0 0       0 if (defined $xyInt)
3570             {
3571 0         0 $xy = $xyInt;
3572 0         0 $resolution = 1;
3573             }
3574 0         0 my @xyTmp=(); ##don't pollute array passed in
3575 0         0 for(my $i=0;$i<=$#$xy;$i++) ## e.g. 3.4 in -> 3400 out
3576             {
3577 0 0       0 if ($xy -> [$i] >= 0) {push @xyTmp,int((($xy -> [$i])*$resolution)+$G_epsilon);}
  0         0  
3578 0         0 else {push @xyTmp,int((($xy -> [$i])*$resolution)-$G_epsilon);}
3579             }
3580 0         0 $self -> printGds2Record(-type => 'XY',-data => \@xyTmp);
3581             }
3582             ################################################################################
3583              
3584              
3585             =head1 Low Level Specific Evaluation Methods
3586              
3587             =cut
3588              
3589             =head2 returnFilePosition - return current byte position (NOT zero based)
3590              
3591             usage:
3592             my $position = $gds2File -> returnFilePosition;
3593              
3594             =cut
3595              
3596             sub returnFilePosition()
3597             {
3598 0     0 1 0 my $self = shift;
3599 0         0 $self -> {'BytesDone'};
3600             }
3601             ################################################################################
3602              
3603             sub tellSize() ## old name
3604             {
3605 0     0 0 0 my $self = shift;
3606 0         0 $self -> {'BytesDone'};
3607             }
3608             ################################################################################
3609              
3610              
3611             =head2 returnBgnextn - returns bgnextn if record is BGNEXTN else returns 0
3612              
3613             usage:
3614              
3615             =cut
3616              
3617             sub returnBgnextn
3618             {
3619 0     0 1 0 my $self = shift;
3620             ## 2 byte signed integer
3621 0 0       0 if ($self -> isBgnextn) { $self -> {'RecordData'}[0]; }
  0         0  
3622 0         0 else { 0; }
3623             }
3624             ################################################################################
3625              
3626             =head2 returnDatatype - returns datatype # if record is DATATYPE else returns -1
3627              
3628             usage:
3629             $dataTypesFound[$gds2File -> returnDatatype] = 1;
3630              
3631             =cut
3632              
3633             sub returnDatatype
3634             {
3635 0     0 1 0 my $self = shift;
3636             ## 2 byte signed integer
3637 0 0       0 if ($self -> isDatatype) { $self -> {'RecordData'}[0]; }
  0         0  
3638 0         0 else { UNKNOWN; }
3639             }
3640             ################################################################################
3641              
3642             =head2 returnEndextn- returns endextn if record is ENDEXTN else returns 0
3643              
3644             usage:
3645              
3646             =cut
3647              
3648             sub returnEndextn
3649             {
3650 0     0 0 0 my $self = shift;
3651             ## 2 byte signed integer
3652 0 0       0 if ($self -> isEndextn) { $self -> {'RecordData'}[0]; }
  0         0  
3653 0         0 else { 0; }
3654             }
3655             ################################################################################
3656              
3657              
3658             =head2 returnLayer - returns layer # if record is LAYER else returns -1
3659              
3660             usage:
3661             $layersFound[$gds2File -> returnLayer] = 1;
3662              
3663             =cut
3664              
3665             sub returnLayer
3666             {
3667 0     0 1 0 my $self = shift;
3668             ## 2 byte signed integer
3669 0 0       0 if ($self -> isLayer) { $self -> {'RecordData'}[0]; }
  0         0  
3670 0         0 else { UNKNOWN; }
3671             }
3672             ################################################################################
3673              
3674             =head2 returnPathtype - returns pathtype # if record is PATHTYPE else returns -1
3675              
3676             usage:
3677              
3678             =cut
3679              
3680             sub returnPathtype
3681             {
3682 0     0 1 0 my $self = shift;
3683             ## 2 byte signed integer
3684 0 0       0 if ($self -> isPathtype) { $self -> {'RecordData'}[0]; }
  0         0  
3685 0         0 else { UNKNOWN; }
3686             }
3687             ################################################################################
3688              
3689             =head2 returnPropattr - returns propattr # if record is PROPATTR else returns -1
3690              
3691             usage:
3692              
3693             =cut
3694              
3695             sub returnPropattr
3696             {
3697 0     0 1 0 my $self = shift;
3698             ## 2 byte signed integer
3699 0 0       0 if ($self -> isPropattr) { $self -> {'RecordData'}[0]; }
  0         0  
3700 0         0 else { UNKNOWN; }
3701             }
3702             ################################################################################
3703              
3704             =head2 returnPropvalue - returns propvalue string if record is PROPVALUE else returns ''
3705              
3706             usage:
3707              
3708             =cut
3709              
3710             sub returnPropvalue
3711             {
3712 0     0 1 0 my $self = shift;
3713 0 0       0 if ($self -> isPropvalue) { $self -> {'RecordData'}[0]; }
  0         0  
3714 0         0 else { ''; }
3715             }
3716             ################################################################################
3717              
3718             =head2 returnSname - return string if record type is SNAME else ''
3719              
3720             =cut
3721              
3722             sub returnSname
3723             {
3724 0     0 1 0 my $self = shift;
3725 0 0       0 if ($self -> isSname) { $self -> {'RecordData'}[0]; }
  0         0  
3726 0         0 else { ''; }
3727             }
3728             ################################################################################
3729              
3730             =head2 returnString - return string if record type is STRING else ''
3731              
3732             =cut
3733              
3734             sub returnString
3735             {
3736 0     0 1 0 my $self = shift;
3737 0 0       0 if ($self -> isString) { $self -> {'RecordData'}[0]; }
  0         0  
3738 0         0 else { ''; }
3739             }
3740             ################################################################################
3741              
3742             =head2 returnStrname - return string if record type is STRNAME else ''
3743              
3744             =cut
3745              
3746             sub returnStrname
3747             {
3748 0     0 1 0 my $self = shift;
3749 0 0       0 if ($self -> isStrname) { $self -> {'RecordData'}[0]; }
  0         0  
3750 0         0 else { ''; }
3751             }
3752             ################################################################################
3753              
3754             =head2 returnTexttype - returns texttype # if record is TEXTTYPE else returns -1
3755              
3756             usage:
3757             $TextTypesFound[$gds2File -> returnTexttype] = 1;
3758              
3759             =cut
3760              
3761             sub returnTexttype
3762             {
3763 0     0 1 0 my $self = shift;
3764             ## 2 byte signed integer
3765 0 0       0 if ($self -> isTexttype) { $self -> {'RecordData'}[0]; }
  0         0  
3766 0         0 else { UNKNOWN; }
3767             }
3768             ################################################################################
3769              
3770             =head2 returnWidth - returns width # if record is WIDTH else returns -1
3771              
3772             usage:
3773              
3774             =cut
3775              
3776             sub returnWidth
3777             {
3778 0     0 1 0 my $self = shift;
3779             ## 4 byte signed integer
3780 0 0       0 if ($self -> isWidth) { $self -> {'RecordData'}[0]; }
  0         0  
3781 0         0 else { UNKNOWN; }
3782             }
3783             ################################################################################
3784              
3785             ################################################################################
3786              
3787             =head1 Low Level Specific Boolean Methods
3788              
3789             =cut
3790              
3791             ################################################################################
3792              
3793             =head2 isAref - return 0 or 1 depending on whether current record is an aref
3794              
3795             =cut
3796              
3797             sub isAref
3798             {
3799 0     0 1 0 my $self = shift;
3800 0 0       0 if ($self -> {'RecordType'} == AREF) { 1; }
  0         0  
3801 0         0 else { 0; }
3802             }
3803             ################################################################################
3804              
3805             =head2 isBgnlib - return 0 or 1 depending on whether current record is a bgnlib
3806              
3807             =cut
3808              
3809             sub isBgnlib
3810             {
3811 0     0 1 0 my $self = shift;
3812 0 0       0 if ($self -> {'RecordType'} == BGNLIB) { 1; }
  0         0  
3813 0         0 else { 0; }
3814             }
3815             ################################################################################
3816              
3817             =head2 isBgnstr - return 0 or 1 depending on whether current record is a bgnstr
3818              
3819             =cut
3820              
3821             sub isBgnstr
3822             {
3823 0     0 1 0 my $self = shift;
3824 0 0       0 if ($self -> {'RecordType'} == BGNSTR) { 1; }
  0         0  
3825 0         0 else { 0; }
3826             }
3827             ################################################################################
3828              
3829             =head2 isBoundary - return 0 or 1 depending on whether current record is a boundary
3830              
3831             =cut
3832              
3833             sub isBoundary
3834             {
3835 0     0 1 0 my $self = shift;
3836 0 0       0 if ($self -> {'RecordType'} == BOUNDARY) { 1; }
  0         0  
3837 0         0 else { 0; }
3838             }
3839             ################################################################################
3840              
3841             =head2 isDatatype - return 0 or 1 depending on whether current record is datatype
3842              
3843             =cut
3844              
3845             sub isDatatype
3846             {
3847 0     0 1 0 my $self = shift;
3848 0 0       0 if ($self -> {'RecordType'} == DATATYPE) { 1; }
  0         0  
3849 0         0 else { 0; }
3850             }
3851             ################################################################################
3852              
3853             =head2 isEndlib - return 0 or 1 depending on whether current record is endlib
3854              
3855             =cut
3856              
3857             sub isEndlib
3858             {
3859 0     0 1 0 my $self = shift;
3860 0 0       0 if ($self -> {'RecordType'} == ENDLIB) { 1; }
  0         0  
3861 0         0 else { 0; }
3862             }
3863             ################################################################################
3864              
3865             =head2 isEndel - return 0 or 1 depending on whether current record is endel
3866              
3867             =cut
3868              
3869             sub isEndel
3870             {
3871 0     0 1 0 my $self = shift;
3872 0 0       0 if ($self -> {'RecordType'} == ENDEL) { 1; }
  0         0  
3873 0         0 else { 0; }
3874             }
3875             ################################################################################
3876              
3877             =head2 isEndstr - return 0 or 1 depending on whether current record is endstr
3878              
3879             =cut
3880              
3881             sub isEndstr
3882             {
3883 0     0 1 0 my $self = shift;
3884 0 0       0 if ($self -> {'RecordType'} == ENDSTR) { 1; }
  0         0  
3885 0         0 else { 0; }
3886             }
3887             ################################################################################
3888              
3889              
3890             =head2 isHeader - return 0 or 1 depending on whether current record is a header
3891              
3892             =cut
3893              
3894             sub isHeader
3895             {
3896 0     0 1 0 my $self = shift;
3897 0 0       0 if ($self -> {'RecordType'} == HEADER) { 1; }
  0         0  
3898 0         0 else { 0; }
3899             }
3900             ################################################################################
3901              
3902             =head2 isLibname - return 0 or 1 depending on whether current record is a libname
3903              
3904             =cut
3905              
3906             sub isLibname
3907             {
3908 0     0 1 0 my $self = shift;
3909 0 0       0 if ($self -> {'RecordType'} == LIBNAME) { 1; }
  0         0  
3910 0         0 else { 0; }
3911             }
3912             ################################################################################
3913              
3914             =head2 isPath - return 0 or 1 depending on whether current record is a path
3915              
3916             =cut
3917              
3918             sub isPath
3919             {
3920 0     0 1 0 my $self = shift;
3921 0 0       0 if ($self -> {'RecordType'} == PATH) { 1; }
  0         0  
3922 0         0 else { 0; }
3923             }
3924             ################################################################################
3925              
3926             =head2 isSref - return 0 or 1 depending on whether current record is an sref
3927              
3928             =cut
3929              
3930             sub isSref
3931             {
3932 0     0 1 0 my $self = shift;
3933 0 0       0 if ($self -> {'RecordType'} == SREF) { 1; }
  0         0  
3934 0         0 else { 0; }
3935             }
3936             ################################################################################
3937              
3938             =head2 isSrfname - return 0 or 1 depending on whether current record is an srfname
3939              
3940             =cut
3941              
3942             sub isSrfname
3943             {
3944 0     0 1 0 my $self = shift;
3945 0 0       0 if ($self -> {'RecordType'} == SRFNAME) { 1; }
  0         0  
3946 0         0 else { 0; }
3947             }
3948             ################################################################################
3949              
3950             =head2 isText - return 0 or 1 depending on whether current record is a text
3951              
3952             =cut
3953              
3954             sub isText
3955             {
3956 0     0 1 0 my $self = shift;
3957 0 0       0 if ($self -> {'RecordType'} == TEXT) { 1; }
  0         0  
3958 0         0 else { 0; }
3959             }
3960             ################################################################################
3961              
3962             =head2 isUnits - return 0 or 1 depending on whether current record is units
3963              
3964             =cut
3965              
3966             sub isUnits
3967             {
3968 0     0 1 0 my $self = shift;
3969 0 0       0 if ($self -> {'RecordType'} == UNITS) { 1; }
  0         0  
3970 0         0 else { 0; }
3971             }
3972             ################################################################################
3973              
3974             =head2 isLayer - return 0 or 1 depending on whether current record is layer
3975              
3976             =cut
3977              
3978             sub isLayer
3979             {
3980 0     0 1 0 my $self = shift;
3981 0 0       0 if ($self -> {'RecordType'} == LAYER) { 1; }
  0         0  
3982 0         0 else { 0; }
3983             }
3984             ################################################################################
3985              
3986             =head2 isStrname - return 0 or 1 depending on whether current record is strname
3987              
3988             =cut
3989              
3990             sub isStrname
3991             {
3992 0     0 1 0 my $self = shift;
3993 0 0       0 if ($self -> {'RecordType'} == STRNAME) { 1; }
  0         0  
3994 0         0 else { 0; }
3995             }
3996             ################################################################################
3997              
3998             =head2 isWidth - return 0 or 1 depending on whether current record is width
3999              
4000             =cut
4001              
4002             sub isWidth
4003             {
4004 0     0 1 0 my $self = shift;
4005 0 0       0 if ($self -> {'RecordType'} == WIDTH) { 1; }
  0         0  
4006 0         0 else { 0; }
4007             }
4008             ################################################################################
4009              
4010             =head2 isXy - return 0 or 1 depending on whether current record is xy
4011              
4012             =cut
4013              
4014             sub isXy
4015             {
4016 0     0 1 0 my $self = shift;
4017 0 0       0 if ($self -> {'RecordType'} == XY) { 1; }
  0         0  
4018 0         0 else { 0; }
4019             }
4020             ################################################################################
4021              
4022             =head2 isSname - return 0 or 1 depending on whether current record is sname
4023              
4024             =cut
4025              
4026             sub isSname
4027             {
4028 0     0 1 0 my $self = shift;
4029 0 0       0 if ($self -> {'RecordType'} == SNAME) { 1; }
  0         0  
4030 0         0 else { 0; }
4031             }
4032             ################################################################################
4033              
4034             =head2 isColrow - return 0 or 1 depending on whether current record is colrow
4035              
4036             =cut
4037              
4038             sub isColrow
4039             {
4040 0     0 1 0 my $self = shift;
4041 0 0       0 if ($self -> {'RecordType'} == COLROW) { 1; }
  0         0  
4042 0         0 else { 0; }
4043             }
4044             ################################################################################
4045              
4046             =head2 isTextnode - return 0 or 1 depending on whether current record is a textnode
4047              
4048             =cut
4049              
4050             sub isTextnode
4051             {
4052 0     0 1 0 my $self = shift;
4053 0 0       0 if ($self -> {'RecordType'} == TEXTNODE) { 1; }
  0         0  
4054 0         0 else { 0; }
4055             }
4056             ################################################################################
4057              
4058             =head2 isNode - return 0 or 1 depending on whether current record is a node
4059              
4060             =cut
4061              
4062             sub isNode
4063             {
4064 0     0 1 0 my $self = shift;
4065 0 0       0 if ($self -> {'RecordType'} == NODE) { 1; }
  0         0  
4066 0         0 else { 0; }
4067             }
4068             ################################################################################
4069              
4070             =head2 isTexttype - return 0 or 1 depending on whether current record is a texttype
4071              
4072             =cut
4073              
4074             sub isTexttype
4075             {
4076 0     0 1 0 my $self = shift;
4077 0 0       0 if ($self -> {'RecordType'} == TEXTTYPE) { 1; }
  0         0  
4078 0         0 else { 0; }
4079             }
4080             ################################################################################
4081              
4082             =head2 isPresentation - return 0 or 1 depending on whether current record is a presentation
4083              
4084             =cut
4085              
4086             sub isPresentation
4087             {
4088 0     0 1 0 my $self = shift;
4089 0 0       0 if ($self -> {'RecordType'} == PRESENTATION) { 1; }
  0         0  
4090 0         0 else { 0; }
4091             }
4092             ################################################################################
4093              
4094             =head2 isSpacing - return 0 or 1 depending on whether current record is a spacing
4095              
4096             =cut
4097              
4098             sub isSpacing
4099             {
4100 0     0 1 0 my $self = shift;
4101 0 0       0 if ($self -> {'RecordType'} == SPACING) { 1; }
  0         0  
4102 0         0 else { 0; }
4103             }
4104             ################################################################################
4105              
4106             =head2 isString - return 0 or 1 depending on whether current record is a string
4107              
4108             =cut
4109              
4110             sub isString
4111             {
4112 0     0 1 0 my $self = shift;
4113 0 0       0 if ($self -> {'RecordType'} == STRING) { 1; }
  0         0  
4114 0         0 else { 0; }
4115             }
4116             ################################################################################
4117              
4118             =head2 isStrans - return 0 or 1 depending on whether current record is a strans
4119              
4120             =cut
4121              
4122             sub isStrans
4123             {
4124 0     0 1 0 my $self = shift;
4125 0 0       0 if ($self -> {'RecordType'} == STRANS) { 1; }
  0         0  
4126 0         0 else { 0; }
4127             }
4128             ################################################################################
4129              
4130             =head2 isMag - return 0 or 1 depending on whether current record is a mag
4131              
4132             =cut
4133              
4134             sub isMag
4135             {
4136 0     0 1 0 my $self = shift;
4137 0 0       0 if ($self -> {'RecordType'} == MAG) { 1; }
  0         0  
4138 0         0 else { 0; }
4139             }
4140             ################################################################################
4141              
4142             =head2 isAngle - return 0 or 1 depending on whether current record is a angle
4143              
4144             =cut
4145              
4146             sub isAngle
4147             {
4148 0     0 1 0 my $self = shift;
4149 0 0       0 if ($self -> {'RecordType'} == ANGLE) { 1; }
  0         0  
4150 0         0 else { 0; }
4151             }
4152             ################################################################################
4153              
4154             =head2 isUinteger - return 0 or 1 depending on whether current record is a uinteger
4155              
4156             =cut
4157              
4158             sub isUinteger
4159             {
4160 0     0 1 0 my $self = shift;
4161 0 0       0 if ($self -> {'RecordType'} == UINTEGER) { 1; }
  0         0  
4162 0         0 else { 0; }
4163             }
4164             ################################################################################
4165              
4166             =head2 isUstring - return 0 or 1 depending on whether current record is a ustring
4167              
4168             =cut
4169              
4170             sub isUstring
4171             {
4172 0     0 1 0 my $self = shift;
4173 0 0       0 if ($self -> {'RecordType'} == USTRING) { 1; }
  0         0  
4174 0         0 else { 0; }
4175             }
4176             ################################################################################
4177              
4178             =head2 isReflibs - return 0 or 1 depending on whether current record is a reflibs
4179              
4180             =cut
4181              
4182             sub isReflibs
4183             {
4184 0     0 1 0 my $self = shift;
4185 0 0       0 if ($self -> {'RecordType'} == REFLIBS) { 1; }
  0         0  
4186 0         0 else { 0; }
4187             }
4188             ################################################################################
4189              
4190             =head2 isFonts - return 0 or 1 depending on whether current record is a fonts
4191              
4192             =cut
4193              
4194             sub isFonts
4195             {
4196 0     0 1 0 my $self = shift;
4197 0 0       0 if ($self -> {'RecordType'} == FONTS) { 1; }
  0         0  
4198 0         0 else { 0; }
4199             }
4200             ################################################################################
4201              
4202             =head2 isPathtype - return 0 or 1 depending on whether current record is a pathtype
4203              
4204             =cut
4205              
4206             sub isPathtype
4207             {
4208 0     0 1 0 my $self = shift;
4209 0 0       0 if ($self -> {'RecordType'} == PATHTYPE) { 1; }
  0         0  
4210 0         0 else { 0; }
4211             }
4212             ################################################################################
4213              
4214             =head2 isGenerations - return 0 or 1 depending on whether current record is a generations
4215              
4216             =cut
4217              
4218             sub isGenerations
4219             {
4220 0     0 1 0 my $self = shift;
4221 0 0       0 if ($self -> {'RecordType'} == GENERATIONS) { 1; }
  0         0  
4222 0         0 else { 0; }
4223             }
4224             ################################################################################
4225              
4226             =head2 isAttrtable - return 0 or 1 depending on whether current record is a attrtable
4227              
4228             =cut
4229              
4230             sub isAttrtable
4231             {
4232 0     0 1 0 my $self = shift;
4233 0 0       0 if ($self -> {'RecordType'} == ATTRTABLE) { 1; }
  0         0  
4234 0         0 else { 0; }
4235             }
4236             ################################################################################
4237              
4238             =head2 isStyptable - return 0 or 1 depending on whether current record is a styptable
4239              
4240             =cut
4241              
4242             sub isStyptable
4243             {
4244 0     0 1 0 my $self = shift;
4245 0 0       0 if ($self -> {'RecordType'} == STYPTABLE) { 1; }
  0         0  
4246 0         0 else { 0; }
4247             }
4248             ################################################################################
4249              
4250             =head2 isStrtype - return 0 or 1 depending on whether current record is a strtype
4251              
4252             =cut
4253              
4254             sub isStrtype
4255             {
4256 0     0 1 0 my $self = shift;
4257 0 0       0 if ($self -> {'RecordType'} == STRTYPE) { 1; }
  0         0  
4258 0         0 else { 0; }
4259             }
4260             ################################################################################
4261              
4262             =head2 isEflags - return 0 or 1 depending on whether current record is a eflags
4263              
4264             =cut
4265              
4266             sub isEflags
4267             {
4268 0     0 1 0 my $self = shift;
4269 0 0       0 if ($self -> {'RecordType'} == EFLAGS) { 1; }
  0         0  
4270 0         0 else { 0; }
4271             }
4272             ################################################################################
4273              
4274             =head2 isElkey - return 0 or 1 depending on whether current record is a elkey
4275              
4276             =cut
4277              
4278             sub isElkey
4279             {
4280 0     0 1 0 my $self = shift;
4281 0 0       0 if ($self -> {'RecordType'} == ELKEY) { 1; }
  0         0  
4282 0         0 else { 0; }
4283             }
4284             ################################################################################
4285              
4286             =head2 isLinktype - return 0 or 1 depending on whether current record is a linktype
4287              
4288             =cut
4289              
4290             sub isLinktype
4291             {
4292 0     0 1 0 my $self = shift;
4293 0 0       0 if ($self -> {'RecordType'} == LINKTYPE) { 1; }
  0         0  
4294 0         0 else { 0; }
4295             }
4296             ################################################################################
4297              
4298             =head2 isLinkkeys - return 0 or 1 depending on whether current record is a linkkeys
4299              
4300             =cut
4301              
4302             sub isLinkkeys
4303             {
4304 0     0 1 0 my $self = shift;
4305 0 0       0 if ($self -> {'RecordType'} == LINKKEYS) { 1; }
  0         0  
4306 0         0 else { 0; }
4307             }
4308             ################################################################################
4309              
4310             =head2 isNodetype - return 0 or 1 depending on whether current record is a nodetype
4311              
4312             =cut
4313              
4314             sub isNodetype
4315             {
4316 0     0 1 0 my $self = shift;
4317 0 0       0 if ($self -> {'RecordType'} == NODETYPE) { 1; }
  0         0  
4318 0         0 else { 0; }
4319             }
4320             ################################################################################
4321              
4322             =head2 isPropattr - return 0 or 1 depending on whether current record is a propattr
4323              
4324             =cut
4325              
4326             sub isPropattr
4327             {
4328 0     0 1 0 my $self = shift;
4329 0 0       0 if ($self -> {'RecordType'} == PROPATTR) { 1; }
  0         0  
4330 0         0 else { 0; }
4331             }
4332             ################################################################################
4333              
4334             =head2 isPropvalue - return 0 or 1 depending on whether current record is a propvalue
4335              
4336             =cut
4337              
4338             sub isPropvalue
4339             {
4340 0     0 1 0 my $self = shift;
4341 0 0       0 if ($self -> {'RecordType'} == PROPVALUE) { 1; }
  0         0  
4342 0         0 else { 0; }
4343             }
4344             ################################################################################
4345              
4346             =head2 isBox - return 0 or 1 depending on whether current record is a box
4347              
4348             =cut
4349              
4350             sub isBox
4351             {
4352 0     0 1 0 my $self = shift;
4353 0 0       0 if ($self -> {'RecordType'} == BOX) { 1; }
  0         0  
4354 0         0 else { 0; }
4355             }
4356             ################################################################################
4357              
4358             =head2 isBoxtype - return 0 or 1 depending on whether current record is a boxtype
4359              
4360             =cut
4361              
4362             sub isBoxtype
4363             {
4364 0     0 1 0 my $self = shift;
4365 0 0       0 if ($self -> {'RecordType'} == BOXTYPE) { 1; }
  0         0  
4366 0         0 else { 0; }
4367             }
4368             ################################################################################
4369              
4370             =head2 isPlex - return 0 or 1 depending on whether current record is a plex
4371              
4372             =cut
4373              
4374             sub isPlex
4375             {
4376 0     0 1 0 my $self = shift;
4377 0 0       0 if ($self -> {'RecordType'} == PLEX) { 1; }
  0         0  
4378 0         0 else { 0; }
4379             }
4380             ################################################################################
4381              
4382             =head2 isBgnextn - return 0 or 1 depending on whether current record is a bgnextn
4383              
4384             =cut
4385              
4386             sub isBgnextn
4387             {
4388 0     0 1 0 my $self = shift;
4389 0 0       0 if ($self -> {'RecordType'} == BGNEXTN) { 1; }
  0         0  
4390 0         0 else { 0; }
4391             }
4392             ################################################################################
4393              
4394             =head2 isEndextn - return 0 or 1 depending on whether current record is a endextn
4395              
4396             =cut
4397              
4398             sub isEndextn
4399             {
4400 0     0 1 0 my $self = shift;
4401 0 0       0 if ($self -> {'RecordType'} == ENDEXTN) { 1; }
  0         0  
4402 0         0 else { 0; }
4403             }
4404             ################################################################################
4405              
4406             =head2 isTapenum - return 0 or 1 depending on whether current record is a tapenum
4407              
4408             =cut
4409              
4410             sub isTapenum
4411             {
4412 0     0 1 0 my $self = shift;
4413 0 0       0 if ($self -> {'RecordType'} == TAPENUM) { 1; }
  0         0  
4414 0         0 else { 0; }
4415             }
4416             ################################################################################
4417              
4418             =head2 isTapecode - return 0 or 1 depending on whether current record is a tapecode
4419              
4420             =cut
4421              
4422             sub isTapecode
4423             {
4424 0     0 1 0 my $self = shift;
4425 0 0       0 if ($self -> {'RecordType'} == TAPECODE) { 1; }
  0         0  
4426 0         0 else { 0; }
4427             }
4428             ################################################################################
4429              
4430             =head2 isStrclass - return 0 or 1 depending on whether current record is a strclass
4431              
4432             =cut
4433              
4434             sub isStrclass
4435             {
4436 0     0 1 0 my $self = shift;
4437 0 0       0 if ($self -> {'RecordType'} == STRCLASS) { 1; }
  0         0  
4438 0         0 else { 0; }
4439             }
4440             ################################################################################
4441              
4442             =head2 isReserved - return 0 or 1 depending on whether current record is a reserved
4443              
4444             =cut
4445              
4446             sub isReserved
4447             {
4448 0     0 1 0 my $self = shift;
4449 0 0       0 if ($self -> {'RecordType'} == RESERVED) { 1; }
  0         0  
4450 0         0 else { 0; }
4451             }
4452             ################################################################################
4453              
4454             =head2 isFormat - return 0 or 1 depending on whether current record is a format
4455              
4456             =cut
4457              
4458             sub isFormat
4459             {
4460 0     0 1 0 my $self = shift;
4461 0 0       0 if ($self -> {'RecordType'} == FORMAT) { 1; }
  0         0  
4462 0         0 else { 0; }
4463             }
4464             ################################################################################
4465              
4466             =head2 isMask - return 0 or 1 depending on whether current record is a mask
4467              
4468             =cut
4469              
4470             sub isMask
4471             {
4472 0     0 1 0 my $self = shift;
4473 0 0       0 if ($self -> {'RecordType'} == MASK) { 1; }
  0         0  
4474 0         0 else { 0; }
4475             }
4476             ################################################################################
4477              
4478             =head2 isEndmasks - return 0 or 1 depending on whether current record is a endmasks
4479              
4480             =cut
4481              
4482             sub isEndmasks
4483             {
4484 0     0 1 0 my $self = shift;
4485 0 0       0 if ($self -> {'RecordType'} == ENDMASKS) { 1; }
  0         0  
4486 0         0 else { 0; }
4487             }
4488             ################################################################################
4489              
4490             =head2 isLibdirsize - return 0 or 1 depending on whether current record is a libdirsize
4491              
4492             =cut
4493              
4494             sub isLibdirsize
4495             {
4496 0     0 1 0 my $self = shift;
4497 0 0       0 if ($self -> {'RecordType'} == LIBDIRSIZE) { 1; }
  0         0  
4498 0         0 else { 0; }
4499             }
4500             ################################################################################
4501              
4502             =head2 isLibsecur - return 0 or 1 depending on whether current record is a libsecur
4503              
4504             =cut
4505              
4506             sub isLibsecur
4507             {
4508 0     0 1 0 my $self = shift;
4509 0 0       0 if ($self -> {'RecordType'} == LIBSECUR) { 1; }
  0         0  
4510 0         0 else { 0; }
4511             }
4512             ################################################################################
4513              
4514             ################################################################################
4515             ## support functions
4516              
4517             sub getRecordData
4518             {
4519 0     0 0 0 my $self = shift;
4520 0         0 my $dt = $self -> {'DataType'};
4521 0 0 0     0 if ($dt == NO_REC_DATA)
    0 0        
    0          
4522             {
4523 0         0 return '';
4524             }
4525             elsif ($dt==INTEGER_2 || $dt==INTEGER_4 || $dt==REAL_8)
4526             {
4527 0         0 my $stuff = $self -> {'CurrentDataList'};
4528 0         0 $stuff =~ s|^,||;
4529 0         0 return(split(/,/,$stuff));
4530             }
4531             elsif ($dt == ACSII_STRING)
4532             {
4533 0         0 my $stuff = $self -> {'CurrentDataList'};
4534 0         0 $stuff =~ s|\0||g;
4535 0         0 return($stuff);
4536             }
4537             else ## bit_array
4538             {
4539 0         0 return ($self -> {'CurrentDataList'});
4540             }
4541             }
4542             ################################################################################
4543              
4544             sub readRecordTypeAndData
4545             {
4546 0     0 0 0 my $self = shift;
4547 0         0 return ($RecordTypeStrings[$self -> {'RecordType'}],$self -> {'RecordData'});
4548             }
4549             ################################################################################
4550              
4551             sub skipGds2RecordData
4552             {
4553 24     24 0 44 my $self = shift;
4554 24 50       55 $self -> readGds2RecordHeader() if ($self -> {'INHEADER'} != TRUE); ## safety - need to read HEADER if INHEADER == UNKNOWN or FALSE
4555 24         38 $self -> {'INHEADER'} = FALSE;
4556 24         36 $self -> {'INDATA'} = TRUE; # in DATA - actually will be at the end of data by the time we test this...
4557             ## 4 should have been just read by readGds2RecordHeader
4558 24         120 seek($self -> {'FileHandle'},$self -> {'Length'} - 4,SEEK_CUR); ## seek seems to run a little faster than read
4559 24         46 $self -> {'DataIndex'} = UNKNOWN;
4560 24         65 return 1;
4561             }
4562             ################################################################################
4563              
4564             ### return number of XY coords if XY record
4565             sub returnNumCoords
4566             {
4567 0     0 0 0 my $self = shift;
4568 0 0       0 if ($self -> {'RecordType'} == XY) ## 4 byte signed integer
4569             {
4570 0         0 int(($self -> {'Length'} - 4) / 8);
4571             }
4572             else
4573             {
4574 0         0 0;
4575             }
4576             }
4577             ################################################################################
4578              
4579             sub roundNum
4580             {
4581 0     0 0 0 my $self = shift;
4582 0         0 my $num = shift;
4583 0         0 my $places = shift;
4584 0         0 sprintf("%.${places}f",$num);
4585             }
4586             ################################################################################
4587              
4588             sub scaleNum($$)
4589             {
4590 0     0 0 0 my $num=shift;
4591 0         0 my $scale=shift;
4592 0 0       0 die "1st number passed into scaleNum() must be an integer $!" if ($num !~ m|^-?\d+|);
4593 0         0 $num = $num * $scale;
4594 0 0       0 $num = int($num+0.5) if ($num =~ m|\.|);
4595 0         0 $num;
4596             }
4597             ################################################################################
4598              
4599             sub snapNum($$)
4600             {
4601 0     0 0 0 my $num = shift;
4602 0 0       0 die "1st number passed into snapNum() must be an integer $!" if ($num !~ m|^-?\d+$|);
4603 0         0 my $snap = shift;
4604 0         0 my $snapLength = length("$snap");
4605 0         0 my $lean=1; ##init
4606 0 0       0 $lean = -1 if($num < 0);
4607             ## snap to grid..
4608 0         0 my $littlePart=substr($num,-$snapLength,$snapLength);
4609 0 0       0 if($num<0)
4610             {
4611 0         0 $littlePart = -$littlePart;
4612             }
4613 0         0 $littlePart = int(($littlePart/$snap)+(0.5*$lean))*$snap;
4614 0         0 my $bigPart=substr($num,0,-$snapLength);
4615 0 0       0 if ($bigPart =~ m|^[-]?$|)
4616             {
4617 0         0 $bigPart=0;
4618             }
4619             else
4620             {
4621 0         0 $bigPart *= 10**$snapLength;
4622             }
4623 0         0 $num = $bigPart + $littlePart;
4624 0         0 $num;
4625             }
4626             ################################################################################
4627              
4628             sub DESTROY
4629             {
4630 8     8   6010375 my $self = shift;
4631             #warn "DESTROYing $self";
4632             }
4633             ################################################################################
4634              
4635             ################################################################################
4636             ## some vendor tools have trouble w/ negative angles and angles >= 360
4637             ## so we normalize to positive equivalent
4638             ################################################################################
4639             sub posAngle($)
4640             {
4641 0     0 0 0 my $angle = shift;
4642 0         0 $angle += 360.0 while ($angle < 0.0);
4643 0         0 $angle -= 360.0 while ($angle >= 360.0);
4644 0         0 $angle = cleanFloatNum($angle);
4645 0         0 $angle;
4646             }
4647             ################################################################################
4648              
4649             =head2 recordSize - return current record size
4650              
4651             usage:
4652             my $len = $gds2File -> recordSize;
4653              
4654              
4655             =cut
4656              
4657             sub recordSize()
4658             {
4659 0     0 1 0 my $self = shift;
4660 0         0 $self -> {'Length'};
4661             }
4662             ################################################################################
4663              
4664             =head2 dataSize - return current record size - 4 (length of data)
4665              
4666             usage:
4667             my $dataLen = $gds2File -> dataSize;
4668              
4669              
4670             =cut
4671              
4672             sub dataSize()
4673             {
4674 0     0 1 0 my $self = shift;
4675 0         0 $self -> {'Length'} - 4;
4676             }
4677             ################################################################################
4678              
4679             =head2 returnUnitsAsArray - return user units and database units as a 2 element array
4680              
4681             usage:
4682             my ($uu,$dbu) = $gds2File -> returnUnitsAsArray;
4683              
4684              
4685             =cut
4686              
4687             sub returnUnitsAsArray
4688             {
4689 0     0 1 0 my $self = shift;
4690 0 0       0 if ($self -> isUnits) { ($self -> {'UUnits'}, $self -> {'DBUnits'}); }
  0         0  
4691 0         0 else { () }
4692             }
4693             ################################################################################
4694              
4695             #######
4696             sub subbyte() ## GDS2::version();
4697             {
4698 0     0 0 0 my($what,$where,$howmuch) = @_;
4699 0         0 unpack("x$where C$howmuch", $what);
4700             }
4701             ################################################################################
4702              
4703             =head2 version - return GDS2 module version string
4704              
4705             =cut
4706              
4707             #######
4708             sub version() ## GDS2::version();
4709             {
4710 0     0 1 0 return $GDS2::VERSION;
4711             }
4712             ################################################################################
4713              
4714             =head2 version - return GDS2 module revision string
4715              
4716             =cut
4717              
4718             #######
4719             sub revision() ## GDS2::revision();
4720             {
4721 0     0 1 0 return $GDS2::revision;
4722             }
4723             ################################################################################
4724              
4725             sub getElmSpace
4726             {
4727 150     150 0 383 return $ElmSpace;
4728             }
4729             ################################################################################
4730              
4731             sub putElmSpace
4732             {
4733 60     60 0 128 $ElmSpace = shift;
4734             }
4735             ################################################################################
4736              
4737             sub getStrSpace
4738             {
4739 164     164 0 443 return $StrSpace;
4740             }
4741             ################################################################################
4742              
4743             sub putStrSpace
4744             {
4745 18     18 0 47 $StrSpace = shift;
4746             }
4747             ################################################################################
4748              
4749             1;
4750             }
4751              
4752             __END__