From: Will Budic Date: Fri, 14 Jul 2023 05:18:00 +0000 (+1000) Subject: upd. to latest CNF. X-Git-Url: https://lifelog.hopto.org/gitweb/?a=commitdiff_plain;h=ad7018c78ba8bd9e8d7a1d704dae4bc00413eb5c;p=LifeLog.git upd. to latest CNF. --- diff --git a/htdocs/cgi-bin/system/modules/CNFJSON.pm b/htdocs/cgi-bin/system/modules/CNFJSON.pm new file mode 100644 index 0000000..8954ba3 --- /dev/null +++ b/htdocs/cgi-bin/system/modules/CNFJSON.pm @@ -0,0 +1,135 @@ +# SQL Processing part for the Configuration Network File Format. +# Programed by : Will Budic +# Source Origin : https://github.com/wbudic/PerlCNF.git +# Open Source License -> https://choosealicense.com/licenses/isc/ +# +package CNFJSON; + +use strict;use warnings;#use warnings::unused; +use Exception::Class ('CNFParserException'); use Carp qw(cluck); +use Syntax::Keyword::Try; +use JSON::ize; + +use constant VERSION => '1.0'; + +sub new { + my ($class, $attrs,$self) = @_; + $self = {}; + $self = \%$attrs if $attrs; + bless $self, $class; +} +### +sub nodeToJSON { + my($self,$node,$tab_cnt) = @_; $tab_cnt=1 if !$tab_cnt; + if($self&&$node){ + my ($buffer,$attributes,$closeBrk)=("","",0); + my $tab = $tab_cnt == 1 ? '' : ' ' x $tab_cnt; + my $name = $node -> {'_'}; + my $val = $node -> {'#'}; $val = $node->{'*'} if !$val; $val = _translateNL($val); + my @arr = sort (keys %$node); + my $regex = $node->PRIVATE_FIELDS(); + foreach my$attr(@arr){ + if($attr !~ /$regex/){ + my $aval = _translateNL($node->{$attr}); + $attributes .= ",\n" if $attributes; + $attributes .= "$tab\"$attr\" : \"$aval\""; + } + } + # + @arr = exists $node-> {'@$'} ? @{$node -> {'@$'}} : (); + # + return \"$tab\"$name\" : \"$val\"" if(!@arr==0 && $val); + $tab_cnt++; + if(@arr){ + foreach (@arr){ + if (!$buffer){ + $attributes.= ",\n" if $attributes; + $buffer = "$attributes$tab\"$name\" : {\n"; + $attributes = ""; $closeBrk = 1; + }else{ + $buffer .= ",\n" + } + my $sub = $_->name(); + my $insert = nodeToJSON($self, $_, $tab_cnt); + if(length($$insert)>0){ + $buffer .= $$insert; + }else{ + $buffer .= $tab.(' ' x $tab_cnt)."\"$sub\" : {}" + } + } + } + if($attributes){ + $closeBrk=2 if (!$buffer && !$node->isRoot()); + $buffer .= $node->isRoot() ? "$tab$attributes" : "$tab\"$name\" : {\n$tab$attributes"; + $attributes = ""; + } + # + @arr = exists $node-> {'@@'} ? @{$node -> {'@@'}} : (); + # + if(@arr){ + foreach (@arr){ + if (!$attributes){ + $attributes = "$tab\"$name\" : [\n" + }else{ + $attributes .= ",\n" + } + $attributes .= $tab.(' ' x $tab_cnt).'"'.$_->val().'"' + } + $buffer .= $attributes."\n$tab]" + } + if ($closeBrk){ + $buffer .= "\n$tab}" + } + if ($node->isRoot()){ + $buffer =~ s/\n/\n /gs; + while (my ($k, $v) = each %$self) { $buffer .= qq(,\n"$k" : "$v") } + $buffer = $tab."{\n ".$buffer."\n"."$tab}"; + } + + return \$buffer + + }else{ + die "Where is the node, my friend?" + } +} + sub _translateNL { + my $val = shift; + if($val){ + $val =~ s/\n/\\n/g; + } + return $val + } + +sub jsonToCNFNode { + my($self,$json,$name) = @_; + if($self&&$json){ + my $obj = jsonize($json); + return _objToCNF($name, $obj) + } + } + sub _jsonToObj { + return jsonize(shift); + } + + sub _objToCNF { + my($name, $obj) = @_; $name = 'root' if !$name; + my $ret = CNFNode->new({'_'=>$name}); + my %perl = %$obj; + foreach my $atrr(keys %perl){ + my $val = $perl{$atrr}; + my $ref = ref($val); + if($ref eq 'HASH'){ + $val = _objToCNF($atrr, $val); + my @arr = $ret->{'@$'} ? $ret->{'@$'} : (); + $arr[@arr] = $val; + $ret->{'@$'} = \@arr; + }elsif($ref eq 'ARRAY'){ + $ret->{'@$'} = \@$val + }else{ + $ret -> {$atrr} = $val + } + } + return $ret; + } + +1; \ No newline at end of file diff --git a/htdocs/cgi-bin/system/modules/CNFMeta.pm b/htdocs/cgi-bin/system/modules/CNFMeta.pm index db77420..d16018b 100644 --- a/htdocs/cgi-bin/system/modules/CNFMeta.pm +++ b/htdocs/cgi-bin/system/modules/CNFMeta.pm @@ -15,12 +15,14 @@ use warnings; ### # TREE instuction meta. use constant HAS_PRIORITY => "HAS_PROCESSING_PRIORITY"; # Schedule to process before the rest in synchronous line of instructions. + # ### # DO instruction meta. # use constant ON_DEMAND => "ON_DEMAND"; #Postpone to evaluate on demand. use constant SHELL => "SHELL"; #Execute via system shell. + # ### @@ -33,14 +35,24 @@ sub _meta { } $constance; } +### +# Priority order no. for instructions. +use constant PRIORITY => qr/(\s*\_+PRIORITY\_(\d+)\_+\s*)/o; +### +# Tree instruction has been scripted in collapsed nodes shorthand format. +# Shortife is parsed faster and with less recursion, but can be prone to script errors, +# resulting in unintended placings. +use constant IN_SHORTIFE => qr/(\s*\_+IN_SHORTIFE\_+\s*)/o; sub import { my $caller = caller; no strict "refs"; { *{"${caller}::meta"} = \&_meta; - *{"${caller}::HAS_PRIORITY"} = \&HAS_PRIORITY; - *{"${caller}::ON_DEMAND"} = \&ON_DEMAND; - *{"${caller}::SHELL"} = \&SHELL; + *{"${caller}::meta_has_priority"} = sub {return _meta(HAS_PRIORITY)}; + *{"${caller}::meta_priority"} = \&PRIORITY; + *{"${caller}::meta_on_demand"} = sub {return _meta(ON_DEMAND)}; + *{"${caller}::meta_node_in_shortife"} =\&IN_SHORTIFE; + *{"${caller}::SHELL"} = \&SHELL; } return 1; } diff --git a/htdocs/cgi-bin/system/modules/CNFNode.pm b/htdocs/cgi-bin/system/modules/CNFNode.pm index 3f7677f..6ad5ccc 100644 --- a/htdocs/cgi-bin/system/modules/CNFNode.pm +++ b/htdocs/cgi-bin/system/modules/CNFNode.pm @@ -20,17 +20,26 @@ sub new { my $self = \%$attrs; bless $self, $class; } -sub name {shift -> {'_'}} -sub parent {shift -> {'@'}} -sub isRoot {not exists shift -> {'@'}} -sub list {shift -> {'@@'}} -sub script {shift -> {'~'}} + +use constant PRIVATE_FIELDS => qr/@\$|[@#_~^&]/o; + +### +# CNFNode uses symbol offcodes for all its own field values, foe efficiancy. +### +sub name {shift -> {'_'}} +sub parent {shift -> {'@'}} +sub isRoot {not exists shift -> {'@'}} +sub list {shift -> {'@@'}} +sub script {shift -> {'~'}} +sub priority {shift -> {'^'}} +sub evaluate {shift -> {'&'}} sub attributes { my $self = shift; my @nodes; + my $regex = PRIVATE_FIELDS(); foreach(sort keys %$self){ my $node = $self->{$_}; - if($_ !~ /@|@\$|#_~/){ + if($_ !~ /$regex/){ $nodes[@nodes] = [$_, $node] } } @@ -56,8 +65,8 @@ sub val { if(!$ret && $self->{'@$'}){ #return from subproperties. my $buf; my @arr = @{$self->{'@$'}}; - foreach my $node(@arr){ - $buf .= $node->val()."\n"; + foreach my $node(@arr){ + $buf .= $node -> val() ."\n"; } return $buf; } @@ -98,7 +107,7 @@ sub val { # NOTICE - 20221222 Future versions might provide also for more complex path statements with regular expressions enabled. ### sub find { - my ($self, $path, $ret, $prev, $seekArray)=@_; + my ($self, $path, $ret, $prev, $seekArray,$ref)=@_; foreach my $name(split(/\//, $path)){ if(ref($self) eq "ARRAY"){ if($name eq '#'){ @@ -115,7 +124,7 @@ sub find { $ret = $prev->{'@$'}; } }else{ - if($name eq '@@') { + if ($name eq '@@') { $ret = $self->{'@@'}; $seekArray = 1; next }elsif($name eq '@$') { @@ -123,64 +132,96 @@ sub find { next }elsif($name eq '#'){ return $ret->val() - }if(ref($ret) eq "CNFNode" && $seekArray){ + }elsif(exists $self->{$name}){ + $ret = $self->{$name}; + next + } + $ref = ref($ret); + if(!$seekArray && $ref eq 'ARRAY'){ # ret can be an array of parent same name elemenents. + foreach my$n(@$ret) { + if ($n->node($name)){ + $ret = $n; last + } + }### TODO - Search further elements if not found. Many to many. + }elsif($ref eq "CNFNode" && $seekArray){ $ret = $ret->{$name}; next }else{ $ret = $self->{'@$'} if ! $seekArray; # This will initiate further search in subproperties names. } } - if($ret){ + $ref = ref($ret); + if($ret && $ref eq 'ARRAY'){ my $found = 0; my @arr; undef $prev; - foreach(@$ret){ - if($seekArray && exists $_->{'@$'}){ - my $n; - foreach (@{$_->{'@$'}}){ - $n = $_; - if ($n->{'_'} eq $name){ - $arr[@arr] = $n; + foreach my $ele(@$ret){ + if($seekArray && exists $ele->{'@$'}){ + foreach my$node(@{$ele->{'@$'}}){ + if ($node->{'_'} eq $name){ + $arr[@arr] = $ele = $node; } } if(@arr>1){ $ret = \@arr; - }else{ - $ret = $n; + }else{ + $ret = $ele } $found++; - }elsif (ref($_) eq "CNFNode" and $_->{'_'} eq $name){ - if($prev){ - $arr[@arr] = $_; - $self = \@arr; - $prev = $_; - }else{ - $arr[@arr] = $_; - $prev = $self = $_ - } - if(!$found){ - $self = $ret = $_ - }else{ - $ret = \@arr; + }elsif (ref($ele) eq "CNFNode"){ + if($ele->{'_'} eq $name){ + if ($prev) { + $arr[@arr] = $ele; + $self = \@arr; + $prev = $ele; + } + else { + $arr[@arr] = $ele; + $prev = $self = $ele; + } + if ( !$found ) { + $self = $ret = $ele; + } + else { + $ret = \@arr; + } + $found = 1 + }elsif(exists $ele->{$name}){ + $ret = $ele->{$name}; + $found = 1 } - $found=1 } } - $ret = $self->{$name} if(!$found && $name ne '@$'); - }else{ - if(ref($ret) ne "ARRAY"){ - $ret = $self->{$name} + if(!$found && $name ne '@$' && exists $self->{$name}){ + $ret = $self->{$name} + }else{ + undef $ret if !$found } + } + elsif($name && $ref eq "CNFNode"){ + $ret = $ret -> {$name} } } return $ret; } ### # Similar to find, put simpler node by path routine. -# Returns first node found based on path.. +# Returns first node found based on path. ### sub node { my ($self, $path, $ret)=@_; + if($path !~ /\//){ + return $self->{$path} if exists $self->{$path}; + $ret = $self->{'@$'}; + if($ret){ + foreach(@$ret){ + if ($_->{'_'} eq $path){ + return $_; + } + } + } + return + } foreach my $name(split(/\//, $path)){ $ret = $self->{'@$'}; if($ret){ @@ -204,8 +245,8 @@ my @linked_subs; sub process { my ($self, $parser, $script)=@_; - my ($sub, $val, $isArray,$body) = (undef,0,0,""); - my ($tag,$sta,$end)=("","",""); + my ($sub, $val, $isArray,$isShortifeScript,$body) = (undef,0,0,0,""); + my ($tag,$sta,$end)=("","",""); my $meta_shortife = &meta_node_in_shortife; my ($opening,$closing,$valing)=(0,0,0); my @array; @@ -220,17 +261,18 @@ sub process { my @lines = split(/\n/, $script); foreach my $ln(@lines){ $ln =~ s/^\s+|\s+$//g; - if(length ($ln)){ - #print $ln, "\n"; + if(length ($ln)){ + my $isShortife = ($ln =~ s/($meta_shortife)/""/sexi); if($ln =~ /^([<>\[\]])(.*)([<>\[\]])$/ && $1 eq $3){ $sta = $1; $tag = $2; - $end = $3; + $end = $3; + $isShortifeScript = 1 if $isShortife; my $isClosing = ($sta =~ /[>\]]/) ? 1 : 0; if($tag =~ /^([#\*\@]+)[\[<](.*)[\]>]\/*[#\*\@]+$/){#<- The \/ can sneak in as included in closing tag. if($1 eq '*'){ my $link = $2; - my $rval = $self -> obtainLink($parser, $link); + my $rval = $self -> obtainLink($parser, $link); $rval = $parser->{$link} if !$rval; #Anon is passed as an unknown constance (immutable). if($rval){ if($opening){ @@ -305,10 +347,67 @@ sub process { } $valing = 0; $tag ="" if $isClosing - }else{ - my $a = $isArray; - my $property = CNFNode->new({'_'=>$sub, '@' => \$self}); - $property -> process($parser, $body); + }else{ + my $property = CNFNode->new({'_'=>$sub, '@' => \$self}); + my $a = $isArray; + if($isShortifeScript){ + my ($sub,$prev,$cnt_nl,$bck_p); + while ($body =~ / (.*)__+ ([\\\|]|\/*) | (.*)[:=](.*) | (.*)\n/gmx){ + my @sel = @{^CAPTURE}; + if(defined $sel[0]){ + if ($sel[1]){ + my $t = substr $sel[1],0,1; + $bck_p=length($sel[1]); + my $parent = $sub; + if($t eq '\\'){ + $parent = $sub ? $sub : $property; + }elsif($t eq '|'){ + $parent = $sub ? $sub->parent() : $prev; + }elsif($t eq '/') { + $parent = $sub; + do{$parent = $parent -> parent() if $parent -> parent()}while(--$bck_p>0); + if ($sel[0] eq ''){ + $sub = $parent; next + } + } + $sub = CNFNode->new({'_'=>$sel[0], '@' => $parent}); + my @elements = exists $parent -> {'@$'} ? $parent -> {'@$'} : (); + $elements[@elements] = $sub; $prev = $parent; $cnt_nl = 0; + $parent -> {'@$'} = \@elements; + } + } + elsif (defined $sel[2] && defined $sel[3]){ + my $attribute = $sel[2]; $attribute =~ s/^\s*|\s*$//g; + my $value = $sel[3]; $value =~ s/^\s*|\s*$//g; + if($sub){ + $sub -> {$attribute} = $value + }else{ + $property -> {$attribute} = $value + } + $cnt_nl = 0; + } + elsif (defined $sel[4]){ + if ($sel[4] eq ''){ + if(++$cnt_nl>1){ #cancel collapse chain and at root of property that is shorted. + ##$sub = $property ; + $cnt_nl =0 + } + next + }elsif($sel[4] !~ /^\s*\#/ ){ + my $parent = $sub ? $sub->parent() : $property; + if (exists $parent->{'#'}){ + $parent->{'#'} .= "\n" . $sel[4] + }else{ + $parent->{'#'} = $sel[4] + } + # $sub =""; + } + } + }#while + $isShortifeScript = 0; + }else{ + $property -> process($parser, $body); + } $isArray = $a; if($tag eq '@@'){ $array[@array] = $property; @@ -344,7 +443,7 @@ sub process { else{$val = $4} }elsif($2 eq '*'){ my $link = $4; - my $rval = $self->obtainLink($parser, $link); + my $rval = $self -> obtainLink($parser, $link); $rval = $parser->{$link} if !$rval; #Anon is passed as an unknown constance (immutable). if($rval){ #Is this a child node? @@ -381,7 +480,6 @@ sub process { $nodes[@nodes] = $property; $self->{'@$'} = \@nodes; } - next }elsif($val){ $val = $self->{'#'}; @@ -459,14 +557,14 @@ sub validate { my ($tag,$sta,$end,$lnc,$errors)=("","","",0,0); my (@opening,@closing,@singels); my ($open,$close) = (0,0); - my @lines = split(/\n/, $self->{'~'}); + my @lines = defined $self -> script() ? split(/\n/, $self->script()) :(); foreach my $ln(@lines){ $ln =~ s/^\s+|\s+$//g; $lnc++; #print $ln, "<-","\n"; if(length ($ln)){ #print $ln, "\n"; - if($ln =~ /^([<>\[\]])(.*)([<>\[\]])$/ && $1 eq $3){ + if($ln =~ /^([<>\[\]])(.*)([<>\[\]])(.*)/ && $1 eq $3){ $sta = $1; $tag = $2; $end = $3; @@ -488,16 +586,15 @@ sub validate { } } } - if(@opening != @closing){ - cluck "Opening and clossing tags mismatch!"; - foreach my $o(@opening){ + if(@opening != @closing){ + cluck "Opening and clossing tags mismatch!"; + foreach my $o(@opening){ my $c = pop @closing; if(!$c){ $errors++; warn "Error unclosed tag-> [".$o->{T}.'[ @'.$o->{L} } - } - + } }else{ my $errors = 0; my $error_tag; my $nesting; my $cnt = $#opening; @@ -523,8 +620,8 @@ sub validate { if($o->{T} ne $c->{T} && $o->{N} ne $c->{N}){ cluck "Error opening and clossing tags mismatch for ". - brk($o).' ln: '.$o->{L}.' idx: '.$o->{idx}. - ' wrongly matched with '.brk($c).' ln: '.$c->{L}.' idx: '.$c->{idx}."\n"; + _brk($o).' ln: '.$o->{L}.' idx: '.$o->{idx}. + ' wrongly matched with '._brk($c).' ln: '.$c->{L}.' idx: '.$c->{idx}."\n"; $errors++; } } @@ -532,9 +629,52 @@ sub validate { return $errors; } -sub brk{ - my $t = shift; - return 'tag: \''.$t->{S}.$t->{T}.$t->{S}.'\'' + sub _brk{ + my $t = shift; + return 'tag: \''.$t->{S}.$t->{T}.$t->{S}.'\'' + } +### +# Compare one node with another if is equal in structure. +## +sub equals { + my ($self, $node, $ref) = @_; $ref = ref($node); + if (ref($node) eq 'CNFNode'){ + my @s = sort keys %$self; + my @o = sort keys %$node; + my $i=$#o; + foreach (0..$i){ + my $n = $o[$i-$_]; + if($n eq '~' || $n eq '^'){ + splice @o,$i-$_,1; + } + } + $i=$#s; + foreach (0..$i){ + my $n = $s[$i-$_]; + if($n eq '~' || $n=~/^CNF_/ || $n=~/^DO_/){ + splice @s,$i-$_,1; + } + }$i=0; + if(@s == @o){ + foreach(@s) { + if($_ ne $o[$i++]){ + return 0 + } + } + if($self -> {'@$'} && $node -> {'@$'}){ + @s = sort keys @{$self -> {'@$'}}; + @o = sort keys @{$node -> {'@$'}}; + $i = 0; + foreach(@s) { + if($_ ne $o[$i++]){ + return 0 + } + } + } + return 1; + } + } + return 0; } 1; \ No newline at end of file diff --git a/htdocs/cgi-bin/system/modules/CNFParser.pm b/htdocs/cgi-bin/system/modules/CNFParser.pm index 2da7500..a552b31 100644 --- a/htdocs/cgi-bin/system/modules/CNFParser.pm +++ b/htdocs/cgi-bin/system/modules/CNFParser.pm @@ -18,14 +18,14 @@ use DateTime; require CNFMeta; CNFMeta::import(); require CNFNode; -require CNFtoJSON; + # Do not remove the following no critic, no security or object issues possible. # We can use perls default behaviour on return. ##no critic qw(Subroutines::RequireFinalReturn) ##no critic Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions -use constant VERSION => '2.8'; +use constant VERSION => '2.9'; our @files; our %lists; our %properties; @@ -101,28 +101,64 @@ sub new { my ($class, $path, $attrs, $del_keys, $self) = @_; sub import { my $caller = caller; no strict "refs"; { - *{"${caller}::configDumpENV"} = \&dumpENV; - *{"${caller}::anon"} = \&anon; - *{"${caller}::SQL"} = \&SQL; + *{"${caller}::configDumpENV"} = \&dumpENV; + *{"${caller}::anon"} = \&anon; + *{"${caller}::SQL"} = \&SQL; } return 1; } +our $meta_has_priority = meta_has_priority(); +our $meta_priority = meta_priority(); +our $meta_on_demand = meta_on_demand(); +### +# The metaverse is that further this can be expanded, +# to provide further dynamic meta processing of the property value of an anon. +# When the future becomes life in anonymity, unknown variables best describe the meta state. +## +package META_PROCESS { + sub constance{ + my($class, $set) = @_; + if(!$set){ + $set = {anonymous=>'*'} + } + bless $set, $class + } + sub process{ + my($self, $property, $val) = @_; + if($self->{anonymous} ne '*'){ + return $self->{anonymous}($property,$val) + } + return $val; + } +} +use constant META => META_PROCESS->constance(); +use constant META_TO_JSON => META_PROCESS->constance({anonymous=>*_to_JSON}); +sub _to_JSON { +my($property, $val) = @_; +return <<__JSON +{"$property"="$val"} +__JSON +} + + + ### -# Post parsing instructed special item objects. +# Post parsing instructed special item objects. They have lower priority to Order of apperance and from CNFNodes. ## package InstructedDataItem { - our $dataItemCounter = int(0); + our $dataItemCounter = int(0); sub new { my ($class, $ele, $ins, $val) = @_; - my $priority = ($val =~ s/CNFMETA::HAS_PRIORITY//sexi)?1:0; + my $priority = ($val =~ s/$meta_has_priority/""/sexi)?2:3; $val =~ s/$meta_priority/""/sexi; + $priority = $2 if $2; bless { ele => $ele, aid => $dataItemCounter++, ins => $ins, val => $val, - priority => $priority + '^' => $priority }, $class } sub toString { @@ -136,6 +172,7 @@ package InstructedDataItem { # PropertyValueStyle objects must have same rule of how an property body can be scripted for attributes. ## package PropertyValueStyle { + sub new { my ($class, $element, $script, $self) = @_; $self = {} if not $self; @@ -160,8 +197,7 @@ package PropertyValueStyle { sub setPlugin{ my ($self, $obj) = @_; $self->{plugin} = $obj; - } - + } sub result { my ($self, $value) = @_; $self->{value} = $value; @@ -169,36 +205,6 @@ package PropertyValueStyle { } # -### -# The metaverse is that further this can be expanded, -# to provide further dynamic meta processing of the property value of an anon. -# When the future becomes life in anonymity, unknown variables best describe the meta state. -## -package META_PROCESS { - sub constance{ - my($class, $set) = @_; - if(!$set){ - $set = {anonymous=>'*'} - } - bless $set, $class - } - sub process{ - my($self, $property, $val) = @_; - if($self->{anonymous} ne '*'){ - return $self->{anonymous}($property,$val) - } - return $val; - } -} -use constant META => META_PROCESS->constance(); -use constant META_TO_JSON => META_PROCESS->constance({anonymous=>*_to_JSON}); -sub _to_JSON { -my($property, $val) = @_; -return <<__JSON -{"$property"="$val"} -__JSON -} - ### # Anon properties are public variables. Constance's are protected and instance specific, both config file provided (parsed in). # Anon properties of an config instance are global by default, means they can also be statically accessed, i.e. CNFParser::anon(NAME) @@ -373,7 +379,7 @@ sub template { my ($self, $property, %macros) = @_; #private to parser sub. sub doInstruction { my ($self,$e,$t,$v) = @_; - my $DO_ENABLED = $self->{'DO_ENABLED'}; + my $DO_ENABLED = $self->{'DO_ENABLED'}; my $priority = 0; $t = "" if not defined $t; if($t eq 'CONST' or $t eq 'CONSTANT'){#Single constant with mulit-line value; @@ -499,9 +505,20 @@ sub doInstruction { my ($self,$e,$t,$v) = @_; }elsif($t eq 'INCLUDE'){ $includes{$e} = {loaded=>0,path=>$e,v=>$v}; }elsif($t eq 'TREE'){ - my $tree = CNFNode->new({'_'=>$e,'~'=>$v}); + my $tree = 0; + if (!$v){ + $v = $e; + $e = 'LAST_DO'; + } + if( $v =~ s/($meta_has_priority)/""/ei){ + $priority = 1; + } + if( $v =~ s/$meta_priority/""/sexi){ + $priority = $2; + } + $tree = CNFNode->new({'_'=>$e,'~'=>$v,'^'=>$priority}); $tree->{DEBUG} = 1 if $self->{DEBUG}; - $instructs{$e} = $tree; + $instructs{$e} = $tree; }elsif($t eq 'TABLE'){ # This has now be late bound and send to the CNFSQL package. since v.2.6 SQL()->createTable($e,$v) } # It is hardly been used. But in future itt might change. elsif($t eq 'INDEX'){ SQL()->createIndex($v)} @@ -516,9 +533,14 @@ sub doInstruction { my ($self,$e,$t,$v) = @_; $v = $e; $e = 'LAST_DO'; } - my $meta = meta(ON_DEMAND()); - if($v=~ s/($meta)//i){ - $anons->{$e} = CNFNode -> new({'_'=>$e,'&'=>$v}); + if( $v =~ s/($meta_has_priority)/""/ei){ + $priority = 1; + } + if( $v =~ s/($meta_priority)/""/sexi){ + $priority = $2; + } + if($v=~ s/($meta_on_demand)/""/ei){ + $anons->{$e} = CNFNode -> new({'_'=>$e,'&'=>$v,'^'=>$priority}); return; } ## no critic BuiltinFunctions::ProhibitStringyEval @@ -572,8 +594,7 @@ sub doInstruction { my ($self,$e,$t,$v) = @_; } } elsif($t eq 'MACRO'){ - $instructs{$e}=$v; - + $instructs{$e}=$v; }else{ #Register application statement as either an anonymous one. Or since v.1.2 a listing type tag. if($e !~ /\$\$$/){ #<- It is not matching {name}$$ here. @@ -806,9 +827,9 @@ sub parse { my ($self, $cnf_file, $content, $del_keys) = @_; doInstruction($self,$e,$t,$v) } } - #Do smart instructions and property linking. - if(%instructs){ - my @ditms; + ### Do the smart instructions and property linking. + if(%instructs){ + my @items; foreach my $e(keys %instructs){ my $struct = $instructs{$e}; my $type = ref($struct); @@ -827,53 +848,34 @@ sub parse { my ($self, $cnf_file, $content, $del_keys) = @_; } $anons->{$e}=$v; }else{ - $ditms[@ditms] = $struct; + $items[@items] = $struct; } } - my @del; my $meta = meta(HAS_PRIORITY()); - for my $idx(0..$#ditms) { - my $struct = $ditms[$idx]; + + @items = sort {$a->{'^'} <=> $b->{'^'}} @items; #sort by priority; + + for my $idx(0..$#items) { + my $struct = $items[$idx]; my $type = ref($struct); - if($type eq 'CNFNode' && ($struct->{'~'} =~ s/$meta//i)){ # This will trim out the flag within if found. + if($type eq 'CNFNode' && $struct-> priority() > 0){ $struct->validate() if $self->{ENABLE_WARNINGS}; - $anons ->{$struct->name()} = $struct->process($self, $struct->script()); - push @del, $idx; + $anons ->{$struct->name()} = $struct->process($self, $struct->script()); + splice @items, $idx, 1 } } - while(@del){ - splice @ditms,pop @del, 1 - } - - for my $idx(0..$#ditms) { - my $struct = $ditms[$idx]; + #Now only what is left instructed data items or plugins, and nodes that have assigned last priority, if any. + for my $idx(0..$#items) { + my $struct = $items[$idx]; my $type = ref($struct); if($type eq 'CNFNode'){ $struct->validate() if $self->{ENABLE_WARNINGS}; - $anons->{$struct->name()} = $struct->process($self, $struct->script()); - push @del, $idx; - }elsif($type eq 'InstructedDataItem' && $struct->{'priority'} || $struct->{'val'} =~ s/$meta//i){ + $anons->{$struct->name()} = $struct->process($self, $struct->script()); + }elsif($type eq 'InstructedDataItem'){ my $t = $struct->{ins}; if($t eq 'PLUGIN'){ instructPlugin($self,$struct,$anons); - } - push @del, $idx; - } - } - while(@del){ - splice @ditms,pop @del, 1 - } - - @ditms = sort {$a->{aid} <=> $b->{aid}} @ditms if $#ditms > 1; - foreach my $struct(@ditms){ - my $type = ref($struct); - if($type eq 'InstructedDataItem'){ - my $t = $struct->{ins}; - if($t eq 'PLUGIN'){ - instructPlugin($self,$struct,$anons); - }else{ - warn "Undefined instruction detected: ".$struct->toString() - } - } + } + }else{warn "What is -> $struct type:$type ?"} } undef %instructs; } @@ -1170,7 +1172,11 @@ our $JSON; sub JSON { my $self = shift; if(!$JSON){ - require CNFtoJSON; $JSON = CNFtoJSON-> new(); + require CNFJSON; + $JSON = CNFJSON-> new( {CNF_VERSION=>$self->{CNF_VERSION}, + CNF_CONTENT=>$self->{CNF_CONTENT}, + DO_ENABLED=>$self->{DO_ENABLED} + } ); } return $JSON; } diff --git a/htdocs/cgi-bin/system/modules/HTMLIndexProcessorPlugin.pm b/htdocs/cgi-bin/system/modules/HTMLIndexProcessorPlugin.pm index 1df0a75..aca2573 100644 --- a/htdocs/cgi-bin/system/modules/HTMLIndexProcessorPlugin.pm +++ b/htdocs/cgi-bin/system/modules/HTMLIndexProcessorPlugin.pm @@ -76,7 +76,7 @@ try{ } $arr = $link -> find('STYLE'); if(ref($arr) eq 'ARRAY'){ - foreach (@$arr){ + foreach (@$arr){ $give_me .= "\n\n" }}else{ $give_me .= "\n\n" diff --git a/htdocs/cgi-bin/system/modules/HTMLProcessorPlugin.pm b/htdocs/cgi-bin/system/modules/HTMLProcessorPlugin.pm new file mode 100644 index 0000000..ba7b641 --- /dev/null +++ b/htdocs/cgi-bin/system/modules/HTMLProcessorPlugin.pm @@ -0,0 +1,203 @@ +### +# HTML converter Plugin from PerlCNF to HTML from TREE instucted properties. +# Processing of these is placed in the data parsers data. +# Programed by : Will Budic +# Notice - This source file is copied and usually placed in a local directory, outside of its project. +# So it could not be the actual or current version, can vary or has been modiefied for what ever purpose in another project. +# Please leave source of origin in this file for future references. +# Source of Origin : https://github.com/wbudic/PerlCNF.git +# Documentation : Specifications_For_CNF_ReadMe.md +# Open Source Code License -> https://choosealicense.com/licenses/isc/ +# +package HTMLProcessorPlugin; + +use strict; +use warnings; +use Syntax::Keyword::Try; +use Exception::Class ('HTMLProcessorPluginException'); +use feature qw(signatures); +use Scalar::Util qw(looks_like_number); +use Date::Manip; + +sub new ($class, $fields={Language=>'English',DateFormat=>'US'}){ + + if(ref($fields) eq 'REF'){ + warn "Hash reference required as argument for fields!" + } + my $lang = $fields->{'Language'}; + my $frmt = $fields->{'DateFormat'}; + Date_Init("Language=$lang","DateFormat=$frmt"); + + return bless $fields, $class +} + +### +# Process config data to contain expected fields and data. +### +sub convert ($self, $parser, $property) { + my ($bfHDR,$style,$jscript,$title, $link, $body_attrs, $header)=("","","","","","",""); + $self->{CNFParser} = $parser; + + my $tree = $parser->anon($property); + die "Tree property '$property' is not available!" if(!$tree or ref($tree) ne 'CNFNode'); + +try{ + $header = $parser-> {'HTTP_HEADER'} if exists $parser->{'HTTP_HEADER'}; + $title = $tree -> {'Title'} if exists $tree->{'Title'}; + $link = $tree -> {'HEADER'}; + $body_attrs .= " ". $tree -> {'Body'} if exists $tree -> {'Body'}; + if($link){ + if(ref($link) eq 'CNFNode'){ + my $arr = $link->find('CSS/@@'); + foreach (@$arr){ + my $v = $_->val(); + $bfHDR .= qq(\t\n); + } + $arr = $link->find('JS/@@'); + foreach (@$arr){ + my $v = $_->val(); + $bfHDR .= qq(\t\n); + } + my $ps = $link -> find('STYLE'); + $style = "\n" if($ps); + $ps = $link -> find('JAVASCRIPT'); + $jscript = "\n" if($ps); + } + + delete $tree -> {'HEADER'}; + } + + my $buffer = qq($header + + +$title$bfHDR $style $jscript + +); + + $buffer .= qq(\n
\n); + foreach + my $node($tree->nodes()){ + my $bf = build($parser, $node); + $buffer .= "$bf\n" if $node; + } + $buffer .= "\n
\n\n\n"; + + $parser->data()->{$property} = \$buffer; + +}catch{ + HTMLProcessorPluginException->throw(error=>$@ ,show_trace=>1); +} +} +# + +### +# Builds the html version out of a CNFNode. +# CNFNode with specific tags here are converted also here, +# those that are out of the scope for normal standard HTML tags. +# i.e. HTML doesn't have row and cell tags. Neither has meta links syntax. +### +sub build { + my $parser = shift; + my $node = shift; + my $tabs = shift; $tabs = 1 if !$tabs; + my $bf; + my $name = lc $node->name(); + if(isParagraphName($name)){ + $bf .= "\t"x$tabs."\n"."\t"x$tabs."
"; + foreach my $n($node->nodes()){ + if($n->{'_'} ne '#'){ + my $b = build($parser, $n, $tabs+1); + $bf .= "$b\n" if $b; + } + } + if($node->{'#'}){ + my $v = $node->val(); + $v =~ s/\n\n+/\<\/br>\n/gs; + $bf .= "\t
\n\t

