jfreeze-ruby-gdsii 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +6 -0
- data/LICENSE.txt +20 -0
- data/README.txt +113 -0
- data/Rakefile +30 -0
- data/bin/rgds-debug +43 -0
- data/bin/rgds-dump +38 -0
- data/bin/rgds-join +98 -0
- data/bin/rgds-layers +53 -0
- data/bin/rgds-sremove +136 -0
- data/bin/rgds-ssplit +113 -0
- data/bin/rgds-stats +134 -0
- data/bin/rgds-structs +41 -0
- data/bin/rgds-tree +167 -0
- data/bin/rgds2rb +99 -0
- data/lib/gdsii.rb +137 -0
- data/lib/gdsii/aref.rb +243 -0
- data/lib/gdsii/bnf.rb +309 -0
- data/lib/gdsii/boundary.rb +53 -0
- data/lib/gdsii/box.rb +65 -0
- data/lib/gdsii/byte_order.rb +36 -0
- data/lib/gdsii/element.rb +172 -0
- data/lib/gdsii/group.rb +98 -0
- data/lib/gdsii/library.rb +518 -0
- data/lib/gdsii/mixins.rb +378 -0
- data/lib/gdsii/node.rb +65 -0
- data/lib/gdsii/path.rb +169 -0
- data/lib/gdsii/property.rb +108 -0
- data/lib/gdsii/record.rb +606 -0
- data/lib/gdsii/record/consts.rb +384 -0
- data/lib/gdsii/record/datatypes/ascii.rb +145 -0
- data/lib/gdsii/record/datatypes/bitarray.rb +101 -0
- data/lib/gdsii/record/datatypes/data.rb +111 -0
- data/lib/gdsii/record/datatypes/int2.rb +67 -0
- data/lib/gdsii/record/datatypes/int4.rb +65 -0
- data/lib/gdsii/record/datatypes/nodata.rb +60 -0
- data/lib/gdsii/record/datatypes/real4.rb +51 -0
- data/lib/gdsii/record/datatypes/real8.rb +120 -0
- data/lib/gdsii/sref.rb +61 -0
- data/lib/gdsii/strans.rb +133 -0
- data/lib/gdsii/structure.rb +352 -0
- data/lib/gdsii/text.rb +203 -0
- data/pkg/ruby-gdsii.gem +46 -0
- data/samples/hello.gds +0 -0
- data/samples/hello.out.rb +84 -0
- data/samples/hello.rb +94 -0
- data/test/baseline/dcp1.gds +0 -0
- data/test/baseline/h_write.gds +0 -0
- data/test/h_pthru.rb +22 -0
- data/test/h_write.rb +117 -0
- data/test/hs_pthru.rb +31 -0
- data/test/l_pthru.rb +23 -0
- data/test/test_gds_group.rb +379 -0
- data/test/test_gds_record.rb +99 -0
- metadata +117 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'gdsii/group'
|
2
|
+
require 'gdsii/mixins'
|
3
|
+
|
4
|
+
module Gdsii
|
5
|
+
|
6
|
+
#
|
7
|
+
# GDSII element property
|
8
|
+
#
|
9
|
+
class Property < Group
|
10
|
+
|
11
|
+
include Comparable
|
12
|
+
|
13
|
+
#
|
14
|
+
# Property BNF description
|
15
|
+
#
|
16
|
+
# <element> ::= {<boundary> | <path> | <sref> | <aref> |
|
17
|
+
# <text> | <node> | <box>} {<property>}* ENDEL
|
18
|
+
# <property> ::= PROPATTR PROPVALUE
|
19
|
+
#
|
20
|
+
self.bnf_spec = BnfSpec.new(
|
21
|
+
BnfItem.new(GRT_PROPATTR),
|
22
|
+
BnfItem.new(GRT_PROPVALUE)
|
23
|
+
)
|
24
|
+
|
25
|
+
#
|
26
|
+
# Property object constructor. A property consists of a attribute
|
27
|
+
# number (Fixnum) and a respective property value as a String.
|
28
|
+
#
|
29
|
+
def initialize(attr=nil, value=nil)
|
30
|
+
super()
|
31
|
+
self.attr = attr unless attr.nil?
|
32
|
+
self.value = value unless value.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Get the attribute number (Fixnum)
|
37
|
+
#
|
38
|
+
def attr() @records.get_data(GRT_PROPATTR); end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Set the attribute record
|
42
|
+
#
|
43
|
+
def attr=(val) @records.set(GRT_PROPATTR,val); end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Get the property value (String)
|
47
|
+
#
|
48
|
+
def value() @records.get_data(GRT_PROPVALUE); end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Set the property value
|
52
|
+
#
|
53
|
+
def value=(val) @records.set(GRT_PROPVALUE,val); end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Define order for sorting and comparing of property values (through
|
57
|
+
# inclusion of Comparable module)
|
58
|
+
#
|
59
|
+
def <=>(other)
|
60
|
+
self.attr <=> other.attr
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
############################################################################
|
66
|
+
|
67
|
+
#
|
68
|
+
# Holds a collection of Property objects. Most methods are mixed in from
|
69
|
+
# the Access::EnumerableGroup module.
|
70
|
+
#
|
71
|
+
class Properties < Group
|
72
|
+
|
73
|
+
include Access::EnumerableGroup
|
74
|
+
|
75
|
+
#
|
76
|
+
# Properties BNF description
|
77
|
+
#
|
78
|
+
# <properties> ::= {<property>}*
|
79
|
+
# <property> ::= PROPATTR PROPVALUE
|
80
|
+
#
|
81
|
+
self.bnf_spec = BnfSpec.new(
|
82
|
+
BnfItem.new(Property, true, true)
|
83
|
+
)
|
84
|
+
|
85
|
+
#
|
86
|
+
# Define a new list of properties
|
87
|
+
#
|
88
|
+
def initialize(properties=[])
|
89
|
+
super()
|
90
|
+
@records[Property] = @list = properties
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
#######################
|
95
|
+
## PROTECTED METHODS ##
|
96
|
+
#######################
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
# Used by Access::EnumerableGroup to validate addition
|
101
|
+
def validate_addition(object)
|
102
|
+
unless object.kind_of?(Property)
|
103
|
+
raise TypeError, "Invalid addition: #{object.class}; expecting Gdsii::Property"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
data/lib/gdsii/record.rb
ADDED
@@ -0,0 +1,606 @@
|
|
1
|
+
require 'gdsii/byte_order.rb'
|
2
|
+
require 'gdsii/record/consts'
|
3
|
+
require 'gdsii/record/datatypes/data.rb'
|
4
|
+
require 'gdsii/record/datatypes/ascii.rb'
|
5
|
+
require 'gdsii/record/datatypes/int2.rb'
|
6
|
+
require 'gdsii/record/datatypes/int4.rb'
|
7
|
+
require 'gdsii/record/datatypes/real4.rb'
|
8
|
+
require 'gdsii/record/datatypes/real8.rb'
|
9
|
+
require 'gdsii/record/datatypes/bitarray.rb'
|
10
|
+
require 'gdsii/record/datatypes/nodata.rb'
|
11
|
+
|
12
|
+
module Gdsii
|
13
|
+
|
14
|
+
#
|
15
|
+
# Basic class for interacting with GDSII records. This class can be used
|
16
|
+
# directly to do low-level GDSII file manipulations. Accordingly, a good
|
17
|
+
# working knowledge of the GDSII file structure is required when using this
|
18
|
+
# class directly.
|
19
|
+
#
|
20
|
+
# For higher-level GDSII manipulations that don't require as much knowledge
|
21
|
+
# of the GDSII file structure consider using the high-level classes such
|
22
|
+
# as Library, Structure, Boundary, Path, Text, etc.
|
23
|
+
#
|
24
|
+
class Record
|
25
|
+
|
26
|
+
include Gdsii::RecData
|
27
|
+
|
28
|
+
#
|
29
|
+
# Class level methods/attributes
|
30
|
+
#
|
31
|
+
class << self
|
32
|
+
|
33
|
+
# A true value indicates that debugging messages should be enabled when
|
34
|
+
# reading a GDSII file. A false (or nil) value will suppress the
|
35
|
+
# messages.
|
36
|
+
def read_debug(); @debug; end
|
37
|
+
|
38
|
+
# Sets the debugging value for reading GDSII records.
|
39
|
+
def read_debug=(value); @debug = value; end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# TODO: decide on this...
|
44
|
+
# Used internally to track the last value of a UNITS record for a given
|
45
|
+
# file object. This allows the "to string" (#to_s) method for subequent
|
46
|
+
# records to apply user units when reporting WIDTH and XY record types
|
47
|
+
# @@file_user_units = {}
|
48
|
+
|
49
|
+
# The integer value corresponding to one of the Gdsii::GRT_* constants. This
|
50
|
+
# indicates the record type for this record.
|
51
|
+
attr_reader :type
|
52
|
+
|
53
|
+
# The pointer to the data object for this record (descended from
|
54
|
+
# the Gdsii::RecData::Data class).
|
55
|
+
attr_reader :data
|
56
|
+
|
57
|
+
#
|
58
|
+
# Construct a GDSII record object given a record type (an integer
|
59
|
+
# represented by one of the Gdsii::GRT_* constants) and also the given data.
|
60
|
+
# The data may be given as a single element or as an array. Data is not
|
61
|
+
# required for records who have data types Gdsii::GDT_NO_DATA. Examples:
|
62
|
+
#
|
63
|
+
# header = Gdsii::Record.new(Gdsii::GRT_ENDLIB)
|
64
|
+
# string = Gdsii::Record.new(Gdsii::GRT_STRING, "Hello World!")
|
65
|
+
# xy = Gdsii::Record.new(Gdsii::GRT_XY, [0,0, 0,10, 10,10, 10,0, 0,0])
|
66
|
+
#
|
67
|
+
def initialize(type, data=nil)
|
68
|
+
# Verify then set the record type
|
69
|
+
@type = type
|
70
|
+
ensure_valid_type
|
71
|
+
self.data = data
|
72
|
+
end
|
73
|
+
|
74
|
+
# Set the data for this record. The value can be a Gdsii::RecData::Data
|
75
|
+
# descendant or the data in its raw form. In cases where data can be
|
76
|
+
# given as an array of items, then an array of these raw items is also
|
77
|
+
# acceptable. Examples:
|
78
|
+
#
|
79
|
+
# val = Gdsii::RecData
|
80
|
+
#
|
81
|
+
# string = Gdsii::Record.new(Gdsii::GRT_STRING, "hi")
|
82
|
+
# string.data = "hello"
|
83
|
+
#
|
84
|
+
# xy = Gdsii::Record.new(Gdsii::GRT_XY, [0,0, 10,10, 20,10, 30,0, 0,0])
|
85
|
+
# xy.data = xy.value.reverse
|
86
|
+
#
|
87
|
+
# xy = Gdsii::Record.new(Gdsii::GRT_XY, [0,0])
|
88
|
+
# xy.data = Gdsii::RecData::Real8.new([10,10])
|
89
|
+
#
|
90
|
+
def data=(data)
|
91
|
+
# Set the data based upon what was given: Gdsii::Data object, a single
|
92
|
+
# object, or an array
|
93
|
+
if data.kind_of?(Data) then
|
94
|
+
# Data given is already descended of Gdsii::Data; leave as-is
|
95
|
+
@data = data
|
96
|
+
else
|
97
|
+
# Raw data given; convert to the appropriate data type object; also
|
98
|
+
# put into an array if it is not given as an array
|
99
|
+
unless data.kind_of?(Array)
|
100
|
+
data = data.nil? ? [] : [data]
|
101
|
+
end
|
102
|
+
|
103
|
+
# convert to a data type object
|
104
|
+
@data = case RECORD_INFO[type].data_type
|
105
|
+
when GDT_ASCII : Ascii.new(data, self)
|
106
|
+
when GDT_INT2 : Int2.new(data)
|
107
|
+
when GDT_INT4 : Int4.new(data)
|
108
|
+
when GDT_REAL8 : Real8.new(data)
|
109
|
+
when GDT_BITARRAY : BitArray.new(data)
|
110
|
+
when GDT_NO_DATA : NoData.new()
|
111
|
+
when GDT_REAL4 : Real4.new(data)
|
112
|
+
else
|
113
|
+
raise TypeError, "Given record type (#{type}) is invalid"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# TODO: maybe remove; had issues with FONT record type when
|
118
|
+
# reading a GDSII file where data length is calculatd after the first
|
119
|
+
# elmement and doesn't meet the correct size as a result.
|
120
|
+
# Verify that the data length is OK
|
121
|
+
#ensure_data_length_valid
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# Returns the value of the data for this record. This method differs
|
126
|
+
# from #data.value because #data.value will always return an array of
|
127
|
+
# data. This method (#data_value) will return the value as a single
|
128
|
+
# object (not an array) if the record type is singular. Otherwise if
|
129
|
+
# the record type is multiple, then an Array of values is returned
|
130
|
+
# (just like #data.value).
|
131
|
+
#
|
132
|
+
def data_value()
|
133
|
+
(single_data_value?) ? @data.value[0] : @data.value
|
134
|
+
end
|
135
|
+
|
136
|
+
#
|
137
|
+
# True if the data value is single or if there are multiple entries
|
138
|
+
# (based upon the RECORD_INFO constant for this record type).
|
139
|
+
#
|
140
|
+
def single_data_value?
|
141
|
+
RECORD_INFO[type].single_data_value?
|
142
|
+
end
|
143
|
+
|
144
|
+
# Quick index lookup for the data property; same as self.data[index].
|
145
|
+
# Example:
|
146
|
+
#
|
147
|
+
# xy = Gdsii::Record.new(Gdsii::GRT_XY, [10,20])
|
148
|
+
# xy[0] #=> 10
|
149
|
+
#
|
150
|
+
def [](index); @data[index]; end
|
151
|
+
|
152
|
+
# Returns the size of this record in bytes (4 bytes header plus data
|
153
|
+
# byte size)
|
154
|
+
def byte_size(); @data.byte_size + 4; end
|
155
|
+
|
156
|
+
# Check that the given record type is valid. The default is to check
|
157
|
+
# the current object type. If a type is supplied, then the type given
|
158
|
+
# is checked.
|
159
|
+
def Record.valid_type?(type)
|
160
|
+
(0...RECORD_INFO.length).member?(type)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Ensures that the current type value for this record is valid. If it is
|
164
|
+
# not then an TypeError exception is raised.
|
165
|
+
def ensure_valid_type(type=@type)
|
166
|
+
unless Record.valid_type? type
|
167
|
+
raise TypeError, "Invalid record type: '#{type}'"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Ensures that the length of the data given is valid for this record
|
172
|
+
# according to the Gdsii::RECORD_INFO array. If the length is not valid
|
173
|
+
# then an ArgumentError exception is raised.
|
174
|
+
def ensure_data_length_valid(type=@type, data_len=@data.byte_size)
|
175
|
+
min = RECORD_INFO[type].min_len
|
176
|
+
max = RECORD_INFO[type].max_len
|
177
|
+
unless ((min..max).member?(data_len))
|
178
|
+
raise ArgumentError,
|
179
|
+
"Data length of #{data_len} is not in the range expected for record '#{self.name}' (#{min}..#{max})"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Reads the next GDSII record from the given file object and returns
|
184
|
+
# a Gdsii::Record object. If EOF is reached in the file or if the record
|
185
|
+
# is a null-space, then nil is returned. Example:
|
186
|
+
#
|
187
|
+
# # Note: 'rb' is required for DOS/Windows compatibility
|
188
|
+
# File.open('mydesign.gds', 'rb') do |file|
|
189
|
+
# record = Gdsii::Record.read(file)
|
190
|
+
# # your code here...
|
191
|
+
# end
|
192
|
+
#
|
193
|
+
def Record.read(file, record_filter=nil)
|
194
|
+
|
195
|
+
begin
|
196
|
+
# Get the file position to save for error reporting
|
197
|
+
orig_file_pos = file.pos
|
198
|
+
|
199
|
+
# Read the header, first two bytes are length, second two are
|
200
|
+
# record type and data type
|
201
|
+
raw = file.read(4)
|
202
|
+
|
203
|
+
# If the 4 bytes weren't read or if this record has no contents
|
204
|
+
# (some GDSII files are null padded at the end) then return nil
|
205
|
+
if raw.nil? or raw == "\000\000" then
|
206
|
+
return nil
|
207
|
+
end
|
208
|
+
|
209
|
+
# get the record's length
|
210
|
+
reclen = raw[0,2]
|
211
|
+
reclen.reverse! if (ByteOrder::little_endian?)
|
212
|
+
reclen = reclen.unpack('S')[0]
|
213
|
+
|
214
|
+
# get the record type
|
215
|
+
type = raw[2,1]
|
216
|
+
type = type.unpack('c')[0]
|
217
|
+
|
218
|
+
# get the record's data type
|
219
|
+
data_type = raw[3,1]
|
220
|
+
data_type = data_type.unpack('c')[0]
|
221
|
+
|
222
|
+
# reclen includes length of header data, must subtract
|
223
|
+
bytes_left = reclen - 4
|
224
|
+
|
225
|
+
# if we are filtering records and this record type is not in the
|
226
|
+
# filter, then return nil; else continue.
|
227
|
+
if record_filter and not record_filter.member?(type)
|
228
|
+
file.seek(bytes_left, IO::SEEK_CUR)
|
229
|
+
return nil
|
230
|
+
end
|
231
|
+
|
232
|
+
if bytes_left < 0 then
|
233
|
+
if type == 0 then
|
234
|
+
# GDSII file is sometimes padded with null characters at the
|
235
|
+
# end of the file... so just stop parsing at this point
|
236
|
+
return nil
|
237
|
+
else
|
238
|
+
raise ArgumentError,
|
239
|
+
"Record (#{self.name}) data length is negative: #{bytes_left}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# Print a debugging message for this record if desired
|
244
|
+
if Record.read_debug
|
245
|
+
printf("Address = 0x%06x (%08d) ; Record = %14s (%2d) ; Length = %4d\n", orig_file_pos, orig_file_pos, Gdsii::grt_name(type), type, reclen)
|
246
|
+
end
|
247
|
+
|
248
|
+
data = case data_type
|
249
|
+
when GDT_ASCII : Ascii.read(file, bytes_left)
|
250
|
+
when GDT_INT2 : Int2.read(file, bytes_left)
|
251
|
+
when GDT_INT4 : Int4.read(file, bytes_left)
|
252
|
+
when GDT_REAL8 : Real8.read(file, bytes_left)
|
253
|
+
when GDT_BITARRAY : BitArray.read(file, bytes_left)
|
254
|
+
when GDT_NO_DATA : NoData.read(file, bytes_left)
|
255
|
+
when GDT_REAL4 : Real4.read(file, bytes_left)
|
256
|
+
else
|
257
|
+
raise TypeError, "Given record type (#{type}) is invalid"
|
258
|
+
end
|
259
|
+
|
260
|
+
# Create the new record
|
261
|
+
rec = Record.new(type, data)
|
262
|
+
|
263
|
+
# Print a debugging message for this record if desired
|
264
|
+
if Record.read_debug
|
265
|
+
puts " --> #{Gdsii.gdt_name(rec.data.type)}: #{rec.data_value.inspect}"
|
266
|
+
end
|
267
|
+
|
268
|
+
yield rec if block_given?
|
269
|
+
rec
|
270
|
+
rescue
|
271
|
+
$stderr.puts "Error reading GDSII file starting at file position #{orig_file_pos}"
|
272
|
+
$stderr.puts "Record length = #{reclen.inspect}"
|
273
|
+
$stderr.puts "Record type = #{Gdsii::grt_name(type)}"
|
274
|
+
$stderr.puts "Data type = #{Gdsii::gdt_name(data_type)}"
|
275
|
+
raise
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
# Reads and yields GDSII records from the given file object until EOF is
|
281
|
+
# reached in the file. Example (a simple GDS dump utility):
|
282
|
+
#
|
283
|
+
# # Note: 'rb' is required for DOS/Windows compatibility
|
284
|
+
# File.open('mydesign.gds', 'rb') do |file|
|
285
|
+
# Gdsii::Record.read_each(file) do |record|
|
286
|
+
# puts record.to_s
|
287
|
+
# end
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
def Record.read_each(file, record_filter=nil)
|
291
|
+
until file.eof? do
|
292
|
+
Record.read(file, record_filter) {|r| return if r.nil?; yield r}
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# Peeks at the next record for the given file object. The record will be
|
297
|
+
# returned and the file position will remain unchanged.
|
298
|
+
def Record.peek(file)
|
299
|
+
pos = file.pos
|
300
|
+
rec = Record.read(file)
|
301
|
+
file.seek pos
|
302
|
+
rec
|
303
|
+
end
|
304
|
+
|
305
|
+
# Write this record to the given file object.
|
306
|
+
def write(file)
|
307
|
+
# write the length & header; always write length (int2) as network
|
308
|
+
# order (as per GDSII spec)
|
309
|
+
file.write [self.byte_size].pack('n')
|
310
|
+
file.write [self.type].pack('c')
|
311
|
+
file.write [self.data.type].pack('c')
|
312
|
+
|
313
|
+
# now write the data...
|
314
|
+
@data.write(file)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Returns the string name of this record type which typically matches the
|
318
|
+
# Gdsii::GRT_* constants but without the "Gdsii::GRT_" (i.e. HEADER, etc.)
|
319
|
+
def name(); RECORD_INFO[@type].name; end
|
320
|
+
|
321
|
+
# Return the value of this record; shortcut for self.data.value
|
322
|
+
def value(); self.data.value; end
|
323
|
+
|
324
|
+
# Set the value of this record; shortcut for self.data.value=
|
325
|
+
def value=(value); self.data.value = value; end
|
326
|
+
|
327
|
+
# Outputs the record in "L" textual layout format which is a string
|
328
|
+
# representation. Note, the string representation can include a newline
|
329
|
+
# character (\n) for some record types (multi-line output).
|
330
|
+
def to_s()
|
331
|
+
|
332
|
+
# Immediately return records that have no data
|
333
|
+
if @data.type == GDT_NO_DATA then
|
334
|
+
return self.name
|
335
|
+
end
|
336
|
+
|
337
|
+
# Raise an exception if an invalid record is encountered
|
338
|
+
unless RECORD_INFO[@type].valid
|
339
|
+
raise "Record type #{self.name} is not valid"
|
340
|
+
end
|
341
|
+
|
342
|
+
# Format other data types...
|
343
|
+
case @type
|
344
|
+
when GRT_STRING
|
345
|
+
self.name + " \"#{@data.to_s}\""
|
346
|
+
when GRT_BGNLIB, GRT_BGNSTR
|
347
|
+
# Format dates for library & structure
|
348
|
+
out_arr = []
|
349
|
+
tmpar = (@type == GRT_BGNLIB) ? ["LASTMOD","LASTACC"] : ["LASTMOD","CREATION"]
|
350
|
+
tmpar.each_with_index do |label, i|
|
351
|
+
j = i * 6
|
352
|
+
out_arr.push sprintf("%s %02d/%02d/%02d %02d:%02d:%02d",label,
|
353
|
+
@data[j],@data[j+1],@data[j+2],
|
354
|
+
@data[j+3],@data[j+4],@data[j+5])
|
355
|
+
end
|
356
|
+
self.name + "\n" + out_arr.join("\n")
|
357
|
+
when GRT_UNITS
|
358
|
+
# @@file_user_units[file] = @data[0].to_f
|
359
|
+
"UNITS\nUSERUNITS #{@data[0].to_s}\nPHYSUNITS #{data[1].to_s}"
|
360
|
+
when GRT_WIDTH
|
361
|
+
units = 1
|
362
|
+
# units = @@file_user_units[file] || 1
|
363
|
+
self.name + " #{@data[0]}"
|
364
|
+
when GRT_XY
|
365
|
+
units = 1
|
366
|
+
# units = @@file_user_units[file] || 1
|
367
|
+
out_arr = ["XY " + (@data.value.length/2).to_s]
|
368
|
+
0.step(@data.value.length-2, 2) do |i|
|
369
|
+
out_arr.push " X #{@data[i]*units}; Y #{@data[i+1]*units}"
|
370
|
+
end
|
371
|
+
out_arr.join(";\n") + ';'
|
372
|
+
when GRT_PRESENTATION, GRT_STRANS
|
373
|
+
if @type == GRT_PRESENTATION then
|
374
|
+
str = [@data.to_s[10,2], @data.to_s[12,2], @data.to_s[14,2]].map {|twobits|
|
375
|
+
[("0"*32+twobits)[-32..-1]].pack("B32").unpack("N")[0].to_s
|
376
|
+
}.join(',')
|
377
|
+
elsif @type == GRT_STRANS then
|
378
|
+
str =[@data.to_s[0,1], @data.to_s[13,1], @data.to_s[14,1]].map {|onebit|
|
379
|
+
[("0"*32+onebit)[-32..-1]].pack("B32").unpack("N")[0].to_s
|
380
|
+
}.join(',')
|
381
|
+
end
|
382
|
+
self.name + ' ' + str
|
383
|
+
else
|
384
|
+
self.name + ' ' + @data.to_s
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
388
|
+
|
389
|
+
|
390
|
+
########################################################################
|
391
|
+
# RECORD TYPE SHORTCUTS
|
392
|
+
########################################################################
|
393
|
+
|
394
|
+
# Returns true if this is a HEADER record or false if not
|
395
|
+
def is_header?(); @type == GRT_HEADER; end
|
396
|
+
|
397
|
+
# Returns true if this is a BGNLIB record or false if not
|
398
|
+
def is_bgnlib?(); @type == GRT_BGNLIB; end
|
399
|
+
|
400
|
+
# Returns true if this is a LIBNAME record or false if not
|
401
|
+
def is_libname?(); @type == GRT_LIBNAME; end
|
402
|
+
|
403
|
+
# Returns true if this is a UNITS record or false if not
|
404
|
+
def is_units?(); @type == GRT_UNITS; end
|
405
|
+
|
406
|
+
# Returns true if this is a ENDLIB record or false if not
|
407
|
+
def is_endlib?(); @type == GRT_ENDLIB; end
|
408
|
+
|
409
|
+
# Returns true if this is a BGNSTR record or false if not
|
410
|
+
def is_bgnstr?(); @type == GRT_BGNSTR; end
|
411
|
+
|
412
|
+
# Returns true if this is a STRNAME record or false if not
|
413
|
+
def is_strname?(); @type == GRT_STRNAME; end
|
414
|
+
|
415
|
+
# Returns true if this is a ENDSTR record or false if not
|
416
|
+
def is_endstr?(); @type == GRT_ENDSTR; end
|
417
|
+
|
418
|
+
# Returns true if this is a BOUNDARY record or false if not
|
419
|
+
def is_boundary?(); @type == GRT_BOUNDARY; end
|
420
|
+
|
421
|
+
# Returns true if this is a PATH record or false if not
|
422
|
+
def is_path?(); @type == GRT_PATH; end
|
423
|
+
|
424
|
+
# Returns true if this is a SREF record or false if not
|
425
|
+
def is_sref?(); @type == GRT_SREF; end
|
426
|
+
|
427
|
+
# Returns true if this is a AREF record or false if not
|
428
|
+
def is_aref?(); @type == GRT_AREF; end
|
429
|
+
|
430
|
+
# Returns true if this is a TEXT record or false if not
|
431
|
+
def is_text?(); @type == GRT_TEXT; end
|
432
|
+
|
433
|
+
# Returns true if this is a LAYER record or false if not
|
434
|
+
def is_layer?(); @type == GRT_LAYER; end
|
435
|
+
|
436
|
+
# Returns true if this is a DATATYPE record or false if not
|
437
|
+
def is_datatype?(); @type == GRT_DATATYPE; end
|
438
|
+
|
439
|
+
# Returns true if this is a WIDTH record or false if not
|
440
|
+
def is_width?(); @type == GRT_WIDTH; end
|
441
|
+
|
442
|
+
# Returns true if this is a XY record or false if not
|
443
|
+
def is_xy?(); @type == GRT_XY; end
|
444
|
+
|
445
|
+
# Returns true if this is a ENDEL record or false if not
|
446
|
+
def is_endel?(); @type == GRT_ENDEL; end
|
447
|
+
|
448
|
+
# Returns true if this is a SNAME record or false if not
|
449
|
+
def is_sname?(); @type == GRT_SNAME; end
|
450
|
+
|
451
|
+
# Returns true if this is a COLROW record or false if not
|
452
|
+
def is_colrow?(); @type == GRT_COLROW; end
|
453
|
+
|
454
|
+
# Returns true if this is a TEXTNODE record or false if not
|
455
|
+
def is_textnode?(); @type == GRT_TEXTNODE; end
|
456
|
+
|
457
|
+
# Returns true if this is a NODE record or false if not
|
458
|
+
def is_node?(); @type == GRT_NODE; end
|
459
|
+
|
460
|
+
# Returns true if this is a TEXTTYPE record or false if not
|
461
|
+
def is_texttype?(); @type == GRT_TEXTTYPE; end
|
462
|
+
|
463
|
+
# Returns true if this is a PRESENTATION record or false if not
|
464
|
+
def is_presentation?(); @type == GRT_PRESENTATION; end
|
465
|
+
|
466
|
+
# Returns true if this is a SPACING record or false if not
|
467
|
+
def is_spacing?(); @type == GRT_SPACING; end
|
468
|
+
|
469
|
+
# Returns true if this is a STRING record or false if not
|
470
|
+
def is_string?(); @type == GRT_STRING; end
|
471
|
+
|
472
|
+
# Returns true if this is a STRANS record or false if not
|
473
|
+
def is_strans?(); @type == GRT_STRANS; end
|
474
|
+
|
475
|
+
# Returns true if this is a MAG record or false if not
|
476
|
+
def is_mag?(); @type == GRT_MAG; end
|
477
|
+
|
478
|
+
# Returns true if this is a ANGLE record or false if not
|
479
|
+
def is_angle?(); @type == GRT_ANGLE; end
|
480
|
+
|
481
|
+
# Returns true if this is a UINTEGER record or false if not
|
482
|
+
def is_uinteger?(); @type == GRT_UINTEGER; end
|
483
|
+
|
484
|
+
# Returns true if this is a USTRING record or false if not
|
485
|
+
def is_ustring?(); @type == GRT_USTRING; end
|
486
|
+
|
487
|
+
# Returns true if this is a REFLIBS record or false if not
|
488
|
+
def is_reflibs?(); @type == GRT_REFLIBS; end
|
489
|
+
|
490
|
+
# Returns true if this is a FONTS record or false if not
|
491
|
+
def is_fonts?(); @type == GRT_FONTS; end
|
492
|
+
|
493
|
+
# Returns true if this is a PATHTYPE record or false if not
|
494
|
+
def is_pathtype?(); @type == GRT_PATHTYPE; end
|
495
|
+
|
496
|
+
# Returns true if this is a GENERATIONS record or false if not
|
497
|
+
def is_generations?(); @type == GRT_GENERATIONS; end
|
498
|
+
|
499
|
+
# Returns true if this is a ATTRTABLE record or false if not
|
500
|
+
def is_attrtable?(); @type == GRT_ATTRTABLE; end
|
501
|
+
|
502
|
+
# Returns true if this is a STYPTABLE record or false if not
|
503
|
+
def is_styptable?(); @type == GRT_STYPTABLE; end
|
504
|
+
|
505
|
+
# Returns true if this is a STRTYPE record or false if not
|
506
|
+
def is_strtype?(); @type == GRT_STRTYPE; end
|
507
|
+
|
508
|
+
# Returns true if this is a ELFLAGS record or false if not
|
509
|
+
def is_elflags?(); @type == GRT_ELFLAGS; end
|
510
|
+
|
511
|
+
# Returns true if this is a ELKEY record or false if not
|
512
|
+
def is_elkey?(); @type == GRT_ELKEY; end
|
513
|
+
|
514
|
+
# Returns true if this is a LINKTYPE record or false if not
|
515
|
+
def is_linktype?(); @type == GRT_LINKTYPE; end
|
516
|
+
|
517
|
+
# Returns true if this is a LINKKEYS record or false if not
|
518
|
+
def is_linkkeys?(); @type == GRT_LINKKEYS; end
|
519
|
+
|
520
|
+
# Returns true if this is a NODETYPE record or false if not
|
521
|
+
def is_nodetype?(); @type == GRT_NODETYPE; end
|
522
|
+
|
523
|
+
# Returns true if this is a PROPATTR record or false if not
|
524
|
+
def is_propattr?(); @type == GRT_PROPATTR; end
|
525
|
+
|
526
|
+
# Returns true if this is a PROPVALUE record or false if not
|
527
|
+
def is_propvalue?(); @type == GRT_PROPVALUE; end
|
528
|
+
|
529
|
+
# Returns true if this is a BOX record or false if not
|
530
|
+
def is_box?(); @type == GRT_BOX; end
|
531
|
+
|
532
|
+
# Returns true if this is a BOXTYPE record or false if not
|
533
|
+
def is_boxtype?(); @type == GRT_BOXTYPE; end
|
534
|
+
|
535
|
+
# Returns true if this is a PLEX record or false if not
|
536
|
+
def is_plex?(); @type == GRT_PLEX; end
|
537
|
+
|
538
|
+
# Returns true if this is a BGNEXTN record or false if not
|
539
|
+
def is_bgnextn?(); @type == GRT_BGNEXTN; end
|
540
|
+
|
541
|
+
# Returns true if this is a ENDEXTN record or false if not
|
542
|
+
def is_endextn?(); @type == GRT_ENDEXTN; end
|
543
|
+
|
544
|
+
# Returns true if this is a TAPENUM record or false if not
|
545
|
+
def is_tapenum?(); @type == GRT_TAPENUM; end
|
546
|
+
|
547
|
+
# Returns true if this is a TAPECODE record or false if not
|
548
|
+
def is_tapecode?(); @type == GRT_TAPECODE; end
|
549
|
+
|
550
|
+
# Returns true if this is a STRCLASS record or false if not
|
551
|
+
def is_strclass?(); @type == GRT_STRCLASS; end
|
552
|
+
|
553
|
+
# Returns true if this is a RESERVED record or false if not
|
554
|
+
def is_reserved?(); @type == GRT_RESERVED; end
|
555
|
+
|
556
|
+
# Returns true if this is a FORMAT record or false if not
|
557
|
+
def is_format?(); @type == GRT_FORMAT; end
|
558
|
+
|
559
|
+
# Returns true if this is a MASK record or false if not
|
560
|
+
def is_mask?(); @type == GRT_MASK; end
|
561
|
+
|
562
|
+
# Returns true if this is a ENDMASKS record or false if not
|
563
|
+
def is_endmasks?(); @type == GRT_ENDMASKS; end
|
564
|
+
|
565
|
+
# Returns true if this is a LIBDIRSIZE record or false if not
|
566
|
+
def is_libdirsize?(); @type == GRT_LIBDIRSIZE; end
|
567
|
+
|
568
|
+
# Returns true if this is a SRFNAME record or false if not
|
569
|
+
def is_srfname?(); @type == GRT_SRFNAME; end
|
570
|
+
|
571
|
+
# Returns true if this is a LIBSECUR record or false if not
|
572
|
+
def is_libsecur?(); @type == GRT_LIBSECUR; end
|
573
|
+
|
574
|
+
# Returns true if this is a BORDER record or false if not
|
575
|
+
def is_border?(); @type == GRT_BORDER; end
|
576
|
+
|
577
|
+
# Returns true if this is a SOFTFENCE record or false if not
|
578
|
+
def is_softfence?(); @type == GRT_SOFTFENCE; end
|
579
|
+
|
580
|
+
# Returns true if this is a HARDFENCE record or false if not
|
581
|
+
def is_hardfence?(); @type == GRT_HARDFENCE; end
|
582
|
+
|
583
|
+
# Returns true if this is a SOFTWIRE record or false if not
|
584
|
+
def is_softwire?(); @type == GRT_SOFTWIRE; end
|
585
|
+
|
586
|
+
# Returns true if this is a HARDWIRE record or false if not
|
587
|
+
def is_hardwire?(); @type == GRT_HARDWIRE; end
|
588
|
+
|
589
|
+
# Returns true if this is a PATHPORT record or false if not
|
590
|
+
def is_pathport?(); @type == GRT_PATHPORT; end
|
591
|
+
|
592
|
+
# Returns true if this is a NODEPORT record or false if not
|
593
|
+
def is_nodeport?(); @type == GRT_NODEPORT; end
|
594
|
+
|
595
|
+
# Returns true if this is a USERCONSTRAINT record or false if not
|
596
|
+
def is_userconstraint?(); @type == GRT_USERCONSTRAINT; end
|
597
|
+
|
598
|
+
# Returns true if this is a SPACER_ERROR record or false if not
|
599
|
+
def is_spacer_error?(); @type == GRT_SPACER_ERROR; end
|
600
|
+
|
601
|
+
# Returns true if this is a CONTACT record or false if not
|
602
|
+
def is_contact?(); @type == GRT_CONTACT; end
|
603
|
+
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|