mirror of
https://github.com/samba-team/samba.git
synced 2025-12-09 00:23:50 +03:00
much cleaner handling of the different types of variables
This commit is contained in:
@@ -59,8 +59,15 @@ sub DumpElement($)
|
|||||||
$res .= "*";
|
$res .= "*";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (defined $element->{ARRAY_LEN} &&
|
||||||
|
$element->{ARRAY_LEN} eq "*") {
|
||||||
|
$res .= "*";
|
||||||
|
}
|
||||||
$res .= "$element->{NAME}";
|
$res .= "$element->{NAME}";
|
||||||
(defined $element->{ARRAY_LEN}) && ($res .= "[$element->{ARRAY_LEN}]");
|
if (defined $element->{ARRAY_LEN} &&
|
||||||
|
$element->{ARRAY_LEN} ne "*") {
|
||||||
|
$res .= "[$element->{ARRAY_LEN}]";
|
||||||
|
}
|
||||||
$res .= ";\n";
|
$res .= ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,5 +132,6 @@ type :
|
|||||||
text: /[\w\s.?-]*/
|
text: /[\w\s.?-]*/
|
||||||
|
|
||||||
constant: /-?\d+/
|
constant: /-?\d+/
|
||||||
|
| '*'
|
||||||
|
|
||||||
cpp_prefix: '#' /.*/
|
cpp_prefix: '#' /.*/
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ sub find_size_var($)
|
|||||||
{
|
{
|
||||||
my($e) = shift;
|
my($e) = shift;
|
||||||
my($fn) = $e->{PARENT};
|
my($fn) = $e->{PARENT};
|
||||||
my($size) = util::has_property($e, "size_is");
|
my($size) = util::array_size($e);
|
||||||
|
|
||||||
if ($fn->{TYPE} ne "FUNCTION") {
|
if ($fn->{TYPE} ne "FUNCTION") {
|
||||||
return "r->$size";
|
return "r->$size";
|
||||||
@@ -75,7 +75,7 @@ sub ParseArrayPull($$)
|
|||||||
my $var_prefix = shift;
|
my $var_prefix = shift;
|
||||||
my $size = find_size_var($e);
|
my $size = find_size_var($e);
|
||||||
|
|
||||||
if (!util::has_property($e, "ref")) {
|
if (util::need_alloc($e)) {
|
||||||
$res .= "\t\tNDR_ALLOC_N_SIZE(ndr, $var_prefix$e->{NAME}, $size, sizeof($var_prefix$e->{NAME}\[0]));\n";
|
$res .= "\t\tNDR_ALLOC_N_SIZE(ndr, $var_prefix$e->{NAME}, $size, sizeof($var_prefix$e->{NAME}\[0]));\n";
|
||||||
}
|
}
|
||||||
if (util::is_scalar_type($e->{TYPE})) {
|
if (util::is_scalar_type($e->{TYPE})) {
|
||||||
@@ -93,26 +93,16 @@ sub ParseElementPushScalar($$$)
|
|||||||
my($e) = shift;
|
my($e) = shift;
|
||||||
my($var_prefix) = shift;
|
my($var_prefix) = shift;
|
||||||
my($ndr_flags) = shift;
|
my($ndr_flags) = shift;
|
||||||
|
my $cprefix = util::c_push_prefix($e);
|
||||||
|
|
||||||
if (defined $e->{VALUE}) {
|
if (defined $e->{VALUE}) {
|
||||||
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $e->{VALUE}));\n";
|
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $e->{VALUE}));\n";
|
||||||
} elsif ($e->{POINTERS} &&
|
} elsif (util::need_wire_pointer($e)) {
|
||||||
!util::has_property($e, "ref")) {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_push_ptr(ndr, $var_prefix$e->{NAME}));\n";
|
$res .= "\tNDR_CHECK(ndr_push_ptr(ndr, $var_prefix$e->{NAME}));\n";
|
||||||
} elsif (util::is_builtin_type($e->{TYPE})) {
|
} elsif (util::is_builtin_type($e->{TYPE})) {
|
||||||
if (util::is_scalar_type($e->{TYPE}) &&
|
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
util::has_property($e, "ref")) {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, *$var_prefix$e->{NAME}));\n";
|
|
||||||
} else {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (util::is_scalar_type($e->{TYPE}) ||
|
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
$e->{POINTERS}) {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}));\n";
|
|
||||||
} else {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, &$var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,34 +113,23 @@ sub ParseElementPullScalar($$$)
|
|||||||
my($e) = shift;
|
my($e) = shift;
|
||||||
my($var_prefix) = shift;
|
my($var_prefix) = shift;
|
||||||
my($ndr_flags) = shift;
|
my($ndr_flags) = shift;
|
||||||
|
my $cprefix = util::c_pull_prefix($e);
|
||||||
|
|
||||||
if (defined $e->{VALUE}) {
|
if (defined $e->{VALUE}) {
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $e->{VALUE}));\n";
|
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $e->{VALUE}));\n";
|
||||||
} elsif ($e->{POINTERS} &&
|
} elsif (util::need_wire_pointer($e)) {
|
||||||
!util::has_property($e, "ref")) {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_uint32(ndr, &_ptr_$e->{NAME}));\n";
|
$res .= "\tNDR_CHECK(ndr_pull_uint32(ndr, &_ptr_$e->{NAME}));\n";
|
||||||
$res .= "\tif (_ptr_$e->{NAME}) {\n";
|
$res .= "\tif (_ptr_$e->{NAME}) {\n";
|
||||||
$res .= "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
|
$res .= "\t\tNDR_ALLOC(ndr, $var_prefix$e->{NAME});\n";
|
||||||
$res .= "\t} else {\n";
|
$res .= "\t} else {\n";
|
||||||
$res .= "\t\t$var_prefix$e->{NAME} = NULL;\n";
|
$res .= "\t\t$var_prefix$e->{NAME} = NULL;\n";
|
||||||
$res .= "\t}\n";
|
$res .= "\t}\n";
|
||||||
} elsif (!util::is_scalar_type($e->{TYPE}) &&
|
} elsif (util::need_alloc($e)) {
|
||||||
util::has_property($e, "ref")) {
|
# no scalar component
|
||||||
if (util::is_builtin_type($e->{TYPE})) {
|
} elsif (util::is_builtin_type($e->{TYPE})) {
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
|
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
} else {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (util::is_builtin_type($e->{TYPE})) {
|
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
if (!util::has_property($e, "ref")) {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, &$var_prefix$e->{NAME}));\n";
|
|
||||||
} else {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, &$var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,34 +139,25 @@ sub ParseElementPushBuffer($$)
|
|||||||
{
|
{
|
||||||
my($e) = shift;
|
my($e) = shift;
|
||||||
my($var_prefix) = shift;
|
my($var_prefix) = shift;
|
||||||
|
my $cprefix = util::c_push_prefix($e);
|
||||||
|
|
||||||
if (util::has_property($e, "ref")) {
|
if (util::is_pure_scalar($e)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util::is_scalar_type($e->{TYPE}) && !$e->{POINTERS}) {
|
if (util::need_wire_pointer($e)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($e->{POINTERS}) {
|
|
||||||
$res .= "\tif ($var_prefix$e->{NAME}) {\n";
|
$res .= "\tif ($var_prefix$e->{NAME}) {\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util::has_property($e, "size_is")) {
|
if (util::array_size($e)) {
|
||||||
ParseArrayPush($e, "r->");
|
ParseArrayPush($e, "r->");
|
||||||
|
} elsif (util::is_builtin_type($e->{TYPE})) {
|
||||||
|
$res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
} else {
|
} else {
|
||||||
if (util::is_scalar_type($e->{TYPE})) {
|
$res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
$res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, *$var_prefix$e->{NAME}));\n";
|
|
||||||
} elsif (!$e->{POINTERS}) {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, ndr_flags, &$var_prefix$e->{NAME}));\n";
|
|
||||||
} elsif (util::is_builtin_type($e->{TYPE})) {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
|
|
||||||
} else {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_push_$e->{TYPE}(ndr, ndr_flags, $var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($e->{POINTERS}) {
|
if (util::need_wire_pointer($e)) {
|
||||||
$res .= "\t}\n";
|
$res .= "\t}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,37 +170,25 @@ sub ParseElementPullBuffer($$$)
|
|||||||
my($e) = shift;
|
my($e) = shift;
|
||||||
my($var_prefix) = shift;
|
my($var_prefix) = shift;
|
||||||
my($ndr_flags) = shift;
|
my($ndr_flags) = shift;
|
||||||
|
my $cprefix = util::c_pull_prefix($e);
|
||||||
|
|
||||||
if (util::has_property($e, "ref")) {
|
if (util::is_pure_scalar($e)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util::is_scalar_type($e->{TYPE}) && !$e->{POINTERS}) {
|
if (util::need_wire_pointer($e)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($e->{POINTERS}) {
|
|
||||||
$res .= "\tif ($var_prefix$e->{NAME}) {\n";
|
$res .= "\tif ($var_prefix$e->{NAME}) {\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util::has_property($e, "size_is")) {
|
if (util::array_size($e)) {
|
||||||
ParseArrayPull($e, "r->");
|
ParseArrayPull($e, "r->");
|
||||||
|
} elsif (util::is_builtin_type($e->{TYPE})) {
|
||||||
|
$res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
} else {
|
} else {
|
||||||
if (!$e->{POINTERS} ||
|
$res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));\n";
|
||||||
$e->{TYPE} =~ "unistr.*") {
|
|
||||||
if (util::is_builtin_type($e->{TYPE})) {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, &$var_prefix$e->{NAME}));\n";
|
|
||||||
} else {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, &$var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
} elsif (util::is_builtin_type($e->{TYPE})) {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $var_prefix$e->{NAME}));\n";
|
|
||||||
} else {
|
|
||||||
$res .= "\t\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}));\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($e->{POINTERS}) {
|
if (util::need_wire_pointer($e)) {
|
||||||
$res .= "\t}\n";
|
$res .= "\t}\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,8 +259,7 @@ sub ParseStructPull($)
|
|||||||
# declare any internal pointers we need
|
# declare any internal pointers we need
|
||||||
foreach my $e (@{$struct->{ELEMENTS}}) {
|
foreach my $e (@{$struct->{ELEMENTS}}) {
|
||||||
$e->{PARENT} = $struct;
|
$e->{PARENT} = $struct;
|
||||||
if ($e->{POINTERS} &&
|
if (util::need_wire_pointer($e)) {
|
||||||
!util::has_property($e, "ref")) {
|
|
||||||
$res .= "\tuint32 _ptr_$e->{NAME};\n";
|
$res .= "\tuint32 _ptr_$e->{NAME};\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -440,7 +397,7 @@ sub ParseFunctionPush($)
|
|||||||
foreach my $e (@{$function->{DATA}}) {
|
foreach my $e (@{$function->{DATA}}) {
|
||||||
if (util::has_property($e, "in")) {
|
if (util::has_property($e, "in")) {
|
||||||
$e->{PARENT} = $function;
|
$e->{PARENT} = $function;
|
||||||
if (util::has_property($e, "size_is")) {
|
if (util::array_size($e)) {
|
||||||
$res .= "\tif (r->in.$e->{NAME}) {\n";
|
$res .= "\tif (r->in.$e->{NAME}) {\n";
|
||||||
if (!util::is_scalar_type($e->{TYPE})) {
|
if (!util::is_scalar_type($e->{TYPE})) {
|
||||||
$res .= "\t\tint ndr_flags = NDR_SCALARS|NDR_BUFFERS;\n";
|
$res .= "\t\tint ndr_flags = NDR_SCALARS|NDR_BUFFERS;\n";
|
||||||
@@ -468,18 +425,17 @@ sub ParseFunctionPull($)
|
|||||||
|
|
||||||
# declare any internal pointers we need
|
# declare any internal pointers we need
|
||||||
foreach my $e (@{$fn->{DATA}}) {
|
foreach my $e (@{$fn->{DATA}}) {
|
||||||
if (util::has_property($e, "out") &&
|
if (util::has_property($e, "out")) {
|
||||||
$e->{POINTERS} &&
|
if (util::need_wire_pointer($e)) {
|
||||||
!util::is_scalar_type($e->{TYPE}) &&
|
$res .= "\tuint32 _ptr_$e->{NAME};\n";
|
||||||
!util::has_property($e, "ref")) {
|
}
|
||||||
$res .= "\tuint32 _ptr_$e->{NAME};\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $e (@{$fn->{DATA}}) {
|
foreach my $e (@{$fn->{DATA}}) {
|
||||||
if (util::has_property($e, "out")) {
|
if (util::has_property($e, "out")) {
|
||||||
$e->{PARENT} = $fn;
|
$e->{PARENT} = $fn;
|
||||||
if (util::has_property($e, "size_is")) {
|
if (util::array_size($e)) {
|
||||||
$res .= "\tif (r->out.$e->{NAME}) {\n";
|
$res .= "\tif (r->out.$e->{NAME}) {\n";
|
||||||
if (!util::is_scalar_type($e->{TYPE})) {
|
if (!util::is_scalar_type($e->{TYPE})) {
|
||||||
$res .= "\t\tint ndr_flags = NDR_SCALARS|NDR_BUFFERS;\n";
|
$res .= "\t\tint ndr_flags = NDR_SCALARS|NDR_BUFFERS;\n";
|
||||||
@@ -487,10 +443,6 @@ sub ParseFunctionPull($)
|
|||||||
ParseArrayPull($e, "r->out.");
|
ParseArrayPull($e, "r->out.");
|
||||||
$res .= "\t}\n";
|
$res .= "\t}\n";
|
||||||
} else {
|
} else {
|
||||||
if ($e->{POINTERS} &&
|
|
||||||
!util::has_property($e, "ref")) {
|
|
||||||
$res .= "\tNDR_ALLOC(ndr, r->out.$e->{NAME});\n";
|
|
||||||
}
|
|
||||||
ParseElementPullScalar($e, "r->out.", "NDR_SCALARS|NDR_BUFFERS");
|
ParseElementPullScalar($e, "r->out.", "NDR_SCALARS|NDR_BUFFERS");
|
||||||
ParseElementPullBuffer($e, "r->out.", "NDR_SCALARS|NDR_BUFFERS");
|
ParseElementPullBuffer($e, "r->out.", "NDR_SCALARS|NDR_BUFFERS");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ sub is_scalar_type($)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# this is used to determine if the ndr push/pull functions will need
|
||||||
|
# a ndr_flags field to split by buffers/scalars
|
||||||
sub is_builtin_type($)
|
sub is_builtin_type($)
|
||||||
{
|
{
|
||||||
my($type) = shift;
|
my($type) = shift;
|
||||||
@@ -200,6 +202,109 @@ sub is_builtin_type($)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# determine if an element needs a reference pointer on the wire
|
||||||
|
# in its NDR representation
|
||||||
|
sub need_wire_pointer($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
if ($e->{POINTERS} &&
|
||||||
|
!has_property($e, "ref")) {
|
||||||
|
return $e->{POINTERS};
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# determine if an element is a pass-by-reference structure
|
||||||
|
sub is_ref_struct($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
if (!is_scalar_type($e->{TYPE}) &&
|
||||||
|
has_property($e, "ref")) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# determine if an element is a pure scalar. pure scalars do not
|
||||||
|
# have a "buffers" section in NDR
|
||||||
|
sub is_pure_scalar($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
if (has_property($e, "ref")) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (is_scalar_type($e->{TYPE}) && !$e->{POINTERS}) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# determine the array size (size_is() or ARRAY_LEN)
|
||||||
|
sub array_size($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
my $size = has_property($e, "size_is");
|
||||||
|
if ($size) {
|
||||||
|
return $size;
|
||||||
|
}
|
||||||
|
$size = $e->{ARRAY_LEN};
|
||||||
|
if ($size) {
|
||||||
|
return $size;
|
||||||
|
}
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
# see if a variable needs to be allocated by the NDR subsystem on pull
|
||||||
|
sub need_alloc($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
|
||||||
|
if (has_property($e, "ref")) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($e->{POINTERS} || array_size($e)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# determine the C prefix used to refer to a variable when passing to a push
|
||||||
|
# function. This will be '*' for pointers to scalar types, '' for scalar
|
||||||
|
# types and normal pointers and '&' for pass-by-reference structures
|
||||||
|
sub c_push_prefix($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
if (is_scalar_type($e->{TYPE}) &&
|
||||||
|
$e->{POINTERS}) {
|
||||||
|
return "*";
|
||||||
|
}
|
||||||
|
if (!is_scalar_type($e->{TYPE}) &&
|
||||||
|
!$e->{POINTERS} &&
|
||||||
|
!array_size($e)) {
|
||||||
|
return "&";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
# determine the C prefix used to refer to a variable when passing to a pull
|
||||||
|
# return '&' or ''
|
||||||
|
sub c_pull_prefix($)
|
||||||
|
{
|
||||||
|
my $e = shift;
|
||||||
|
|
||||||
|
if (!$e->{POINTERS} && !array_size($e)) {
|
||||||
|
return "&";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($e->{TYPE} =~ "unistr.*") {
|
||||||
|
return "&";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user