\n".$v."

\n\t
\n"; + } + $bf .= "\t
\t\n" + }elsif( $name eq 'row' || $name eq 'cell' ){ + $bf .= "\t"x$tabs."
\n"; + foreach my $n($node->nodes()){ + if($n->{'_'} ne '#'){ + my $b = build($parser,$n,$tabs+1); + $bf .= "$b\n" if $b; + } + } + $bf .= $node->val()."\n" if $node->{'#'}; + $bf .= "\t"x$tabs."
" + }elsif( $name eq 'img' ){ + $bf .= "\t\t\n"; + }elsif($name eq 'list_images'){ + my $paths = $node->{'@@'}; + foreach my $ndp (@$paths){ + my $path = $ndp -> val(); + my @ext = split(',',"jpg,jpeg,png,gif"); + my $exp = " ".$path."/*.". join (" ".$path."/*.", @ext); + my @images = glob($exp); + $bf .= "\t
Directory: $path
"; + foreach my $file(@images){ + ($file=~/.*\/(.*)$/); + my $fn = $1; + my $enc = "img@".ShortLink::obtain($file); + $bf .= qq(\t
); + $bf .= qq(\t
$fn
\n
\n); + } + } + }elsif($node->{'*'}){ #Links are already captured, in future this might be needed as a relink from here for dynamic stuff? + my $lval = $node->{'*'}; + if($name eq 'file_list_html'){ #Special case where html links are provided. + foreach(split(/\n/,$lval)){ + $bf .= qq( [ $_ ] |) if $_ + } + $bf =~ s/\|$//g; + }else{ #Generic included link value. + #is there property data for it? + my $prop = $parser->data()->{$node->name()}; + warn "Not found as property link -> ".$node->name() if !$prop; + if($prop){ + $bf .= $$prop; + }else{ + $bf .= $lval; + } + } + } + else{ + $bf .= "\t"x$tabs."<".$node->name().placeAttributes($node).">"; + foreach my $n($node->nodes()){ + my $b = build($parser, $n,$tabs+1); + $bf .= "$b\n" if $b; + } + $bf .= $node->val() if $node->{'#'}; + $bf .= "name().">"; + + } + return $bf; +} +# + + +sub placeAttributes { + my $node = shift; + my $ret = ""; + my @attr = $node -> attributes(); + foreach (@attr){ + if(@$_[0] ne '#' && @$_[0] ne '_'){ + if(@$_[1]){ + $ret .= " ".@$_[0]."=\"".@$_[1]."\""; + }else{ + $ret .= " ".@$_[0]." "; + } + } + } + return $ret; +} + +sub isParagraphName { + my $name = shift; + return $name eq 'p' || $name eq 'paragraph' ? 1 : 0 +} + + + +1; \ No newline at end of file