char *name;
} varspec_t;
+const char *vartype_to_string(vartype_t type)
+{
+ switch (type) {
+ case VAR_SCALAR:
+ return "SCALAR";
+ case VAR_ARRAY:
+ return "ARRAY";
+ case VAR_HASH:
+ return "HASH";
+ case VAR_CODE:
+ return "CODE";
+ case VAR_IO:
+ return "IO";
+ default:
+ return "unknown";
+ }
+}
+
+I32 vartype_to_svtype(vartype_t type)
+{
+ switch (type) {
+ case VAR_SCALAR:
+ return SVt_PV; /* or whatever */
+ case VAR_ARRAY:
+ return SVt_PVAV;
+ case VAR_HASH:
+ return SVt_PVHV;
+ case VAR_CODE:
+ return SVt_PVCV;
+ case VAR_IO:
+ return SVt_PVIO;
+ default:
+ return SVt_NULL;
+ }
+}
+
vartype_t string_to_vartype(char *vartype)
{
if (strEQ(vartype, "SCALAR")) {
case VAR_CODE:
return sv_type == SVt_PVCV;
case VAR_IO:
- return sv_type == SVt_PVGV;
+ return sv_type == SVt_PVIO;
default:
return 0;
}
return (HV*)SvRV(ret);
}
+SV *_get_name(SV *self)
+{
+ dSP;
+ SV *ret;
+
+ PUSHMARK(SP);
+ XPUSHs(self);
+ PUTBACK;
+
+ call_method("name", G_SCALAR);
+
+ SPAGAIN;
+ ret = POPs;
+ PUTBACK;
+
+ return ret;
+}
+
MODULE = Package::Stash PACKAGE = Package::Stash
PROTOTYPES: DISABLE
RETVAL
void
+add_package_symbol(self, variable, initial=NULL, ...)
+ SV *self
+ varspec_t variable
+ SV *initial
+ PREINIT:
+ SV *name;
+ GV *glob;
+ CODE:
+ if (initial && !_valid_for_type(initial, variable.type))
+ croak("%s is not of type %s",
+ SvPV_nolen(initial), vartype_to_string(variable.type));
+
+ name = newSVsv(_get_name(self));
+ sv_catpvs(name, "::");
+ sv_catpv(name, variable.name);
+
+ /* XXX: come back to this when i feel like reimplementing caller() */
+/*
+ my $filename = $opts{filename};
+ my $first_line_num = $opts{first_line_num};
+
+ (undef, $filename, $first_line_num) = caller
+ if not defined $filename;
+
+ my $last_line_num = $opts{last_line_num} || ($first_line_num ||= 0);
+
+ # http://perldoc.perl.org/perldebguts.html#Debugger-Internals
+ $DB::sub{$pkg . '::' . $name} = "$filename:$first_line_num-$last_line_num";
+*/
+/*
+ if (items > 2 && (PL_perldb & 0x10) && variable.type == VAR_CODE) {
+ int i;
+ char *filename = NULL, *name;
+ I32 first_line_num, last_line_num;
+
+ if ((items - 3) % 2)
+ croak("add_package_symbol: Odd number of elements in %%opts");
+
+ for (i = 3; i < items; i += 2) {
+ char *key;
+ key = SvPV_nolen(ST(i));
+ if (strEQ(key, "filename")) {
+ if (!SvPOK(ST(i + 1)))
+ croak("add_package_symbol: filename must be a string");
+ filename = SvPV_nolen(ST(i + 1));
+ }
+ else if (strEQ(key, "first_line_num")) {
+ if (!SvIOK(ST(i + 1)))
+ croak("add_package_symbol: first_line_num must be an integer");
+ first_line_num = SvIV(ST(i + 1));
+ }
+ else if (strEQ(key, "last_line_num")) {
+ if (!SvIOK(ST(i + 1)))
+ croak("add_package_symbol: last_line_num must be an integer");
+ last_line_num = SvIV(ST(i + 1));
+ }
+ }
+
+ if (!filename) {
+ }
+ }
+*/
+
+ glob = gv_fetchsv(name, GV_ADD, vartype_to_svtype(variable.type));
+
+ if (initial) {
+ SV *val;
+
+ if (SvROK(initial)) {
+ val = SvRV(initial);
+ SvREFCNT_inc(val);
+ }
+ else {
+ val = newSVsv(initial);
+ }
+
+ switch (variable.type) {
+ case VAR_SCALAR:
+ GvSV(glob) = val;
+ break;
+ case VAR_ARRAY:
+ GvAV(glob) = (AV*)val;
+ break;
+ case VAR_HASH:
+ GvHV(glob) = (HV*)val;
+ break;
+ case VAR_CODE:
+ GvCV(glob) = (CV*)val;
+ break;
+ case VAR_IO:
+ GvIOp(glob) = (IO*)val;
+ break;
+ }
+ }
+
+void
remove_package_glob(self, name)
SV *self
char *name
GvCV(glob) = Nullcv;
break;
case VAR_IO:
- GvIOp(glob) = Null(struct io*);
+ GvIOp(glob) = Null(IO*);
break;
}
}
L<http://perldoc.perl.org/perldebguts.html#Debugger-Internals> for more
information about C<%DB::sub>.
-=cut
-
-sub _valid_for_type {
- my $self = shift;
- my ($value, $type) = @_;
- if ($type eq 'HASH' || $type eq 'ARRAY'
- || $type eq 'IO' || $type eq 'CODE') {
- return reftype($value) eq $type;
- }
- else {
- my $ref = reftype($value);
- return !defined($ref) || $ref eq 'SCALAR' || $ref eq 'REF' || $ref eq 'LVALUE';
- }
-}
-
-sub add_package_symbol {
- my ($self, $variable, $initial_value, %opts) = @_;
-
- my ($name, $sigil, $type) = ref $variable eq 'HASH'
- ? @{$variable}{qw[name sigil type]}
- : $self->_deconstruct_variable_name($variable);
-
- my $pkg = $self->name;
-
- if (@_ > 2) {
- $self->_valid_for_type($initial_value, $type)
- || confess "$initial_value is not of type $type";
-
- # cheap fail-fast check for PERLDBf_SUBLINE and '&'
- if ($^P and $^P & 0x10 && $sigil eq '&') {
- my $filename = $opts{filename};
- my $first_line_num = $opts{first_line_num};
-
- (undef, $filename, $first_line_num) = caller
- if not defined $filename;
-
- my $last_line_num = $opts{last_line_num} || ($first_line_num ||= 0);
-
- # http://perldoc.perl.org/perldebguts.html#Debugger-Internals
- $DB::sub{$pkg . '::' . $name} = "$filename:$first_line_num-$last_line_num";
- }
- }
-
- no strict 'refs';
- no warnings 'redefine', 'misc', 'prototype';
- *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value;
-}
-
=method remove_package_glob $name
Removes all package variables with the given name, regardless of sigil.
is((Foo->funk())[0], 'Foo::funk', '... got the right value from the function');
my $line = (Foo->funk())[1];
+{ local $TODO = "need to reimplement the db stuff in xs";
is $DB::sub{'Foo::funk'}, sprintf "%s:%d-%d", __FILE__, $line, $line,
'... got the right %DB::sub value for funk default args';
is $DB::sub{'Foo::dunk'}, sprintf "%s:%d-%d", "FileName", 100, 199,
'... got the right %DB::sub value for dunk with specified args';
+}
done_testing;