Permit but check duplicate DBD entries
Record types cannot be duplicated however. DBD sub-objects now have a ->what method for their description. This also adds a method to look up a breaktable by name.
This commit is contained in:
+15
-10
@@ -29,22 +29,27 @@ sub new {
|
||||
|
||||
sub add {
|
||||
my ($this, $obj) = @_;
|
||||
my $obj_class;
|
||||
foreach (keys %{$this}) {
|
||||
next unless m/^DBD::/;
|
||||
$obj_class = $_ and last if $obj->isa($_);
|
||||
}
|
||||
confess "Unknown object type"
|
||||
unless defined $obj_class;
|
||||
my $obj_class = ref $obj;
|
||||
confess "DBD::add: Unknown DBD object type '$obj_class'"
|
||||
unless $obj_class =~ m/^DBD::/
|
||||
and exists $this->{$obj_class};
|
||||
my $obj_name = $obj->name;
|
||||
dieContext("Duplicate name '$obj_name'")
|
||||
if exists $this->{$obj_class}->{$obj_name};
|
||||
$this->{$obj_class}->{$obj_name} = $obj;
|
||||
if (exists $this->{$obj_class}->{$obj_name}) {
|
||||
return if $obj->equals($this->{$obj_class}->{$obj_name});
|
||||
dieContext("A different $obj->{WHAT} named '$obj_name' already exists");
|
||||
}
|
||||
else {
|
||||
$this->{$obj_class}->{$obj_name} = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
sub breaktables {
|
||||
return shift->{'DBD::Breaktable'};
|
||||
}
|
||||
sub breaktable {
|
||||
my ($this, $name) = @_;
|
||||
return $this->{'DBD::Breaktable'}->{$name};
|
||||
}
|
||||
|
||||
sub drivers {
|
||||
return shift->{'DBD::Driver'};
|
||||
|
||||
+19
-7
@@ -34,19 +34,19 @@ sub pushContext {
|
||||
|
||||
sub popContext {
|
||||
my ($ctxt) = @_;
|
||||
my ($pop) = shift @context;
|
||||
my $pop = shift @context;
|
||||
($ctxt ne $pop) and
|
||||
dieContext("Exiting context \"$ctxt\", found \"$pop\" instead.",
|
||||
"\tBraces must close in the same file they were opened.");
|
||||
dieContext("Leaving context \"$ctxt\", found \"$pop\" instead.",
|
||||
"\tBraces must be closed in the same file they open in.");
|
||||
}
|
||||
|
||||
sub dieContext {
|
||||
my ($msg) = join "\n\t", @_;
|
||||
my $msg = join "\n\t", @_;
|
||||
die "$msg\nContext: ", join(' in ', @context), "\n";
|
||||
}
|
||||
|
||||
sub warnContext {
|
||||
my ($msg) = join "\n\t", @_;
|
||||
my $msg = join "\n\t", @_;
|
||||
print STDERR "$msg\nContext: ", join(' in ', @context), "\n";
|
||||
}
|
||||
|
||||
@@ -77,7 +77,8 @@ sub is_reserved {
|
||||
sub identifier {
|
||||
my ($id, $what) = @_;
|
||||
unquote $id;
|
||||
confess "$what undefined!" unless defined $id;
|
||||
confess "DBD::Base::identifier: $what undefined!"
|
||||
unless defined $id;
|
||||
$id =~ m/^$RXident$/o or dieContext("Illegal $what '$id'",
|
||||
"Identifiers are used in C code so must start with a letter, followed",
|
||||
"by letters, digits and/or underscore characters only.");
|
||||
@@ -114,7 +115,8 @@ sub new {
|
||||
|
||||
sub init {
|
||||
my ($this, $name, $what) = @_;
|
||||
$this->{NAME} = identifier($name, $what);
|
||||
$this->{NAME} = identifier($name, "$what name");
|
||||
$this->{WHAT} = $what;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -122,4 +124,14 @@ sub name {
|
||||
return shift->{NAME};
|
||||
}
|
||||
|
||||
sub what {
|
||||
return shift->{WHAT};
|
||||
}
|
||||
|
||||
sub equals {
|
||||
my ($a, $b) = @_;
|
||||
return $a->{NAME} eq $b->{NAME}
|
||||
&& $a->{WHAT} eq $b->{WHAT};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
+20
-11
@@ -5,23 +5,25 @@ use DBD::Base;
|
||||
use Carp;
|
||||
|
||||
sub init {
|
||||
my ($this, $name) = @_;
|
||||
$this->SUPER::init($name, "breakpoint table name");
|
||||
$this->{POINT_LIST} = [];
|
||||
return $this;
|
||||
my ($this, $name) = @_;
|
||||
$this->SUPER::init($name, "breakpoint table");
|
||||
$this->{POINT_LIST} = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
sub add_point {
|
||||
my ($this, $raw, $eng) = @_;
|
||||
confess "Raw value undefined!" unless defined $raw;
|
||||
confess "Engineering value undefined!" unless defined $eng;
|
||||
unquote $raw;
|
||||
unquote $eng;
|
||||
push @{$this->{POINT_LIST}}, [$raw, $eng];
|
||||
my ($this, $raw, $eng) = @_;
|
||||
confess "DBD::Breaktable::add_point: Raw value undefined!"
|
||||
unless defined $raw;
|
||||
confess "DBD::Breaktable::add_point: Engineering value undefined!"
|
||||
unless defined $eng;
|
||||
unquote $raw;
|
||||
unquote $eng;
|
||||
push @{$this->{POINT_LIST}}, [$raw, $eng];
|
||||
}
|
||||
|
||||
sub points {
|
||||
return @{shift->{POINT_LIST}};
|
||||
return @{shift->{POINT_LIST}};
|
||||
}
|
||||
|
||||
sub point {
|
||||
@@ -29,4 +31,11 @@ sub point {
|
||||
return $this->{POINT_LIST}[$idx];
|
||||
}
|
||||
|
||||
sub equals {
|
||||
my ($a, $b) = @_;
|
||||
return $a->SUPER::equals($b)
|
||||
&& join(',', map "$_->[0]:$_->[1]", @{$a->{POINT_LIST}})
|
||||
eq join(',', map "$_->[0]:$_->[1]", @{$b->{POINT_LIST}});
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
+32
-25
@@ -3,43 +3,50 @@ use DBD::Base;
|
||||
@ISA = qw(DBD::Base);
|
||||
|
||||
my %link_types = (
|
||||
CONSTANT => qr/$RXnum/o,
|
||||
PV_LINK => qr/$RXname \s+ [.NPCAMS ]*/ox,
|
||||
VME_IO => qr/\# (?: \s* [CS] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
CAMAC_IO => qr/\# (?: \s* [BCNAF] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
RF_IO => qr/\# (?: \s* [RMDE] \s* $RXintx)*/ox,
|
||||
AB_IO => qr/\# (?: \s* [LACS] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
GPIB_IO => qr/\# (?: \s* [LA] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
BITBUS_IO => qr/\# (?: \s* [LNPS] \s* $RXuintx)* \s* (?: @ .*)?/ox,
|
||||
BBGPIB_IO => qr/\# (?: \s* [LBG] \s* $RXuintx)* \s* (?: @ .*)?/ox,
|
||||
VXI_IO => qr/\# (?: \s* [VCS] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
INST_IO => qr/@.*/
|
||||
CONSTANT => qr/$RXnum/o,
|
||||
PV_LINK => qr/$RXname \s+ [.NPCAMS ]*/ox,
|
||||
VME_IO => qr/\# (?: \s* [CS] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
CAMAC_IO => qr/\# (?: \s* [BCNAF] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
RF_IO => qr/\# (?: \s* [RMDE] \s* $RXintx)*/ox,
|
||||
AB_IO => qr/\# (?: \s* [LACS] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
GPIB_IO => qr/\# (?: \s* [LA] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
BITBUS_IO => qr/\# (?: \s* [LNPS] \s* $RXuintx)* \s* (?: @ .*)?/ox,
|
||||
BBGPIB_IO => qr/\# (?: \s* [LBG] \s* $RXuintx)* \s* (?: @ .*)?/ox,
|
||||
VXI_IO => qr/\# (?: \s* [VCS] \s* $RXintx)* \s* (?: @ .*)?/ox,
|
||||
INST_IO => qr/@.*/
|
||||
);
|
||||
|
||||
sub init {
|
||||
my ($this, $link_type, $dset, $choice) = @_;
|
||||
unquote $choice;
|
||||
dieContext("Unknown link type '$link_type', valid types are:",
|
||||
sort keys %link_types) unless exists $link_types{$link_type};
|
||||
$this->SUPER::init($dset, "DSET name");
|
||||
$this->{LINK_TYPE} = $link_type;
|
||||
$this->{CHOICE} = $choice;
|
||||
return $this;
|
||||
my ($this, $link_type, $dset, $choice) = @_;
|
||||
unquote $choice;
|
||||
dieContext("Unknown link type '$link_type', valid types are:",
|
||||
sort keys %link_types) unless exists $link_types{$link_type};
|
||||
$this->SUPER::init($dset, "device support (dset)");
|
||||
$this->{LINK_TYPE} = $link_type;
|
||||
$this->{CHOICE} = $choice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
sub link_type {
|
||||
return shift->{LINK_TYPE};
|
||||
return shift->{LINK_TYPE};
|
||||
}
|
||||
|
||||
sub choice {
|
||||
return shift->{CHOICE};
|
||||
return shift->{CHOICE};
|
||||
}
|
||||
|
||||
sub legal_addr {
|
||||
my ($this, $addr) = @_;
|
||||
my $rx = $link_types{$this->{LINK_TYPE}};
|
||||
unquote $addr;
|
||||
return $addr =~ m/^ $rx $/x;
|
||||
my ($this, $addr) = @_;
|
||||
my $rx = $link_types{$this->{LINK_TYPE}};
|
||||
unquote $addr;
|
||||
return $addr =~ m/^ $rx $/x;
|
||||
}
|
||||
|
||||
sub equals {
|
||||
my ($a, $b) = @_;
|
||||
return $a->SUPER::equals($b)
|
||||
&& $a->{LINK_TYPE} eq $b->{LINK_TYPE}
|
||||
&& $a->{CHOICE} eq $b->{CHOICE};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -3,7 +3,7 @@ use DBD::Base;
|
||||
@ISA = qw(DBD::Base);
|
||||
|
||||
sub init {
|
||||
return shift->SUPER::init(shift, "driver entry table name");
|
||||
return shift->SUPER::init(shift, "driver support (drvet)");
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
@@ -3,8 +3,7 @@ use DBD::Base;
|
||||
@ISA = qw(DBD::Base);
|
||||
|
||||
sub init {
|
||||
return shift->SUPER::init(shift, "function name");
|
||||
return shift->SUPER::init(shift, "function");
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use DBD::Base;
|
||||
|
||||
sub init {
|
||||
my ($this, $name) = @_;
|
||||
$this->SUPER::init($name, "menu name");
|
||||
$this->SUPER::init($name, "menu");
|
||||
$this->{CHOICE_LIST} = [];
|
||||
$this->{CHOICE_INDEX} = {};
|
||||
return $this;
|
||||
@@ -39,6 +39,13 @@ sub legal_choice {
|
||||
return exists $this->{CHOICE_INDEX}->{$value};
|
||||
}
|
||||
|
||||
sub equals {
|
||||
my ($a, $b) = @_;
|
||||
return $a->SUPER::equals($b)
|
||||
&& join(',', map "$_->[0]:$_->[1]", @{$a->{CHOICE_LIST}})
|
||||
eq join(',', map "$_->[0]:$_->[1]", @{$b->{CHOICE_LIST}});
|
||||
}
|
||||
|
||||
sub toDeclaration {
|
||||
my $this = shift;
|
||||
my $name = $this->name;
|
||||
|
||||
@@ -48,7 +48,10 @@ sub OutputRecordtypes {
|
||||
printf $out " field(%s, %s) {\n",
|
||||
$field->name, $field->dbf_type;
|
||||
while (my ($attr, $val) = each %{$field->attributes}) {
|
||||
$val = "\"$val\"" if $val !~ m/^$RXname$/ox;
|
||||
$val = "\"$val\""
|
||||
if $val !~ m/^$RXname$/ox
|
||||
|| $attr eq 'prompt'
|
||||
|| $attr eq 'initial';
|
||||
printf $out " %s(%s)\n", $attr, $val;
|
||||
}
|
||||
print $out " }\n";
|
||||
|
||||
@@ -49,7 +49,7 @@ sub ParseDBD {
|
||||
}
|
||||
elsif (m/\G variable \s* \( \s* $RXstr \s* \)/oxgc) {
|
||||
print "Variable: $1\n" if $debug;
|
||||
$dbd->add(DBD::Variable->new($1, 'int'));
|
||||
$dbd->add(DBD::Variable->new($1));
|
||||
}
|
||||
elsif (m/\G variable \s* \( \s* $RXstr \s* , \s* $RXstr \s* \)/oxgc) {
|
||||
print "Variable: $1, $2\n" if $debug;
|
||||
@@ -59,7 +59,8 @@ sub ParseDBD {
|
||||
\s* $RXstr \s* , \s*$RXstr \s* \)/oxgc) {
|
||||
print "Device: $1, $2, $3, $4\n" if $debug;
|
||||
my $rtyp = $dbd->recordtype($1);
|
||||
dieContext("Unknown record type '$1'") unless defined $rtyp;
|
||||
dieContext("Unknown record type '$1'")
|
||||
unless defined $rtyp;
|
||||
$rtyp->add_device(DBD::Device->new($2, $3, $4));
|
||||
} else {
|
||||
last unless m/\G (.*) $/moxgc;
|
||||
|
||||
@@ -3,6 +3,7 @@ use DBD::Base;
|
||||
@ISA = qw(DBD::Base);
|
||||
|
||||
# The hash value is a regexp that matches all legal values of this field
|
||||
# NB: The regexps are not currently used, and are wrong for some types.
|
||||
our %field_types = (
|
||||
DBF_STRING => qr/.{0,40}/,
|
||||
DBF_CHAR => $RXintx,
|
||||
@@ -49,7 +50,7 @@ sub new {
|
||||
sub init {
|
||||
my ($this, $name, $type) = @_;
|
||||
unquote $type;
|
||||
$this->SUPER::init($name, "record field name");
|
||||
$this->SUPER::init($name, "record field");
|
||||
dieContext("Illegal field type '$type', valid field types are:",
|
||||
sort keys %field_types) unless exists $field_types{$type};
|
||||
$this->{DBF_TYPE} = $type;
|
||||
@@ -91,6 +92,10 @@ sub attribute {
|
||||
return $this->attributes->{$attr};
|
||||
}
|
||||
|
||||
sub equals {
|
||||
dieContext("Record field objects are not comparable");
|
||||
}
|
||||
|
||||
sub check_valid {
|
||||
my ($this) = @_;
|
||||
my $name = $this->name;
|
||||
|
||||
+17
-15
@@ -5,8 +5,8 @@ use DBD::Base;
|
||||
use Carp;
|
||||
|
||||
sub init {
|
||||
my $this = shift;
|
||||
$this->SUPER::init(@_);
|
||||
my ($this, $name) = @_;
|
||||
$this->SUPER::init($name, "record type");
|
||||
$this->{FIELD_LIST} = [];
|
||||
$this->{FIELD_INDEX} = {};
|
||||
$this->{DEVICE_LIST} = [];
|
||||
@@ -17,7 +17,8 @@ sub init {
|
||||
|
||||
sub add_field {
|
||||
my ($this, $field) = @_;
|
||||
confess "Not a DBD::Recfield" unless $field->isa('DBD::Recfield');
|
||||
confess "DBD::Recordtype::add_field: Not a DBD::Recfield"
|
||||
unless $field->isa('DBD::Recfield');
|
||||
my $field_name = $field->name;
|
||||
dieContext("Duplicate field name '$field_name'")
|
||||
if exists $this->{FIELD_INDEX}->{$field_name};
|
||||
@@ -32,12 +33,7 @@ sub fields {
|
||||
}
|
||||
|
||||
sub field_names { # In their original order...
|
||||
my $this = shift;
|
||||
my @names = ();
|
||||
foreach ($this->fields) {
|
||||
push @names, $_->name
|
||||
}
|
||||
return @names;
|
||||
return map {$_->name} @{shift->{FIELD_LIST}};
|
||||
}
|
||||
|
||||
sub field {
|
||||
@@ -47,17 +43,18 @@ sub field {
|
||||
|
||||
sub add_device {
|
||||
my ($this, $device) = @_;
|
||||
confess "Not a DBD::Device" unless $device->isa('DBD::Device');
|
||||
confess "DBD::Recordtype::add_device: Not a DBD::Device"
|
||||
unless $device->isa('DBD::Device');
|
||||
my $choice = $device->choice;
|
||||
if (exists $this->{DEVICE_INDEX}->{$choice}) {
|
||||
my @warning = ("Duplicate device type '$choice'");
|
||||
return if $device->equals($this->{DEVICE_INDEX}->{$choice});
|
||||
my @warning = ("Two $this->{NAME} device supports '$choice' conflict");
|
||||
my $old = $this->{DEVICE_INDEX}->{$choice};
|
||||
push @warning, "Link types differ"
|
||||
if ($old->link_type ne $device->link_type);
|
||||
if $old->link_type ne $device->link_type;
|
||||
push @warning, "DSETs differ"
|
||||
if ($old->name ne $device->name);
|
||||
warnContext(@warning);
|
||||
return;
|
||||
if $old->name ne $device->name;
|
||||
dieContext(@warning);
|
||||
}
|
||||
push @{$this->{DEVICE_LIST}}, $device;
|
||||
$this->{DEVICE_INDEX}->{$choice} = $device;
|
||||
@@ -85,6 +82,11 @@ sub toCdefs {
|
||||
return join("\n", shift->cdefs) . "\n\n";
|
||||
}
|
||||
|
||||
sub equals {
|
||||
my ($a, $b) = @_;
|
||||
dieContext("Duplicate definition of record type '$a->{NAME}'");
|
||||
}
|
||||
|
||||
sub toDeclaration {
|
||||
my $this = shift;
|
||||
my @fields = map {
|
||||
|
||||
@@ -3,9 +3,7 @@ use DBD::Base;
|
||||
@ISA = qw(DBD::Base);
|
||||
|
||||
sub init {
|
||||
return shift->SUPER::init(shift, "registrar function name");
|
||||
return shift->SUPER::init(shift, "registrar function");
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ sub init {
|
||||
exists $valid_types{$type} or
|
||||
dieContext("Unknown variable type '$type', valid types are:",
|
||||
sort keys %valid_types);
|
||||
$this->SUPER::init($name, "variable name");
|
||||
$this->SUPER::init($name, "variable");
|
||||
$this->{VAR_TYPE} = $type;
|
||||
return $this;
|
||||
}
|
||||
@@ -33,4 +33,10 @@ sub iocshArg_type {
|
||||
return $valid_types{$this->{VAR_TYPE}};
|
||||
}
|
||||
|
||||
sub equals {
|
||||
my ($a, $b) = @_;
|
||||
return $a->SUPER::equals($b)
|
||||
&& $a->{VAR_TYPE} eq $b->{VAR_TYPE};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
Reference in New Issue
Block a user